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