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