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