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