Mercurial > projects > ddmd
comparison dmd/EnumDeclaration.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 427f8aa74d28 1628b221808d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:10317f0c89a5 |
---|---|
1 module dmd.EnumDeclaration; | |
2 | |
3 import dmd.ScopeDsymbol; | |
4 import dmd.AddExp; | |
5 import dmd.Type; | |
6 import dmd.CmpExp; | |
7 import dmd.IntegerExp; | |
8 import dmd.EqualExp; | |
9 import dmd.TOK; | |
10 import dmd.Id; | |
11 import dmd.TY; | |
12 import dmd.DsymbolTable; | |
13 import dmd.STC; | |
14 import dmd.Expression; | |
15 import dmd.Identifier; | |
16 import dmd.Dsymbol; | |
17 import dmd.Scope; | |
18 import dmd.OutBuffer; | |
19 import dmd.HdrGenState; | |
20 import dmd.Global; | |
21 import dmd.Loc; | |
22 import dmd.TypeEnum; | |
23 import dmd.EnumMember; | |
24 import dmd.DYNCAST; | |
25 import dmd.WANT; | |
26 import dmd.Id; | |
27 import dmd.Lexer; | |
28 | |
29 import dmd.backend.SC; | |
30 import dmd.backend.FL; | |
31 import dmd.backend.Util; | |
32 import dmd.backend.Symbol; | |
33 import dmd.backend.Classsym; | |
34 import dmd.backend.SFL; | |
35 import dmd.backend.LIST; | |
36 import dmd.codegen.Util; | |
37 | |
38 import std.stdio : writef; | |
39 | |
40 class EnumDeclaration : ScopeDsymbol | |
41 { /* enum ident : memtype { ... } | |
42 */ | |
43 Type type; // the TypeEnum | |
44 Type memtype; // type of the members | |
45 | |
46 version (DMDV1) { | |
47 ulong maxval; | |
48 ulong minval; | |
49 ulong defaultval; // default initializer | |
50 } else { | |
51 Expression maxval; | |
52 Expression minval; | |
53 Expression defaultval; // default initializer | |
54 } | |
55 bool isdeprecated; | |
56 | |
57 this(Loc loc, Identifier id, Type memtype) | |
58 { | |
59 super(id); | |
60 this.loc = loc; | |
61 type = new TypeEnum(this); | |
62 this.memtype = memtype; | |
63 } | |
64 | |
65 Dsymbol syntaxCopy(Dsymbol s) | |
66 { | |
67 assert(false); | |
68 } | |
69 | |
70 void semantic(Scope sc) | |
71 { | |
72 Type t; | |
73 Scope sce; | |
74 | |
75 //writef("EnumDeclaration.semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), toChars()); | |
76 //writef("EnumDeclaration.semantic() %s\n", toChars()); | |
77 if (!members) // enum ident; | |
78 return; | |
79 | |
80 if (!memtype && !isAnonymous()) | |
81 { | |
82 // Set memtype if we can to reduce fwd reference errors | |
83 memtype = Type.tint32; // case 1) enum ident { ... } | |
84 } | |
85 | |
86 if (symtab) // if already done | |
87 { | |
88 if (!scope_) | |
89 return; // semantic() already completed | |
90 } | |
91 else | |
92 symtab = new DsymbolTable(); | |
93 | |
94 Scope scx = null; | |
95 if (scope_) | |
96 { sc = scope_; | |
97 scx = scope_; // save so we don't make redundant copies | |
98 scope_ = null; | |
99 } | |
100 | |
101 if (sc.stc & STC.STCdeprecated) | |
102 isdeprecated = true; | |
103 | |
104 parent = sc.parent; | |
105 | |
106 /* The separate, and distinct, cases are: | |
107 * 1. enum { ... } | |
108 * 2. enum : memtype { ... } | |
109 * 3. enum ident { ... } | |
110 * 4. enum ident : memtype { ... } | |
111 */ | |
112 | |
113 if (memtype) | |
114 { | |
115 memtype = memtype.semantic(loc, sc); | |
116 | |
117 /* Check to see if memtype is forward referenced | |
118 */ | |
119 if (memtype.ty == TY.Tenum) | |
120 { EnumDeclaration sym = cast(EnumDeclaration)memtype.toDsymbol(sc); | |
121 if (!sym.memtype || !sym.members || !sym.symtab || sym.scope_) | |
122 { | |
123 // memtype is forward referenced, so try again later | |
124 scope_ = scx ? scx : new Scope(sc); | |
125 scope_.setNoFree(); | |
126 scope_.module_.addDeferredSemantic(this); | |
127 writef("\tdeferring %s\n", toChars()); | |
128 return; | |
129 } | |
130 } | |
131 static if (false) { | |
132 // Decided to abandon this restriction for D 2.0 | |
133 if (!memtype.isintegral()) | |
134 { error("base type must be of integral type, not %s", memtype.toChars()); | |
135 memtype = Type.tint32; | |
136 } | |
137 } | |
138 } | |
139 | |
140 type = type.semantic(loc, sc); | |
141 if (isAnonymous()) | |
142 sce = sc; | |
143 else | |
144 { sce = sc.push(this); | |
145 sce.parent = this; | |
146 } | |
147 if (members.dim == 0) | |
148 error("enum %s must have at least one member", toChars()); | |
149 int first = 1; | |
150 Expression elast = null; | |
151 for (int i = 0; i < members.dim; i++) | |
152 { | |
153 EnumMember em = (cast(Dsymbol)members.data[i]).isEnumMember(); | |
154 Expression e; | |
155 | |
156 if (!em) | |
157 /* The e.semantic(sce) can insert other symbols, such as | |
158 * template instances and function literals. | |
159 */ | |
160 continue; | |
161 | |
162 //printf(" Enum member '%s'\n",em.toChars()); | |
163 if (em.type) | |
164 em.type = em.type.semantic(em.loc, sce); | |
165 e = em.value; | |
166 if (e) | |
167 { | |
168 assert(e.dyncast() == DYNCAST.DYNCAST_EXPRESSION); | |
169 e = e.semantic(sce); | |
170 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
171 if (memtype) | |
172 { | |
173 e = e.implicitCastTo(sce, memtype); | |
174 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
175 if (!isAnonymous()) | |
176 e = e.castTo(sce, type); | |
177 t = memtype; | |
178 } | |
179 else if (em.type) | |
180 { | |
181 e = e.implicitCastTo(sce, em.type); | |
182 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
183 assert(isAnonymous()); | |
184 t = e.type; | |
185 } | |
186 else | |
187 t = e.type; | |
188 } | |
189 else if (first) | |
190 { | |
191 if (memtype) | |
192 t = memtype; | |
193 else if (em.type) | |
194 t = em.type; | |
195 else | |
196 t = Type.tint32; | |
197 e = new IntegerExp(em.loc, 0, Type.tint32); | |
198 e = e.implicitCastTo(sce, t); | |
199 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
200 if (!isAnonymous()) | |
201 e = e.castTo(sce, type); | |
202 } | |
203 else | |
204 { | |
205 // Set value to (elast + 1). | |
206 // But first check that (elast != t.max) | |
207 assert(elast); | |
208 e = new EqualExp(TOK.TOKequal, em.loc, elast, t.getProperty(Loc(0), Id.max)); | |
209 e = e.semantic(sce); | |
210 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
211 if (e.toInteger()) | |
212 error("overflow of enum value %s", elast.toChars()); | |
213 | |
214 // Now set e to (elast + 1) | |
215 e = new AddExp(em.loc, elast, new IntegerExp(em.loc, 1, Type.tint32)); | |
216 e = e.semantic(sce); | |
217 e = e.castTo(sce, elast.type); | |
218 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
219 } | |
220 elast = e; | |
221 em.value = e; | |
222 | |
223 // Add to symbol table only after evaluating 'value' | |
224 if (isAnonymous()) | |
225 { | |
226 /* Anonymous enum members get added to enclosing scope. | |
227 */ | |
228 for (Scope scxx = sce; scxx; scxx = scxx.enclosing) | |
229 { | |
230 if (scxx.scopesym) | |
231 { | |
232 if (!scxx.scopesym.symtab) | |
233 scxx.scopesym.symtab = new DsymbolTable(); | |
234 em.addMember(sce, scxx.scopesym, 1); | |
235 break; | |
236 } | |
237 } | |
238 } | |
239 else | |
240 em.addMember(sc, this, 1); | |
241 | |
242 /* Compute .min, .max and .default values. | |
243 * If enum doesn't have a name, we can never identify the enum type, | |
244 * so there is no purpose for a .min, .max or .default | |
245 */ | |
246 if (!isAnonymous()) | |
247 { | |
248 if (first) | |
249 { defaultval = e; | |
250 minval = e; | |
251 maxval = e; | |
252 } | |
253 else | |
254 { Expression ec; | |
255 | |
256 /* In order to work successfully with UDTs, | |
257 * build expressions to do the comparisons, | |
258 * and let the semantic analyzer and constant | |
259 * folder give us the result. | |
260 */ | |
261 | |
262 // Compute if(e < minval) | |
263 ec = new CmpExp(TOK.TOKlt, em.loc, e, minval); | |
264 ec = ec.semantic(sce); | |
265 ec = ec.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
266 if (ec.toInteger()) | |
267 minval = e; | |
268 | |
269 ec = new CmpExp(TOK.TOKgt, em.loc, e, maxval); | |
270 ec = ec.semantic(sce); | |
271 ec = ec.optimize(WANT.WANTvalue | WANT.WANTinterpret); | |
272 if (ec.toInteger()) | |
273 maxval = e; | |
274 } | |
275 } | |
276 first = 0; | |
277 } | |
278 //printf("defaultval = %lld\n", defaultval); | |
279 | |
280 //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); | |
281 if (sc != sce) | |
282 sce.pop(); | |
283 //members.print(); | |
284 } | |
285 | |
286 bool oneMember(Dsymbol* ps) | |
287 { | |
288 assert(false); | |
289 } | |
290 | |
291 void toCBuffer(OutBuffer buf, HdrGenState* hgs) | |
292 { | |
293 assert(false); | |
294 } | |
295 | |
296 Type getType() | |
297 { | |
298 return type; | |
299 } | |
300 | |
301 string kind() | |
302 { | |
303 return "enum"; | |
304 } | |
305 | |
306 version (DMDV2) { | |
307 Dsymbol search(Loc, Identifier ident, int flags) | |
308 { | |
309 //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); | |
310 if (scope_) | |
311 // Try one last time to resolve this enum | |
312 semantic(scope_); | |
313 | |
314 if (!members || !symtab || scope_) | |
315 { | |
316 error("is forward referenced when looking for '%s'", ident.toChars()); | |
317 //*(char*)0=0; | |
318 return null; | |
319 } | |
320 | |
321 return ScopeDsymbol.search(loc, ident, flags); | |
322 } | |
323 } | |
324 bool isDeprecated() // is Dsymbol deprecated? | |
325 { | |
326 return isdeprecated; | |
327 } | |
328 | |
329 void emitComment(Scope sc) | |
330 { | |
331 assert(false); | |
332 } | |
333 | |
334 void toDocBuffer(OutBuffer buf) | |
335 { | |
336 assert(false); | |
337 } | |
338 | |
339 EnumDeclaration isEnumDeclaration() { return this; } | |
340 | |
341 void toObjFile(int multiobj) // compile to .obj file | |
342 { | |
343 //printf("EnumDeclaration::toObjFile('%s')\n", toChars()); | |
344 version (DMDV2) { | |
345 if (isAnonymous()) | |
346 return; | |
347 } | |
348 | |
349 if (global.params.symdebug) | |
350 toDebug(); | |
351 | |
352 type.getTypeInfo(null); // generate TypeInfo | |
353 | |
354 TypeEnum tc = cast(TypeEnum)type; | |
355 if (!tc.sym.defaultval || type.isZeroInit(Loc(0))) { | |
356 ; | |
357 } else { | |
358 SC scclass = SCglobal; | |
359 if (inTemplateInstance()) | |
360 scclass = SCcomdat; | |
361 | |
362 // Generate static initializer | |
363 toInitializer(); | |
364 sinit.Sclass = scclass; | |
365 sinit.Sfl = FLdata; | |
366 version (ELFOBJ) { // Burton | |
367 sinit.Sseg = Segment.CDATA; | |
368 } | |
369 version (MACHOBJ) { | |
370 sinit.Sseg = Segment.DATA; | |
371 } | |
372 version (DMDV1) { | |
373 dtnbytes(&sinit.Sdt, tc.size(0), cast(char*)&tc.sym.defaultval); | |
374 //sinit->Sdt = tc->sym->init->toDt(); | |
375 } | |
376 version (DMDV2) { | |
377 tc.sym.defaultval.toDt(&sinit.Sdt); | |
378 } | |
379 outdata(sinit); | |
380 } | |
381 } | |
382 | |
383 void toDebug() | |
384 { | |
385 assert(false); | |
386 } | |
387 | |
388 int cvMember(ubyte* p) | |
389 { | |
390 assert(false); | |
391 } | |
392 | |
393 Symbol* sinit; | |
394 | |
395 Symbol* toInitializer() | |
396 { | |
397 Symbol* s; | |
398 Classsym* stag; | |
399 | |
400 if (!sinit) | |
401 { | |
402 stag = fake_classsym(Id.ClassInfo); | |
403 Identifier ident_save = ident; | |
404 if (!ident) | |
405 ident = Lexer.uniqueId("__enum"); | |
406 s = toSymbolX("__init", SCextern, stag.Stype, "Z"); | |
407 ident = ident_save; | |
408 s.Sfl = FLextern; | |
409 s.Sflags |= SFLnodebug; | |
410 slist_add(s); | |
411 sinit = s; | |
412 } | |
413 | |
414 return sinit; | |
415 } | |
416 }; |