1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_idlc.hxx"
26 #include <idlc/astunion.hxx>
27 #include <idlc/astbasetype.hxx>
28 #include <idlc/errorhandler.hxx>
29
30 #include "registry/version.h"
31 #include "registry/writer.hxx"
32
33 using namespace ::rtl;
34
AstUnion(const::rtl::OString & name,AstType * pDiscType,AstScope * pScope)35 AstUnion::AstUnion(const ::rtl::OString& name, AstType* pDiscType, AstScope* pScope)
36 : AstStruct(NT_union, name, NULL, pScope)
37 , m_pDiscriminantType(pDiscType)
38 , m_discExprType(ET_long)
39 {
40 AstBaseType* pBaseType;
41
42 if ( !pDiscType )
43 {
44 m_pDiscriminantType = NULL;
45 m_discExprType = ET_none;
46 return;
47 }
48 /*
49 * If the discriminator type is a predefined type
50 * then install the equivalent coercion target type in
51 * the pd_udisc_type field.
52 */
53 if ( pDiscType->getNodeType() == NT_predefined )
54 {
55 pBaseType = (AstBaseType*)pDiscType;
56 if ( !pBaseType )
57 {
58 m_pDiscriminantType = NULL;
59 m_discExprType = ET_none;
60 return;
61 }
62 m_pDiscriminantType = pDiscType;
63 switch (pBaseType->getExprType())
64 {
65 case ET_long:
66 case ET_ulong:
67 case ET_short:
68 case ET_ushort:
69 case ET_char:
70 case ET_boolean:
71 m_discExprType = pBaseType->getExprType();
72 break;
73 default:
74 m_discExprType = ET_none;
75 m_pDiscriminantType = NULL;
76 break;
77 }
78 } else
79 if (pDiscType->getNodeType() == NT_enum)
80 {
81 m_discExprType = ET_any;
82 m_pDiscriminantType = pDiscType;
83 } else
84 {
85 m_discExprType = ET_none;
86 m_pDiscriminantType = NULL;
87 }
88
89 if ( !m_pDiscriminantType )
90 idlc()->error()->error2(EIDL_DISC_TYPE, this, pDiscType);
91 }
92
~AstUnion()93 AstUnion::~AstUnion()
94 {
95 }
96
addDeclaration(AstDeclaration * pDecl)97 AstDeclaration* AstUnion::addDeclaration(AstDeclaration* pDecl)
98 {
99 if ( pDecl->getNodeType() == NT_union_branch )
100 {
101 AstUnionBranch* pBranch = (AstUnionBranch*)pDecl;
102 if ( lookupBranch(pBranch) )
103 {
104 idlc()->error()->error2(EIDL_MULTIPLE_BRANCH, this, pDecl);
105 return NULL;
106 }
107 }
108
109 return AstScope::addDeclaration(pDecl);
110 }
111
lookupBranch(AstUnionBranch * pBranch)112 AstUnionBranch* AstUnion::lookupBranch(AstUnionBranch* pBranch)
113 {
114 AstUnionLabel* pLabel = NULL;
115
116 if ( pBranch )
117 pLabel = pBranch->getLabel();
118
119 if ( pLabel )
120 {
121 if (pLabel->getLabelKind() == UL_default)
122 return lookupDefault();
123 if (m_discExprType == ET_any)
124 /* CONVENTION: indicates enum discr */
125 return lookupEnum(pBranch);
126 return lookupLabel(pBranch);
127 }
128 return NULL;
129 }
130
lookupDefault(sal_Bool bReportError)131 AstUnionBranch* AstUnion::lookupDefault(sal_Bool bReportError)
132 {
133 DeclList::const_iterator iter = getIteratorBegin();
134 DeclList::const_iterator end = getIteratorEnd();
135 AstUnionBranch *pBranch = NULL;
136 AstDeclaration *pDecl = NULL;
137
138 while ( iter != end )
139 {
140 pDecl = *iter;
141 if ( pDecl->getNodeType() == NT_union_branch )
142 {
143 pBranch = (AstUnionBranch*)pDecl;
144 if (pBranch == NULL)
145 {
146 ++iter;
147 continue;
148 }
149 if ( pBranch->getLabel() != NULL &&
150 pBranch->getLabel()->getLabelKind() == UL_default)
151 {
152 if ( bReportError )
153 idlc()->error()->error2(EIDL_MULTIPLE_BRANCH, this, pBranch);
154 return pBranch;
155 }
156 }
157 ++iter;
158 }
159 return NULL;
160 }
161
lookupLabel(AstUnionBranch * pBranch)162 AstUnionBranch* AstUnion::lookupLabel(AstUnionBranch* pBranch)
163 {
164 AstUnionLabel* pLabel = pBranch->getLabel();
165
166 if ( !pLabel->getLabelValue() )
167 return pBranch;
168 // pLabel->getLabelValue()->setExprValue(pLabel->getLabelValue()->coerce(m_discExprType, sal_False));
169 AstExprValue* pLabelValue = pLabel->getLabelValue()->coerce(
170 m_discExprType, sal_False);
171 if ( !pLabelValue )
172 {
173 idlc()->error()->evalError(pLabel->getLabelValue());
174 return pBranch;
175 } else
176 {
177 pLabel->getLabelValue()->setExprValue(pLabelValue);
178 }
179
180 DeclList::const_iterator iter = getIteratorBegin();
181 DeclList::const_iterator end = getIteratorEnd();
182 AstUnionBranch* pB = NULL;
183 AstDeclaration* pDecl = NULL;
184
185 while ( iter != end )
186 {
187 pDecl = *iter;
188 if ( pDecl->getNodeType() == NT_union_branch )
189 {
190 pB = (AstUnionBranch*)pDecl;
191 if ( !pB )
192 {
193 ++iter;
194 continue;
195 }
196 if ( pB->getLabel() != NULL &&
197 pB->getLabel()->getLabelKind() == UL_label &&
198 pB->getLabel()->getLabelValue()->compare(pLabel->getLabelValue()) )
199 {
200 idlc()->error()->error2(EIDL_MULTIPLE_BRANCH, this, pBranch);
201 return pBranch;
202 }
203 }
204 ++iter;
205 }
206 return NULL;
207 }
208
lookupEnum(AstUnionBranch * pBranch)209 AstUnionBranch* AstUnion::lookupEnum(AstUnionBranch* pBranch)
210 {
211 AstDeclaration const * pType = resolveTypedefs(m_pDiscriminantType);
212 if ( pType->getNodeType() != NT_enum )
213 return NULL;
214
215 AstUnionLabel* pLabel = pBranch->getLabel();
216 AstExpression* pExpr = pLabel->getLabelValue();
217 if ( !pExpr )
218 return pBranch;
219
220 /*
221 * Expecting a symbol label
222 */
223 if ( pExpr->getCombOperator() != EC_symbol)
224 {
225 idlc()->error()->enumValExpected(this);
226 return pBranch;
227 }
228
229 /*
230 * See if the symbol defines a constant in the discriminator enum
231 */
232 AstEnum* pEnum = (AstEnum*)pType;
233 AstDeclaration* pDecl = pEnum->lookupByName(*pExpr->getSymbolicName());
234 if ( pDecl == NULL || pDecl->getScope() != pEnum)
235 {
236 idlc()->error()->enumValLookupFailure(this, pEnum, *pExpr->getSymbolicName());
237 return pBranch;
238 }
239
240
241 DeclList::const_iterator iter = getIteratorBegin();
242 DeclList::const_iterator end = getIteratorEnd();
243 AstUnionBranch* pB = NULL;
244 pDecl = NULL;
245
246 while ( iter != end )
247 {
248 pDecl = *iter;
249 if ( pDecl->getNodeType() == NT_union_branch )
250 {
251 pB = (AstUnionBranch*)pDecl;
252 if ( !pB )
253 {
254 ++iter;
255 continue;
256 }
257 if ( pB->getLabel() != NULL &&
258 pB->getLabel()->getLabelKind() == UL_label &&
259 pB->getLabel()->getLabelValue()->compare(pLabel->getLabelValue()) )
260 {
261 idlc()->error()->error2(EIDL_MULTIPLE_BRANCH, this, pBranch);
262 return pBranch;
263 }
264 }
265 ++iter;
266 }
267 return NULL;
268 }
269
dump(RegistryKey & rKey)270 sal_Bool AstUnion::dump(RegistryKey& rKey)
271 {
272 RegistryKey localKey;
273 if (rKey.createKey( OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8 ), localKey))
274 {
275 fprintf(stderr, "%s: warning, could not create key '%s' in '%s'\n",
276 idlc()->getOptions()->getProgramName().getStr(),
277 getFullName().getStr(), OUStringToOString(rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr());
278 return sal_False;
279 }
280
281 sal_uInt16 nMember = getNodeCount(NT_union_branch);
282
283 OUString emptyStr;
284 typereg::Writer aBlob(
285 TYPEREG_VERSION_0, getDocumentation(), emptyStr, RT_TYPE_UNION,
286 false, OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), 1,
287 nMember, 0, 0);
288 aBlob.setSuperTypeName(
289 0,
290 OStringToOUString(
291 getDiscrimantType()->getScopedName(), RTL_TEXTENCODING_UTF8));
292
293 if ( nMember > 0 )
294 {
295 DeclList::const_iterator iter = getIteratorBegin();
296 DeclList::const_iterator end = getIteratorEnd();
297 AstDeclaration* pDecl = NULL;
298 AstUnionBranch* pBranch = NULL;
299 AstUnionBranch* pDefault = lookupDefault(sal_False);
300 AstUnionLabel* pLabel = NULL;
301 AstExprValue* pExprValue = NULL;
302 RTConstValue aConst;
303 RTFieldAccess access = RT_ACCESS_READWRITE;
304 OUString docu;
305 sal_uInt16 index = 0;
306 if ( pDefault )
307 index = 1;
308
309 sal_Int64 disc = 0;
310 while ( iter != end )
311 {
312 pDecl = *iter;
313 if ( pDecl->getNodeType() == NT_union_branch )
314 {
315 pBranch = (AstUnionBranch*)pDecl;
316 if (pBranch == pDefault)
317 {
318 ++iter;
319 continue;
320 }
321
322 pLabel = pBranch->getLabel();
323 pExprValue = pLabel->getLabelValue()->coerce(ET_hyper, sal_False);
324 aConst.m_type = RT_TYPE_INT64;
325 aConst.m_value.aHyper = pExprValue->u.hval;
326 if ( aConst.m_value.aHyper > disc )
327 disc = aConst.m_value.aHyper;
328
329 aBlob.setFieldData(
330 index++, pBranch->getDocumentation(), emptyStr, RT_ACCESS_READWRITE,
331 OStringToOUString(
332 pBranch->getLocalName(), RTL_TEXTENCODING_UTF8),
333 OStringToOUString(
334 pBranch->getType()->getRelativName(),
335 RTL_TEXTENCODING_UTF8),
336 aConst);
337 }
338 ++iter;
339 }
340
341 if ( pDefault )
342 {
343 access = RT_ACCESS_DEFAULT;
344 aConst.m_type = RT_TYPE_INT64;
345 aConst.m_value.aHyper = disc + 1;
346 aBlob.setFieldData(
347 0, pDefault->getDocumentation(), emptyStr, RT_ACCESS_DEFAULT,
348 OStringToOUString(
349 pDefault->getLocalName(), RTL_TEXTENCODING_UTF8),
350 OStringToOUString(
351 pDefault->getType()->getRelativName(),
352 RTL_TEXTENCODING_UTF8),
353 aConst);
354 }
355 }
356
357 sal_uInt32 aBlobSize;
358 void const * pBlob = aBlob.getBlob(&aBlobSize);
359
360 if (localKey.setValue(OUString(), RG_VALUETYPE_BINARY,
361 (RegValue)pBlob, aBlobSize))
362 {
363 fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n",
364 idlc()->getOptions()->getProgramName().getStr(),
365 getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr());
366 return sal_False;
367 }
368
369 return sal_True;
370 }
371
AstUnionBranch(AstUnionLabel * pLabel,AstType const * pType,const::rtl::OString & name,AstScope * pScope)372 AstUnionBranch::AstUnionBranch(AstUnionLabel* pLabel, AstType const * pType, const ::rtl::OString& name, AstScope* pScope)
373 : AstMember(NT_union_branch, pType, name, pScope)
374 , m_pLabel(pLabel)
375 {
376 }
377
~AstUnionBranch()378 AstUnionBranch::~AstUnionBranch()
379 {
380 if ( m_pLabel )
381 delete m_pLabel;
382 }
383
AstUnionLabel(UnionLabel labelKind,AstExpression * pExpr)384 AstUnionLabel::AstUnionLabel(UnionLabel labelKind, AstExpression* pExpr)
385 : m_label(labelKind)
386 , m_pLabelValue(pExpr)
387 {
388 if ( m_pLabelValue )
389 m_pLabelValue->evaluate(EK_const);
390 }
391
~AstUnionLabel()392 AstUnionLabel::~AstUnionLabel()
393 {
394 if ( m_pLabelValue )
395 delete m_pLabelValue;
396 }
397
398