root/branches/dmdfe-2.0/enum.c

Revision 905, 8.8 kB (checked in by Gregor, 3 months ago)

MERGE: DMD 2.016

Line 
1 // Copyright (c) 1999-2008 by Digital Mars
2 // All Rights Reserved
3 // written by Walter Bright
4 // http://www.digitalmars.com
5 // License for redistribution is by either the Artistic License
6 // in artistic.txt, or the GNU General Public License in gnu.txt.
7 // See the included readme.txt for details.
8
9 #include <stdio.h>
10 #include <assert.h>
11
12 #include "root.h"
13 #include "enum.h"
14 #include "mtype.h"
15 #include "scope.h"
16 #include "id.h"
17 #include "expression.h"
18 #include "module.h"
19 #include "declaration.h"
20
21 /********************************* EnumDeclaration ****************************/
22
23 EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
24     : ScopeDsymbol(id)
25 {
26     this->loc = loc;
27     type = new TypeEnum(this);
28     this->memtype = memtype;
29     maxval = NULL;
30     minval = NULL;
31     defaultval = NULL;
32     sinit = NULL;
33     scope = NULL;
34     isdeprecated = 0;
35 }
36
37 Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
38 {
39     Type *t = NULL;
40     if (memtype)
41     t = memtype->syntaxCopy();
42
43     EnumDeclaration *ed;
44     if (s)
45     {   ed = (EnumDeclaration *)s;
46     ed->memtype = t;
47     }
48     else
49     ed = new EnumDeclaration(loc, ident, t);
50     ScopeDsymbol::syntaxCopy(ed);
51     return ed;
52 }
53
54 void EnumDeclaration::semantic(Scope *sc)
55 {
56     Type *t;
57     Scope *sce;
58
59     //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
60     //printf("EnumDeclaration::semantic() %s\n", toChars());
61     if (!members)       // enum ident;
62     return;
63
64     if (!memtype && !isAnonymous())
65     {   // Set memtype if we can to reduce fwd reference errors
66     memtype = Type::tint32; // case 1)  enum ident { ... }
67     }
68
69     if (symtab)         // if already done
70     {   if (!scope)
71         return;     // semantic() already completed
72     }
73     else
74     symtab = new DsymbolTable();
75
76     Scope *scx = NULL;
77     if (scope)
78     {   sc = scope;
79         scx = scope;            // save so we don't make redundant copies
80         scope = NULL;
81     }
82
83     if (sc->stc & STCdeprecated)
84     isdeprecated = 1;
85
86     parent = sc->parent;
87
88     /* The separate, and distinct, cases are:
89      *  1. enum { ... }
90      *  2. enum : memtype { ... }
91      *  3. enum ident { ... }
92      *  4. enum ident : memtype { ... }
93      */
94
95     if (memtype)
96     {
97     memtype = memtype->semantic(loc, sc);
98
99     /* Check to see if memtype is forward referenced
100      */
101     if (memtype->ty == Tenum)
102     {   EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
103         if (!sym->memtype || !sym->members || !sym->symtab || sym->scope)
104         {   // memtype is forward referenced, so try again later
105         scope = scx ? scx : new Scope(*sc);
106         scope->setNoFree();
107         scope->module->addDeferredSemantic(this);
108         printf("\tdeferring %s\n", toChars());
109         return;
110         }
111     }
112 #if 0   // Decided to abandon this restriction for D 2.0
113     if (!memtype->isintegral())
114     {   error("base type must be of integral type, not %s", memtype->toChars());
115         memtype = Type::tint32;
116     }
117 #endif
118     }
119
120     type = type->semantic(loc, sc);
121     if (isAnonymous())
122         sce = sc;
123     else
124     {   sce = sc->push(this);
125     sce->parent = this;
126     }
127     if (members->dim == 0)
128     error("enum %s must have at least one member", toChars());
129     int first = 1;
130     Expression *elast = NULL;
131     for (int i = 0; i < members->dim; i++)
132     {
133     EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember();
134     Expression *e;
135
136     if (!em)
137         /* The e->semantic(sce) can insert other symbols, such as
138          * template instances and function literals.
139          */
140         continue;
141
142     //printf("  Enum member '%s'\n",em->toChars());
143     if (em->type)
144         em->type = em->type->semantic(em->loc, sce);
145     e = em->value;
146     if (e)
147     {
148         assert(e->dyncast() == DYNCAST_EXPRESSION);
149         e = e->semantic(sce);
150         e = e->optimize(WANTvalue | WANTinterpret);
151         if (memtype)
152         {
153         e = e->implicitCastTo(sce, memtype);
154         e = e->optimize(WANTvalue | WANTinterpret);
155         if (!isAnonymous())
156             e = e->castTo(sce, type);
157         t = memtype;
158         }
159         else if (em->type)
160         {
161         e = e->implicitCastTo(sce, em->type);
162         e = e->optimize(WANTvalue | WANTinterpret);
163         assert(isAnonymous());
164         t = e->type;
165         }
166         else
167         t = e->type;
168     }
169     else if (first)
170     {
171         if (memtype)
172         t = memtype;
173         else if (em->type)
174         t = em->type;
175         else
176         t = Type::tint32;
177         e = new IntegerExp(em->loc, 0, Type::tint32);
178         e = e->implicitCastTo(sce, t);
179         e = e->optimize(WANTvalue | WANTinterpret);
180         if (!isAnonymous())
181         e = e->castTo(sce, type);
182     }
183     else
184     {
185         // Set value to (elast + 1).
186         // But first check that (elast != t.max)
187         assert(elast);
188         e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max));
189         e = e->semantic(sce);
190         e = e->optimize(WANTvalue | WANTinterpret);
191         if (e->toInteger())
192         error("overflow of enum value %s", elast->toChars());
193
194         // Now set e to (elast + 1)
195         e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32));
196         e = e->semantic(sce);
197         e = e->castTo(sce, elast->type);
198         e = e->optimize(WANTvalue | WANTinterpret);
199     }
200     elast = e;
201     em->value = e;
202
203     // Add to symbol table only after evaluating 'value'
204     if (isAnonymous())
205     {
206         /* Anonymous enum members get added to enclosing scope.
207          */
208         for (Scope *scx = sce; scx; scx = scx->enclosing)
209         {
210         if (scx->scopesym)
211         {
212             if (!scx->scopesym->symtab)
213             scx->scopesym->symtab = new DsymbolTable();
214             em->addMember(sce, scx->scopesym, 1);
215             break;
216         }
217         }
218     }
219     else
220         em->addMember(sc, this, 1);
221
222     /* Compute .min, .max and .default values.
223      * If enum doesn't have a name, we can never identify the enum type,
224      * so there is no purpose for a .min, .max or .default
225      */
226     if (!isAnonymous())
227     {
228         if (first)
229         {   defaultval = e;
230         minval = e;
231         maxval = e;
232         }
233         else
234         {   Expression *ec;
235
236         /* In order to work successfully with UDTs,
237          * build expressions to do the comparisons,
238          * and let the semantic analyzer and constant
239          * folder give us the result.
240          */
241
242         // Compute if(e < minval)
243         ec = new CmpExp(TOKlt, em->loc, e, minval);
244         ec = ec->semantic(sce);
245         ec = ec->optimize(WANTvalue | WANTinterpret);
246         if (ec->toInteger())
247             minval = e;
248
249         ec = new CmpExp(TOKgt, em->loc, e, maxval);
250         ec = ec->semantic(sce);
251         ec = ec->optimize(WANTvalue | WANTinterpret);
252         if (ec->toInteger())
253             maxval = e;
254         }
255     }
256     first = 0;
257     }
258     //printf("defaultval = %lld\n", defaultval);
259
260     //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
261     if (sc != sce)
262     sce->pop();
263     //members->print();
264 }
265
266 int EnumDeclaration::oneMember(Dsymbol **ps)
267 {
268     if (isAnonymous())
269     return Dsymbol::oneMembers(members, ps);
270     return Dsymbol::oneMember(ps);
271 }
272
273 void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
274 {   int i;
275
276     buf->writestring("enum ");
277     if (ident)
278     {   buf->writestring(ident->toChars());
279     buf->writeByte(' ');
280     }
281     if (memtype)
282     {
283     buf->writestring(": ");
284     memtype->toCBuffer(buf, NULL, hgs);
285     }
286     if (!members)
287     {
288     buf->writeByte(';');
289     buf->writenl();
290     return;
291     }
292     buf->writenl();
293     buf->writeByte('{');
294     buf->writenl();
295     for (i = 0; i < members->dim; i++)
296     {
297     EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember();
298     if (!em)
299         continue;
300     //buf->writestring("    ");
301     em->toCBuffer(buf, hgs);
302     buf->writeByte(',');
303     buf->writenl();
304     }
305     buf->writeByte('}');
306     buf->writenl();
307 }
308
309 Type *EnumDeclaration::getType()
310 {
311     return type;
312 }
313
314 const char *EnumDeclaration::kind()
315 {
316     return "enum";
317 }
318
319 int EnumDeclaration::isDeprecated()
320 {
321     return isdeprecated;
322 }
323
324 Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags)
325 {
326     //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
327     if (scope)
328     // Try one last time to resolve this enum
329         semantic(scope);
330
331     if (!members || !symtab || scope)
332     {   error("is forward referenced when looking for '%s'", ident->toChars());
333         //*(char*)0=0;
334         return NULL;
335     }
336
337     Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
338     return s;
339 }
340
341 /********************************* EnumMember ****************************/
342
343 EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type)
344     : Dsymbol(id)
345 {
346     this->value = value;
347     this->type = type;
348     this->loc = loc;
349 }
350
351 Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
352 {
353     Expression *e = NULL;
354     if (value)
355     e = value->syntaxCopy();
356
357     Type *t = NULL;
358     if (type)
359     t = type->syntaxCopy();
360
361     EnumMember *em;
362     if (s)
363     {   em = (EnumMember *)s;
364     em->loc = loc;
365     em->value = e;
366     em->type = t;
367     }
368     else
369     em = new EnumMember(loc, ident, e, t);
370     return em;
371 }
372
373 void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
374 {
375     if (type)
376     type->toCBuffer(buf, ident, hgs);
377     else
378     buf->writestring(ident->toChars());
379     if (value)
380     {
381     buf->writestring(" = ");
382     value->toCBuffer(buf, hgs);
383     }
384 }
385
386 const char *EnumMember::kind()
387 {
388     return "enum member";
389 }
Note: See TracBrowser for help on using the browser.