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