Mercurial > projects > ldc
annotate dmd/statement.c @ 305:2b72433d5c8c trunk
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
Fixed problems with label collisions when using labels inside inline asm. LabelStatement is now easily reached given its
Identifier, which should be useful elsewhere too.
Enabled inline asm for building the lib/compiler/llvmdc runtime code, fixing branches out of asm makes this possible.
author | lindquist |
---|---|
date | Fri, 27 Jun 2008 22:04:35 +0200 |
parents | 3ebc136702dd |
children | d59c363fccad |
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; | |
563 enclosingtryfinally = NULL; | |
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 | |
585 enclosingtryfinally = sc->tfOfTry; | |
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; | |
776 enclosingtryfinally = NULL; | |
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 | |
811 enclosingtryfinally = sc->tfOfTry; | |
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; | |
878 enclosingtryfinally = NULL; | |
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 { | |
890 enclosingtryfinally = sc->tfOfTry; | |
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; | |
954 this->enclosingtryfinally = NULL; | |
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 { | |
974 enclosingtryfinally = sc->tfOfTry; | |
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; | |
1088 this->enclosingtryfinally = NULL; | |
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 | |
1117 enclosingtryfinally = sc->tfOfTry; | |
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 | |
1984 enclosingtryfinally = NULL; | |
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 | |
1999 enclosingtryfinally = sc->tfOfTry; | |
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; | |
2287 enclosingtryfinally = NULL; | |
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 { | |
2298 enclosingtryfinally = sc->tfOfTry; | |
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; | |
2322 enclosingtryfinally = NULL; | |
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 { | |
2335 enclosingtryfinally = sc->tfOfTry; | |
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; | |
2394 this->enclosingtryfinally = NULL; | |
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()); | |
2409 this->enclosingtryfinally = sc->tfOfTry; | |
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; | |
2670 this->enclosingtryfinally = NULL; | |
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 { | |
2681 enclosingtryfinally = sc->tfOfTry; | |
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; | |
2764 this->enclosingtryfinally = NULL; | |
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 { | |
2775 enclosingtryfinally = sc->tfOfTry; | |
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; | |
2869 } | |
2870 | |
2871 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) | |
2872 : Statement(loc) | |
2873 { | |
2874 this->exp = NULL; | |
2875 this->body = body; | |
2876 this->esync = esync; | |
2877 } | |
2878 | |
2879 Statement *SynchronizedStatement::syntaxCopy() | |
2880 { | |
2881 Expression *e = exp ? exp->syntaxCopy() : NULL; | |
2882 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); | |
2883 return s; | |
2884 } | |
2885 | |
2886 Statement *SynchronizedStatement::semantic(Scope *sc) | |
2887 { | |
2888 if (exp) | |
2889 { ClassDeclaration *cd; | |
2890 | |
2891 exp = exp->semantic(sc); | |
2892 exp = resolveProperties(sc, exp); | |
2893 cd = exp->type->isClassHandle(); | |
2894 if (!cd) | |
2895 error("can only synchronize on class objects, not '%s'", exp->type->toChars()); | |
2896 else if (cd->isInterfaceDeclaration()) | |
2897 { Type *t = new TypeIdentifier(0, Id::Object); | |
2898 | |
2899 t = t->semantic(0, sc); | |
2900 exp = new CastExp(loc, exp, t); | |
2901 exp = exp->semantic(sc); | |
2902 } | |
2903 } | |
2904 if (body) | |
2905 body = body->semantic(sc); | |
2906 return this; | |
2907 } | |
2908 | |
2909 int SynchronizedStatement::hasBreak() | |
2910 { | |
2911 return FALSE; //TRUE; | |
2912 } | |
2913 | |
2914 int SynchronizedStatement::hasContinue() | |
2915 { | |
2916 return FALSE; //TRUE; | |
2917 } | |
2918 | |
2919 int SynchronizedStatement::usesEH() | |
2920 { | |
2921 return TRUE; | |
2922 } | |
2923 | |
2924 int SynchronizedStatement::fallOffEnd() | |
2925 { | |
2926 return body ? body->fallOffEnd() : TRUE; | |
2927 } | |
2928 | |
2929 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2930 { | |
2931 buf->writestring("synchronized"); | |
2932 if (exp) | |
2933 { buf->writebyte('('); | |
2934 exp->toCBuffer(buf, hgs); | |
2935 buf->writebyte(')'); | |
2936 } | |
2937 if (body) | |
2938 { | |
2939 buf->writebyte(' '); | |
2940 body->toCBuffer(buf, hgs); | |
2941 } | |
2942 } | |
2943 | |
2944 /******************************** WithStatement ***************************/ | |
2945 | |
2946 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) | |
2947 : Statement(loc) | |
2948 { | |
2949 this->exp = exp; | |
2950 this->body = body; | |
2951 wthis = NULL; | |
2952 } | |
2953 | |
2954 Statement *WithStatement::syntaxCopy() | |
2955 { | |
2956 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); | |
2957 return s; | |
2958 } | |
2959 | |
2960 Statement *WithStatement::semantic(Scope *sc) | |
2961 { ScopeDsymbol *sym; | |
2962 Initializer *init; | |
2963 | |
2964 //printf("WithStatement::semantic()\n"); | |
2965 exp = exp->semantic(sc); | |
2966 exp = resolveProperties(sc, exp); | |
2967 if (exp->op == TOKimport) | |
2968 { ScopeExp *es = (ScopeExp *)exp; | |
2969 | |
2970 sym = es->sds; | |
2971 } | |
2972 else if (exp->op == TOKtype) | |
2973 { TypeExp *es = (TypeExp *)exp; | |
2974 | |
2975 sym = es->type->toDsymbol(sc)->isScopeDsymbol(); | |
2976 if (!sym) | |
2977 { error("%s has no members", es->toChars()); | |
2978 body = body->semantic(sc); | |
2979 return this; | |
2980 } | |
2981 } | |
2982 else | |
2983 { Type *t = exp->type; | |
2984 | |
2985 assert(t); | |
2986 t = t->toBasetype(); | |
2987 if (t->isClassHandle()) | |
2988 { | |
2989 init = new ExpInitializer(loc, exp); | |
2990 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); | |
2991 wthis->semantic(sc); | |
2992 | |
2993 sym = new WithScopeSymbol(this); | |
2994 sym->parent = sc->scopesym; | |
2995 } | |
2996 else if (t->ty == Tstruct) | |
2997 { | |
2998 Expression *e = exp->addressOf(sc); | |
2999 init = new ExpInitializer(loc, e); | |
3000 wthis = new VarDeclaration(loc, e->type, Id::withSym, init); | |
3001 wthis->semantic(sc); | |
3002 sym = new WithScopeSymbol(this); | |
3003 sym->parent = sc->scopesym; | |
3004 } | |
3005 else | |
3006 { error("with expressions must be class objects, not '%s'", exp->type->toChars()); | |
3007 return NULL; | |
3008 } | |
3009 } | |
3010 sc = sc->push(sym); | |
3011 | |
3012 if (body) | |
3013 body = body->semantic(sc); | |
3014 | |
3015 sc->pop(); | |
3016 | |
3017 return this; | |
3018 } | |
3019 | |
3020 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3021 { | |
3022 buf->writestring("with ("); | |
3023 exp->toCBuffer(buf, hgs); | |
3024 buf->writestring(")\n"); | |
3025 if (body) | |
3026 body->toCBuffer(buf, hgs); | |
3027 } | |
3028 | |
3029 int WithStatement::usesEH() | |
3030 { | |
3031 return body ? body->usesEH() : 0; | |
3032 } | |
3033 | |
3034 int WithStatement::fallOffEnd() | |
3035 { | |
3036 return body ? body->fallOffEnd() : TRUE; | |
3037 } | |
3038 | |
3039 /******************************** TryCatchStatement ***************************/ | |
3040 | |
3041 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) | |
3042 : Statement(loc) | |
3043 { | |
3044 this->body = body; | |
3045 this->catches = catches; | |
3046 } | |
3047 | |
3048 Statement *TryCatchStatement::syntaxCopy() | |
3049 { | |
3050 Array *a = new Array(); | |
3051 a->setDim(catches->dim); | |
3052 for (int i = 0; i < a->dim; i++) | |
3053 { Catch *c; | |
3054 | |
3055 c = (Catch *)catches->data[i]; | |
3056 c = c->syntaxCopy(); | |
3057 a->data[i] = c; | |
3058 } | |
3059 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); | |
3060 return s; | |
3061 } | |
3062 | |
3063 Statement *TryCatchStatement::semantic(Scope *sc) | |
3064 { | |
3065 body = body->semanticScope(sc, NULL /*this*/, NULL); | |
3066 | |
3067 for (int i = 0; i < catches->dim; i++) | |
3068 { Catch *c; | |
3069 | |
3070 c = (Catch *)catches->data[i]; | |
3071 c->semantic(sc); | |
3072 | |
3073 // Determine if current catch 'hides' any previous catches | |
3074 for (int j = 0; j < i; j++) | |
3075 { Catch *cj = (Catch *)catches->data[j]; | |
3076 char *si = c->loc.toChars(); | |
3077 char *sj = cj->loc.toChars(); | |
3078 | |
3079 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) | |
3080 error("catch at %s hides catch at %s", sj, si); | |
3081 } | |
3082 } | |
3083 return this; | |
3084 } | |
3085 | |
3086 int TryCatchStatement::hasBreak() | |
3087 { | |
3088 return FALSE; //TRUE; | |
3089 } | |
3090 | |
3091 int TryCatchStatement::usesEH() | |
3092 { | |
3093 return TRUE; | |
3094 } | |
3095 | |
3096 int TryCatchStatement::fallOffEnd() | |
3097 { | |
3098 int result = FALSE; | |
3099 | |
3100 if (body) | |
3101 result = body->fallOffEnd(); | |
3102 for (int i = 0; i < catches->dim; i++) | |
3103 { Catch *c; | |
3104 | |
3105 c = (Catch *)catches->data[i]; | |
3106 if (c->handler) | |
3107 result |= c->handler->fallOffEnd(); | |
3108 } | |
3109 return result; | |
3110 } | |
3111 | |
3112 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3113 { | |
3114 buf->writestring("try"); | |
3115 buf->writenl(); | |
3116 if (body) | |
3117 body->toCBuffer(buf, hgs); | |
3118 int i; | |
3119 for (i = 0; i < catches->dim; i++) | |
3120 { | |
3121 Catch *c = (Catch *)catches->data[i]; | |
3122 c->toCBuffer(buf, hgs); | |
3123 } | |
3124 } | |
3125 | |
3126 /******************************** Catch ***************************/ | |
3127 | |
3128 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) | |
3129 { | |
3130 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); | |
3131 this->loc = loc; | |
3132 this->type = t; | |
3133 this->ident = id; | |
3134 this->handler = handler; | |
3135 var = NULL; | |
3136 } | |
3137 | |
3138 Catch *Catch::syntaxCopy() | |
3139 { | |
3140 Catch *c = new Catch(loc, | |
3141 (type ? type->syntaxCopy() : NULL), | |
3142 ident, | |
3143 (handler ? handler->syntaxCopy() : NULL)); | |
3144 return c; | |
3145 } | |
3146 | |
3147 void Catch::semantic(Scope *sc) | |
3148 { ScopeDsymbol *sym; | |
3149 | |
3150 //printf("Catch::semantic(%s)\n", ident->toChars()); | |
3151 | |
3152 #ifndef IN_GCC | |
3153 if (sc->tf) | |
3154 { | |
3155 /* This is because the _d_local_unwind() gets the stack munged | |
3156 * up on this. The workaround is to place any try-catches into | |
3157 * a separate function, and call that. | |
3158 * To fix, have the compiler automatically convert the finally | |
3159 * body into a nested function. | |
3160 */ | |
3161 error(loc, "cannot put catch statement inside finally block"); | |
3162 } | |
3163 #endif | |
3164 | |
3165 sym = new ScopeDsymbol(); | |
3166 sym->parent = sc->scopesym; | |
3167 sc = sc->push(sym); | |
3168 | |
3169 if (!type) | |
3170 type = new TypeIdentifier(0, Id::Object); | |
3171 type = type->semantic(loc, sc); | |
3172 if (!type->toBasetype()->isClassHandle()) | |
3173 error("can only catch class objects, not '%s'", type->toChars()); | |
3174 else if (ident) | |
3175 { | |
3176 var = new VarDeclaration(loc, type, ident, NULL); | |
3177 var->parent = sc->parent; | |
3178 sc->insert(var); | |
3179 } | |
3180 handler = handler->semantic(sc); | |
3181 | |
3182 sc->pop(); | |
3183 } | |
3184 | |
3185 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3186 { | |
3187 buf->writestring("catch"); | |
3188 if (type) | |
3189 { buf->writebyte('('); | |
3190 type->toCBuffer(buf, ident, hgs); | |
3191 buf->writebyte(')'); | |
3192 } | |
3193 buf->writenl(); | |
3194 buf->writebyte('{'); | |
3195 buf->writenl(); | |
3196 handler->toCBuffer(buf, hgs); | |
3197 buf->writebyte('}'); | |
3198 buf->writenl(); | |
3199 } | |
3200 | |
3201 /****************************** TryFinallyStatement ***************************/ | |
3202 | |
3203 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) | |
3204 : Statement(loc) | |
3205 { | |
3206 this->body = body; | |
3207 this->finalbody = finalbody; | |
3208 this->enclosingtryfinally = NULL; | |
3209 } | |
3210 | |
3211 Statement *TryFinallyStatement::syntaxCopy() | |
3212 { | |
3213 TryFinallyStatement *s = new TryFinallyStatement(loc, | |
3214 body->syntaxCopy(), finalbody->syntaxCopy()); | |
3215 return s; | |
3216 } | |
3217 | |
3218 Statement *TryFinallyStatement::semantic(Scope *sc) | |
3219 { | |
3220 //printf("TryFinallyStatement::semantic()\n"); | |
3221 | |
3222 enclosingtryfinally = sc->tfOfTry; | |
3223 sc->tfOfTry = this; | |
3224 body = body->semantic(sc); | |
3225 sc->tfOfTry = enclosingtryfinally; | |
3226 | |
3227 sc = sc->push(); | |
3228 sc->tf = this; | |
3229 sc->sbreak = NULL; | |
3230 sc->scontinue = NULL; // no break or continue out of finally block | |
3231 finalbody = finalbody->semantic(sc); | |
3232 sc->pop(); | |
3233 return this; | |
3234 } | |
3235 | |
3236 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3237 { | |
3238 buf->printf("try\n{\n"); | |
3239 body->toCBuffer(buf, hgs); | |
3240 buf->printf("}\nfinally\n{\n"); | |
3241 finalbody->toCBuffer(buf, hgs); | |
3242 buf->writeByte('}'); | |
3243 buf->writenl(); | |
3244 } | |
3245 | |
3246 int TryFinallyStatement::hasBreak() | |
3247 { | |
3248 return FALSE; //TRUE; | |
3249 } | |
3250 | |
3251 int TryFinallyStatement::hasContinue() | |
3252 { | |
3253 return FALSE; //TRUE; | |
3254 } | |
3255 | |
3256 int TryFinallyStatement::usesEH() | |
3257 { | |
3258 return TRUE; | |
3259 } | |
3260 | |
3261 int TryFinallyStatement::fallOffEnd() | |
3262 { int result; | |
3263 | |
3264 result = body ? body->fallOffEnd() : TRUE; | |
3265 // if (finalbody) | |
3266 // result = finalbody->fallOffEnd(); | |
3267 return result; | |
3268 } | |
3269 | |
3270 /****************************** OnScopeStatement ***************************/ | |
3271 | |
3272 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) | |
3273 : Statement(loc) | |
3274 { | |
3275 this->tok = tok; | |
3276 this->statement = statement; | |
3277 } | |
3278 | |
3279 Statement *OnScopeStatement::syntaxCopy() | |
3280 { | |
3281 OnScopeStatement *s = new OnScopeStatement(loc, | |
3282 tok, statement->syntaxCopy()); | |
3283 return s; | |
3284 } | |
3285 | |
3286 Statement *OnScopeStatement::semantic(Scope *sc) | |
3287 { | |
3288 /* semantic is called on results of scopeCode() */ | |
3289 return this; | |
3290 } | |
3291 | |
3292 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3293 { | |
3294 buf->writestring(Token::toChars(tok)); | |
3295 buf->writebyte(' '); | |
3296 statement->toCBuffer(buf, hgs); | |
3297 } | |
3298 | |
3299 int OnScopeStatement::usesEH() | |
3300 { | |
3301 return (tok != TOKon_scope_success); | |
3302 } | |
3303 | |
3304 void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) | |
3305 { | |
3306 //printf("OnScopeStatement::scopeCode()\n"); | |
3307 //print(); | |
3308 *sentry = NULL; | |
3309 *sexception = NULL; | |
3310 *sfinally = NULL; | |
3311 switch (tok) | |
3312 { | |
3313 case TOKon_scope_exit: | |
3314 *sfinally = statement; | |
3315 break; | |
3316 | |
3317 case TOKon_scope_failure: | |
3318 *sexception = statement; | |
3319 break; | |
3320 | |
3321 case TOKon_scope_success: | |
3322 { | |
3323 /* Create: | |
3324 * sentry: int x = 0; | |
3325 * sexception: x = 1; | |
3326 * sfinally: if (!x) statement; | |
3327 */ | |
3328 static int num; | |
3329 char name[5 + sizeof(num) * 3 + 1]; | |
3330 sprintf(name, "__osf%d", ++num); | |
3331 Identifier *id = Lexer::idPool(name); | |
3332 | |
3333 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); | |
3334 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); | |
3335 *sentry = new DeclarationStatement(loc, v); | |
3336 | |
3337 Expression *e = new IntegerExp(1); | |
3338 e = new AssignExp(0, new VarExp(0, v), e); | |
3339 *sexception = new ExpStatement(0, e); | |
3340 | |
3341 e = new VarExp(0, v); | |
3342 e = new NotExp(0, e); | |
3343 *sfinally = new IfStatement(0, NULL, e, statement, NULL); | |
3344 | |
3345 break; | |
3346 } | |
3347 | |
3348 default: | |
3349 assert(0); | |
3350 } | |
3351 } | |
3352 | |
3353 /******************************** ThrowStatement ***************************/ | |
3354 | |
3355 ThrowStatement::ThrowStatement(Loc loc, Expression *exp) | |
3356 : Statement(loc) | |
3357 { | |
3358 this->exp = exp; | |
3359 } | |
3360 | |
3361 Statement *ThrowStatement::syntaxCopy() | |
3362 { | |
3363 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); | |
3364 return s; | |
3365 } | |
3366 | |
3367 Statement *ThrowStatement::semantic(Scope *sc) | |
3368 { | |
3369 //printf("ThrowStatement::semantic()\n"); | |
3370 | |
3371 FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
3372 fd->hasReturnExp |= 2; | |
3373 | |
3374 if (sc->incontract) | |
3375 error("Throw statements cannot be in contracts"); | |
3376 exp = exp->semantic(sc); | |
3377 exp = resolveProperties(sc, exp); | |
3378 if (!exp->type->toBasetype()->isClassHandle()) | |
3379 error("can only throw class objects, not type %s", exp->type->toChars()); | |
3380 return this; | |
3381 } | |
3382 | |
3383 int ThrowStatement::fallOffEnd() | |
3384 { | |
3385 return FALSE; | |
3386 } | |
3387 | |
3388 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3389 { | |
3390 buf->printf("throw "); | |
3391 exp->toCBuffer(buf, hgs); | |
3392 buf->writeByte(';'); | |
3393 buf->writenl(); | |
3394 } | |
3395 | |
3396 /******************************** VolatileStatement **************************/ | |
3397 | |
3398 VolatileStatement::VolatileStatement(Loc loc, Statement *statement) | |
3399 : Statement(loc) | |
3400 { | |
3401 this->statement = statement; | |
3402 } | |
3403 | |
3404 Statement *VolatileStatement::syntaxCopy() | |
3405 { | |
3406 VolatileStatement *s = new VolatileStatement(loc, | |
3407 statement ? statement->syntaxCopy() : NULL); | |
3408 return s; | |
3409 } | |
3410 | |
3411 Statement *VolatileStatement::semantic(Scope *sc) | |
3412 { | |
3413 statement = statement ? statement->semantic(sc) : NULL; | |
3414 return this; | |
3415 } | |
3416 | |
3417 Statements *VolatileStatement::flatten(Scope *sc) | |
3418 { | |
3419 Statements *a; | |
3420 | |
3421 a = statement ? statement->flatten(sc) : NULL; | |
3422 if (a) | |
3423 { for (int i = 0; i < a->dim; i++) | |
3424 { Statement *s = (Statement *)a->data[i]; | |
3425 | |
3426 s = new VolatileStatement(loc, s); | |
3427 a->data[i] = s; | |
3428 } | |
3429 } | |
3430 | |
3431 return a; | |
3432 } | |
3433 | |
3434 int VolatileStatement::fallOffEnd() | |
3435 { | |
3436 return statement ? statement->fallOffEnd() : TRUE; | |
3437 } | |
3438 | |
3439 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3440 { | |
3441 buf->writestring("volatile"); | |
3442 if (statement) | |
3443 { if (statement->isScopeStatement()) | |
3444 buf->writenl(); | |
3445 else | |
3446 buf->writebyte(' '); | |
3447 statement->toCBuffer(buf, hgs); | |
3448 } | |
3449 } | |
3450 | |
3451 | |
3452 /******************************** GotoStatement ***************************/ | |
3453 | |
3454 GotoStatement::GotoStatement(Loc loc, Identifier *ident) | |
3455 : Statement(loc) | |
3456 { | |
3457 this->ident = ident; | |
3458 this->label = NULL; | |
3459 this->tf = NULL; | |
3460 this->enclosingtryfinally = NULL; | |
3461 } | |
3462 | |
3463 Statement *GotoStatement::syntaxCopy() | |
3464 { | |
3465 GotoStatement *s = new GotoStatement(loc, ident); | |
3466 return s; | |
3467 } | |
3468 | |
3469 Statement *GotoStatement::semantic(Scope *sc) | |
3470 { FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
3471 | |
3472 //printf("GotoStatement::semantic()\n"); | |
3473 tf = sc->tf; | |
3474 enclosingtryfinally = sc->tfOfTry; | |
3475 label = fd->searchLabel(ident); | |
3476 if (!label->statement && sc->fes) | |
3477 { | |
3478 /* Either the goto label is forward referenced or it | |
3479 * is in the function that the enclosing foreach is in. | |
3480 * Can't know yet, so wrap the goto in a compound statement | |
3481 * so we can patch it later, and add it to a 'look at this later' | |
3482 * list. | |
3483 */ | |
3484 Statements *a = new Statements(); | |
3485 Statement *s; | |
3486 | |
3487 a->push(this); | |
3488 s = new CompoundStatement(loc, a); | |
3489 sc->fes->gotos.push(s); // 'look at this later' list | |
3490 return s; | |
3491 } | |
3492 if (label->statement && label->statement->tf != sc->tf) | |
3493 error("cannot goto in or out of finally block"); | |
3494 return this; | |
3495 } | |
3496 | |
3497 int GotoStatement::fallOffEnd() | |
3498 { | |
3499 return FALSE; | |
3500 } | |
3501 | |
3502 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3503 { | |
3504 buf->writestring("goto "); | |
3505 buf->writestring(ident->toChars()); | |
3506 buf->writebyte(';'); | |
3507 buf->writenl(); | |
3508 } | |
3509 | |
3510 /******************************** LabelStatement ***************************/ | |
3511 | |
3512 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) | |
3513 : Statement(loc) | |
3514 { | |
3515 this->ident = ident; | |
3516 this->statement = statement; | |
3517 this->tf = NULL; | |
3518 this->enclosingtryfinally = NULL; | |
3519 this->lblock = NULL; | |
3520 this->isReturnLabel = 0; | |
3521 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
|
3522 this->asmLabel = false; |
159 | 3523 } |
3524 | |
3525 Statement *LabelStatement::syntaxCopy() | |
3526 { | |
3527 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); | |
3528 return s; | |
3529 } | |
3530 | |
3531 Statement *LabelStatement::semantic(Scope *sc) | |
3532 { LabelDsymbol *ls; | |
3533 FuncDeclaration *fd = sc->parent->isFuncDeclaration(); | |
3534 | |
3535 //printf("LabelStatement::semantic()\n"); | |
3536 ls = fd->searchLabel(ident); | |
3537 if (ls->statement) | |
3538 error("Label '%s' already defined", ls->toChars()); | |
3539 else | |
3540 ls->statement = this; | |
3541 tf = sc->tf; | |
3542 enclosingtryfinally = sc->tfOfTry; | |
3543 sc = sc->push(); | |
3544 sc->scopesym = sc->enclosing->scopesym; | |
3545 sc->callSuper |= CSXlabel; | |
3546 sc->slabel = this; | |
3547 if (statement) | |
3548 statement = statement->semantic(sc); | |
3549 sc->pop(); | |
305
2b72433d5c8c
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
lindquist
parents:
304
diff
changeset
|
3550 |
2b72433d5c8c
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
lindquist
parents:
304
diff
changeset
|
3551 // 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
|
3552 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
|
3553 |
159 | 3554 return this; |
3555 } | |
3556 | |
3557 Statements *LabelStatement::flatten(Scope *sc) | |
3558 { | |
3559 Statements *a = NULL; | |
3560 | |
3561 if (statement) | |
3562 { | |
3563 a = statement->flatten(sc); | |
3564 if (a) | |
3565 { | |
3566 if (!a->dim) | |
3567 { | |
3568 a->push(new ExpStatement(loc, NULL)); | |
3569 } | |
3570 Statement *s = (Statement *)a->data[0]; | |
3571 | |
3572 s = new LabelStatement(loc, ident, s); | |
3573 a->data[0] = s; | |
3574 } | |
3575 } | |
3576 | |
3577 return a; | |
3578 } | |
3579 | |
3580 | |
3581 int LabelStatement::usesEH() | |
3582 { | |
3583 return statement ? statement->usesEH() : FALSE; | |
3584 } | |
3585 | |
3586 int LabelStatement::fallOffEnd() | |
3587 { | |
3588 return statement ? statement->fallOffEnd() : TRUE; | |
3589 } | |
3590 | |
3591 int LabelStatement::comeFrom() | |
3592 { | |
3593 //printf("LabelStatement::comeFrom()\n"); | |
3594 return TRUE; | |
3595 } | |
3596 | |
3597 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
3598 { | |
3599 buf->writestring(ident->toChars()); | |
3600 buf->writebyte(':'); | |
3601 buf->writenl(); | |
3602 if (statement) | |
3603 statement->toCBuffer(buf, hgs); | |
3604 } | |
3605 | |
3606 | |
3607 /******************************** LabelDsymbol ***************************/ | |
3608 | |
3609 LabelDsymbol::LabelDsymbol(Identifier *ident) | |
3610 : Dsymbol(ident) | |
3611 { | |
3612 statement = NULL; | |
3613 } | |
3614 | |
3615 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? | |
3616 { | |
3617 return this; | |
3618 } | |
3619 | |
3620 |