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