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