Mercurial > projects > ldc
annotate dmd/statement.c @ 1168:ab186e535e72
A different fix to #218 and DMD2682 that does not lead to constant folding regressions.
Fixes run/const_15, run/c/const_16_B.
The price is removing the lvalueness of struct literals. If it turns out too
much code depends on this behavior or we don't want to break with DMD, we
could keep struct literals as lvalues and instead convert struct literals used
as expression initializers into struct initializers.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Sun, 29 Mar 2009 11:43:45 +0200 |
parents | 166042b48c28 |
children | e961851fb8be |
rev | line source |
---|---|
159 | 1 |
2 // Compiler implementation of the D programming language | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
3 // Copyright (c) 1999-2009 by Digital Mars |
159 | 4 // All Rights Reserved |
5 // written by Walter Bright | |
6 // http://www.digitalmars.com | |
7 // License for redistribution is by either the Artistic License | |
8 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
9 // See the included readme.txt for details. | |
10 | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <assert.h> | |
14 | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
15 #include "rmem.h" |
159 | 16 |
17 #include "statement.h" | |
18 #include "expression.h" | |
19 #include "cond.h" | |
20 #include "init.h" | |
21 #include "staticassert.h" | |
22 #include "mtype.h" | |
23 #include "scope.h" | |
24 #include "declaration.h" | |
25 #include "aggregate.h" | |
26 #include "id.h" | |
27 #include "hdrgen.h" | |
28 #include "parse.h" | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
29 #include "template.h" |
159 | 30 |
31 /******************************** Statement ***************************/ | |
32 | |
33 Statement::Statement(Loc loc) | |
34 : loc(loc) | |
35 { | |
36 #ifdef _DH | |
37 // If this is an in{} contract scope statement (skip for determining | |
38 // inlineStatus of a function body for header content) | |
39 incontract = 0; | |
40 #endif | |
41 } | |
42 | |
43 Statement *Statement::syntaxCopy() | |
44 { | |
45 assert(0); | |
46 return NULL; | |
47 } | |
48 | |
49 void Statement::print() | |
50 { | |
51 fprintf(stdmsg, "%s\n", toChars()); | |
52 fflush(stdmsg); | |
53 } | |
54 | |
55 char *Statement::toChars() | |
56 { OutBuffer *buf; | |
57 HdrGenState hgs; | |
58 | |
59 buf = new OutBuffer(); | |
60 toCBuffer(buf, &hgs); | |
61 return buf->toChars(); | |
62 } | |
63 | |
64 void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
65 { | |
66 buf->printf("Statement::toCBuffer()"); | |
67 buf->writenl(); | |
68 } | |
69 | |
70 Statement *Statement::semantic(Scope *sc) | |
71 { | |
72 return this; | |
73 } | |
74 | |
75 // Same as semantic(), but do create a new scope | |
76 | |
77 Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) | |
78 { Scope *scd; | |
79 Statement *s; | |
80 | |
81 scd = sc->push(); | |
82 if (sbreak) | |
83 scd->sbreak = sbreak; | |
84 if (scontinue) | |
85 scd->scontinue = scontinue; | |
86 s = semantic(scd); | |
87 scd->pop(); | |
88 return s; | |
89 } | |
90 | |
91 void Statement::error(const char *format, ...) | |
92 { | |
93 va_list ap; | |
94 va_start(ap, format); | |
95 ::verror(loc, format, ap); | |
96 va_end( ap ); | |
97 } | |
98 | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
99 void Statement::warning(const char *format, ...) |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
100 { |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
101 if (global.params.warnings && !global.gag) |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
102 { |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
103 va_list ap; |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
104 va_start(ap, format); |
1124
e7f0c2b48047
Fix a bug where ::warning() was called with a va_list argument instead of an
Frits van Bommel <fvbommel wxs.nl>
parents:
1103
diff
changeset
|
105 ::vwarning(loc, format, ap); |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
106 va_end( ap ); |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
107 } |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
108 } |
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
109 |
159 | 110 int Statement::hasBreak() |
111 { | |
112 //printf("Statement::hasBreak()\n"); | |
113 return FALSE; | |
114 } | |
115 | |
116 int Statement::hasContinue() | |
117 { | |
118 return FALSE; | |
119 } | |
120 | |
121 // TRUE if statement uses exception handling | |
122 | |
123 int Statement::usesEH() | |
124 { | |
125 return FALSE; | |
126 } | |
127 | |
336 | 128 /* Only valid after semantic analysis |
129 */ | |
130 int Statement::blockExit() | |
131 { | |
132 printf("Statement::blockExit(%p)\n", this); | |
133 printf("%s\n", toChars()); | |
134 assert(0); | |
135 return BEany; | |
136 } | |
137 | |
159 | 138 // TRUE if statement 'comes from' somewhere else, like a goto |
139 | |
140 int Statement::comeFrom() | |
141 { | |
142 //printf("Statement::comeFrom()\n"); | |
143 return FALSE; | |
144 } | |
145 | |
146 /**************************************** | |
147 * If this statement has code that needs to run in a finally clause | |
148 * at the end of the current scope, return that code in the form of | |
149 * a Statement. | |
150 * Output: | |
151 * *sentry code executed upon entry to the scope | |
152 * *sexception code executed upon exit from the scope via exception | |
153 * *sfinally code executed in finally block | |
154 */ | |
155 | |
156 void Statement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) | |
157 { | |
158 //printf("Statement::scopeCode()\n"); | |
159 //print(); | |
160 *sentry = NULL; | |
161 *sexception = NULL; | |
162 *sfinally = NULL; | |
163 } | |
164 | |
165 /********************************* | |
166 * Flatten out the scope by presenting the statement | |
167 * as an array of statements. | |
168 * Returns NULL if no flattening necessary. | |
169 */ | |
170 | |
171 Statements *Statement::flatten(Scope *sc) | |
172 { | |
173 return NULL; | |
174 } | |
175 | |
176 | |
177 /******************************** ExpStatement ***************************/ | |
178 | |
179 ExpStatement::ExpStatement(Loc loc, Expression *exp) | |
180 : Statement(loc) | |
181 { | |
182 this->exp = exp; | |
183 } | |
184 | |
185 Statement *ExpStatement::syntaxCopy() | |
186 { | |
187 Expression *e = exp ? exp->syntaxCopy() : NULL; | |
188 ExpStatement *es = new ExpStatement(loc, e); | |
189 return es; | |
190 } | |
191 | |
192 void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
193 { | |
194 if (exp) | |
195 exp->toCBuffer(buf, hgs); | |
196 buf->writeByte(';'); | |
197 if (!hgs->FLinit.init) | |
198 buf->writenl(); | |
199 } | |
200 | |
201 Statement *ExpStatement::semantic(Scope *sc) | |
202 { | |
203 if (exp) | |
204 { | |
205 //printf("ExpStatement::semantic() %s\n", exp->toChars()); | |
206 exp = exp->semantic(sc); | |
207 exp = resolveProperties(sc, exp); | |
208 exp->checkSideEffect(0); | |
209 exp = exp->optimize(0); | |
210 //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); | |
211 } | |
212 return this; | |
213 } | |
214 | |
336 | 215 int ExpStatement::blockExit() |
216 { int result = BEfallthru; | |
217 | |
218 if (exp) | |
219 { | |
220 if (exp->op == TOKhalt) | |
221 return BEhalt; | |
222 if (exp->op == TOKassert) | |
223 { AssertExp *a = (AssertExp *)exp; | |
224 | |
225 if (a->e1->isBool(FALSE)) // if it's an assert(0) | |
226 return BEhalt; | |
227 } | |
228 if (exp->canThrow()) | |
229 result |= BEthrow; | |
230 } | |
231 return result; | |
232 } | |
233 | |
159 | 234 |
235 /******************************** CompileStatement ***************************/ | |
236 | |
237 CompileStatement::CompileStatement(Loc loc, Expression *exp) | |
238 : Statement(loc) | |
239 { | |
240 this->exp = exp; | |
241 } | |
242 | |
243 Statement *CompileStatement::syntaxCopy() | |
244 { | |
245 Expression *e = exp->syntaxCopy(); | |
246 CompileStatement *es = new CompileStatement(loc, e); | |
247 return es; | |
248 } | |
249 | |
250 void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
251 { | |
252 buf->writestring("mixin("); | |
253 exp->toCBuffer(buf, hgs); | |
254 buf->writestring(");"); | |
255 if (!hgs->FLinit.init) | |
256 buf->writenl(); | |
257 } | |
258 | |
336 | 259 Statements *CompileStatement::flatten(Scope *sc) |
159 | 260 { |
336 | 261 //printf("CompileStatement::flatten() %s\n", exp->toChars()); |
159 | 262 exp = exp->semantic(sc); |
263 exp = resolveProperties(sc, exp); | |
264 exp = exp->optimize(WANTvalue | WANTinterpret); | |
265 if (exp->op != TOKstring) | |
266 { error("argument to mixin must be a string, not (%s)", exp->toChars()); | |
336 | 267 return NULL; |
159 | 268 } |
269 StringExp *se = (StringExp *)exp; | |
270 se = se->toUTF8(sc); | |
271 Parser p(sc->module, (unsigned char *)se->string, se->len, 0); | |
272 p.loc = loc; | |
273 p.nextToken(); | |
274 | |
336 | 275 Statements *a = new Statements(); |
159 | 276 while (p.token.value != TOKeof) |
277 { | |
278 Statement *s = p.parseStatement(PSsemi | PScurlyscope); | |
336 | 279 a->push(s); |
159 | 280 } |
336 | 281 return a; |
282 } | |
283 | |
284 Statement *CompileStatement::semantic(Scope *sc) | |
285 { | |
286 //printf("CompileStatement::semantic() %s\n", exp->toChars()); | |
287 Statements *a = flatten(sc); | |
288 if (!a) | |
289 return NULL; | |
290 Statement *s = new CompoundStatement(loc, a); | |
159 | 291 return s->semantic(sc); |
292 } | |
293 | |
294 | |
295 /******************************** DeclarationStatement ***************************/ | |
296 | |
297 DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) | |
298 : ExpStatement(loc, new DeclarationExp(loc, declaration)) | |
299 { | |
300 } | |
301 | |
302 DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) | |
303 : ExpStatement(loc, exp) | |
304 { | |
305 } | |
306 | |
307 Statement *DeclarationStatement::syntaxCopy() | |
308 { | |
309 DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); | |
310 return ds; | |
311 } | |
312 | |
313 void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) | |
314 { | |
315 //printf("DeclarationStatement::scopeCode()\n"); | |
316 //print(); | |
317 | |
318 *sentry = NULL; | |
319 *sexception = NULL; | |
320 *sfinally = NULL; | |
321 | |
322 if (exp) | |
323 { | |
324 if (exp->op == TOKdeclaration) | |
325 { | |
326 DeclarationExp *de = (DeclarationExp *)(exp); | |
327 VarDeclaration *v = de->declaration->isVarDeclaration(); | |
328 if (v) | |
329 { Expression *e; | |
330 | |
331 e = v->callAutoDtor(); | |
332 if (e) | |
333 { | |
334 //printf("dtor is: "); e->print(); | |
335 *sfinally = new ExpStatement(loc, e); | |
336 } | |
337 } | |
338 } | |
339 } | |
340 } | |
341 | |
342 void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
343 { | |
344 exp->toCBuffer(buf, hgs); | |
345 } | |
346 | |
347 | |
348 /******************************** CompoundStatement ***************************/ | |
349 | |
350 CompoundStatement::CompoundStatement(Loc loc, Statements *s) | |
351 : Statement(loc) | |
352 { | |
353 statements = s; | |
354 } | |
355 | |
356 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) | |
357 : Statement(loc) | |
358 { | |
359 statements = new Statements(); | |
360 statements->reserve(2); | |
361 statements->push(s1); | |
362 statements->push(s2); | |
363 } | |
364 | |
365 Statement *CompoundStatement::syntaxCopy() | |
366 { | |
367 Statements *a = new Statements(); | |
368 a->setDim(statements->dim); | |
369 for (size_t i = 0; i < statements->dim; i++) | |
370 { Statement *s = (Statement *)statements->data[i]; | |
371 if (s) | |
372 s = s->syntaxCopy(); | |
373 a->data[i] = s; | |
374 } | |
375 CompoundStatement *cs = new CompoundStatement(loc, a); | |
376 return cs; | |
377 } | |
378 | |
379 | |
380 Statement *CompoundStatement::semantic(Scope *sc) | |
381 { Statement *s; | |
382 | |
383 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); | |
384 | |
385 for (size_t i = 0; i < statements->dim; ) | |
386 { | |
387 s = (Statement *) statements->data[i]; | |
388 if (s) | |
389 { Statements *a = s->flatten(sc); | |
390 | |
391 if (a) | |
392 { | |
393 statements->remove(i); | |
394 statements->insert(i, a); | |
395 continue; | |
396 } | |
397 s = s->semantic(sc); | |
398 statements->data[i] = s; | |
399 if (s) | |
400 { | |
401 Statement *sentry; | |
402 Statement *sexception; | |
403 Statement *sfinally; | |
404 | |
405 s->scopeCode(&sentry, &sexception, &sfinally); | |
406 if (sentry) | |
407 { | |
408 sentry = sentry->semantic(sc); | |
409 statements->data[i] = sentry; | |
410 } | |
411 if (sexception) | |
412 { | |
413 if (i + 1 == statements->dim && !sfinally) | |
414 { | |
415 #if 1 | |
416 sexception = sexception->semantic(sc); | |
417 #else | |
418 statements->push(sexception); | |
419 if (sfinally) | |
420 // Assume sexception does not throw | |
421 statements->push(sfinally); | |
422 #endif | |
423 } | |
424 else | |
425 { | |
426 /* Rewrite: | |
427 * s; s1; s2; | |
428 * As: | |
429 * s; | |
430 * try { s1; s2; } | |
431 * catch (Object __o) | |
432 * { sexception; throw __o; } | |
433 */ | |
434 Statement *body; | |
435 Statements *a = new Statements(); | |
436 | |
437 for (int j = i + 1; j < statements->dim; j++) | |
438 { | |
439 a->push(statements->data[j]); | |
440 } | |
441 body = new CompoundStatement(0, a); | |
442 body = new ScopeStatement(0, body); | |
443 | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
444 Identifier *id = Lexer::uniqueId("__o"); |
159 | 445 |
446 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); | |
447 handler = new CompoundStatement(0, sexception, handler); | |
448 | |
449 Array *catches = new Array(); | |
450 Catch *ctch = new Catch(0, NULL, id, handler); | |
451 catches->push(ctch); | |
452 s = new TryCatchStatement(0, body, catches); | |
453 | |
454 if (sfinally) | |
455 s = new TryFinallyStatement(0, s, sfinally); | |
456 s = s->semantic(sc); | |
457 statements->setDim(i + 1); | |
458 statements->push(s); | |
459 break; | |
460 } | |
461 } | |
462 else if (sfinally) | |
463 { | |
464 if (0 && i + 1 == statements->dim) | |
465 { | |
466 statements->push(sfinally); | |
467 } | |
468 else | |
469 { | |
470 /* Rewrite: | |
471 * s; s1; s2; | |
472 * As: | |
473 * s; try { s1; s2; } finally { sfinally; } | |
474 */ | |
475 Statement *body; | |
476 Statements *a = new Statements(); | |
477 | |
478 for (int j = i + 1; j < statements->dim; j++) | |
479 { | |
480 a->push(statements->data[j]); | |
481 } | |
482 body = new CompoundStatement(0, a); | |
483 s = new TryFinallyStatement(0, body, sfinally); | |
484 s = s->semantic(sc); | |
485 statements->setDim(i + 1); | |
486 statements->push(s); | |
487 break; | |
488 } | |
489 } | |
490 } | |
491 } | |
492 i++; | |
493 } | |
232
092468448d25
[svn r248] Fixed: labels in inline asm block now work for the normal case.
lindquist
parents:
215
diff
changeset
|
494 if (statements->dim == 1 && !isAsmBlockStatement()) |
336 | 495 { |
496 return (Statement *)statements->data[0]; | |
497 } | |
159 | 498 return this; |
499 } | |
500 | |
501 Statements *CompoundStatement::flatten(Scope *sc) | |
502 { | |
503 return statements; | |
504 } | |
505 | |
506 ReturnStatement *CompoundStatement::isReturnStatement() | |
336 | 507 { |
159 | 508 ReturnStatement *rs = NULL; |
509 | |
336 | 510 for (int i = 0; i < statements->dim; i++) |
511 { Statement *s = (Statement *) statements->data[i]; | |
159 | 512 if (s) |
513 { | |
514 rs = s->isReturnStatement(); | |
515 if (rs) | |
516 break; | |
517 } | |
518 } | |
519 return rs; | |
520 } | |
521 | |
522 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
336 | 523 { |
524 for (int i = 0; i < statements->dim; i++) | |
525 { Statement *s = (Statement *) statements->data[i]; | |
159 | 526 if (s) |
527 s->toCBuffer(buf, hgs); | |
528 } | |
529 } | |
530 | |
531 int CompoundStatement::usesEH() | |
532 { | |
533 for (int i = 0; i < statements->dim; i++) | |
336 | 534 { Statement *s = (Statement *) statements->data[i]; |
159 | 535 if (s && s->usesEH()) |
536 return TRUE; | |
537 } | |
538 return FALSE; | |
539 } | |
540 | |
336 | 541 int CompoundStatement::blockExit() |
542 { | |
543 //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); | |
544 int result = BEfallthru; | |
545 for (size_t i = 0; i < statements->dim; i++) | |
546 { Statement *s = (Statement *) statements->data[i]; | |
547 if (s) | |
548 { | |
549 //printf("result = x%x\n", result); | |
550 //printf("%s\n", s->toChars()); | |
551 if (!(result & BEfallthru) && !s->comeFrom()) | |
552 { | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
553 s->warning("statement is not reachable"); |
336 | 554 } |
555 | |
556 result &= ~BEfallthru; | |
557 result |= s->blockExit(); | |
558 } | |
559 } | |
560 return result; | |
561 } | |
562 | |
159 | 563 int CompoundStatement::comeFrom() |
564 { int comefrom = FALSE; | |
565 | |
566 //printf("CompoundStatement::comeFrom()\n"); | |
567 for (int i = 0; i < statements->dim; i++) | |
568 { Statement *s = (Statement *)statements->data[i]; | |
569 | |
570 if (!s) | |
571 continue; | |
572 | |
573 comefrom |= s->comeFrom(); | |
574 } | |
575 return comefrom; | |
576 } | |
577 | |
578 | |
579 /**************************** UnrolledLoopStatement ***************************/ | |
580 | |
581 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) | |
582 : Statement(loc) | |
583 { | |
584 statements = s; | |
585 } | |
586 | |
587 Statement *UnrolledLoopStatement::syntaxCopy() | |
588 { | |
589 Statements *a = new Statements(); | |
590 a->setDim(statements->dim); | |
591 for (size_t i = 0; i < statements->dim; i++) | |
592 { Statement *s = (Statement *)statements->data[i]; | |
593 if (s) | |
594 s = s->syntaxCopy(); | |
595 a->data[i] = s; | |
596 } | |
597 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); | |
598 return cs; | |
599 } | |
600 | |
601 | |
602 Statement *UnrolledLoopStatement::semantic(Scope *sc) | |
603 { | |
604 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); | |
605 | |
606 sc->noctor++; | |
607 Scope *scd = sc->push(); | |
608 scd->sbreak = this; | |
609 scd->scontinue = this; | |
610 | |
611 for (size_t i = 0; i < statements->dim; i++) | |
612 { | |
613 Statement *s = (Statement *) statements->data[i]; | |
614 if (s) | |
615 { | |
616 s = s->semantic(scd); | |
617 statements->data[i] = s; | |
618 } | |
619 } | |
620 | |
621 scd->pop(); | |
622 sc->noctor--; | |
623 return this; | |
624 } | |
625 | |
626 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
627 { | |
628 buf->writestring("unrolled {"); | |
629 buf->writenl(); | |
630 | |
631 for (size_t i = 0; i < statements->dim; i++) | |
632 { Statement *s; | |
633 | |
634 s = (Statement *) statements->data[i]; | |
635 if (s) | |
636 s->toCBuffer(buf, hgs); | |
637 } | |
638 | |
639 buf->writeByte('}'); | |
640 buf->writenl(); | |
641 } | |
642 | |
643 int UnrolledLoopStatement::hasBreak() | |
644 { | |
645 return TRUE; | |
646 } | |
647 | |
648 int UnrolledLoopStatement::hasContinue() | |
649 { | |
650 return TRUE; | |
651 } | |
652 | |
653 int UnrolledLoopStatement::usesEH() | |
654 { | |
655 for (size_t i = 0; i < statements->dim; i++) | |
336 | 656 { Statement *s = (Statement *) statements->data[i]; |
159 | 657 if (s && s->usesEH()) |
658 return TRUE; | |
659 } | |
660 return FALSE; | |
661 } | |
662 | |
336 | 663 int UnrolledLoopStatement::blockExit() |
664 { | |
665 int result = BEfallthru; | |
666 for (size_t i = 0; i < statements->dim; i++) | |
667 { Statement *s = (Statement *) statements->data[i]; | |
668 if (s) | |
669 { | |
670 int r = s->blockExit(); | |
671 result |= r & ~(BEbreak | BEcontinue); | |
672 } | |
673 } | |
674 return result; | |
675 } | |
676 | |
159 | 677 int UnrolledLoopStatement::comeFrom() |
678 { int comefrom = FALSE; | |
679 | |
680 //printf("UnrolledLoopStatement::comeFrom()\n"); | |
681 for (size_t i = 0; i < statements->dim; i++) | |
682 { Statement *s = (Statement *)statements->data[i]; | |
683 | |
684 if (!s) | |
685 continue; | |
686 | |
687 comefrom |= s->comeFrom(); | |
688 } | |
689 return comefrom; | |
690 } | |
691 | |
692 | |
693 /******************************** ScopeStatement ***************************/ | |
694 | |
695 ScopeStatement::ScopeStatement(Loc loc, Statement *s) | |
696 : Statement(loc) | |
697 { | |
698 this->statement = s; | |
699 } | |
700 | |
701 Statement *ScopeStatement::syntaxCopy() | |
702 { | |
703 Statement *s; | |
704 | |
705 s = statement ? statement->syntaxCopy() : NULL; | |
706 s = new ScopeStatement(loc, s); | |
707 return s; | |
708 } | |
709 | |
710 | |
711 Statement *ScopeStatement::semantic(Scope *sc) | |
712 { ScopeDsymbol *sym; | |
713 | |
714 //printf("ScopeStatement::semantic(sc = %p)\n", sc); | |
715 if (statement) | |
716 { Statements *a; | |
717 | |
718 sym = new ScopeDsymbol(); | |
719 sym->parent = sc->scopesym; | |
720 sc = sc->push(sym); | |
721 | |
722 a = statement->flatten(sc); | |
723 if (a) | |
724 { | |
725 statement = new CompoundStatement(loc, a); | |
726 } | |
727 | |
728 statement = statement->semantic(sc); | |
729 if (statement) | |
730 { | |
731 Statement *sentry; | |
732 Statement *sexception; | |
733 Statement *sfinally; | |
734 | |
735 statement->scopeCode(&sentry, &sexception, &sfinally); | |
736 if (sfinally) | |
737 { | |
738 //printf("adding sfinally\n"); | |
739 statement = new CompoundStatement(loc, statement, sfinally); | |
740 } | |
741 } | |
742 | |
743 sc->pop(); | |
744 } | |
745 return this; | |
746 } | |
747 | |
748 int ScopeStatement::hasBreak() | |
749 { | |
750 //printf("ScopeStatement::hasBreak() %s\n", toChars()); | |
751 return statement ? statement->hasBreak() : FALSE; | |
752 } | |
753 | |
754 int ScopeStatement::hasContinue() | |
755 { | |
756 return statement ? statement->hasContinue() : FALSE; | |
757 } | |
758 | |
759 int ScopeStatement::usesEH() | |
760 { | |
761 return statement ? statement->usesEH() : FALSE; | |
762 } | |
763 | |
336 | 764 int ScopeStatement::blockExit() |
765 { | |
766 //printf("ScopeStatement::blockExit(%p)\n", statement); | |
767 return statement ? statement->blockExit() : BEfallthru; | |
768 } | |
769 | |
159 | 770 int ScopeStatement::comeFrom() |
771 { | |
772 //printf("ScopeStatement::comeFrom()\n"); | |
773 return statement ? statement->comeFrom() : FALSE; | |
774 } | |
775 | |
776 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
777 { | |
778 buf->writeByte('{'); | |
779 buf->writenl(); | |
780 | |
781 if (statement) | |
782 statement->toCBuffer(buf, hgs); | |
783 | |
784 buf->writeByte('}'); | |
785 buf->writenl(); | |
786 } | |
787 | |
788 /******************************** WhileStatement ***************************/ | |
789 | |
790 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) | |
791 : Statement(loc) | |
792 { | |
793 condition = c; | |
794 body = b; | |
795 } | |
796 | |
797 Statement *WhileStatement::syntaxCopy() | |
798 { | |
799 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); | |
800 return s; | |
801 } | |
802 | |
803 | |
804 Statement *WhileStatement::semantic(Scope *sc) | |
805 { | |
806 #if 0 | |
807 if (condition->op == TOKmatch) | |
808 { | |
809 /* Rewrite while (condition) body as: | |
810 * if (condition) | |
811 * do | |
812 * body | |
813 * while ((_match = _match.opNext), _match); | |
814 */ | |
815 | |
816 Expression *ew = new IdentifierExp(0, Id::_match); | |
817 ew = new DotIdExp(0, ew, Id::next); | |
818 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew); | |
819 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0)); | |
820 Expression *ev = new IdentifierExp(0, Id::_match); | |
821 //ev = new CastExp(0, ev, Type::tvoidptr); | |
822 ew = new CommaExp(0, ew, ev); | |
823 Statement *sw = new DoStatement(loc, body, ew); | |
824 Statement *si = new IfStatement(loc, condition, sw, NULL); | |
825 return si->semantic(sc); | |
826 } | |
827 #endif | |
828 | |
829 condition = condition->semantic(sc); | |
830 condition = resolveProperties(sc, condition); | |
831 condition = condition->optimize(WANTvalue); | |
832 condition = condition->checkToBoolean(); | |
833 | |
834 sc->noctor++; | |
835 | |
836 Scope *scd = sc->push(); | |
837 scd->sbreak = this; | |
838 scd->scontinue = this; | |
839 if (body) | |
840 body = body->semantic(scd); | |
841 scd->pop(); | |
842 | |
843 sc->noctor--; | |
844 | |
845 return this; | |
846 } | |
847 | |
848 int WhileStatement::hasBreak() | |
849 { | |
850 return TRUE; | |
851 } | |
852 | |
853 int WhileStatement::hasContinue() | |
854 { | |
855 return TRUE; | |
856 } | |
857 | |
858 int WhileStatement::usesEH() | |
859 { | |
860 return body ? body->usesEH() : 0; | |
861 } | |
862 | |
336 | 863 int WhileStatement::blockExit() |
864 { | |
865 //printf("WhileStatement::blockExit(%p)\n", this); | |
866 | |
867 int result = BEnone; | |
868 if (condition->canThrow()) | |
869 result |= BEthrow; | |
870 if (condition->isBool(TRUE)) | |
871 { | |
872 if (body) | |
873 { result |= body->blockExit(); | |
874 if (result & BEbreak) | |
875 result |= BEfallthru; | |
876 } | |
877 } | |
878 else if (condition->isBool(FALSE)) | |
879 { | |
880 result |= BEfallthru; | |
881 } | |
882 else | |
883 { | |
884 if (body) | |
885 result |= body->blockExit(); | |
886 result |= BEfallthru; | |
887 } | |
888 result &= ~(BEbreak | BEcontinue); | |
889 return result; | |
890 } | |
891 | |
159 | 892 int WhileStatement::comeFrom() |
893 { | |
894 if (body) | |
895 return body->comeFrom(); | |
896 return FALSE; | |
897 } | |
898 | |
899 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
900 { | |
901 buf->writestring("while ("); | |
902 condition->toCBuffer(buf, hgs); | |
903 buf->writebyte(')'); | |
904 buf->writenl(); | |
905 if (body) | |
906 body->toCBuffer(buf, hgs); | |
907 } | |
908 | |
909 /******************************** DoStatement ***************************/ | |
910 | |
911 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) | |
912 : Statement(loc) | |
913 { | |
914 body = b; | |
915 condition = c; | |
916 } | |
917 | |
918 Statement *DoStatement::syntaxCopy() | |
919 { | |
920 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); | |
921 return s; | |
922 } | |
923 | |
924 | |
925 Statement *DoStatement::semantic(Scope *sc) | |
926 { | |
927 sc->noctor++; | |
928 if (body) | |
929 body = body->semanticScope(sc, this, this); | |
930 sc->noctor--; | |
931 condition = condition->semantic(sc); | |
932 condition = resolveProperties(sc, condition); | |
933 condition = condition->optimize(WANTvalue); | |
934 | |
935 condition = condition->checkToBoolean(); | |
936 | |
937 return this; | |
938 } | |
939 | |
940 int DoStatement::hasBreak() | |
941 { | |
942 return TRUE; | |
943 } | |
944 | |
945 int DoStatement::hasContinue() | |
946 { | |
947 return TRUE; | |
948 } | |
949 | |
950 int DoStatement::usesEH() | |
951 { | |
952 return body ? body->usesEH() : 0; | |
953 } | |
954 | |
336 | 955 int DoStatement::blockExit() |
956 { int result; | |
957 | |
958 if (body) | |
959 { result = body->blockExit(); | |
960 if (result == BEbreak) | |
961 return BEfallthru; | |
962 if (result & BEcontinue) | |
963 result |= BEfallthru; | |
964 } | |
965 else | |
966 result = BEfallthru; | |
967 if (result & BEfallthru) | |
968 { if (condition->canThrow()) | |
969 result |= BEthrow; | |
970 if (!(result & BEbreak) && condition->isBool(TRUE)) | |
971 result &= ~BEfallthru; | |
972 } | |
973 result &= ~(BEbreak | BEcontinue); | |
974 return result; | |
975 } | |
976 | |
159 | 977 int DoStatement::comeFrom() |
978 { | |
979 if (body) | |
980 return body->comeFrom(); | |
981 return FALSE; | |
982 } | |
983 | |
984 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
985 { | |
986 buf->writestring("do"); | |
987 buf->writenl(); | |
988 if (body) | |
989 body->toCBuffer(buf, hgs); | |
990 buf->writestring("while ("); | |
991 condition->toCBuffer(buf, hgs); | |
992 buf->writebyte(')'); | |
993 } | |
994 | |
995 /******************************** ForStatement ***************************/ | |
996 | |
997 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) | |
998 : Statement(loc) | |
999 { | |
1000 this->init = init; | |
1001 this->condition = condition; | |
1002 this->increment = increment; | |
1003 this->body = body; | |
1004 } | |
1005 | |
1006 Statement *ForStatement::syntaxCopy() | |
1007 { | |
1008 Statement *i = NULL; | |
1009 if (init) | |
1010 i = init->syntaxCopy(); | |
1011 Expression *c = NULL; | |
1012 if (condition) | |
1013 c = condition->syntaxCopy(); | |
1014 Expression *inc = NULL; | |
1015 if (increment) | |
1016 inc = increment->syntaxCopy(); | |
1017 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); | |
1018 return s; | |
1019 } | |
1020 | |
1021 Statement *ForStatement::semantic(Scope *sc) | |
1022 { | |
1023 ScopeDsymbol *sym = new ScopeDsymbol(); | |
1024 sym->parent = sc->scopesym; | |
1025 sc = sc->push(sym); | |
1026 if (init) | |
1027 init = init->semantic(sc); | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
1028 #if 0 |
159 | 1029 if (!condition) |
1030 // Use a default value | |
1031 condition = new IntegerExp(loc, 1, Type::tboolean); | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
1032 #endif |
159 | 1033 sc->noctor++; |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1034 if (condition) |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1035 { |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1036 condition = condition->semantic(sc); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1037 condition = resolveProperties(sc, condition); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1038 condition = condition->optimize(WANTvalue); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1039 condition = condition->checkToBoolean(); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1040 } |
159 | 1041 if (increment) |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1042 { increment = increment->semantic(sc); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1043 increment = resolveProperties(sc, increment); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1044 } |
159 | 1045 |
1046 sc->sbreak = this; | |
1047 sc->scontinue = this; | |
1048 body = body->semantic(sc); | |
1049 sc->noctor--; | |
1050 | |
1051 sc->pop(); | |
1052 return this; | |
1053 } | |
1054 | |
1055 void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) | |
1056 { | |
1057 //printf("ForStatement::scopeCode()\n"); | |
1058 //print(); | |
1059 if (init) | |
1060 init->scopeCode(sentry, sexception, sfinally); | |
1061 else | |
1062 Statement::scopeCode(sentry, sexception, sfinally); | |
1063 } | |
1064 | |
1065 int ForStatement::hasBreak() | |
1066 { | |
1067 //printf("ForStatement::hasBreak()\n"); | |
1068 return TRUE; | |
1069 } | |
1070 | |
1071 int ForStatement::hasContinue() | |
1072 { | |
1073 return TRUE; | |
1074 } | |
1075 | |
1076 int ForStatement::usesEH() | |
1077 { | |
1078 return (init && init->usesEH()) || body->usesEH(); | |
1079 } | |
1080 | |
336 | 1081 int ForStatement::blockExit() |
1082 { int result = BEfallthru; | |
1083 | |
1084 if (init) | |
1085 { result = init->blockExit(); | |
1086 if (!(result & BEfallthru)) | |
1087 return result; | |
1088 } | |
1089 if (condition) | |
1090 { if (condition->canThrow()) | |
1091 result |= BEthrow; | |
1092 } | |
1093 else | |
1094 result &= ~BEfallthru; // the body must do the exiting | |
1095 if (body) | |
1096 { int r = body->blockExit(); | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
1097 if (r & (BEbreak | BEgoto)) |
336 | 1098 result |= BEfallthru; |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
1099 result |= r & ~(BEfallthru | BEbreak | BEcontinue); |
336 | 1100 } |
1101 if (increment && increment->canThrow()) | |
1102 result |= BEthrow; | |
1103 return result; | |
1104 } | |
1105 | |
159 | 1106 int ForStatement::comeFrom() |
1107 { | |
1108 //printf("ForStatement::comeFrom()\n"); | |
1109 if (body) | |
1110 { int result = body->comeFrom(); | |
1111 //printf("result = %d\n", result); | |
1112 return result; | |
1113 } | |
1114 return FALSE; | |
1115 } | |
1116 | |
1117 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
1118 { | |
1119 buf->writestring("for ("); | |
1120 if (init) | |
1121 { | |
1122 hgs->FLinit.init++; | |
1123 hgs->FLinit.decl = 0; | |
1124 init->toCBuffer(buf, hgs); | |
1125 if (hgs->FLinit.decl > 0) | |
1126 buf->writebyte(';'); | |
1127 hgs->FLinit.decl = 0; | |
1128 hgs->FLinit.init--; | |
1129 } | |
1130 else | |
1131 buf->writebyte(';'); | |
1132 if (condition) | |
1133 { buf->writebyte(' '); | |
1134 condition->toCBuffer(buf, hgs); | |
1135 } | |
1136 buf->writebyte(';'); | |
1137 if (increment) | |
1138 { buf->writebyte(' '); | |
1139 increment->toCBuffer(buf, hgs); | |
1140 } | |
1141 buf->writebyte(')'); | |
1142 buf->writenl(); | |
1143 buf->writebyte('{'); | |
1144 buf->writenl(); | |
1145 body->toCBuffer(buf, hgs); | |
1146 buf->writebyte('}'); | |
1147 buf->writenl(); | |
1148 } | |
1149 | |
1150 /******************************** ForeachStatement ***************************/ | |
1151 | |
1152 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, | |
1153 Expression *aggr, Statement *body) | |
1154 : Statement(loc) | |
1155 { | |
1156 this->op = op; | |
1157 this->arguments = arguments; | |
1158 this->aggr = aggr; | |
1159 this->body = body; | |
1160 | |
1161 this->key = NULL; | |
1162 this->value = NULL; | |
1163 | |
1164 this->func = NULL; | |
1165 } | |
1166 | |
1167 Statement *ForeachStatement::syntaxCopy() | |
1168 { | |
1169 Arguments *args = Argument::arraySyntaxCopy(arguments); | |
1170 Expression *exp = aggr->syntaxCopy(); | |
1171 ForeachStatement *s = new ForeachStatement(loc, op, args, exp, | |
1172 body ? body->syntaxCopy() : NULL); | |
1173 return s; | |
1174 } | |
1175 | |
1176 Statement *ForeachStatement::semantic(Scope *sc) | |
1177 { | |
1178 //printf("ForeachStatement::semantic() %p\n", this); | |
1179 ScopeDsymbol *sym; | |
1180 Statement *s = this; | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1181 size_t dim = arguments->dim; |
159 | 1182 TypeAArray *taa = NULL; |
1183 | |
1184 Type *tn = NULL; | |
1185 Type *tnv = NULL; | |
1186 | |
1187 func = sc->func; | |
1188 if (func->fes) | |
1189 func = func->fes->func; | |
1190 | |
1191 aggr = aggr->semantic(sc); | |
1192 aggr = resolveProperties(sc, aggr); | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1193 aggr = aggr->optimize(WANTvalue); |
159 | 1194 if (!aggr->type) |
1195 { | |
1196 error("invalid foreach aggregate %s", aggr->toChars()); | |
1197 return this; | |
1198 } | |
1199 | |
1200 inferApplyArgTypes(op, arguments, aggr); | |
1201 | |
1202 /* Check for inference errors | |
1203 */ | |
1204 if (dim != arguments->dim) | |
1205 { | |
1206 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); | |
1207 error("cannot uniquely infer foreach argument types"); | |
1208 return this; | |
1209 } | |
1210 | |
1211 Type *tab = aggr->type->toBasetype(); | |
1212 | |
1213 if (tab->ty == Ttuple) // don't generate new scope for tuple loops | |
1214 { | |
1215 if (dim < 1 || dim > 2) | |
1216 { | |
1217 error("only one (value) or two (key,value) arguments for tuple foreach"); | |
1218 return s; | |
1219 } | |
1220 | |
1221 TypeTuple *tuple = (TypeTuple *)tab; | |
1222 Statements *statements = new Statements(); | |
1223 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); | |
1224 size_t n; | |
1225 TupleExp *te = NULL; | |
1226 if (aggr->op == TOKtuple) // expression tuple | |
1227 { te = (TupleExp *)aggr; | |
1228 n = te->exps->dim; | |
1229 } | |
1230 else if (aggr->op == TOKtype) // type tuple | |
1231 { | |
1232 n = Argument::dim(tuple->arguments); | |
1233 } | |
1234 else | |
1235 assert(0); | |
1236 for (size_t j = 0; j < n; j++) | |
1237 { size_t k = (op == TOKforeach) ? j : n - 1 - j; | |
1238 Expression *e; | |
1239 Type *t; | |
1240 if (te) | |
1241 e = (Expression *)te->exps->data[k]; | |
1242 else | |
1243 t = Argument::getNth(tuple->arguments, k)->type; | |
1244 Argument *arg = (Argument *)arguments->data[0]; | |
1245 Statements *st = new Statements(); | |
1246 | |
1247 if (dim == 2) | |
1248 { // Declare key | |
1249 if (arg->storageClass & (STCout | STCref | STClazy)) | |
1250 error("no storage class for key %s", arg->ident->toChars()); | |
1251 TY keyty = arg->type->ty; | |
275
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1252 if (global.params.is64bit) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1253 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1254 if (keyty != Tint32 && keyty != Tuns32 && keyty != Tint64 && keyty != Tuns64) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1255 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1256 error("foreach: key type must be int, uint, long or ulong, not %s", key->type->toChars()); |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1257 } |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1258 } |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1259 else if (keyty != Tint32 && keyty != Tuns32) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1260 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1261 error("foreach: key type must be int or uint, not %s", key->type->toChars()); |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1262 } |
159 | 1263 Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); |
1264 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); | |
1265 var->storage_class |= STCconst; | |
1266 DeclarationExp *de = new DeclarationExp(loc, var); | |
1267 st->push(new ExpStatement(loc, de)); | |
1268 arg = (Argument *)arguments->data[1]; // value | |
1269 } | |
1270 // Declare value | |
1271 if (arg->storageClass & (STCout | STCref | STClazy)) | |
1272 error("no storage class for value %s", arg->ident->toChars()); | |
1273 Dsymbol *var; | |
1274 if (te) | |
1275 { | |
1276 if (e->type->toBasetype()->ty == Tfunction && | |
1277 e->op == TOKvar) | |
1278 { VarExp *ve = (VarExp *)e; | |
1279 var = new AliasDeclaration(loc, arg->ident, ve->var); | |
1280 } | |
1281 else | |
1282 { | |
1283 arg->type = e->type; | |
1284 Initializer *ie = new ExpInitializer(0, e); | |
1285 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); | |
1286 if (e->isConst()) | |
1287 v->storage_class |= STCconst; | |
1288 var = v; | |
1289 } | |
1290 } | |
1291 else | |
1292 { | |
1293 var = new AliasDeclaration(loc, arg->ident, t); | |
1294 } | |
1295 DeclarationExp *de = new DeclarationExp(loc, var); | |
1296 st->push(new ExpStatement(loc, de)); | |
1297 | |
1298 st->push(body->syntaxCopy()); | |
1299 s = new CompoundStatement(loc, st); | |
1300 s = new ScopeStatement(loc, s); | |
1301 statements->push(s); | |
1302 } | |
1303 | |
1304 s = new UnrolledLoopStatement(loc, statements); | |
1305 s = s->semantic(sc); | |
1306 return s; | |
1307 } | |
1308 | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1309 for (size_t i = 0; i < dim; i++) |
159 | 1310 { Argument *arg = (Argument *)arguments->data[i]; |
1311 if (!arg->type) | |
1312 { | |
1313 error("cannot infer type for %s", arg->ident->toChars()); | |
1314 return this; | |
1315 } | |
1316 } | |
1317 | |
1318 sym = new ScopeDsymbol(); | |
1319 sym->parent = sc->scopesym; | |
1320 sc = sc->push(sym); | |
1321 | |
1322 sc->noctor++; | |
1323 | |
1324 switch (tab->ty) | |
1325 { | |
1326 case Tarray: | |
1327 case Tsarray: | |
1328 if (dim < 1 || dim > 2) | |
1329 { | |
1330 error("only one or two arguments for array foreach"); | |
1331 break; | |
1332 } | |
1333 | |
1334 /* Look for special case of parsing char types out of char type | |
1335 * array. | |
1336 */ | |
1337 tn = tab->nextOf()->toBasetype(); | |
1338 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) | |
1339 { Argument *arg; | |
1340 | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1341 int i = (dim == 1) ? 0 : 1; // index of value |
159 | 1342 arg = (Argument *)arguments->data[i]; |
1343 arg->type = arg->type->semantic(loc, sc); | |
1344 tnv = arg->type->toBasetype(); | |
1345 if (tnv->ty != tn->ty && | |
1346 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) | |
1347 { | |
1348 if (arg->storageClass & STCref) | |
1349 error("foreach: value of UTF conversion cannot be ref"); | |
1350 if (dim == 2) | |
1351 { arg = (Argument *)arguments->data[0]; | |
1352 if (arg->storageClass & STCref) | |
1353 error("foreach: key cannot be ref"); | |
1354 } | |
1355 goto Lapply; | |
1356 } | |
1357 } | |
1358 | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1359 for (size_t i = 0; i < dim; i++) |
159 | 1360 { // Declare args |
1361 Argument *arg = (Argument *)arguments->data[i]; | |
1362 VarDeclaration *var; | |
1363 | |
1364 var = new VarDeclaration(loc, arg->type, arg->ident, NULL); | |
1365 var->storage_class |= STCforeach; | |
1366 var->storage_class |= arg->storageClass & (STCin | STCout | STCref); | |
1367 #if 1 | |
1368 DeclarationExp *de = new DeclarationExp(loc, var); | |
1369 de->semantic(sc); | |
1370 #else | |
1371 var->semantic(sc); | |
1372 if (!sc->insert(var)) | |
1373 error("%s already defined", var->ident->toChars()); | |
1374 #endif | |
1375 if (dim == 2 && i == 0) | |
1376 key = var; | |
1377 else | |
1378 value = var; | |
1379 } | |
1380 | |
1381 sc->sbreak = this; | |
1382 sc->scontinue = this; | |
1383 body = body->semantic(sc); | |
1384 | |
1385 if (!value->type->equals(tab->next)) | |
1386 { | |
1387 if (aggr->op == TOKstring) | |
1388 aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); | |
1389 else | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1390 error("foreach: %s is not an array of %s", |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1391 tab->toChars(), value->type->toChars()); |
159 | 1392 } |
1393 | |
275
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1394 if (key) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1395 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1396 if (global.params.is64bit) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1397 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1398 if (key->type->ty != Tint32 && key->type->ty != Tuns32 && key->type->ty != Tint64 && key->type->ty != Tuns64) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1399 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1400 error("foreach: key type must be int, uint, long or ulong, not %s", key->type->toChars()); |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1401 } |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1402 } |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1403 else if (key->type->ty != Tint32 && key->type->ty != Tuns32) |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1404 { |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1405 error("foreach: key type must be int or uint, not %s", key->type->toChars()); |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1406 } |
665b81613475
[svn r296] Removed: the 'suite' dir, it never took off!
lindquist
parents:
262
diff
changeset
|
1407 } |
159 | 1408 |
1409 if (key && key->storage_class & (STCout | STCref)) | |
1410 error("foreach: key cannot be out or ref"); | |
1411 break; | |
1412 | |
1413 case Taarray: | |
1414 taa = (TypeAArray *)tab; | |
1415 if (dim < 1 || dim > 2) | |
1416 { | |
1417 error("only one or two arguments for associative array foreach"); | |
1418 break; | |
1419 } | |
1420 if (op == TOKforeach_reverse) | |
1421 { | |
1422 error("no reverse iteration on associative arrays"); | |
1423 } | |
1424 goto Lapply; | |
1425 | |
1426 case Tclass: | |
1427 case Tstruct: | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1428 #if DMDV2 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1429 { /* Look for range iteration, i.e. the properties |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1430 * .empty, .next, .retreat, .head and .rear |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1431 * foreach (e; range) { ... } |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1432 * translates to: |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1433 * for (auto __r = range; !__r.empty; __r.next) |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1434 * { auto e = __r.head; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1435 * ... |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1436 * } |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1437 */ |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1438 if (dim != 1) // only one argument allowed with ranges |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1439 goto Lapply; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1440 AggregateDeclaration *ad = (tab->ty == Tclass) |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1441 ? (AggregateDeclaration *)((TypeClass *)tab)->sym |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1442 : (AggregateDeclaration *)((TypeStruct *)tab)->sym; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1443 Identifier *idhead; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1444 Identifier *idnext; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1445 if (op == TOKforeach) |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1446 { idhead = Id::Fhead; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1447 idnext = Id::Fnext; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1448 } |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1449 else |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1450 { idhead = Id::Frear; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1451 idnext = Id::Fretreat; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1452 } |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1453 Dsymbol *shead = search_function(ad, idhead); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1454 if (!shead) |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1455 goto Lapply; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1456 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1457 /* Generate a temporary __r and initialize it with the aggregate. |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1458 */ |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1459 Identifier *id = Identifier::generateId("__r"); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1460 VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, aggr)); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1461 r->semantic(sc); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1462 Statement *init = new DeclarationStatement(loc, r); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1463 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1464 // !__r.empty |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1465 Expression *e = new VarExp(loc, r); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1466 e = new DotIdExp(loc, e, Id::Fempty); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1467 Expression *condition = new NotExp(loc, e); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1468 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1469 // __r.next |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1470 e = new VarExp(loc, r); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1471 Expression *increment = new DotIdExp(loc, e, idnext); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1472 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1473 /* Declaration statement for e: |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1474 * auto e = __r.idhead; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1475 */ |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1476 e = new VarExp(loc, r); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1477 Expression *einit = new DotIdExp(loc, e, idhead); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1478 einit = einit->semantic(sc); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1479 Argument *arg = (Argument *)arguments->data[0]; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1480 VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1481 ve->storage_class |= STCforeach; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1482 ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1483 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1484 DeclarationExp *de = new DeclarationExp(loc, ve); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1485 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1486 Statement *body = new CompoundStatement(loc, |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1487 new DeclarationStatement(loc, de), this->body); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1488 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1489 s = new ForStatement(loc, init, condition, increment, body); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1490 s = s->semantic(sc); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1491 break; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1492 } |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1493 #endif |
159 | 1494 case Tdelegate: |
1495 Lapply: | |
1496 { FuncDeclaration *fdapply; | |
1497 Arguments *args; | |
1498 Expression *ec; | |
1499 Expression *e; | |
1500 FuncLiteralDeclaration *fld; | |
1501 Argument *a; | |
1502 Type *t; | |
1503 Expression *flde; | |
1504 Identifier *id; | |
1505 Type *tret; | |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1506 TypeDelegate* dgty; |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1507 TypeDelegate* dgty2; |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1508 TypeDelegate* fldeTy; |
159 | 1509 |
1510 tret = func->type->nextOf(); | |
1511 | |
1512 // Need a variable to hold value from any return statements in body. | |
1513 if (!sc->func->vresult && tret && tret != Type::tvoid) | |
1514 { VarDeclaration *v; | |
1515 | |
1516 v = new VarDeclaration(loc, tret, Id::result, NULL); | |
1517 v->noauto = 1; | |
1518 v->semantic(sc); | |
1519 if (!sc->insert(v)) | |
1520 assert(0); | |
1521 v->parent = sc->func; | |
1522 sc->func->vresult = v; | |
1523 } | |
1524 | |
1525 /* Turn body into the function literal: | |
1526 * int delegate(ref T arg) { body } | |
1527 */ | |
1528 args = new Arguments(); | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1529 for (size_t i = 0; i < dim; i++) |
159 | 1530 { Argument *arg = (Argument *)arguments->data[i]; |
1531 | |
1532 arg->type = arg->type->semantic(loc, sc); | |
1533 if (arg->storageClass & STCref) | |
1534 id = arg->ident; | |
1535 else | |
1536 { // Make a copy of the ref argument so it isn't | |
1537 // a reference. | |
1538 VarDeclaration *v; | |
1539 Initializer *ie; | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1540 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
1541 id = Lexer::uniqueId("__applyArg", i); |
159 | 1542 |
1543 ie = new ExpInitializer(0, new IdentifierExp(0, id)); | |
1544 v = new VarDeclaration(0, arg->type, arg->ident, ie); | |
1545 s = new DeclarationStatement(0, v); | |
1546 body = new CompoundStatement(loc, s, body); | |
1547 } | |
1548 a = new Argument(STCref, arg->type, id, NULL); | |
1549 args->push(a); | |
1550 } | |
1551 t = new TypeFunction(args, Type::tint32, 0, LINKd); | |
1552 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); | |
1553 fld->fbody = body; | |
1554 flde = new FuncExp(loc, fld); | |
1555 flde = flde->semantic(sc); | |
1556 | |
1557 // Resolve any forward referenced goto's | |
1558 for (int i = 0; i < gotos.dim; i++) | |
1559 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i]; | |
1560 GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; | |
1561 | |
1562 if (!gs->label->statement) | |
1563 { // 'Promote' it to this scope, and replace with a return | |
1564 cases.push(gs); | |
1565 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1)); | |
1566 cs->statements->data[0] = (void *)s; | |
1567 } | |
1568 } | |
1569 | |
1570 if (tab->ty == Taarray) | |
1571 { | |
1572 // Check types | |
1573 Argument *arg = (Argument *)arguments->data[0]; | |
1574 if (dim == 2) | |
1575 { | |
1576 if (arg->storageClass & STCref) | |
1577 error("foreach: index cannot be ref"); | |
1578 if (!arg->type->equals(taa->index)) | |
1579 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); | |
1580 arg = (Argument *)arguments->data[1]; | |
1581 } | |
1582 if (!arg->type->equals(taa->nextOf())) | |
1583 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); | |
1584 | |
1585 /* Call: | |
1586 * _aaApply(aggr, keysize, flde) | |
1587 */ | |
664
eef8ac26c66c
Some missed LLVMDC -> LDC.
Christian Kamm <kamm incasoftware de>
parents:
510
diff
changeset
|
1588 //LDC: Build arguments. |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1589 static FuncDeclaration *aaApply2_fd = NULL; |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1590 static TypeDelegate* aaApply2_dg; |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1591 if(!aaApply2_fd) { |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1592 Arguments* args = new Arguments; |
715
30b42a283c8e
Removed TypeOpaque from DMD.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
1593 args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1594 args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1595 Arguments* dgargs = new Arguments; |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1596 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1597 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1598 aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1599 args->push(new Argument(STCin, aaApply2_dg, NULL, NULL)); |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1600 aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2"); |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1601 } |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1602 static FuncDeclaration *aaApply_fd = NULL; |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1603 static TypeDelegate* aaApply_dg; |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1604 if(!aaApply_fd) { |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1605 Arguments* args = new Arguments; |
715
30b42a283c8e
Removed TypeOpaque from DMD.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
1606 args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1607 args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1608 Arguments* dgargs = new Arguments; |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1609 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1610 aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1611 args->push(new Argument(STCin, aaApply_dg, NULL, NULL)); |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1612 aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply"); |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1613 } |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1614 if (dim == 2) { |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1615 fdapply = aaApply2_fd; |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1616 fldeTy = aaApply2_dg; |
389
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1617 } else { |
722f5e90c39c
Made setup for runtime calls in dmd frontend allocate less.
Christian Kamm <kamm incasoftware de>
parents:
380
diff
changeset
|
1618 fdapply = aaApply_fd; |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1619 fldeTy = aaApply_dg; |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1620 } |
159 | 1621 ec = new VarExp(0, fdapply); |
1622 Expressions *exps = new Expressions(); | |
1623 exps->push(aggr); | |
1624 size_t keysize = taa->key->size(); | |
765
f08e0ff8d28c
Fixed 32bit assumption in statement.c when calling aaApply(2).
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
719
diff
changeset
|
1625 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); |
159 | 1626 exps->push(new IntegerExp(0, keysize, Type::tsize_t)); |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1627 |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1628 // LDC paint delegate argument to the type runtime expects |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1629 if (!fldeTy->equals(flde->type)) |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1630 { |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1631 flde = new CastExp(loc, flde, flde->type); |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1632 flde->type = fldeTy; |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1633 } |
159 | 1634 exps->push(flde); |
1635 e = new CallExp(loc, ec, exps); | |
1636 e->type = Type::tindex; // don't run semantic() on e | |
1637 } | |
1638 else if (tab->ty == Tarray || tab->ty == Tsarray) | |
1639 { | |
1640 /* Call: | |
1641 * _aApply(aggr, flde) | |
1642 */ | |
1643 static char fntab[9][3] = | |
1644 { "cc","cw","cd", | |
1645 "wc","cc","wd", | |
1646 "dc","dw","dd" | |
1647 }; | |
1648 char fdname[7+1+2+ sizeof(dim)*3 + 1]; | |
1649 int flag; | |
1650 | |
1651 switch (tn->ty) | |
1652 { | |
1653 case Tchar: flag = 0; break; | |
1654 case Twchar: flag = 3; break; | |
1655 case Tdchar: flag = 6; break; | |
1656 default: assert(0); | |
1657 } | |
1658 switch (tnv->ty) | |
1659 { | |
1660 case Tchar: flag += 0; break; | |
1661 case Twchar: flag += 1; break; | |
1662 case Tdchar: flag += 2; break; | |
1663 default: assert(0); | |
1664 } | |
1665 const char *r = (op == TOKforeach_reverse) ? "R" : ""; | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
1666 int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); |
159 | 1667 assert(j < sizeof(fdname)); |
664
eef8ac26c66c
Some missed LLVMDC -> LDC.
Christian Kamm <kamm incasoftware de>
parents:
510
diff
changeset
|
1668 //LDC: Build arguments. |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1669 Arguments* args = new Arguments; |
715
30b42a283c8e
Removed TypeOpaque from DMD.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
1670 args->push(new Argument(STCin, tn->arrayOf(), NULL, NULL)); |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1671 if (dim == 2) { |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1672 Arguments* dgargs = new Arguments; |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1673 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1674 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1675 dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1676 args->push(new Argument(STCin, dgty, NULL, NULL)); |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1677 fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1678 } else { |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1679 Arguments* dgargs = new Arguments; |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1680 dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1681 dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); |
378
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1682 args->push(new Argument(STCin, dgty, NULL, NULL)); |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1683 fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); |
d8234836b40f
Get rid of runTimeHack and instead add proper argument info to the frontend
Christian Kamm <kamm incasoftware de>
parents:
353
diff
changeset
|
1684 } |
159 | 1685 |
1686 ec = new VarExp(0, fdapply); | |
1687 Expressions *exps = new Expressions(); | |
1688 if (tab->ty == Tsarray) | |
1689 aggr = aggr->castTo(sc, tn->arrayOf()); | |
715
30b42a283c8e
Removed TypeOpaque from DMD.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
664
diff
changeset
|
1690 exps->push(aggr); |
719
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1691 |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1692 // LDC paint delegate argument to the type runtime expects |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1693 if (!dgty->equals(flde->type)) |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1694 { |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1695 flde = new CastExp(loc, flde, flde->type); |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1696 flde->type = dgty; |
7261ff0f95ff
Implemented first class delegates. closes #101
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
715
diff
changeset
|
1697 } |
159 | 1698 exps->push(flde); |
1699 e = new CallExp(loc, ec, exps); | |
1700 e->type = Type::tindex; // don't run semantic() on e | |
1701 } | |
1702 else if (tab->ty == Tdelegate) | |
1703 { | |
1704 /* Call: | |
1705 * aggr(flde) | |
1706 */ | |
1707 Expressions *exps = new Expressions(); | |
1708 exps->push(flde); | |
1709 e = new CallExp(loc, aggr, exps); | |
1710 e = e->semantic(sc); | |
1711 if (e->type != Type::tint32) | |
1712 error("opApply() function for %s must return an int", tab->toChars()); | |
1713 } | |
1714 else | |
1715 { | |
1716 /* Call: | |
1717 * aggr.apply(flde) | |
1718 */ | |
1719 ec = new DotIdExp(loc, aggr, | |
1720 (op == TOKforeach_reverse) ? Id::applyReverse | |
1721 : Id::apply); | |
1722 Expressions *exps = new Expressions(); | |
1723 exps->push(flde); | |
1724 e = new CallExp(loc, ec, exps); | |
1725 e = e->semantic(sc); | |
1726 if (e->type != Type::tint32) | |
1727 error("opApply() function for %s must return an int", tab->toChars()); | |
1728 } | |
1729 | |
1730 if (!cases.dim) | |
1731 // Easy case, a clean exit from the loop | |
1732 s = new ExpStatement(loc, e); | |
1733 else | |
1734 { // Construct a switch statement around the return value | |
1735 // of the apply function. | |
1736 Statements *a = new Statements(); | |
1737 | |
1738 // default: break; takes care of cases 0 and 1 | |
1739 s = new BreakStatement(0, NULL); | |
1740 s = new DefaultStatement(0, s); | |
1741 a->push(s); | |
1742 | |
1743 // cases 2... | |
1744 for (int i = 0; i < cases.dim; i++) | |
1745 { | |
1746 s = (Statement *)cases.data[i]; | |
1747 s = new CaseStatement(0, new IntegerExp(i + 2), s); | |
1748 a->push(s); | |
1749 } | |
1750 | |
1751 s = new CompoundStatement(loc, a); | |
1752 s = new SwitchStatement(loc, e, s); | |
1753 s = s->semantic(sc); | |
1754 } | |
1755 break; | |
1756 } | |
1757 | |
1758 default: | |
1759 error("foreach: %s is not an aggregate type", aggr->type->toChars()); | |
1760 break; | |
1761 } | |
1762 sc->noctor--; | |
1763 sc->pop(); | |
1764 return s; | |
1765 } | |
1766 | |
1767 int ForeachStatement::hasBreak() | |
1768 { | |
1769 return TRUE; | |
1770 } | |
1771 | |
1772 int ForeachStatement::hasContinue() | |
1773 { | |
1774 return TRUE; | |
1775 } | |
1776 | |
1777 int ForeachStatement::usesEH() | |
1778 { | |
1779 return body->usesEH(); | |
1780 } | |
1781 | |
336 | 1782 int ForeachStatement::blockExit() |
1783 { int result = BEfallthru; | |
1784 | |
1785 if (aggr->canThrow()) | |
1786 result |= BEthrow; | |
1787 | |
1788 if (body) | |
1789 { | |
1790 result |= body->blockExit() & ~(BEbreak | BEcontinue); | |
1791 } | |
1792 return result; | |
1793 } | |
1794 | |
159 | 1795 int ForeachStatement::comeFrom() |
1796 { | |
1797 if (body) | |
1798 return body->comeFrom(); | |
1799 return FALSE; | |
1800 } | |
1801 | |
1802 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
1803 { | |
1804 buf->writestring(Token::toChars(op)); | |
1805 buf->writestring(" ("); | |
1806 for (int i = 0; i < arguments->dim; i++) | |
1807 { | |
1808 Argument *a = (Argument *)arguments->data[i]; | |
1809 if (i) | |
1810 buf->writestring(", "); | |
1811 if (a->storageClass & STCref) | |
1812 buf->writestring((global.params.Dversion == 1) | |
1813 ? (char*)"inout " : (char*)"ref "); | |
1814 if (a->type) | |
1815 a->type->toCBuffer(buf, a->ident, hgs); | |
1816 else | |
1817 buf->writestring(a->ident->toChars()); | |
1818 } | |
1819 buf->writestring("; "); | |
1820 aggr->toCBuffer(buf, hgs); | |
1821 buf->writebyte(')'); | |
1822 buf->writenl(); | |
1823 buf->writebyte('{'); | |
1824 buf->writenl(); | |
1825 if (body) | |
1826 body->toCBuffer(buf, hgs); | |
1827 buf->writebyte('}'); | |
1828 buf->writenl(); | |
1829 } | |
1830 | |
1831 /******************************** IfStatement ***************************/ | |
1832 | |
1833 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) | |
1834 : Statement(loc) | |
1835 { | |
1836 this->arg = arg; | |
1837 this->condition = condition; | |
1838 this->ifbody = ifbody; | |
1839 this->elsebody = elsebody; | |
1840 this->match = NULL; | |
1841 } | |
1842 | |
1843 Statement *IfStatement::syntaxCopy() | |
1844 { | |
1845 Statement *i = NULL; | |
1846 if (ifbody) | |
1847 i = ifbody->syntaxCopy(); | |
1848 | |
1849 Statement *e = NULL; | |
1850 if (elsebody) | |
1851 e = elsebody->syntaxCopy(); | |
1852 | |
1853 Argument *a = arg ? arg->syntaxCopy() : NULL; | |
1854 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); | |
1855 return s; | |
1856 } | |
1857 | |
1858 Statement *IfStatement::semantic(Scope *sc) | |
1859 { | |
1860 condition = condition->semantic(sc); | |
1861 condition = resolveProperties(sc, condition); | |
1862 condition = condition->checkToBoolean(); | |
1863 | |
1864 // If we can short-circuit evaluate the if statement, don't do the | |
1865 // semantic analysis of the skipped code. | |
1866 // This feature allows a limited form of conditional compilation. | |
1867 condition = condition->optimize(WANTflags); | |
1868 | |
1869 // Evaluate at runtime | |
1870 unsigned cs0 = sc->callSuper; | |
1871 unsigned cs1; | |
1872 | |
1873 Scope *scd; | |
1874 if (arg) | |
1875 { /* Declare arg, which we will set to be the | |
1876 * result of condition. | |
1877 */ | |
1878 ScopeDsymbol *sym = new ScopeDsymbol(); | |
1879 sym->parent = sc->scopesym; | |
1880 scd = sc->push(sym); | |
1881 | |
1882 Type *t = arg->type ? arg->type : condition->type; | |
1883 match = new VarDeclaration(loc, t, arg->ident, NULL); | |
1884 match->noauto = 1; | |
1885 match->semantic(scd); | |
1886 if (!scd->insert(match)) | |
1887 assert(0); | |
1888 match->parent = sc->func; | |
1889 | |
1890 /* Generate: | |
1891 * (arg = condition) | |
1892 */ | |
1893 VarExp *v = new VarExp(0, match); | |
1894 condition = new AssignExp(loc, v, condition); | |
1895 condition = condition->semantic(scd); | |
1896 } | |
1897 else | |
1898 scd = sc->push(); | |
1899 ifbody = ifbody->semantic(scd); | |
1900 scd->pop(); | |
1901 | |
1902 cs1 = sc->callSuper; | |
1903 sc->callSuper = cs0; | |
1904 if (elsebody) | |
1905 elsebody = elsebody->semanticScope(sc, NULL, NULL); | |
1906 sc->mergeCallSuper(loc, cs1); | |
1907 | |
1908 return this; | |
1909 } | |
1910 | |
1911 int IfStatement::usesEH() | |
1912 { | |
1913 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); | |
1914 } | |
1915 | |
336 | 1916 int IfStatement::blockExit() |
1917 { | |
1918 //printf("IfStatement::blockExit(%p)\n", this); | |
1919 | |
1920 int result = BEnone; | |
1921 if (condition->canThrow()) | |
1922 result |= BEthrow; | |
1923 if (condition->isBool(TRUE)) | |
1924 { | |
1925 if (ifbody) | |
1926 result |= ifbody->blockExit(); | |
1927 else | |
1928 result |= BEfallthru; | |
1929 } | |
1930 else if (condition->isBool(FALSE)) | |
1931 { | |
1932 if (elsebody) | |
1933 result |= elsebody->blockExit(); | |
1934 else | |
1935 result |= BEfallthru; | |
1936 } | |
1937 else | |
1938 { | |
1939 if (ifbody) | |
1940 result |= ifbody->blockExit(); | |
1941 else | |
1942 result |= BEfallthru; | |
1943 if (elsebody) | |
1944 result |= elsebody->blockExit(); | |
1945 else | |
1946 result |= BEfallthru; | |
1947 } | |
1948 //printf("IfStatement::blockExit(%p) = x%x\n", this, result); | |
1949 return result; | |
1950 } | |
1951 | |
159 | 1952 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
1953 { | |
1954 buf->writestring("if ("); | |
1955 if (arg) | |
1956 { | |
1957 if (arg->type) | |
1958 arg->type->toCBuffer(buf, arg->ident, hgs); | |
1959 else | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
1960 { buf->writestring("auto "); |
159 | 1961 buf->writestring(arg->ident->toChars()); |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
1962 } |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
1963 buf->writestring(" = "); |
159 | 1964 } |
1965 condition->toCBuffer(buf, hgs); | |
1966 buf->writebyte(')'); | |
1967 buf->writenl(); | |
1968 ifbody->toCBuffer(buf, hgs); | |
1969 if (elsebody) | |
1970 { buf->writestring("else"); | |
1971 buf->writenl(); | |
1972 elsebody->toCBuffer(buf, hgs); | |
1973 } | |
1974 } | |
1975 | |
1976 /******************************** ConditionalStatement ***************************/ | |
1977 | |
1978 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) | |
1979 : Statement(loc) | |
1980 { | |
1981 this->condition = condition; | |
1982 this->ifbody = ifbody; | |
1983 this->elsebody = elsebody; | |
1984 } | |
1985 | |
1986 Statement *ConditionalStatement::syntaxCopy() | |
1987 { | |
1988 Statement *e = NULL; | |
1989 if (elsebody) | |
1990 e = elsebody->syntaxCopy(); | |
1991 ConditionalStatement *s = new ConditionalStatement(loc, | |
1992 condition->syntaxCopy(), ifbody->syntaxCopy(), e); | |
1993 return s; | |
1994 } | |
1995 | |
1996 Statement *ConditionalStatement::semantic(Scope *sc) | |
1997 { | |
1998 //printf("ConditionalStatement::semantic()\n"); | |
1999 | |
2000 // If we can short-circuit evaluate the if statement, don't do the | |
2001 // semantic analysis of the skipped code. | |
2002 // This feature allows a limited form of conditional compilation. | |
2003 if (condition->include(sc, NULL)) | |
2004 { | |
2005 ifbody = ifbody->semantic(sc); | |
2006 return ifbody; | |
2007 } | |
2008 else | |
2009 { | |
2010 if (elsebody) | |
2011 elsebody = elsebody->semantic(sc); | |
2012 return elsebody; | |
2013 } | |
2014 } | |
2015 | |
2016 Statements *ConditionalStatement::flatten(Scope *sc) | |
2017 { | |
2018 Statement *s; | |
2019 | |
2020 if (condition->include(sc, NULL)) | |
2021 s = ifbody; | |
2022 else | |
2023 s = elsebody; | |
2024 | |
2025 Statements *a = new Statements(); | |
2026 a->push(s); | |
2027 return a; | |
2028 } | |
2029 | |
2030 int ConditionalStatement::usesEH() | |
2031 { | |
2032 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); | |
2033 } | |
2034 | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2035 int ConditionalStatement::blockExit() |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2036 { |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2037 int result = ifbody->blockExit(); |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2038 if (elsebody) |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2039 result |= elsebody->blockExit(); |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2040 return result; |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2041 } |
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
389
diff
changeset
|
2042 |
159 | 2043 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2044 { | |
2045 condition->toCBuffer(buf, hgs); | |
2046 buf->writenl(); | |
336 | 2047 buf->writeByte('{'); |
2048 buf->writenl(); | |
159 | 2049 if (ifbody) |
2050 ifbody->toCBuffer(buf, hgs); | |
336 | 2051 buf->writeByte('}'); |
2052 buf->writenl(); | |
159 | 2053 if (elsebody) |
2054 { | |
2055 buf->writestring("else"); | |
2056 buf->writenl(); | |
336 | 2057 buf->writeByte('{'); |
2058 buf->writenl(); | |
159 | 2059 elsebody->toCBuffer(buf, hgs); |
336 | 2060 buf->writeByte('}'); |
2061 buf->writenl(); | |
159 | 2062 } |
2063 buf->writenl(); | |
2064 } | |
2065 | |
2066 | |
2067 /******************************** PragmaStatement ***************************/ | |
2068 | |
2069 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) | |
2070 : Statement(loc) | |
2071 { | |
2072 this->ident = ident; | |
2073 this->args = args; | |
2074 this->body = body; | |
2075 } | |
2076 | |
2077 Statement *PragmaStatement::syntaxCopy() | |
2078 { | |
2079 Statement *b = NULL; | |
2080 if (body) | |
2081 b = body->syntaxCopy(); | |
2082 PragmaStatement *s = new PragmaStatement(loc, | |
2083 ident, Expression::arraySyntaxCopy(args), b); | |
2084 return s; | |
2085 } | |
2086 | |
2087 Statement *PragmaStatement::semantic(Scope *sc) | |
2088 { // Should be merged with PragmaDeclaration | |
2089 //printf("PragmaStatement::semantic() %s\n", toChars()); | |
2090 //printf("body = %p\n", body); | |
2091 if (ident == Id::msg) | |
2092 { | |
2093 if (args) | |
2094 { | |
2095 for (size_t i = 0; i < args->dim; i++) | |
2096 { | |
2097 Expression *e = (Expression *)args->data[i]; | |
2098 | |
2099 e = e->semantic(sc); | |
2100 e = e->optimize(WANTvalue | WANTinterpret); | |
2101 if (e->op == TOKstring) | |
2102 { | |
2103 StringExp *se = (StringExp *)e; | |
794
661384d6a936
Fix warnings on x86-64. By fvbommel.
Christian Kamm <kamm incasoftware de>
parents:
765
diff
changeset
|
2104 fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); |
159 | 2105 } |
2106 else | |
2107 error("string expected for message, not '%s'", e->toChars()); | |
2108 } | |
2109 fprintf(stdmsg, "\n"); | |
2110 } | |
2111 } | |
2112 else if (ident == Id::lib) | |
2113 { | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2114 #if 1 |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2115 /* Should this be allowed? |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2116 */ |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2117 error("pragma(lib) not allowed as statement"); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2118 #else |
159 | 2119 if (!args || args->dim != 1) |
2120 error("string expected for library name"); | |
2121 else | |
2122 { | |
2123 Expression *e = (Expression *)args->data[0]; | |
2124 | |
2125 e = e->semantic(sc); | |
2126 e = e->optimize(WANTvalue | WANTinterpret); | |
2127 args->data[0] = (void *)e; | |
2128 if (e->op != TOKstring) | |
2129 error("string expected for library name, not '%s'", e->toChars()); | |
2130 else if (global.params.verbose) | |
2131 { | |
2132 StringExp *se = (StringExp *)e; | |
2133 char *name = (char *)mem.malloc(se->len + 1); | |
2134 memcpy(name, se->string, se->len); | |
2135 name[se->len] = 0; | |
2136 printf("library %s\n", name); | |
2137 mem.free(name); | |
2138 } | |
2139 } | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2140 #endif |
159 | 2141 } |
945
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2142 |
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2143 // LDC |
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2144 else if (ident == Id::allow_inline) |
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2145 { |
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2146 sc->func->allowInlining = true; |
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2147 } |
03d7c4aac654
SWITCHED TO LLVM 2.5 !
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
908
diff
changeset
|
2148 |
159 | 2149 else |
2150 error("unrecognized pragma(%s)", ident->toChars()); | |
2151 | |
2152 if (body) | |
2153 { | |
2154 body = body->semantic(sc); | |
2155 } | |
2156 return body; | |
2157 } | |
2158 | |
2159 int PragmaStatement::usesEH() | |
2160 { | |
2161 return body && body->usesEH(); | |
2162 } | |
2163 | |
336 | 2164 int PragmaStatement::blockExit() |
2165 { | |
2166 int result = BEfallthru; | |
2167 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru | |
2168 if (arrayExpressionCanThrow(args)) | |
2169 result |= BEthrow; | |
2170 if (body) | |
2171 result |= body->blockExit(); | |
2172 #endif | |
2173 return result; | |
2174 } | |
2175 | |
159 | 2176 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2177 { | |
2178 buf->writestring("pragma ("); | |
2179 buf->writestring(ident->toChars()); | |
2180 if (args && args->dim) | |
2181 { | |
2182 buf->writestring(", "); | |
2183 argsToCBuffer(buf, args, hgs); | |
2184 } | |
2185 buf->writeByte(')'); | |
2186 if (body) | |
2187 { | |
2188 buf->writenl(); | |
2189 buf->writeByte('{'); | |
2190 buf->writenl(); | |
2191 | |
2192 body->toCBuffer(buf, hgs); | |
2193 | |
2194 buf->writeByte('}'); | |
2195 buf->writenl(); | |
2196 } | |
2197 else | |
2198 { | |
2199 buf->writeByte(';'); | |
2200 buf->writenl(); | |
2201 } | |
2202 } | |
2203 | |
2204 | |
2205 /******************************** StaticAssertStatement ***************************/ | |
2206 | |
2207 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) | |
2208 : Statement(sa->loc) | |
2209 { | |
2210 this->sa = sa; | |
2211 } | |
2212 | |
2213 Statement *StaticAssertStatement::syntaxCopy() | |
2214 { | |
2215 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); | |
2216 return s; | |
2217 } | |
2218 | |
2219 Statement *StaticAssertStatement::semantic(Scope *sc) | |
2220 { | |
2221 sa->semantic2(sc); | |
2222 return NULL; | |
2223 } | |
2224 | |
2225 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2226 { | |
2227 sa->toCBuffer(buf, hgs); | |
2228 } | |
2229 | |
2230 | |
2231 /******************************** SwitchStatement ***************************/ | |
2232 | |
2233 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b) | |
2234 : Statement(loc) | |
2235 { | |
2236 condition = c; | |
2237 body = b; | |
2238 sdefault = NULL; | |
2239 cases = NULL; | |
2240 hasNoDefault = 0; | |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2241 // LDC |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2242 enclosingScopeExit = NULL; |
159 | 2243 } |
2244 | |
2245 Statement *SwitchStatement::syntaxCopy() | |
2246 { | |
2247 SwitchStatement *s = new SwitchStatement(loc, | |
2248 condition->syntaxCopy(), body->syntaxCopy()); | |
2249 return s; | |
2250 } | |
2251 | |
2252 Statement *SwitchStatement::semantic(Scope *sc) | |
2253 { | |
2254 //printf("SwitchStatement::semantic(%p)\n", this); | |
2255 assert(!cases); // ensure semantic() is only run once | |
2256 | |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2257 // LDC |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2258 enclosingScopeExit = sc->enclosingScopeExit; |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2259 |
159 | 2260 condition = condition->semantic(sc); |
2261 condition = resolveProperties(sc, condition); | |
2262 if (condition->type->isString()) | |
2263 { | |
2264 // If it's not an array, cast it to one | |
2265 if (condition->type->ty != Tarray) | |
2266 { | |
2267 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); | |
2268 } | |
2269 } | |
2270 else | |
2271 { condition = condition->integralPromotions(sc); | |
2272 condition->checkIntegral(); | |
2273 } | |
2274 condition = condition->optimize(WANTvalue); | |
2275 | |
2276 sc = sc->push(); | |
2277 sc->sbreak = this; | |
2278 sc->sw = this; | |
2279 | |
2280 cases = new Array(); | |
2281 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead | |
2282 body = body->semantic(sc); | |
2283 sc->noctor--; | |
2284 | |
2285 // Resolve any goto case's with exp | |
2286 for (int i = 0; i < gotoCases.dim; i++) | |
2287 { | |
2288 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; | |
2289 | |
2290 if (!gcs->exp) | |
2291 { | |
2292 gcs->error("no case statement following goto case;"); | |
2293 break; | |
2294 } | |
2295 | |
2296 for (Scope *scx = sc; scx; scx = scx->enclosing) | |
2297 { | |
2298 if (!scx->sw) | |
2299 continue; | |
2300 for (int j = 0; j < scx->sw->cases->dim; j++) | |
2301 { | |
2302 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; | |
2303 | |
2304 if (cs->exp->equals(gcs->exp)) | |
2305 { | |
2306 gcs->cs = cs; | |
2307 goto Lfoundcase; | |
2308 } | |
2309 } | |
2310 } | |
2311 gcs->error("case %s not found", gcs->exp->toChars()); | |
2312 | |
2313 Lfoundcase: | |
2314 ; | |
2315 } | |
2316 | |
2317 if (!sc->sw->sdefault) | |
2318 { hasNoDefault = 1; | |
2319 | |
1103
b30fe7e1dbb9
- Updated to DMD frontend 1.041.
Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
parents:
945
diff
changeset
|
2320 warning("switch statement has no default"); |
159 | 2321 |
2322 // Generate runtime error if the default is hit | |
2323 Statements *a = new Statements(); | |
2324 CompoundStatement *cs; | |
2325 Statement *s; | |
2326 | |
2327 if (global.params.useSwitchError) | |
2328 s = new SwitchErrorStatement(loc); | |
2329 else | |
2330 { Expression *e = new HaltExp(loc); | |
2331 s = new ExpStatement(loc, e); | |
2332 } | |
2333 | |
2334 a->reserve(4); | |
2335 a->push(body); | |
901 | 2336 |
2337 // LDC needs semantic to be run on break | |
2338 Statement *breakstmt = new BreakStatement(loc, NULL); | |
2339 breakstmt->semantic(sc); | |
2340 a->push(breakstmt); | |
2341 | |
159 | 2342 sc->sw->sdefault = new DefaultStatement(loc, s); |
2343 a->push(sc->sw->sdefault); | |
2344 cs = new CompoundStatement(loc, a); | |
2345 body = cs; | |
2346 } | |
2347 | |
2348 sc->pop(); | |
2349 return this; | |
2350 } | |
2351 | |
2352 int SwitchStatement::hasBreak() | |
2353 { | |
2354 return TRUE; | |
2355 } | |
2356 | |
2357 int SwitchStatement::usesEH() | |
2358 { | |
2359 return body ? body->usesEH() : 0; | |
2360 } | |
2361 | |
336 | 2362 int SwitchStatement::blockExit() |
2363 { int result = BEnone; | |
2364 if (condition->canThrow()) | |
2365 result |= BEthrow; | |
2366 | |
2367 if (body) | |
2368 { result |= body->blockExit(); | |
2369 if (result & BEbreak) | |
2370 { result |= BEfallthru; | |
2371 result &= ~BEbreak; | |
2372 } | |
2373 } | |
2374 else | |
2375 result |= BEfallthru; | |
2376 | |
2377 return result; | |
2378 } | |
2379 | |
159 | 2380 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2381 { | |
2382 buf->writestring("switch ("); | |
2383 condition->toCBuffer(buf, hgs); | |
2384 buf->writebyte(')'); | |
2385 buf->writenl(); | |
2386 if (body) | |
2387 { | |
2388 if (!body->isScopeStatement()) | |
2389 { buf->writebyte('{'); | |
2390 buf->writenl(); | |
2391 body->toCBuffer(buf, hgs); | |
2392 buf->writebyte('}'); | |
2393 buf->writenl(); | |
2394 } | |
2395 else | |
2396 { | |
2397 body->toCBuffer(buf, hgs); | |
2398 } | |
2399 } | |
2400 } | |
2401 | |
2402 /******************************** CaseStatement ***************************/ | |
2403 | |
2404 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) | |
2405 : Statement(loc) | |
2406 { | |
2407 this->exp = exp; | |
2408 this->statement = s; | |
2409 cblock = NULL; | |
2410 bodyBB = NULL; | |
262
88252a1af660
[svn r280] Fixed a bunch of issues with switch statements. Ended up a bit far reaching...
lindquist
parents:
232
diff
changeset
|
2411 llvmIdx = NULL; |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2412 // LDC |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2413 enclosingScopeExit = NULL; |
159 | 2414 } |
2415 | |
2416 Statement *CaseStatement::syntaxCopy() | |
2417 { | |
2418 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); | |
2419 return s; | |
2420 } | |
2421 | |
2422 Statement *CaseStatement::semantic(Scope *sc) | |
2423 { SwitchStatement *sw = sc->sw; | |
2424 | |
2425 //printf("CaseStatement::semantic() %s\n", toChars()); | |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2426 |
159 | 2427 exp = exp->semantic(sc); |
2428 if (sw) | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2429 { |
1164
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2430 // LDC |
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2431 enclosingScopeExit = sc->enclosingScopeExit; |
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2432 if (enclosingScopeExit != sw->enclosingScopeExit) |
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2433 { |
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2434 error("case must be inside the same try, synchronized or volatile level as switch"); |
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2435 } |
166042b48c28
Fix bug in CaseStatement::semantic when there's no enclosing switch.
Christian Kamm <kamm incasoftware de>
parents:
1159
diff
changeset
|
2436 |
159 | 2437 exp = exp->implicitCastTo(sc, sw->condition->type); |
2438 exp = exp->optimize(WANTvalue | WANTinterpret); | |
2439 if (exp->op != TOKstring && exp->op != TOKint64) | |
2440 { | |
2441 error("case must be a string or an integral constant, not %s", exp->toChars()); | |
2442 exp = new IntegerExp(0); | |
2443 } | |
2444 | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2445 for (int i = 0; i < sw->cases->dim; i++) |
159 | 2446 { |
2447 CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; | |
2448 | |
2449 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); | |
2450 if (cs->exp->equals(exp)) | |
2451 { error("duplicate case %s in switch statement", exp->toChars()); | |
2452 break; | |
2453 } | |
2454 } | |
2455 | |
2456 sw->cases->push(this); | |
2457 | |
2458 // Resolve any goto case's with no exp to this case statement | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2459 for (size_t i = 0; i < sw->gotoCases.dim; i++) |
159 | 2460 { |
2461 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; | |
2462 | |
2463 if (!gcs->exp) | |
2464 { | |
2465 gcs->cs = this; | |
2466 sw->gotoCases.remove(i); // remove from array | |
2467 } | |
2468 } | |
2469 } | |
2470 else | |
2471 error("case not in switch statement"); | |
2472 statement = statement->semantic(sc); | |
2473 return this; | |
2474 } | |
2475 | |
2476 int CaseStatement::compare(Object *obj) | |
2477 { | |
2478 // Sort cases so we can do an efficient lookup | |
2479 CaseStatement *cs2 = (CaseStatement *)(obj); | |
2480 | |
2481 return exp->compare(cs2->exp); | |
2482 } | |
2483 | |
2484 int CaseStatement::usesEH() | |
2485 { | |
2486 return statement->usesEH(); | |
2487 } | |
2488 | |
336 | 2489 int CaseStatement::blockExit() |
2490 { | |
2491 return statement->blockExit(); | |
2492 } | |
2493 | |
159 | 2494 int CaseStatement::comeFrom() |
2495 { | |
2496 return TRUE; | |
2497 } | |
2498 | |
2499 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2500 { | |
2501 buf->writestring("case "); | |
2502 exp->toCBuffer(buf, hgs); | |
2503 buf->writebyte(':'); | |
2504 buf->writenl(); | |
2505 statement->toCBuffer(buf, hgs); | |
2506 } | |
2507 | |
2508 /******************************** DefaultStatement ***************************/ | |
2509 | |
2510 DefaultStatement::DefaultStatement(Loc loc, Statement *s) | |
2511 : Statement(loc) | |
2512 { | |
2513 this->statement = s; | |
2514 #if IN_GCC | |
2515 + cblock = NULL; | |
2516 #endif | |
2517 bodyBB = NULL; | |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2518 // LDC |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2519 enclosingScopeExit = NULL; |
159 | 2520 } |
2521 | |
2522 Statement *DefaultStatement::syntaxCopy() | |
2523 { | |
2524 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); | |
2525 return s; | |
2526 } | |
2527 | |
2528 Statement *DefaultStatement::semantic(Scope *sc) | |
2529 { | |
336 | 2530 //printf("DefaultStatement::semantic()\n"); |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2531 |
159 | 2532 if (sc->sw) |
2533 { | |
2534 if (sc->sw->sdefault) | |
2535 { | |
2536 error("switch statement already has a default"); | |
2537 } | |
2538 sc->sw->sdefault = this; | |
1159
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2539 |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2540 // LDC |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2541 enclosingScopeExit = sc->enclosingScopeExit; |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2542 if (enclosingScopeExit != sc->sw->enclosingScopeExit) |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2543 { |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2544 error("default must be inside the same try, synchronized or volatile level as switch"); |
c6d6a68bb5db
Add back some enclosing scope-exit information to the frontend to produce
Christian Kamm <kamm incasoftware de>
parents:
1141
diff
changeset
|
2545 } |
159 | 2546 } |
2547 else | |
2548 error("default not in switch statement"); | |
2549 statement = statement->semantic(sc); | |
2550 return this; | |
2551 } | |
2552 | |
2553 int DefaultStatement::usesEH() | |
2554 { | |
2555 return statement->usesEH(); | |
2556 } | |
2557 | |
336 | 2558 int DefaultStatement::blockExit() |
2559 { | |
2560 return statement->blockExit(); | |
2561 } | |
2562 | |
159 | 2563 int DefaultStatement::comeFrom() |
2564 { | |
2565 return TRUE; | |
2566 } | |
2567 | |
2568 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2569 { | |
2570 buf->writestring("default:\n"); | |
2571 statement->toCBuffer(buf, hgs); | |
2572 } | |
2573 | |
2574 /******************************** GotoDefaultStatement ***************************/ | |
2575 | |
2576 GotoDefaultStatement::GotoDefaultStatement(Loc loc) | |
2577 : Statement(loc) | |
2578 { | |
2579 sw = NULL; | |
2580 } | |
2581 | |
2582 Statement *GotoDefaultStatement::syntaxCopy() | |
2583 { | |
2584 GotoDefaultStatement *s = new GotoDefaultStatement(loc); | |
2585 return s; | |
2586 } | |
2587 | |
2588 Statement *GotoDefaultStatement::semantic(Scope *sc) | |
2589 { | |
2590 sw = sc->sw; | |
2591 if (!sw) | |
2592 error("goto default not in switch statement"); | |
2593 return this; | |
2594 } | |
2595 | |
336 | 2596 int GotoDefaultStatement::blockExit() |
2597 { | |
2598 return BEgoto; | |
2599 } | |
2600 | |
159 | 2601 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2602 { | |
2603 buf->writestring("goto default;\n"); | |
2604 } | |
2605 | |
2606 /******************************** GotoCaseStatement ***************************/ | |
2607 | |
2608 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) | |
2609 : Statement(loc) | |
2610 { | |
2611 cs = NULL; | |
2612 this->exp = exp; | |
2613 sw = NULL; | |
2614 } | |
2615 | |
2616 Statement *GotoCaseStatement::syntaxCopy() | |
2617 { | |
2618 Expression *e = exp ? exp->syntaxCopy() : NULL; | |
2619 GotoCaseStatement *s = new GotoCaseStatement(loc, e); | |
2620 return s; | |
2621 } | |
2622 | |
2623 Statement *GotoCaseStatement::semantic(Scope *sc) | |
2624 { | |
2625 if (exp) | |
2626 exp = exp->semantic(sc); | |
2627 | |
2628 if (!sc->sw) | |
2629 error("goto case not in switch statement"); | |
2630 else | |
2631 { | |
2632 sw = sc->sw; | |
2633 sc->sw->gotoCases.push(this); | |
2634 if (exp) | |
2635 { | |
2636 exp = exp->implicitCastTo(sc, sc->sw->condition->type); | |
2637 exp = exp->optimize(WANTvalue); | |
2638 } | |
2639 } | |
2640 return this; | |
2641 } | |
2642 | |
336 | 2643 int GotoCaseStatement::blockExit() |
2644 { | |
2645 return BEgoto; | |
2646 } | |
2647 | |
159 | 2648 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2649 { | |
2650 buf->writestring("goto case"); | |
2651 if (exp) | |
2652 { buf->writebyte(' '); | |
2653 exp->toCBuffer(buf, hgs); | |
2654 } | |
2655 buf->writebyte(';'); | |
2656 buf->writenl(); | |
2657 } | |
2658 | |
2659 /******************************** SwitchErrorStatement ***************************/ | |
2660 | |
2661 SwitchErrorStatement::SwitchErrorStatement(Loc loc) | |
2662 : Statement(loc) | |
2663 { | |
2664 } | |
2665 | |
336 | 2666 int SwitchErrorStatement::blockExit() |
2667 { | |
2668 return BEthrow; | |
2669 } | |
2670 | |
159 | 2671 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2672 { | |
2673 buf->writestring("SwitchErrorStatement::toCBuffer()"); | |
2674 buf->writenl(); | |
2675 } | |
2676 | |
2677 /******************************** ReturnStatement ***************************/ | |
2678 | |
2679 ReturnStatement::ReturnStatement(Loc loc, Expression *exp) | |
2680 : Statement(loc) | |
2681 { | |
2682 this->exp = exp; | |
2683 } | |
2684 | |
2685 Statement *ReturnStatement::syntaxCopy() | |
2686 { | |
2687 Expression *e = NULL; | |
2688 if (exp) | |
2689 e = exp->syntaxCopy(); | |
2690 ReturnStatement *s = new ReturnStatement(loc, e); | |
2691 return s; | |
2692 } | |
2693 | |
2694 Statement *ReturnStatement::semantic(Scope *sc) | |
2695 { | |
2696 //printf("ReturnStatement::semantic() %s\n", toChars()); | |
2697 | |
2698 FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
2699 Scope *scx = sc; | |
2700 int implicit0 = 0; | |
2701 | |
2702 if (sc->fes) | |
2703 { | |
2704 // Find scope of function foreach is in | |
2705 for (; 1; scx = scx->enclosing) | |
2706 { | |
2707 assert(scx); | |
2708 if (scx->func != fd) | |
2709 { fd = scx->func; // fd is now function enclosing foreach | |
2710 break; | |
2711 } | |
2712 } | |
2713 } | |
2714 | |
2715 Type *tret = fd->type->nextOf(); | |
2716 if (fd->tintro) | |
336 | 2717 /* We'll be implicitly casting the return expression to tintro |
2718 */ | |
159 | 2719 tret = fd->tintro->nextOf(); |
2720 Type *tbret = NULL; | |
2721 | |
2722 if (tret) | |
2723 tbret = tret->toBasetype(); | |
2724 | |
2725 // main() returns 0, even if it returns void | |
2726 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) | |
2727 { implicit0 = 1; | |
2728 exp = new IntegerExp(0); | |
2729 } | |
2730 | |
2731 if (sc->incontract || scx->incontract) | |
2732 error("return statements cannot be in contracts"); | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
2733 if (sc->enclosingFinally || scx->enclosingFinally) |
159 | 2734 error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); |
2735 | |
2736 if (fd->isCtorDeclaration()) | |
2737 { | |
2738 // Constructors implicitly do: | |
2739 // return this; | |
2740 if (exp && exp->op != TOKthis) | |
2741 error("cannot return expression from constructor"); | |
2742 exp = new ThisExp(0); | |
2743 } | |
2744 | |
2745 if (!exp) | |
2746 fd->nrvo_can = 0; | |
2747 | |
2748 if (exp) | |
2749 { | |
2750 fd->hasReturnExp |= 1; | |
2751 | |
2752 exp = exp->semantic(sc); | |
2753 exp = resolveProperties(sc, exp); | |
2754 exp = exp->optimize(WANTvalue); | |
2755 | |
2756 if (fd->nrvo_can && exp->op == TOKvar) | |
2757 { VarExp *ve = (VarExp *)exp; | |
2758 VarDeclaration *v = ve->var->isVarDeclaration(); | |
2759 | |
2760 if (!v || v->isOut() || v->isRef()) | |
2761 fd->nrvo_can = 0; | |
2762 else if (fd->nrvo_var == NULL) | |
2763 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) | |
2764 fd->nrvo_var = v; | |
2765 else | |
2766 fd->nrvo_can = 0; | |
2767 } | |
2768 else if (fd->nrvo_var != v) | |
2769 fd->nrvo_can = 0; | |
2770 } | |
2771 else | |
2772 fd->nrvo_can = 0; | |
2773 | |
2774 if (fd->returnLabel && tbret->ty != Tvoid) | |
2775 { | |
2776 } | |
2777 else if (fd->inferRetType) | |
2778 { | |
2779 if (fd->type->nextOf()) | |
2780 { | |
2781 if (!exp->type->equals(fd->type->nextOf())) | |
2782 error("mismatched function return type inference of %s and %s", | |
2783 exp->type->toChars(), fd->type->nextOf()->toChars()); | |
2784 } | |
2785 else | |
2786 { | |
2787 fd->type->next = exp->type; | |
2788 fd->type = fd->type->semantic(loc, sc); | |
2789 if (!fd->tintro) | |
2790 { tret = fd->type->nextOf(); | |
2791 tbret = tret->toBasetype(); | |
2792 } | |
2793 } | |
2794 } | |
2795 else if (tbret->ty != Tvoid) | |
2796 { | |
2797 exp = exp->implicitCastTo(sc, tret); | |
2798 } | |
2799 } | |
2800 else if (fd->inferRetType) | |
2801 { | |
2802 if (fd->type->nextOf()) | |
2803 { | |
2804 if (fd->type->nextOf()->ty != Tvoid) | |
2805 error("mismatched function return type inference of void and %s", | |
2806 fd->type->nextOf()->toChars()); | |
2807 } | |
2808 else | |
2809 { | |
2810 fd->type->next = Type::tvoid; | |
2811 fd->type = fd->type->semantic(loc, sc); | |
2812 if (!fd->tintro) | |
2813 { tret = Type::tvoid; | |
2814 tbret = tret; | |
2815 } | |
2816 } | |
2817 } | |
2818 else if (tbret->ty != Tvoid) // if non-void return | |
2819 error("return expression expected"); | |
2820 | |
2821 if (sc->fes) | |
2822 { | |
2823 Statement *s; | |
2824 | |
2825 if (exp && !implicit0) | |
2826 { | |
2827 exp = exp->implicitCastTo(sc, tret); | |
2828 } | |
2829 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || | |
2830 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || | |
2831 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || | |
2832 exp->op == TOKstring) | |
2833 { | |
2834 sc->fes->cases.push(this); | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2835 // Construct: return cases.dim+1; |
159 | 2836 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); |
2837 } | |
2838 else if (fd->type->nextOf()->toBasetype() == Type::tvoid) | |
2839 { | |
2840 s = new ReturnStatement(0, NULL); | |
2841 sc->fes->cases.push(s); | |
2842 | |
2843 // Construct: { exp; return cases.dim + 1; } | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2844 Statement *s1 = new ExpStatement(loc, exp); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2845 Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); |
159 | 2846 s = new CompoundStatement(loc, s1, s2); |
2847 } | |
2848 else | |
2849 { | |
2850 // Construct: return vresult; | |
2851 if (!fd->vresult) | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2852 { // Declare vresult |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2853 VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); |
159 | 2854 v->noauto = 1; |
2855 v->semantic(scx); | |
2856 if (!scx->insert(v)) | |
2857 assert(0); | |
2858 v->parent = fd; | |
2859 fd->vresult = v; | |
2860 } | |
2861 | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2862 s = new ReturnStatement(0, new VarExp(0, fd->vresult)); |
159 | 2863 sc->fes->cases.push(s); |
2864 | |
2865 // Construct: { vresult = exp; return cases.dim + 1; } | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2866 exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp); |
159 | 2867 exp = exp->semantic(sc); |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2868 Statement *s1 = new ExpStatement(loc, exp); |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2869 Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); |
159 | 2870 s = new CompoundStatement(loc, s1, s2); |
2871 } | |
2872 return s; | |
2873 } | |
2874 | |
2875 if (exp) | |
2876 { | |
2877 if (fd->returnLabel && tbret->ty != Tvoid) | |
2878 { | |
2879 assert(fd->vresult); | |
2880 VarExp *v = new VarExp(0, fd->vresult); | |
2881 | |
2882 exp = new AssignExp(loc, v, exp); | |
2883 exp = exp->semantic(sc); | |
2884 } | |
2885 //exp->dump(0); | |
2886 //exp->print(); | |
2887 exp->checkEscape(); | |
2888 } | |
2889 | |
2890 /* BUG: need to issue an error on: | |
2891 * this | |
2892 * { if (x) return; | |
2893 * super(); | |
2894 * } | |
2895 */ | |
2896 | |
2897 if (sc->callSuper & CSXany_ctor && | |
2898 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) | |
2899 error("return without calling constructor"); | |
2900 | |
2901 sc->callSuper |= CSXreturn; | |
2902 | |
2903 // See if all returns are instead to be replaced with a goto returnLabel; | |
2904 if (fd->returnLabel) | |
2905 { | |
2906 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); | |
2907 | |
2908 gs->label = fd->returnLabel; | |
2909 if (exp) | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2910 { /* Replace: return exp; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2911 * with: exp; goto returnLabel; |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2912 */ |
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
2913 Statement *s = new ExpStatement(0, exp); |
159 | 2914 return new CompoundStatement(loc, s, gs); |
2915 } | |
2916 return gs; | |
2917 } | |
2918 | |
2919 if (exp && tbret->ty == Tvoid && !fd->isMain()) | |
336 | 2920 { |
2921 /* Replace: | |
2922 * return exp; | |
2923 * with: | |
2924 * exp; return; | |
2925 */ | |
2926 Statement *s = new ExpStatement(loc, exp); | |
159 | 2927 loc = 0; |
2928 exp = NULL; | |
2929 return new CompoundStatement(loc, s, this); | |
2930 } | |
2931 | |
2932 return this; | |
2933 } | |
2934 | |
336 | 2935 int ReturnStatement::blockExit() |
2936 { int result = BEreturn; | |
2937 | |
2938 if (exp && exp->canThrow()) | |
2939 result |= BEthrow; | |
2940 return result; | |
2941 } | |
2942 | |
159 | 2943 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
2944 { | |
2945 buf->printf("return "); | |
2946 if (exp) | |
2947 exp->toCBuffer(buf, hgs); | |
2948 buf->writeByte(';'); | |
2949 buf->writenl(); | |
2950 } | |
2951 | |
2952 /******************************** BreakStatement ***************************/ | |
2953 | |
2954 BreakStatement::BreakStatement(Loc loc, Identifier *ident) | |
2955 : Statement(loc) | |
2956 { | |
2957 this->ident = ident; | |
2958 } | |
2959 | |
2960 Statement *BreakStatement::syntaxCopy() | |
2961 { | |
2962 BreakStatement *s = new BreakStatement(loc, ident); | |
2963 return s; | |
2964 } | |
2965 | |
2966 Statement *BreakStatement::semantic(Scope *sc) | |
2967 { | |
336 | 2968 //printf("BreakStatement::semantic()\n"); |
159 | 2969 // If: |
2970 // break Identifier; | |
2971 if (ident) | |
2972 { | |
2973 Scope *scx; | |
2974 FuncDeclaration *thisfunc = sc->func; | |
2975 | |
2976 for (scx = sc; scx; scx = scx->enclosing) | |
2977 { | |
2978 LabelStatement *ls; | |
2979 | |
2980 if (scx->func != thisfunc) // if in enclosing function | |
2981 { | |
2982 if (sc->fes) // if this is the body of a foreach | |
2983 { | |
2984 /* Post this statement to the fes, and replace | |
2985 * it with a return value that caller will put into | |
2986 * a switch. Caller will figure out where the break | |
2987 * label actually is. | |
2988 * Case numbers start with 2, not 0, as 0 is continue | |
2989 * and 1 is break. | |
2990 */ | |
2991 Statement *s; | |
2992 sc->fes->cases.push(this); | |
2993 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); | |
2994 return s; | |
2995 } | |
2996 break; // can't break to it | |
2997 } | |
2998 | |
2999 ls = scx->slabel; | |
3000 if (ls && ls->ident == ident) | |
3001 { | |
3002 Statement *s = ls->statement; | |
3003 | |
3004 if (!s->hasBreak()) | |
3005 error("label '%s' has no break", ident->toChars()); | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3006 if (ls->enclosingFinally != sc->enclosingFinally) |
159 | 3007 error("cannot break out of finally block"); |
3008 | |
3009 this->target = ls; | |
3010 return this; | |
3011 } | |
3012 } | |
3013 error("enclosing label '%s' for break not found", ident->toChars()); | |
3014 } | |
3015 else if (!sc->sbreak) | |
3016 { | |
3017 if (sc->fes) | |
3018 { Statement *s; | |
3019 | |
3020 // Replace break; with return 1; | |
3021 s = new ReturnStatement(0, new IntegerExp(1)); | |
3022 return s; | |
3023 } | |
3024 error("break is not inside a loop or switch"); | |
3025 } | |
3026 return this; | |
3027 } | |
3028 | |
336 | 3029 int BreakStatement::blockExit() |
3030 { | |
3031 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); | |
3032 return ident ? BEgoto : BEbreak; | |
3033 } | |
3034 | |
159 | 3035 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3036 { | |
3037 buf->writestring("break"); | |
3038 if (ident) | |
3039 { buf->writebyte(' '); | |
3040 buf->writestring(ident->toChars()); | |
3041 } | |
3042 buf->writebyte(';'); | |
3043 buf->writenl(); | |
3044 } | |
3045 | |
3046 /******************************** ContinueStatement ***************************/ | |
3047 | |
3048 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) | |
3049 : Statement(loc) | |
3050 { | |
3051 this->ident = ident; | |
3052 } | |
3053 | |
3054 Statement *ContinueStatement::syntaxCopy() | |
3055 { | |
3056 ContinueStatement *s = new ContinueStatement(loc, ident); | |
3057 return s; | |
3058 } | |
3059 | |
3060 Statement *ContinueStatement::semantic(Scope *sc) | |
3061 { | |
3062 //printf("ContinueStatement::semantic() %p\n", this); | |
3063 if (ident) | |
3064 { | |
3065 Scope *scx; | |
3066 FuncDeclaration *thisfunc = sc->func; | |
3067 | |
3068 for (scx = sc; scx; scx = scx->enclosing) | |
3069 { | |
3070 LabelStatement *ls; | |
3071 | |
3072 if (scx->func != thisfunc) // if in enclosing function | |
3073 { | |
3074 if (sc->fes) // if this is the body of a foreach | |
3075 { | |
3076 for (; scx; scx = scx->enclosing) | |
3077 { | |
3078 ls = scx->slabel; | |
3079 if (ls && ls->ident == ident && ls->statement == sc->fes) | |
3080 { | |
3081 // Replace continue ident; with return 0; | |
3082 return new ReturnStatement(0, new IntegerExp(0)); | |
3083 } | |
3084 } | |
3085 | |
3086 /* Post this statement to the fes, and replace | |
3087 * it with a return value that caller will put into | |
3088 * a switch. Caller will figure out where the break | |
3089 * label actually is. | |
3090 * Case numbers start with 2, not 0, as 0 is continue | |
3091 * and 1 is break. | |
3092 */ | |
3093 Statement *s; | |
3094 sc->fes->cases.push(this); | |
3095 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); | |
3096 return s; | |
3097 } | |
3098 break; // can't continue to it | |
3099 } | |
3100 | |
3101 ls = scx->slabel; | |
3102 if (ls && ls->ident == ident) | |
3103 { | |
3104 Statement *s = ls->statement; | |
3105 | |
3106 if (!s->hasContinue()) | |
3107 error("label '%s' has no continue", ident->toChars()); | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3108 if (ls->enclosingFinally != sc->enclosingFinally) |
159 | 3109 error("cannot continue out of finally block"); |
3110 | |
3111 this->target = ls; | |
3112 return this; | |
3113 } | |
3114 } | |
3115 error("enclosing label '%s' for continue not found", ident->toChars()); | |
3116 } | |
3117 else if (!sc->scontinue) | |
3118 { | |
3119 if (sc->fes) | |
3120 { Statement *s; | |
3121 | |
3122 // Replace continue; with return 0; | |
3123 s = new ReturnStatement(0, new IntegerExp(0)); | |
3124 return s; | |
3125 } | |
3126 error("continue is not inside a loop"); | |
3127 } | |
3128 return this; | |
3129 } | |
3130 | |
336 | 3131 int ContinueStatement::blockExit() |
3132 { | |
3133 return ident ? BEgoto : BEcontinue; | |
3134 } | |
3135 | |
159 | 3136 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3137 { | |
3138 buf->writestring("continue"); | |
3139 if (ident) | |
3140 { buf->writebyte(' '); | |
3141 buf->writestring(ident->toChars()); | |
3142 } | |
3143 buf->writebyte(';'); | |
3144 buf->writenl(); | |
3145 } | |
3146 | |
3147 /******************************** SynchronizedStatement ***************************/ | |
3148 | |
3149 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) | |
3150 : Statement(loc) | |
3151 { | |
3152 this->exp = exp; | |
3153 this->body = body; | |
3154 this->esync = NULL; | |
664
eef8ac26c66c
Some missed LLVMDC -> LDC.
Christian Kamm <kamm incasoftware de>
parents:
510
diff
changeset
|
3155 // LDC |
309 | 3156 this->llsync = NULL; |
159 | 3157 } |
3158 | |
3159 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) | |
3160 : Statement(loc) | |
3161 { | |
3162 this->exp = NULL; | |
3163 this->body = body; | |
3164 this->esync = esync; | |
664
eef8ac26c66c
Some missed LLVMDC -> LDC.
Christian Kamm <kamm incasoftware de>
parents:
510
diff
changeset
|
3165 // LDC |
309 | 3166 this->llsync = NULL; |
159 | 3167 } |
3168 | |
3169 Statement *SynchronizedStatement::syntaxCopy() | |
3170 { | |
3171 Expression *e = exp ? exp->syntaxCopy() : NULL; | |
3172 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); | |
3173 return s; | |
3174 } | |
3175 | |
3176 Statement *SynchronizedStatement::semantic(Scope *sc) | |
3177 { | |
3178 if (exp) | |
3179 { ClassDeclaration *cd; | |
3180 | |
3181 exp = exp->semantic(sc); | |
3182 exp = resolveProperties(sc, exp); | |
3183 cd = exp->type->isClassHandle(); | |
3184 if (!cd) | |
3185 error("can only synchronize on class objects, not '%s'", exp->type->toChars()); | |
3186 else if (cd->isInterfaceDeclaration()) | |
3187 { Type *t = new TypeIdentifier(0, Id::Object); | |
3188 | |
3189 t = t->semantic(0, sc); | |
3190 exp = new CastExp(loc, exp, t); | |
3191 exp = exp->semantic(sc); | |
3192 } | |
3193 } | |
3194 if (body) | |
309 | 3195 { |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3196 Statement* oldScopeExit = sc->enclosingScopeExit; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3197 sc->enclosingScopeExit = this; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3198 body = body->semantic(sc); |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3199 sc->enclosingScopeExit = oldScopeExit; |
309 | 3200 } |
159 | 3201 return this; |
3202 } | |
3203 | |
3204 int SynchronizedStatement::hasBreak() | |
3205 { | |
3206 return FALSE; //TRUE; | |
3207 } | |
3208 | |
3209 int SynchronizedStatement::hasContinue() | |
3210 { | |
3211 return FALSE; //TRUE; | |
3212 } | |
3213 | |
3214 int SynchronizedStatement::usesEH() | |
3215 { | |
3216 return TRUE; | |
3217 } | |
3218 | |
336 | 3219 int SynchronizedStatement::blockExit() |
3220 { | |
3221 return body ? body->blockExit() : BEfallthru; | |
3222 } | |
3223 | |
159 | 3224 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3225 { | |
3226 buf->writestring("synchronized"); | |
3227 if (exp) | |
3228 { buf->writebyte('('); | |
3229 exp->toCBuffer(buf, hgs); | |
3230 buf->writebyte(')'); | |
3231 } | |
3232 if (body) | |
3233 { | |
3234 buf->writebyte(' '); | |
3235 body->toCBuffer(buf, hgs); | |
3236 } | |
3237 } | |
3238 | |
3239 /******************************** WithStatement ***************************/ | |
3240 | |
3241 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) | |
3242 : Statement(loc) | |
3243 { | |
3244 this->exp = exp; | |
3245 this->body = body; | |
3246 wthis = NULL; | |
3247 } | |
3248 | |
3249 Statement *WithStatement::syntaxCopy() | |
3250 { | |
3251 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); | |
3252 return s; | |
3253 } | |
3254 | |
3255 Statement *WithStatement::semantic(Scope *sc) | |
3256 { ScopeDsymbol *sym; | |
3257 Initializer *init; | |
3258 | |
3259 //printf("WithStatement::semantic()\n"); | |
3260 exp = exp->semantic(sc); | |
3261 exp = resolveProperties(sc, exp); | |
3262 if (exp->op == TOKimport) | |
3263 { ScopeExp *es = (ScopeExp *)exp; | |
3264 | |
3265 sym = es->sds; | |
3266 } | |
3267 else if (exp->op == TOKtype) | |
3268 { TypeExp *es = (TypeExp *)exp; | |
3269 | |
3270 sym = es->type->toDsymbol(sc)->isScopeDsymbol(); | |
3271 if (!sym) | |
3272 { error("%s has no members", es->toChars()); | |
3273 body = body->semantic(sc); | |
3274 return this; | |
3275 } | |
3276 } | |
3277 else | |
3278 { Type *t = exp->type; | |
3279 | |
3280 assert(t); | |
3281 t = t->toBasetype(); | |
3282 if (t->isClassHandle()) | |
3283 { | |
3284 init = new ExpInitializer(loc, exp); | |
3285 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); | |
3286 wthis->semantic(sc); | |
3287 | |
3288 sym = new WithScopeSymbol(this); | |
3289 sym->parent = sc->scopesym; | |
3290 } | |
3291 else if (t->ty == Tstruct) | |
3292 { | |
3293 Expression *e = exp->addressOf(sc); | |
3294 init = new ExpInitializer(loc, e); | |
3295 wthis = new VarDeclaration(loc, e->type, Id::withSym, init); | |
3296 wthis->semantic(sc); | |
3297 sym = new WithScopeSymbol(this); | |
3298 sym->parent = sc->scopesym; | |
3299 } | |
3300 else | |
3301 { error("with expressions must be class objects, not '%s'", exp->type->toChars()); | |
3302 return NULL; | |
3303 } | |
3304 } | |
3305 sc = sc->push(sym); | |
3306 | |
3307 if (body) | |
3308 body = body->semantic(sc); | |
3309 | |
3310 sc->pop(); | |
3311 | |
3312 return this; | |
3313 } | |
3314 | |
3315 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3316 { | |
3317 buf->writestring("with ("); | |
3318 exp->toCBuffer(buf, hgs); | |
3319 buf->writestring(")\n"); | |
3320 if (body) | |
3321 body->toCBuffer(buf, hgs); | |
3322 } | |
3323 | |
3324 int WithStatement::usesEH() | |
3325 { | |
3326 return body ? body->usesEH() : 0; | |
3327 } | |
3328 | |
336 | 3329 int WithStatement::blockExit() |
3330 { | |
3331 int result = BEnone; | |
3332 if (exp->canThrow()) | |
3333 result = BEthrow; | |
3334 if (body) | |
3335 result |= body->blockExit(); | |
3336 else | |
3337 result |= BEfallthru; | |
3338 return result; | |
3339 } | |
3340 | |
159 | 3341 /******************************** TryCatchStatement ***************************/ |
3342 | |
3343 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) | |
3344 : Statement(loc) | |
3345 { | |
3346 this->body = body; | |
3347 this->catches = catches; | |
3348 } | |
3349 | |
3350 Statement *TryCatchStatement::syntaxCopy() | |
3351 { | |
3352 Array *a = new Array(); | |
3353 a->setDim(catches->dim); | |
3354 for (int i = 0; i < a->dim; i++) | |
3355 { Catch *c; | |
3356 | |
3357 c = (Catch *)catches->data[i]; | |
3358 c = c->syntaxCopy(); | |
3359 a->data[i] = c; | |
3360 } | |
3361 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); | |
3362 return s; | |
3363 } | |
3364 | |
3365 Statement *TryCatchStatement::semantic(Scope *sc) | |
3366 { | |
3367 body = body->semanticScope(sc, NULL /*this*/, NULL); | |
3368 | |
336 | 3369 /* Even if body is NULL, still do semantic analysis on catches |
3370 */ | |
3371 for (size_t i = 0; i < catches->dim; i++) | |
3372 { Catch *c = (Catch *)catches->data[i]; | |
159 | 3373 c->semantic(sc); |
3374 | |
3375 // Determine if current catch 'hides' any previous catches | |
336 | 3376 for (size_t j = 0; j < i; j++) |
159 | 3377 { Catch *cj = (Catch *)catches->data[j]; |
3378 char *si = c->loc.toChars(); | |
3379 char *sj = cj->loc.toChars(); | |
3380 | |
3381 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) | |
3382 error("catch at %s hides catch at %s", sj, si); | |
3383 } | |
3384 } | |
3385 return this; | |
3386 } | |
3387 | |
3388 int TryCatchStatement::hasBreak() | |
3389 { | |
3390 return FALSE; //TRUE; | |
3391 } | |
3392 | |
3393 int TryCatchStatement::usesEH() | |
3394 { | |
3395 return TRUE; | |
3396 } | |
3397 | |
336 | 3398 int TryCatchStatement::blockExit() |
3399 { int result; | |
3400 | |
3401 assert(body); | |
3402 result = body->blockExit(); | |
3403 | |
3404 for (size_t i = 0; i < catches->dim; i++) | |
3405 { | |
3406 Catch *c = (Catch *)catches->data[i]; | |
3407 result |= c->blockExit(); | |
3408 } | |
3409 return result; | |
3410 } | |
3411 | |
159 | 3412 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3413 { | |
3414 buf->writestring("try"); | |
3415 buf->writenl(); | |
3416 if (body) | |
3417 body->toCBuffer(buf, hgs); | |
336 | 3418 for (size_t i = 0; i < catches->dim; i++) |
159 | 3419 { |
3420 Catch *c = (Catch *)catches->data[i]; | |
3421 c->toCBuffer(buf, hgs); | |
3422 } | |
3423 } | |
3424 | |
3425 /******************************** Catch ***************************/ | |
3426 | |
3427 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) | |
3428 { | |
3429 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); | |
3430 this->loc = loc; | |
3431 this->type = t; | |
3432 this->ident = id; | |
3433 this->handler = handler; | |
3434 var = NULL; | |
3435 } | |
3436 | |
3437 Catch *Catch::syntaxCopy() | |
3438 { | |
3439 Catch *c = new Catch(loc, | |
3440 (type ? type->syntaxCopy() : NULL), | |
3441 ident, | |
3442 (handler ? handler->syntaxCopy() : NULL)); | |
3443 return c; | |
3444 } | |
3445 | |
3446 void Catch::semantic(Scope *sc) | |
3447 { ScopeDsymbol *sym; | |
3448 | |
3449 //printf("Catch::semantic(%s)\n", ident->toChars()); | |
3450 | |
3451 #ifndef IN_GCC | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3452 if (sc->enclosingFinally) |
159 | 3453 { |
3454 /* This is because the _d_local_unwind() gets the stack munged | |
3455 * up on this. The workaround is to place any try-catches into | |
3456 * a separate function, and call that. | |
3457 * To fix, have the compiler automatically convert the finally | |
3458 * body into a nested function. | |
3459 */ | |
3460 error(loc, "cannot put catch statement inside finally block"); | |
3461 } | |
3462 #endif | |
3463 | |
3464 sym = new ScopeDsymbol(); | |
3465 sym->parent = sc->scopesym; | |
3466 sc = sc->push(sym); | |
3467 | |
3468 if (!type) | |
3469 type = new TypeIdentifier(0, Id::Object); | |
3470 type = type->semantic(loc, sc); | |
3471 if (!type->toBasetype()->isClassHandle()) | |
3472 error("can only catch class objects, not '%s'", type->toChars()); | |
3473 else if (ident) | |
3474 { | |
3475 var = new VarDeclaration(loc, type, ident, NULL); | |
3476 var->parent = sc->parent; | |
3477 sc->insert(var); | |
3478 } | |
3479 handler = handler->semantic(sc); | |
3480 | |
3481 sc->pop(); | |
3482 } | |
3483 | |
336 | 3484 int Catch::blockExit() |
3485 { | |
3486 return handler ? handler->blockExit() : BEfallthru; | |
3487 } | |
3488 | |
159 | 3489 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3490 { | |
3491 buf->writestring("catch"); | |
3492 if (type) | |
3493 { buf->writebyte('('); | |
3494 type->toCBuffer(buf, ident, hgs); | |
3495 buf->writebyte(')'); | |
3496 } | |
3497 buf->writenl(); | |
3498 buf->writebyte('{'); | |
3499 buf->writenl(); | |
336 | 3500 if (handler) |
3501 handler->toCBuffer(buf, hgs); | |
159 | 3502 buf->writebyte('}'); |
3503 buf->writenl(); | |
3504 } | |
3505 | |
3506 /****************************** TryFinallyStatement ***************************/ | |
3507 | |
3508 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) | |
3509 : Statement(loc) | |
3510 { | |
3511 this->body = body; | |
3512 this->finalbody = finalbody; | |
3513 } | |
3514 | |
3515 Statement *TryFinallyStatement::syntaxCopy() | |
3516 { | |
3517 TryFinallyStatement *s = new TryFinallyStatement(loc, | |
3518 body->syntaxCopy(), finalbody->syntaxCopy()); | |
3519 return s; | |
3520 } | |
3521 | |
3522 Statement *TryFinallyStatement::semantic(Scope *sc) | |
3523 { | |
3524 //printf("TryFinallyStatement::semantic()\n"); | |
3525 | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3526 Statement* oldScopeExit = sc->enclosingScopeExit; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3527 sc->enclosingScopeExit = this; |
159 | 3528 body = body->semantic(sc); |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3529 sc->enclosingScopeExit = oldScopeExit; |
159 | 3530 |
3531 sc = sc->push(); | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3532 sc->enclosingFinally = this; |
159 | 3533 sc->sbreak = NULL; |
3534 sc->scontinue = NULL; // no break or continue out of finally block | |
3535 finalbody = finalbody->semantic(sc); | |
3536 sc->pop(); | |
3537 return this; | |
3538 } | |
3539 | |
3540 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3541 { | |
3542 buf->printf("try\n{\n"); | |
3543 body->toCBuffer(buf, hgs); | |
3544 buf->printf("}\nfinally\n{\n"); | |
3545 finalbody->toCBuffer(buf, hgs); | |
3546 buf->writeByte('}'); | |
3547 buf->writenl(); | |
3548 } | |
3549 | |
3550 int TryFinallyStatement::hasBreak() | |
3551 { | |
3552 return FALSE; //TRUE; | |
3553 } | |
3554 | |
3555 int TryFinallyStatement::hasContinue() | |
3556 { | |
3557 return FALSE; //TRUE; | |
3558 } | |
3559 | |
3560 int TryFinallyStatement::usesEH() | |
3561 { | |
3562 return TRUE; | |
3563 } | |
3564 | |
336 | 3565 int TryFinallyStatement::blockExit() |
3566 { | |
875
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
846
diff
changeset
|
3567 if (body) |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
846
diff
changeset
|
3568 return body->blockExit(); |
330f999ade44
Merged DMD 1.038
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
846
diff
changeset
|
3569 return BEfallthru; |
336 | 3570 } |
3571 | |
159 | 3572 |
3573 /****************************** OnScopeStatement ***************************/ | |
3574 | |
3575 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) | |
3576 : Statement(loc) | |
3577 { | |
3578 this->tok = tok; | |
3579 this->statement = statement; | |
3580 } | |
3581 | |
3582 Statement *OnScopeStatement::syntaxCopy() | |
3583 { | |
3584 OnScopeStatement *s = new OnScopeStatement(loc, | |
3585 tok, statement->syntaxCopy()); | |
3586 return s; | |
3587 } | |
3588 | |
3589 Statement *OnScopeStatement::semantic(Scope *sc) | |
3590 { | |
3591 /* semantic is called on results of scopeCode() */ | |
3592 return this; | |
3593 } | |
3594 | |
336 | 3595 int OnScopeStatement::blockExit() |
3596 { // At this point, this statement is just an empty placeholder | |
3597 return BEfallthru; | |
3598 } | |
3599 | |
159 | 3600 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3601 { | |
3602 buf->writestring(Token::toChars(tok)); | |
3603 buf->writebyte(' '); | |
3604 statement->toCBuffer(buf, hgs); | |
3605 } | |
3606 | |
3607 int OnScopeStatement::usesEH() | |
3608 { | |
3609 return (tok != TOKon_scope_success); | |
3610 } | |
3611 | |
3612 void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) | |
3613 { | |
3614 //printf("OnScopeStatement::scopeCode()\n"); | |
3615 //print(); | |
3616 *sentry = NULL; | |
3617 *sexception = NULL; | |
3618 *sfinally = NULL; | |
3619 switch (tok) | |
3620 { | |
3621 case TOKon_scope_exit: | |
3622 *sfinally = statement; | |
3623 break; | |
3624 | |
3625 case TOKon_scope_failure: | |
3626 *sexception = statement; | |
3627 break; | |
3628 | |
3629 case TOKon_scope_success: | |
3630 { | |
3631 /* Create: | |
3632 * sentry: int x = 0; | |
3633 * sexception: x = 1; | |
3634 * sfinally: if (!x) statement; | |
3635 */ | |
846
bc982f1ad106
Merged DMD 1.037 frontend
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
794
diff
changeset
|
3636 Identifier *id = Lexer::uniqueId("__os"); |
159 | 3637 |
3638 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); | |
3639 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); | |
3640 *sentry = new DeclarationStatement(loc, v); | |
3641 | |
3642 Expression *e = new IntegerExp(1); | |
3643 e = new AssignExp(0, new VarExp(0, v), e); | |
3644 *sexception = new ExpStatement(0, e); | |
3645 | |
3646 e = new VarExp(0, v); | |
3647 e = new NotExp(0, e); | |
3648 *sfinally = new IfStatement(0, NULL, e, statement, NULL); | |
3649 | |
3650 break; | |
3651 } | |
3652 | |
3653 default: | |
3654 assert(0); | |
3655 } | |
3656 } | |
3657 | |
3658 /******************************** ThrowStatement ***************************/ | |
3659 | |
3660 ThrowStatement::ThrowStatement(Loc loc, Expression *exp) | |
3661 : Statement(loc) | |
3662 { | |
3663 this->exp = exp; | |
3664 } | |
3665 | |
3666 Statement *ThrowStatement::syntaxCopy() | |
3667 { | |
3668 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); | |
3669 return s; | |
3670 } | |
3671 | |
3672 Statement *ThrowStatement::semantic(Scope *sc) | |
3673 { | |
3674 //printf("ThrowStatement::semantic()\n"); | |
3675 | |
3676 FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
3677 fd->hasReturnExp |= 2; | |
3678 | |
3679 if (sc->incontract) | |
3680 error("Throw statements cannot be in contracts"); | |
3681 exp = exp->semantic(sc); | |
3682 exp = resolveProperties(sc, exp); | |
3683 if (!exp->type->toBasetype()->isClassHandle()) | |
3684 error("can only throw class objects, not type %s", exp->type->toChars()); | |
3685 return this; | |
3686 } | |
3687 | |
336 | 3688 int ThrowStatement::blockExit() |
3689 { | |
3690 return BEthrow; // obviously | |
3691 } | |
3692 | |
159 | 3693 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3694 { | |
3695 buf->printf("throw "); | |
3696 exp->toCBuffer(buf, hgs); | |
3697 buf->writeByte(';'); | |
3698 buf->writenl(); | |
3699 } | |
3700 | |
3701 /******************************** VolatileStatement **************************/ | |
3702 | |
3703 VolatileStatement::VolatileStatement(Loc loc, Statement *statement) | |
3704 : Statement(loc) | |
3705 { | |
3706 this->statement = statement; | |
3707 } | |
3708 | |
3709 Statement *VolatileStatement::syntaxCopy() | |
3710 { | |
3711 VolatileStatement *s = new VolatileStatement(loc, | |
3712 statement ? statement->syntaxCopy() : NULL); | |
3713 return s; | |
3714 } | |
3715 | |
3716 Statement *VolatileStatement::semantic(Scope *sc) | |
3717 { | |
309 | 3718 if (statement) |
3719 { | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3720 Statement* oldScopeExit = sc->enclosingScopeExit; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3721 sc->enclosingScopeExit = this; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3722 statement = statement->semantic(sc); |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3723 sc->enclosingScopeExit = oldScopeExit; |
309 | 3724 } |
159 | 3725 return this; |
3726 } | |
3727 | |
3728 Statements *VolatileStatement::flatten(Scope *sc) | |
3729 { | |
3730 Statements *a; | |
3731 | |
3732 a = statement ? statement->flatten(sc) : NULL; | |
3733 if (a) | |
3734 { for (int i = 0; i < a->dim; i++) | |
3735 { Statement *s = (Statement *)a->data[i]; | |
3736 | |
3737 s = new VolatileStatement(loc, s); | |
3738 a->data[i] = s; | |
3739 } | |
3740 } | |
3741 | |
3742 return a; | |
3743 } | |
3744 | |
336 | 3745 int VolatileStatement::blockExit() |
3746 { | |
3747 return statement ? statement->blockExit() : BEfallthru; | |
3748 } | |
3749 | |
159 | 3750 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3751 { | |
3752 buf->writestring("volatile"); | |
3753 if (statement) | |
3754 { if (statement->isScopeStatement()) | |
3755 buf->writenl(); | |
3756 else | |
3757 buf->writebyte(' '); | |
3758 statement->toCBuffer(buf, hgs); | |
3759 } | |
3760 } | |
3761 | |
3762 | |
3763 /******************************** GotoStatement ***************************/ | |
3764 | |
3765 GotoStatement::GotoStatement(Loc loc, Identifier *ident) | |
3766 : Statement(loc) | |
3767 { | |
3768 this->ident = ident; | |
3769 this->label = NULL; | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3770 this->enclosingFinally = NULL; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3771 this->enclosingScopeExit = NULL; |
159 | 3772 } |
3773 | |
3774 Statement *GotoStatement::syntaxCopy() | |
3775 { | |
3776 GotoStatement *s = new GotoStatement(loc, ident); | |
3777 return s; | |
3778 } | |
3779 | |
3780 Statement *GotoStatement::semantic(Scope *sc) | |
3781 { FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
3782 | |
3783 //printf("GotoStatement::semantic()\n"); | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3784 enclosingFinally = sc->enclosingFinally; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3785 enclosingScopeExit = sc->enclosingScopeExit; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3786 |
159 | 3787 label = fd->searchLabel(ident); |
3788 if (!label->statement && sc->fes) | |
3789 { | |
3790 /* Either the goto label is forward referenced or it | |
3791 * is in the function that the enclosing foreach is in. | |
3792 * Can't know yet, so wrap the goto in a compound statement | |
3793 * so we can patch it later, and add it to a 'look at this later' | |
3794 * list. | |
3795 */ | |
3796 Statements *a = new Statements(); | |
3797 Statement *s; | |
3798 | |
3799 a->push(this); | |
3800 s = new CompoundStatement(loc, a); | |
3801 sc->fes->gotos.push(s); // 'look at this later' list | |
3802 return s; | |
3803 } | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3804 if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) |
159 | 3805 error("cannot goto in or out of finally block"); |
3806 return this; | |
3807 } | |
3808 | |
336 | 3809 int GotoStatement::blockExit() |
3810 { | |
3811 //printf("GotoStatement::blockExit(%p)\n", this); | |
3812 return BEgoto; | |
3813 } | |
3814 | |
159 | 3815 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) |
3816 { | |
3817 buf->writestring("goto "); | |
3818 buf->writestring(ident->toChars()); | |
3819 buf->writebyte(';'); | |
3820 buf->writenl(); | |
3821 } | |
3822 | |
3823 /******************************** LabelStatement ***************************/ | |
3824 | |
3825 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) | |
3826 : Statement(loc) | |
3827 { | |
3828 this->ident = ident; | |
3829 this->statement = statement; | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3830 this->enclosingFinally = NULL; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3831 this->enclosingScopeExit = NULL; |
159 | 3832 this->lblock = NULL; |
3833 this->isReturnLabel = 0; | |
305
2b72433d5c8c
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
lindquist
parents:
304
diff
changeset
|
3834 this->asmLabel = false; |
159 | 3835 } |
3836 | |
3837 Statement *LabelStatement::syntaxCopy() | |
3838 { | |
3839 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); | |
3840 return s; | |
3841 } | |
3842 | |
3843 Statement *LabelStatement::semantic(Scope *sc) | |
3844 { LabelDsymbol *ls; | |
3845 FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
3846 | |
3847 //printf("LabelStatement::semantic()\n"); | |
3848 ls = fd->searchLabel(ident); | |
3849 if (ls->statement) | |
3850 error("Label '%s' already defined", ls->toChars()); | |
3851 else | |
3852 ls->statement = this; | |
1141
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3853 |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3854 enclosingFinally = sc->enclosingFinally; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3855 enclosingScopeExit = sc->enclosingScopeExit; |
f99a3b393c03
Reorganize EnclosingHandlers to require less changes to the frontend and allow us to
Christian Kamm <kamm incasoftware de>
parents:
1133
diff
changeset
|
3856 |
159 | 3857 sc = sc->push(); |
3858 sc->scopesym = sc->enclosing->scopesym; | |
3859 sc->callSuper |= CSXlabel; | |
3860 sc->slabel = this; | |
3861 if (statement) | |
3862 statement = statement->semantic(sc); | |
3863 sc->pop(); | |
305
2b72433d5c8c
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
lindquist
parents:
304
diff
changeset
|
3864 |
664
eef8ac26c66c
Some missed LLVMDC -> LDC.
Christian Kamm <kamm incasoftware de>
parents:
510
diff
changeset
|
3865 // LDC put in labmap |
305
2b72433d5c8c
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
lindquist
parents:
304
diff
changeset
|
3866 fd->labmap[ident->toChars()] = this; |
2b72433d5c8c
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
lindquist
parents:
304
diff
changeset
|
3867 |
159 | 3868 return this; |
3869 } | |
3870 | |
3871 Statements *LabelStatement::flatten(Scope *sc) | |
3872 { | |
3873 Statements *a = NULL; | |
3874 | |
3875 if (statement) | |
3876 { | |
3877 a = statement->flatten(sc); | |
3878 if (a) | |
3879 { | |
3880 if (!a->dim) | |
3881 { | |
3882 a->push(new ExpStatement(loc, NULL)); | |
3883 } | |
3884 Statement *s = (Statement *)a->data[0]; | |
3885 | |
3886 s = new LabelStatement(loc, ident, s); | |
3887 a->data[0] = s; | |
3888 } | |
3889 } | |
3890 | |
3891 return a; | |
3892 } | |
3893 | |
3894 | |
3895 int LabelStatement::usesEH() | |
3896 { | |
3897 return statement ? statement->usesEH() : FALSE; | |
3898 } | |
3899 | |
336 | 3900 int LabelStatement::blockExit() |
3901 { | |
3902 //printf("LabelStatement::blockExit(%p)\n", this); | |
3903 return statement ? statement->blockExit() : BEfallthru; | |
3904 } | |
3905 | |
159 | 3906 int LabelStatement::comeFrom() |
3907 { | |
3908 //printf("LabelStatement::comeFrom()\n"); | |
3909 return TRUE; | |
3910 } | |
3911 | |
3912 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3913 { | |
3914 buf->writestring(ident->toChars()); | |
3915 buf->writebyte(':'); | |
3916 buf->writenl(); | |
3917 if (statement) | |
3918 statement->toCBuffer(buf, hgs); | |
3919 } | |
3920 | |
3921 | |
3922 /******************************** LabelDsymbol ***************************/ | |
3923 | |
3924 LabelDsymbol::LabelDsymbol(Identifier *ident) | |
3925 : Dsymbol(ident) | |
3926 { | |
3927 statement = NULL; | |
3928 } | |
3929 | |
3930 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? | |
3931 { | |
3932 return this; | |
3933 } |