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