Mercurial > projects > ddmd
annotate dmd/SwitchStatement.d @ 162:438eaa11eed4
updated build script to use dmd2.039
some missing methods implemented
author | korDen |
---|---|
date | Tue, 21 Sep 2010 14:59:56 +0400 |
parents | af1bebfd96a4 |
children | af724d3510d7 |
rev | line source |
---|---|
0 | 1 module dmd.SwitchStatement; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Statement; |
5 import dmd.Expression; | |
162 | 6 import dmd.GlobalExpressions; |
0 | 7 import dmd.DefaultStatement; |
8 import dmd.TryFinallyStatement; | |
9 import dmd.Array; | |
10 import dmd.Loc; | |
11 import dmd.Scope; | |
12 import dmd.OutBuffer; | |
13 import dmd.HdrGenState; | |
14 import dmd.InlineScanState; | |
15 import dmd.IRState; | |
16 import dmd.InterState; | |
17 import dmd.BE; | |
18 import dmd.TY; | |
19 import dmd.WANT; | |
20 import dmd.GotoCaseStatement; | |
21 import dmd.CaseStatement; | |
22 import dmd.ArrayTypes; | |
23 import dmd.CompoundStatement; | |
24 import dmd.Global; | |
25 import dmd.SwitchErrorStatement; | |
26 import dmd.Type; | |
27 import dmd.HaltExp; | |
28 import dmd.ExpStatement; | |
29 import dmd.BreakStatement; | |
30 import dmd.EnumDeclaration; | |
31 import dmd.TypeEnum; | |
32 import dmd.Dsymbol; | |
33 import dmd.EnumMember; | |
34 import dmd.TypeTypedef; | |
35 import dmd.TOK; | |
36 import dmd.StringExp; | |
162 | 37 import dmd.expression.Equal; |
0 | 38 |
39 import dmd.backend.Util; | |
40 import dmd.backend.block; | |
41 import dmd.backend.Blockx; | |
42 import dmd.backend.elem; | |
43 import dmd.backend.OPER; | |
44 import dmd.backend.TYM; | |
45 import dmd.backend.BC; | |
46 import dmd.backend.dt_t; | |
47 import dmd.backend.Symbol; | |
48 import dmd.backend.SC; | |
49 import dmd.backend.FL; | |
50 import dmd.backend.RTLSYM; | |
51 import dmd.backend.targ_types; | |
52 | |
4 | 53 import core.memory; |
2 | 54 |
5
63623152e82a
Fixed memory corruption bug which was introduced when attempting to restore GC functionality
dkoroskin <>
parents:
4
diff
changeset
|
55 import core.stdc.stdlib; |
63623152e82a
Fixed memory corruption bug which was introduced when attempting to restore GC functionality
dkoroskin <>
parents:
4
diff
changeset
|
56 |
0 | 57 class SwitchStatement : Statement |
58 { | |
59 Expression condition; | |
60 Statement body_; | |
61 bool isFinal; | |
62 | |
63 DefaultStatement sdefault = null; | |
64 TryFinallyStatement tf = null; | |
65 Array gotoCases; // array of unresolved GotoCaseStatement's | |
66 Array cases; // array of CaseStatement's | |
67 int hasNoDefault = 0; // !=0 if no default statement | |
68 int hasVars = 0; // !=0 if has variable case values | |
69 | |
70 this(Loc loc, Expression c, Statement b, bool isFinal) | |
71 { | |
72 super(loc); | |
73 | |
74 this.condition = c; | |
75 this.body_ = b; | |
76 this.isFinal = isFinal; | |
77 | |
78 gotoCases = new Array(); | |
79 } | |
80 | |
72 | 81 override Statement syntaxCopy() |
0 | 82 { |
53 | 83 SwitchStatement s = new SwitchStatement(loc, |
84 condition.syntaxCopy(), body_.syntaxCopy(), isFinal); | |
85 return s; | |
0 | 86 } |
87 | |
72 | 88 override Statement semantic(Scope sc) |
0 | 89 { |
90 //printf("SwitchStatement.semantic(%p)\n", this); | |
91 tf = sc.tf; | |
92 assert(!cases); // ensure semantic() is only run once | |
93 condition = condition.semantic(sc); | |
94 condition = resolveProperties(sc, condition); | |
95 if (condition.type.isString()) | |
96 { | |
97 // If it's not an array, cast it to one | |
98 if (condition.type.ty != Tarray) | |
99 { | |
100 condition = condition.implicitCastTo(sc, condition.type.nextOf().arrayOf()); | |
101 } | |
102 condition.type = condition.type.constOf(); | |
103 } | |
104 else | |
105 { | |
106 condition = condition.integralPromotions(sc); | |
107 condition.checkIntegral(); | |
108 } | |
109 condition = condition.optimize(WANTvalue); | |
110 | |
111 sc = sc.push(); | |
112 sc.sbreak = this; | |
113 sc.sw = this; | |
114 | |
115 cases = new Array(); | |
116 sc.noctor++; // BUG: should use Scope.mergeCallSuper() for each case instead | |
117 body_ = body_.semantic(sc); | |
118 sc.noctor--; | |
119 | |
120 // Resolve any goto case's with exp | |
121 for (int i = 0; i < gotoCases.dim; i++) | |
122 { | |
123 GotoCaseStatement gcs = cast(GotoCaseStatement)gotoCases.data[i]; | |
124 | |
125 if (!gcs.exp) | |
126 { | |
127 gcs.error("no case statement following goto case;"); | |
128 break; | |
129 } | |
130 | |
131 for (Scope scx = sc; scx; scx = scx.enclosing) | |
132 { | |
133 if (!scx.sw) | |
134 continue; | |
135 for (int j = 0; j < scx.sw.cases.dim; j++) | |
136 { | |
137 CaseStatement cs = cast(CaseStatement)scx.sw.cases.data[j]; | |
138 | |
139 if (cs.exp.equals(gcs.exp)) | |
140 { | |
141 gcs.cs = cs; | |
142 goto Lfoundcase; | |
143 } | |
144 } | |
145 } | |
146 gcs.error("case %s not found", gcs.exp.toChars()); | |
147 | |
148 Lfoundcase: | |
149 ; | |
150 } | |
151 | |
152 if (!sc.sw.sdefault && !isFinal) | |
153 { | |
154 hasNoDefault = 1; | |
155 | |
156 warning("switch statement has no default"); | |
157 | |
158 // Generate runtime error if the default is hit | |
159 Statements a = new Statements(); | |
160 CompoundStatement cs; | |
161 Statement s; | |
162 | |
163 if (global.params.useSwitchError) | |
164 s = new SwitchErrorStatement(loc); | |
165 else | |
166 { | |
167 Expression e = new HaltExp(loc); | |
168 s = new ExpStatement(loc, e); | |
169 } | |
170 | |
171 a.reserve(4); | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
172 a.push(body_); |
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
173 a.push(new BreakStatement(loc, null)); |
0 | 174 sc.sw.sdefault = new DefaultStatement(loc, s); |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
175 a.push(sc.sw.sdefault); |
0 | 176 cs = new CompoundStatement(loc, a); |
177 body_ = cs; | |
178 } | |
179 | |
180 version (DMDV2) { | |
181 if (isFinal) | |
182 { | |
183 Type t = condition.type; | |
184 while (t.ty == Ttypedef) | |
185 { | |
186 // Don't use toBasetype() because that will skip past enums | |
187 t = (cast(TypeTypedef)t).sym.basetype; | |
188 } | |
189 if (condition.type.ty == Tenum) | |
190 { | |
191 TypeEnum te = cast(TypeEnum)condition.type; | |
192 EnumDeclaration ed = te.toDsymbol(sc).isEnumDeclaration(); | |
193 assert(ed); | |
194 size_t dim = ed.members.dim; | |
77
ad4792a1cfd6
more D-ification container accessing
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
195 foreach (Dsymbol s; ed.members) |
0 | 196 { |
77
ad4792a1cfd6
more D-ification container accessing
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
197 if (auto em = s.isEnumMember()) |
0 | 198 { |
199 for (size_t j = 0; j < cases.dim; j++) | |
200 { | |
201 CaseStatement cs = cast(CaseStatement)cases.data[j]; | |
202 if (cs.exp.equals(em.value)) | |
203 goto L1; | |
204 } | |
205 error("enum member %s not represented in final switch", em.toChars()); | |
206 } | |
207 L1: | |
208 ; | |
209 } | |
210 } | |
211 } | |
212 } | |
213 | |
214 sc.pop(); | |
215 return this; | |
216 } | |
217 | |
72 | 218 override bool hasBreak() |
0 | 219 { |
220 assert(false); | |
221 } | |
222 | |
72 | 223 override bool usesEH() |
0 | 224 { |
225 assert(false); | |
226 } | |
227 | |
72 | 228 override BE blockExit() |
0 | 229 { |
230 BE result = BE.BEnone; | |
231 if (condition.canThrow()) | |
232 result |= BE.BEthrow; | |
233 | |
234 if (body_) | |
235 { result |= body_.blockExit(); | |
236 if (result & BE.BEbreak) | |
237 { | |
238 result |= BE.BEfallthru; | |
239 result &= ~BE.BEbreak; | |
240 } | |
241 } | |
242 else | |
243 result |= BE.BEfallthru; | |
244 | |
245 return result; | |
246 } | |
247 | |
72 | 248 override Expression interpret(InterState istate) |
0 | 249 { |
162 | 250 version (LOG) { |
251 printf("SwitchStatement.interpret()\n"); | |
252 } | |
253 if (istate.start == this) | |
254 istate.start = null; | |
255 Expression e = null; | |
256 | |
257 if (istate.start) | |
258 { | |
259 e = body_ ? body_.interpret(istate) : null; | |
260 if (istate.start) | |
261 return null; | |
262 if (e is EXP_CANT_INTERPRET) | |
263 return e; | |
264 if (e is EXP_BREAK_INTERPRET) | |
265 return null; | |
266 return e; | |
267 } | |
268 | |
269 | |
270 Expression econdition = condition.interpret(istate); | |
271 if (econdition is EXP_CANT_INTERPRET) | |
272 return EXP_CANT_INTERPRET; | |
273 | |
274 Statement s = null; | |
275 if (cases) | |
276 { | |
277 for (size_t i = 0; i < cases.dim; i++) | |
278 { | |
279 CaseStatement cs = cast(CaseStatement)cases.data[i]; | |
280 e = Equal(TOKequal, Type.tint32, econdition, cs.exp); | |
281 if (e is EXP_CANT_INTERPRET) | |
282 return EXP_CANT_INTERPRET; | |
283 if (e.isBool(true)) | |
284 { | |
285 s = cs; | |
286 break; | |
287 } | |
288 } | |
289 } | |
290 if (!s) | |
291 { | |
292 if (hasNoDefault) | |
293 error("no default or case for %s in switch statement", econdition.toChars()); | |
294 s = sdefault; | |
295 } | |
296 | |
297 assert(s); | |
298 istate.start = s; | |
299 e = body_ ? body_.interpret(istate) : null; | |
300 assert(!istate.start); | |
301 if (e is EXP_BREAK_INTERPRET) | |
302 return null; | |
303 return e; | |
0 | 304 } |
305 | |
72 | 306 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 307 { |
308 assert(false); | |
309 } | |
310 | |
72 | 311 override Statement inlineScan(InlineScanState* iss) |
0 | 312 { |
313 //printf("SwitchStatement.inlineScan()\n"); | |
314 condition = condition.inlineScan(iss); | |
315 body_ = body_ ? body_.inlineScan(iss) : null; | |
316 if (sdefault) | |
317 sdefault = cast(DefaultStatement)sdefault.inlineScan(iss); | |
318 if (cases) | |
319 { | |
320 for (int i = 0; i < cases.dim; i++) | |
321 { | |
322 Statement s = cast(Statement)cases.data[i]; | |
323 cases.data[i] = cast(void*)s.inlineScan(iss); | |
324 } | |
325 } | |
326 return this; | |
327 } | |
328 | |
72 | 329 override void toIR(IRState* irs) |
0 | 330 { |
331 int string; | |
332 Blockx* blx = irs.blx; | |
333 | |
334 //printf("SwitchStatement.toIR()\n"); | |
335 IRState mystate = IRState(irs,this); | |
336 | |
337 mystate.switchBlock = blx.curblock; | |
338 | |
339 /* Block for where "break" goes to | |
340 */ | |
341 mystate.breakBlock = block_calloc(blx); | |
342 | |
343 /* Block for where "default" goes to. | |
344 * If there is a default statement, then that is where default goes. | |
345 * If not, then do: | |
346 * default: break; | |
347 * by making the default block the same as the break block. | |
348 */ | |
349 mystate.defaultBlock = sdefault ? block_calloc(blx) : mystate.breakBlock; | |
350 | |
351 int numcases = 0; | |
352 if (cases) | |
353 numcases = cases.dim; | |
354 | |
355 incUsage(irs, loc); | |
356 elem* econd = condition.toElem(&mystate); | |
357 | |
358 version (DMDV2) { | |
359 if (hasVars) | |
360 { | |
361 /* Generate a sequence of if-then-else blocks for the cases. | |
362 */ | |
363 if (econd.Eoper != OPvar) | |
364 { | |
365 elem* e = exp2_copytotemp(econd); | |
366 block_appendexp(mystate.switchBlock, e); | |
367 econd = e.E2; | |
368 } | |
369 | |
370 for (int i = 0; i < numcases; i++) | |
371 { | |
372 CaseStatement cs = cast(CaseStatement)cases.data[i]; | |
373 | |
374 elem* ecase = cs.exp.toElem(&mystate); | |
375 elem* e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase); | |
376 block* b = blx.curblock; | |
377 block_appendexp(b, e); | |
378 block* bcase = block_calloc(blx); | |
379 cs.cblock = bcase; | |
380 block_next(blx, BCiftrue, null); | |
381 list_append(&b.Bsucc, bcase); | |
382 list_append(&b.Bsucc, blx.curblock); | |
383 } | |
384 | |
385 /* The final 'else' clause goes to the default | |
386 */ | |
387 block* b = blx.curblock; | |
388 block_next(blx, BCgoto, null); | |
389 list_append(&b.Bsucc, mystate.defaultBlock); | |
390 | |
391 body_.toIR(&mystate); | |
392 | |
393 /* Have the end of the switch body fall through to the block | |
394 * following the switch statement. | |
395 */ | |
396 block_goto(blx, BCgoto, mystate.breakBlock); | |
397 return; | |
398 } | |
399 } | |
400 | |
401 if (condition.type.isString()) | |
402 { | |
403 // Number the cases so we can unscramble things after the sort() | |
404 for (int i = 0; i < numcases; i++) | |
405 { | |
406 CaseStatement cs = cast(CaseStatement)cases.data[i]; | |
407 cs.index = i; | |
408 } | |
409 | |
410 cases.sort(); | |
411 | |
412 /* Create a sorted array of the case strings, and si | |
413 * will be the symbol for it. | |
414 */ | |
415 dt_t* dt = null; | |
416 Symbol* si = symbol_generate(SCstatic,type_fake(TYullong)); | |
417 version (MACHOBJ) { | |
418 si.Sseg = Segment.DATA; | |
419 } | |
420 dtdword(&dt, numcases); | |
421 dtxoff(&dt, si, 8, TYnptr); | |
422 | |
423 for (int i = 0; i < numcases; i++) | |
424 { | |
425 CaseStatement cs = cast(CaseStatement)cases.data[i]; | |
426 | |
427 if (cs.exp.op != TOKstring) | |
428 { | |
429 error("case '%s' is not a string", cs.exp.toChars()); // BUG: this should be an assert | |
430 } | |
431 else | |
432 { | |
433 StringExp se = cast(StringExp)(cs.exp); | |
434 uint len = se.len; | |
435 dtdword(&dt, len); | |
436 dtabytes(&dt, TYnptr, 0, se.len * se.sz, cast(char*)se.string_); | |
437 } | |
438 } | |
439 | |
440 si.Sdt = dt; | |
441 si.Sfl = FLdata; | |
442 outdata(si); | |
443 | |
444 /* Call: | |
445 * _d_switch_string(string[] si, string econd) | |
446 */ | |
447 elem* eparam = el_param(econd, el_var(si)); | |
448 switch (condition.type.nextOf().ty) | |
449 { | |
450 case Tchar: | |
451 econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_STRING]), eparam); | |
452 break; | |
453 case Twchar: | |
454 econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_USTRING]), eparam); | |
455 break; | |
456 case Tdchar: // BUG: implement | |
457 econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_DSTRING]), eparam); | |
458 break; | |
459 default: | |
460 assert(0); | |
461 } | |
462 elem_setLoc(econd, loc); | |
463 string = 1; | |
464 } | |
465 else | |
466 string = 0; | |
467 block_appendexp(mystate.switchBlock, econd); | |
468 block_next(blx,BCswitch,null); | |
469 | |
135 | 470 // Corresponding free is in block_free |
5
63623152e82a
Fixed memory corruption bug which was introduced when attempting to restore GC functionality
dkoroskin <>
parents:
4
diff
changeset
|
471 targ_llong* pu = cast(targ_llong*) malloc(targ_llong.sizeof * (numcases + 1)); |
0 | 472 mystate.switchBlock.Bswitch = pu; |
473 /* First pair is the number of cases, and the default block | |
474 */ | |
475 *pu++ = numcases; | |
476 list_append(&mystate.switchBlock.Bsucc, mystate.defaultBlock); | |
477 | |
478 /* Fill in the first entry in each pair, which is the case value. | |
479 * CaseStatement.toIR() will fill in | |
480 * the second entry for each pair with the block. | |
481 */ | |
482 for (int i = 0; i < numcases; i++) | |
483 { | |
484 CaseStatement cs = cast(CaseStatement)cases.data[i]; | |
485 if (string) | |
486 { | |
487 pu[cs.index] = i; | |
488 } | |
489 else | |
490 { | |
491 pu[i] = cs.exp.toInteger(); | |
492 } | |
493 } | |
494 | |
495 body_.toIR(&mystate); | |
496 | |
497 /* Have the end of the switch body fall through to the block | |
498 * following the switch statement. | |
499 */ | |
500 block_goto(blx, BCgoto, mystate.breakBlock); | |
501 } | |
72 | 502 } |