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