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