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