xref: /aoo4110/main/idlc/source/astunion.cxx (revision b1cdbd2c)
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