Mercurial > projects > ddmd
annotate dmd/IfStatement.d @ 178:e3afd1303184
Many small bugs fixed
Made all classes derive from TObject to detect memory leaks (functionality is disabled for now)
Began work on overriding backend memory allocations (to avoid memory leaks)
author | korDen |
---|---|
date | Sun, 17 Oct 2010 07:42:00 +0400 |
parents | af724d3510d7 |
children | b0d41ff5e0df |
rev | line source |
---|---|
0 | 1 module dmd.IfStatement; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Statement; |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
5 import dmd.Parameter; |
0 | 6 import dmd.Loc; |
7 import dmd.Expression; | |
8 import dmd.VarDeclaration; | |
9 import dmd.Scope; | |
10 import dmd.InterState; | |
11 import dmd.OutBuffer; | |
154
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
12 import dmd.GlobalExpressions; |
0 | 13 import dmd.HdrGenState; |
14 import dmd.InlineCostState; | |
15 import dmd.InlineDoState; | |
16 import dmd.InlineScanState; | |
17 import dmd.IRState; | |
18 import dmd.BE; | |
19 import dmd.WANT; | |
20 import dmd.ScopeDsymbol; | |
21 import dmd.Type; | |
22 import dmd.CondExp; | |
23 import dmd.AndAndExp; | |
24 import dmd.OrOrExp; | |
25 import dmd.AssignExp; | |
26 import dmd.VarExp; | |
27 | |
28 import dmd.backend.elem; | |
29 import dmd.backend.Util; | |
30 import dmd.backend.block; | |
31 import dmd.backend.Blockx; | |
32 import dmd.backend.BC; | |
33 | |
34 class IfStatement : Statement | |
35 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
36 Parameter arg; |
0 | 37 Expression condition; |
38 Statement ifbody; | |
39 Statement elsebody; | |
40 | |
41 VarDeclaration match; // for MatchExpression results | |
42 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
43 this(Loc loc, Parameter arg, Expression condition, Statement ifbody, Statement elsebody) |
0 | 44 { |
178 | 45 register(); |
0 | 46 super(loc); |
47 this.arg = arg; | |
48 this.condition = condition; | |
49 this.ifbody = ifbody; | |
50 this.elsebody = elsebody; | |
51 } | |
52 | |
72 | 53 override Statement syntaxCopy() |
0 | 54 { |
51 | 55 Statement i = null; |
56 if (ifbody) | |
57 i = ifbody.syntaxCopy(); | |
58 | |
59 Statement e = null; | |
60 if (elsebody) | |
61 e = elsebody.syntaxCopy(); | |
62 | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
63 Parameter a = arg ? arg.syntaxCopy() : null; |
51 | 64 IfStatement s = new IfStatement(loc, a, condition.syntaxCopy(), i, e); |
65 return s; | |
0 | 66 } |
67 | |
72 | 68 override Statement semantic(Scope sc) |
0 | 69 { |
70 condition = condition.semantic(sc); | |
71 condition = resolveProperties(sc, condition); | |
72 condition = condition.checkToBoolean(); | |
73 | |
74 // If we can short-circuit evaluate the if statement, don't do the | |
75 // semantic analysis of the skipped code. | |
76 // This feature allows a limited form of conditional compilation. | |
77 condition = condition.optimize(WANT.WANTflags); | |
78 | |
79 // Evaluate at runtime | |
80 uint cs0 = sc.callSuper; | |
81 uint cs1; | |
82 | |
83 Scope scd; | |
84 if (arg) | |
85 { | |
86 /* Declare arg, which we will set to be the | |
87 * result of condition. | |
88 */ | |
89 ScopeDsymbol sym = new ScopeDsymbol(); | |
90 sym.parent = sc.scopesym; | |
91 scd = sc.push(sym); | |
92 | |
93 Type t = arg.type ? arg.type : condition.type; | |
94 match = new VarDeclaration(loc, t, arg.ident, null); | |
95 match.noauto = true; | |
96 match.semantic(scd); | |
97 if (!scd.insert(match)) | |
98 assert(0); | |
99 | |
100 match.parent = sc.func; | |
101 | |
102 /* Generate: | |
103 * (arg = condition) | |
104 */ | |
105 VarExp v = new VarExp(Loc(0), match); | |
106 condition = new AssignExp(loc, v, condition); | |
107 condition = condition.semantic(scd); | |
108 } | |
109 else | |
110 scd = sc.push(); | |
111 | |
112 ifbody = ifbody.semantic(scd); | |
113 scd.pop(); | |
114 | |
115 cs1 = sc.callSuper; | |
116 sc.callSuper = cs0; | |
117 if (elsebody) | |
118 elsebody = elsebody.semanticScope(sc, null, null); | |
119 | |
120 sc.mergeCallSuper(loc, cs1); | |
121 | |
122 return this; | |
123 } | |
124 | |
72 | 125 override Expression interpret(InterState istate) |
0 | 126 { |
154
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
127 version(LOG) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
128 writef("IfStatement::interpret(%s)\n", condition.toChars()); |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
129 |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
130 if (istate.start is this) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
131 istate.start = null; |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
132 if (istate.start) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
133 { |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
134 Expression e = null; |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
135 if (ifbody) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
136 e = ifbody.interpret(istate); |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
137 if (istate.start && elsebody) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
138 e = elsebody.interpret(istate); |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
139 return e; |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
140 } |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
141 |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
142 Expression e = condition.interpret(istate); |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
143 assert(e); |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
144 //if (e is EXP_CANT_INTERPRET) writef("cannot interpret\n"); |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
145 if (e !is EXP_CANT_INTERPRET) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
146 { |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
147 if (e.isBool(true)) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
148 e = ifbody ? ifbody.interpret(istate) : null; |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
149 else if (e.isBool(false)) |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
150 e = elsebody ? elsebody.interpret(istate) : null; |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
151 else |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
152 { |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
153 e = EXP_CANT_INTERPRET; |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
154 } |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
155 } |
14feb7ae01a6
* changed the build system to build a release version if the debug one compiles
trass3r
parents:
130
diff
changeset
|
156 return e; |
0 | 157 } |
158 | |
72 | 159 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 160 { |
174 | 161 buf.writestring("if ("); |
162 if (arg) | |
163 { | |
164 if (arg.type) | |
165 arg.type.toCBuffer(buf, arg.ident, hgs); | |
166 else | |
167 { | |
168 buf.writestring("auto "); | |
169 buf.writestring(arg.ident.toChars()); | |
170 } | |
171 buf.writestring(" = "); | |
172 } | |
173 condition.toCBuffer(buf, hgs); | |
174 buf.writebyte(')'); | |
175 buf.writenl(); | |
176 ifbody.toCBuffer(buf, hgs); | |
177 if (elsebody) | |
178 { | |
179 buf.writestring("else"); | |
180 buf.writenl(); | |
181 elsebody.toCBuffer(buf, hgs); | |
182 } | |
0 | 183 } |
184 | |
72 | 185 override bool usesEH() |
0 | 186 { |
187 assert(false); | |
188 } | |
189 | |
72 | 190 override BE blockExit() |
0 | 191 { |
192 //printf("IfStatement::blockExit(%p)\n", this); | |
193 | |
194 BE result = BE.BEnone; | |
195 if (condition.canThrow()) | |
196 result |= BE.BEthrow; | |
197 if (condition.isBool(true)) | |
198 { | |
199 if (ifbody) | |
200 result |= ifbody.blockExit(); | |
201 else | |
202 result |= BE.BEfallthru; | |
203 } | |
204 else if (condition.isBool(false)) | |
205 { | |
206 if (elsebody) | |
207 result |= elsebody.blockExit(); | |
208 else | |
209 result |= BE.BEfallthru; | |
210 } | |
211 else | |
212 { | |
213 if (ifbody) | |
214 result |= ifbody.blockExit(); | |
215 else | |
216 result |= BE.BEfallthru; | |
217 | |
218 if (elsebody) | |
219 result |= elsebody.blockExit(); | |
220 else | |
221 result |= BE.BEfallthru; | |
222 } | |
223 | |
224 //printf("IfStatement::blockExit(%p) = x%x\n", this, result); | |
225 return result; | |
226 } | |
227 | |
72 | 228 override IfStatement isIfStatement() { return this; } |
0 | 229 |
72 | 230 override int inlineCost(InlineCostState* ics) |
0 | 231 { |
232 int cost; | |
233 | |
234 /* Can't declare variables inside ?: expressions, so | |
235 * we cannot inline if a variable is declared. | |
236 */ | |
237 if (arg) | |
238 return COST_MAX; | |
239 | |
240 cost = condition.inlineCost(ics); | |
241 | |
242 /* Specifically allow: | |
243 * if (condition) | |
244 * return exp1; | |
245 * else | |
246 * return exp2; | |
247 * Otherwise, we can't handle return statements nested in if's. | |
248 */ | |
249 | |
250 if (elsebody && ifbody && | |
251 ifbody.isReturnStatement() && | |
252 elsebody.isReturnStatement()) | |
253 { | |
254 cost += ifbody.inlineCost(ics); | |
255 cost += elsebody.inlineCost(ics); | |
256 //printf("cost = %d\n", cost); | |
257 } | |
258 else | |
259 { | |
260 ics.nested += 1; | |
261 if (ifbody) | |
262 cost += ifbody.inlineCost(ics); | |
263 if (elsebody) | |
264 cost += elsebody.inlineCost(ics); | |
265 ics.nested -= 1; | |
266 } | |
267 return cost; | |
268 } | |
269 | |
72 | 270 override Expression doInline(InlineDoState ids) |
0 | 271 { |
272 Expression econd; | |
273 Expression e1; | |
274 Expression e2; | |
275 Expression e; | |
276 | |
277 assert(!arg); | |
278 econd = condition.doInline(ids); | |
279 assert(econd); | |
280 if (ifbody) | |
281 e1 = ifbody.doInline(ids); | |
282 else | |
283 e1 = null; | |
284 if (elsebody) | |
285 e2 = elsebody.doInline(ids); | |
286 else | |
287 e2 = null; | |
288 if (e1 && e2) | |
289 { | |
290 e = new CondExp(econd.loc, econd, e1, e2); | |
291 e.type = e1.type; | |
292 } | |
293 else if (e1) | |
294 { | |
295 e = new AndAndExp(econd.loc, econd, e1); | |
296 e.type = Type.tvoid; | |
297 } | |
298 else if (e2) | |
299 { | |
300 e = new OrOrExp(econd.loc, econd, e2); | |
301 e.type = Type.tvoid; | |
302 } | |
303 else | |
304 { | |
305 e = econd; | |
306 } | |
307 return e; | |
308 } | |
309 | |
72 | 310 override Statement inlineScan(InlineScanState* iss) |
0 | 311 { |
312 condition = condition.inlineScan(iss); | |
313 if (ifbody) | |
314 ifbody = ifbody.inlineScan(iss); | |
315 if (elsebody) | |
316 elsebody = elsebody.inlineScan(iss); | |
317 return this; | |
318 } | |
319 | |
72 | 320 override void toIR(IRState* irs) |
0 | 321 { |
322 elem* e; | |
323 Blockx* blx = irs.blx; | |
324 | |
325 //printf("IfStatement::toIR('%s')\n", condition.toChars()); | |
326 | |
327 IRState mystate = IRState(irs, this); | |
328 | |
329 // bexit is the block that gets control after this IfStatement is done | |
330 block* bexit = mystate.breakBlock ? mystate.breakBlock : block_calloc(); | |
331 | |
332 incUsage(irs, loc); | |
333 static if (false) { | |
334 if (match) | |
335 { | |
336 /* Generate: | |
337 * if (match = RTLSYM_IFMATCH(string, pattern)) ... | |
338 */ | |
339 assert(condition.op == TOK.TOKmatch); | |
340 e = matchexp_toelem(cast(MatchExp)condition, &mystate, RTLSYM.RTLSYM_IFMATCH); | |
341 Symbol *s = match.toSymbol(); | |
342 symbol_add(s); | |
343 e = el_bin(OPeq, TYnptr, el_var(s), e); | |
344 } | |
345 else | |
346 { | |
347 e = condition.toElem(&mystate); | |
348 } | |
349 } else { | |
350 e = condition.toElem(&mystate); | |
351 } | |
352 block_appendexp(blx.curblock, e); | |
353 block* bcond = blx.curblock; | |
354 block_next(blx, BC.BCiftrue, null); | |
355 | |
356 list_append(&bcond.Bsucc, blx.curblock); | |
357 if (ifbody) | |
358 ifbody.toIR(&mystate); | |
359 | |
360 list_append(&blx.curblock.Bsucc, bexit); | |
361 | |
362 if (elsebody) | |
363 { | |
364 block_next(blx, BC.BCgoto, null); | |
365 list_append(&bcond.Bsucc, blx.curblock); | |
366 elsebody.toIR(&mystate); | |
367 list_append(&blx.curblock.Bsucc, bexit); | |
368 } | |
369 else | |
370 list_append(&bcond.Bsucc, bexit); | |
371 | |
372 block_next(blx, BC.BCgoto, bexit); | |
373 } | |
72 | 374 } |