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