Scan dynamic libraries for GC roots
[delight/core.git] / dmd2 / statement.c
blob479f02c7c5d9c61077eafbf0fe7335d76c6242ac
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, September 2004
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <assert.h>
21 #include "mem.h"
23 #include "statement.h"
24 #include "expression.h"
25 #include "cond.h"
26 #include "init.h"
27 #include "staticassert.h"
28 #include "mtype.h"
29 #include "scope.h"
30 #include "declaration.h"
31 #include "aggregate.h"
32 #include "id.h"
33 #include "hdrgen.h"
34 #include "parse.h"
35 #include "template.h"
37 /******************************** Statement ***************************/
39 Statement::Statement(Loc loc)
40 : loc(loc)
42 #ifdef _DH
43 // If this is an in{} contract scope statement (skip for determining
44 // inlineStatus of a function body for header content)
45 incontract = 0;
46 #endif
49 Statement *Statement::syntaxCopy()
51 assert(0);
52 return NULL;
55 void Statement::print()
57 fprintf(stdmsg, "%s\n", toChars());
58 fflush(stdmsg);
61 char *Statement::toChars()
62 { OutBuffer *buf;
63 HdrGenState hgs;
65 buf = new OutBuffer();
66 toCBuffer(buf, &hgs);
67 return buf->toChars();
70 void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
72 buf->printf("Statement::toCBuffer()");
73 buf->writenl();
76 Statement *Statement::semantic(Scope *sc)
78 return this;
81 // Same as semantic(), but do create a new scope
83 Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
84 { Scope *scd;
85 Statement *s;
87 scd = sc->push();
88 if (sbreak)
89 scd->sbreak = sbreak;
90 if (scontinue)
91 scd->scontinue = scontinue;
92 s = semantic(scd);
93 scd->pop();
94 return s;
97 void Statement::error(const char *format, ...)
99 va_list ap;
100 va_start(ap, format);
101 ::verror(loc, format, ap);
102 va_end( ap );
105 int Statement::hasBreak()
107 //printf("Statement::hasBreak()\n");
108 return FALSE;
111 int Statement::hasContinue()
113 return FALSE;
116 // TRUE if statement uses exception handling
118 int Statement::usesEH()
120 return FALSE;
123 /* Only valid after semantic analysis
125 int Statement::blockExit()
127 printf("Statement::blockExit(%p)\n", this);
128 printf("%s\n", toChars());
129 assert(0);
130 return BEany;
133 // TRUE if statement may fall off the end without a throw or return
135 int Statement::fallOffEnd()
137 return TRUE;
140 // TRUE if statement 'comes from' somewhere else, like a goto
142 int Statement::comeFrom()
144 //printf("Statement::comeFrom()\n");
145 return FALSE;
148 /****************************************
149 * If this statement has code that needs to run in a finally clause
150 * at the end of the current scope, return that code in the form of
151 * a Statement.
152 * Output:
153 * *sentry code executed upon entry to the scope
154 * *sexception code executed upon exit from the scope via exception
155 * *sfinally code executed in finally block
158 void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
160 //printf("Statement::scopeCode()\n");
161 //print();
162 *sentry = NULL;
163 *sexception = NULL;
164 *sfinally = NULL;
167 /*********************************
168 * Flatten out the scope by presenting the statement
169 * as an array of statements.
170 * Returns NULL if no flattening necessary.
173 Statements *Statement::flatten(Scope *sc)
175 return NULL;
179 /******************************** ExpStatement ***************************/
181 ExpStatement::ExpStatement(Loc loc, Expression *exp)
182 : Statement(loc)
184 this->exp = exp;
187 Statement *ExpStatement::syntaxCopy()
189 Expression *e = exp ? exp->syntaxCopy() : NULL;
190 ExpStatement *es = new ExpStatement(loc, e);
191 return es;
194 void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
196 if (exp)
197 exp->toCBuffer(buf, hgs);
198 buf->writeByte(';');
199 if (!hgs->FLinit.init)
200 buf->writenl();
203 Statement *ExpStatement::semantic(Scope *sc)
205 if (exp)
207 //printf("ExpStatement::semantic() %s\n", exp->toChars());
208 exp = exp->semantic(sc);
209 exp = resolveProperties(sc, exp);
210 exp->checkSideEffect(0);
211 exp = exp->optimize(0);
212 //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
214 return this;
217 int ExpStatement::blockExit()
218 { int result = BEfallthru;
220 if (exp)
222 if (exp->op == TOKhalt)
223 return BEhalt;
224 if (exp->op == TOKassert)
225 { AssertExp *a = (AssertExp *)exp;
227 if (a->e1->isBool(FALSE)) // if it's an assert(0)
228 return BEhalt;
230 if (exp->canThrow())
231 result |= BEthrow;
233 return result;
236 int ExpStatement::fallOffEnd()
238 if (exp)
240 if (exp->op == TOKassert)
241 { AssertExp *a = (AssertExp *)exp;
243 if (a->e1->isBool(FALSE)) // if it's an assert(0)
244 return FALSE;
246 else if (exp->op == TOKhalt)
247 return FALSE;
249 return TRUE;
252 /******************************** CompileStatement ***************************/
254 CompileStatement::CompileStatement(Loc loc, Expression *exp)
255 : Statement(loc)
257 this->exp = exp;
260 Statement *CompileStatement::syntaxCopy()
262 Expression *e = exp->syntaxCopy();
263 CompileStatement *es = new CompileStatement(loc, e);
264 return es;
267 void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
269 buf->writestring("mixin(");
270 exp->toCBuffer(buf, hgs);
271 buf->writestring(");");
272 if (!hgs->FLinit.init)
273 buf->writenl();
276 Statement *CompileStatement::semantic(Scope *sc)
278 //printf("CompileStatement::semantic() %s\n", exp->toChars());
279 exp = exp->semantic(sc);
280 exp = resolveProperties(sc, exp);
281 exp = exp->optimize(WANTvalue | WANTinterpret);
282 if (exp->op != TOKstring)
283 { error("argument to mixin must be a string, not (%s)", exp->toChars());
284 return this;
286 StringExp *se = (StringExp *)exp;
287 se = se->toUTF8(sc);
288 Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
289 p.loc = loc;
290 p.nextToken();
292 Statements *statements = new Statements();
293 while (p.token.value != TOKeof)
295 Statement *s = p.parseStatement(PSsemi | PScurlyscope);
296 statements->push(s);
299 Statement *s = new CompoundStatement(loc, statements);
300 return s->semantic(sc);
304 /******************************** DeclarationStatement ***************************/
306 DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration)
307 : ExpStatement(loc, new DeclarationExp(loc, declaration))
311 DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp)
312 : ExpStatement(loc, exp)
316 Statement *DeclarationStatement::syntaxCopy()
318 DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy());
319 return ds;
322 void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
324 //printf("DeclarationStatement::scopeCode()\n");
325 //print();
327 *sentry = NULL;
328 *sexception = NULL;
329 *sfinally = NULL;
331 if (exp)
333 if (exp->op == TOKdeclaration)
335 DeclarationExp *de = (DeclarationExp *)(exp);
336 VarDeclaration *v = de->declaration->isVarDeclaration();
337 if (v)
338 { Expression *e;
340 e = v->callAutoDtor(sc);
341 if (e)
343 //printf("dtor is: "); e->print();
344 *sfinally = new ExpStatement(loc, e);
351 void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
353 exp->toCBuffer(buf, hgs);
357 /******************************** InjectorMainBody ***************************/
359 static Expressions *getAutoArgs(Loc loc, Arguments *arguments, Scope *sc) {
360 Expressions *args = new Expressions();
362 // Collect all the objects we need for the constructor's arguments
363 for (int i = 0; i < arguments->dim; i++) {
364 Argument *arg = (Argument *) arguments->data[i];
365 if (arg->ident == Id::args) {
366 // For 'args', just pass through the string[] passed to main()
367 args->push(new IdentifierExp(loc, arg->ident));
368 } else {
369 // For everything else, call a getter in a dlt._externals.type module
370 Type *type = arg->type->semantic(loc, sc);
371 char* typeStr = strdup(type->toChars());
373 char* typeName = strrchr(typeStr, '.');
374 if (typeName == NULL) {
375 error("Expected '.' in main-injected type %s", typeName);
376 return NULL;
378 *typeName = '\0';
379 typeName++;
381 Array *dlt_package = new Array();
382 dlt_package->push(Id::_externals);
384 Expression *getter = new IdentifierExp(loc, Id::_externals);
385 while (char *p = strchr(typeStr, '.')) {
386 *p = '\0';
387 Identifier* component = new Identifier(typeStr, TOKidentifier);
388 dlt_package->push(component);
389 getter = new DotIdExp(loc, getter, component);
390 typeStr = p + 1;
392 Identifier* component = new Identifier(typeStr, TOKidentifier);
393 getter = new DotIdExp(loc, getter, component);
394 getter = new DotIdExp(loc, getter, arg->ident);
396 Import *im = new Import(loc, dlt_package, component, NULL, true);
397 sc->module->members->shift(im);
398 im->addMember(NULL, sc->scopesym, 1);
399 im->semantic(sc);
402 HdrGenState hgs;
403 OutBuffer *buf = new OutBuffer();
404 im->toCBuffer(buf, &hgs);
405 fprintf(stderr, "i: %s\n", buf->toChars());
408 getter = new CallExp(loc, getter);
410 //fprintf(stderr, "e: %s\n", getter->toChars());
411 //fprintf(stderr, "type: %s\n", getter->type->toChars());
413 args->push(getter);
417 return args;
420 InjectorMainBody::InjectorMainBody(Loc loc, ClassDeclaration *mainClass)
421 : Statement(loc), mainClass(mainClass)
425 Statement *InjectorMainBody::semantic(Scope *sc)
427 // Find the constructor and the main method
428 CtorDeclaration *ctor = NULL;
429 FuncDeclaration *mainDecl = NULL;
430 for (int i = 0; i < mainClass->members->dim; i++) {
431 Dsymbol *s;
433 s = (Dsymbol *)mainClass->members->data[i];
435 CtorDeclaration *thisCtor = s->isCtorDeclaration();
436 if (thisCtor) {
437 if (ctor) {
438 error("Multiple constructors for Main class!");
439 return NULL;
440 } else {
441 ctor = thisCtor;
445 FuncDeclaration *thisMethod = s->isFuncDeclaration();
446 if (thisMethod && thisMethod->ident == Id::main) {
447 if (mainDecl) {
448 error("Multiple main methods for Main class!");
449 return NULL;
450 } else {
451 mainDecl = thisMethod;
456 if (mainDecl == NULL) {
457 error("No main method in Main class!");
458 return NULL;
461 if (mainDecl->type->nextOf()->ty != Tvoid) {
462 error("Main.main must return void (throw SystemExit to return a non-zero exit code)");
465 Expression *newMain = new NewExp(loc, NULL, NULL, mainClass->getType(),
466 ctor ? getAutoArgs(ctor->loc, ctor->arguments, sc) : NULL);
468 // Then invoke the main() method inside it
469 // mainObject.main(...)
470 Expression *mainMethod = new DotIdExp(mainDecl->loc, newMain, Id::main);
471 Expression *mainCall = new CallExp(mainMethod->loc, mainMethod,
472 getAutoArgs(mainDecl->loc,
473 ((TypeFunction *) mainDecl->type)->parameters,
474 sc));
476 Statement *body = new ExpStatement(loc, mainCall);
478 return body->semantic(sc);
481 /******************************** CompoundStatement ***************************/
483 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
484 : Statement(loc)
486 statements = s;
489 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
490 : Statement(loc)
492 statements = new Statements();
493 statements->reserve(2);
494 statements->push(s1);
495 statements->push(s2);
498 Statement *CompoundStatement::syntaxCopy()
500 Statements *a = new Statements();
501 a->setDim(statements->dim);
502 for (size_t i = 0; i < statements->dim; i++)
503 { Statement *s = (Statement *)statements->data[i];
504 if (s)
505 s = s->syntaxCopy();
506 a->data[i] = s;
508 CompoundStatement *cs = new CompoundStatement(loc, a);
509 return cs;
513 Statement *CompoundStatement::semantic(Scope *sc)
514 { Statement *s;
516 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
518 for (size_t i = 0; i < statements->dim; )
520 s = (Statement *) statements->data[i];
521 if (s)
522 { Statements *a = s->flatten(sc);
524 if (a)
526 statements->remove(i);
527 statements->insert(i, a);
528 continue;
530 s = s->semantic(sc);
531 statements->data[i] = s;
532 if (s)
534 Statement *sentry;
535 Statement *sexception;
536 Statement *sfinally;
538 s->scopeCode(sc, &sentry, &sexception, &sfinally);
539 if (sentry)
541 sentry = sentry->semantic(sc);
542 statements->data[i] = sentry;
544 if (sexception)
546 if (i + 1 == statements->dim && !sfinally)
548 #if 1
549 sexception = sexception->semantic(sc);
550 #else
551 statements->push(sexception);
552 if (sfinally)
553 // Assume sexception does not throw
554 statements->push(sfinally);
555 #endif
557 else
559 /* Rewrite:
560 * s; s1; s2;
561 * As:
562 * s;
563 * try { s1; s2; }
564 * catch (Object __o)
565 * { sexception; throw __o; }
567 Statement *body;
568 Statements *a = new Statements();
570 for (int j = i + 1; j < statements->dim; j++)
572 a->push(statements->data[j]);
574 body = new CompoundStatement(0, a);
575 body = new ScopeStatement(0, body);
577 Identifier *id = Lexer::uniqueId("__o");
579 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
580 handler = new CompoundStatement(0, sexception, handler);
582 Array *catches = new Array();
583 Catch *ctch = new Catch(0, NULL, id, handler);
584 catches->push(ctch);
585 s = new TryCatchStatement(0, body, catches);
587 if (sfinally)
588 s = new TryFinallyStatement(0, s, sfinally);
589 s = s->semantic(sc);
590 statements->setDim(i + 1);
591 statements->push(s);
592 break;
595 else if (sfinally)
597 if (0 && i + 1 == statements->dim)
599 statements->push(sfinally);
601 else
603 /* Rewrite:
604 * s; s1; s2;
605 * As:
606 * s; try { s1; s2; } finally { sfinally; }
608 Statement *body;
609 Statements *a = new Statements();
611 for (int j = i + 1; j < statements->dim; j++)
613 a->push(statements->data[j]);
615 body = new CompoundStatement(0, a);
616 s = new TryFinallyStatement(0, body, sfinally);
617 s = s->semantic(sc);
618 statements->setDim(i + 1);
619 statements->push(s);
620 break;
625 i++;
627 if (statements->dim == 1)
628 return s;
629 return this;
632 Statements *CompoundStatement::flatten(Scope *sc)
634 return statements;
637 ReturnStatement *CompoundStatement::isReturnStatement()
638 { int i;
639 ReturnStatement *rs = NULL;
641 for (i = 0; i < statements->dim; i++)
642 { Statement *s;
644 s = (Statement *) statements->data[i];
645 if (s)
647 rs = s->isReturnStatement();
648 if (rs)
649 break;
652 return rs;
655 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
656 { int i;
658 for (i = 0; i < statements->dim; i++)
659 { Statement *s;
661 s = (Statement *) statements->data[i];
662 if (s)
663 s->toCBuffer(buf, hgs);
667 int CompoundStatement::usesEH()
669 for (int i = 0; i < statements->dim; i++)
670 { Statement *s;
672 s = (Statement *) statements->data[i];
673 if (s && s->usesEH())
674 return TRUE;
676 return FALSE;
679 int CompoundStatement::blockExit()
681 //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
682 int result = BEfallthru;
683 for (size_t i = 0; i < statements->dim; i++)
684 { Statement *s = (Statement *) statements->data[i];
685 if (s)
687 //printf("result = x%x\n", result);
688 //printf("%s\n", s->toChars());
689 if (!(result & BEfallthru) && !s->comeFrom())
691 if (global.params.warnings)
692 { fprintf(stdmsg, "warning - ");
693 s->error("statement is not reachable");
697 result &= ~BEfallthru;
698 result |= s->blockExit();
701 return result;
704 int CompoundStatement::fallOffEnd()
705 { int falloff = TRUE;
707 //printf("CompoundStatement::fallOffEnd()\n");
708 for (int i = 0; i < statements->dim; i++)
709 { Statement *s = (Statement *)statements->data[i];
711 if (!s)
712 continue;
714 #if 0
715 if (!falloff && global.params.warnings && !s->comeFrom())
717 fprintf(stdmsg, "warning - ");
718 s->error("statement is not reachable");
720 #endif
721 falloff = s->fallOffEnd();
723 return falloff;
726 int CompoundStatement::comeFrom()
727 { int comefrom = FALSE;
729 //printf("CompoundStatement::comeFrom()\n");
730 for (int i = 0; i < statements->dim; i++)
731 { Statement *s = (Statement *)statements->data[i];
733 if (!s)
734 continue;
736 comefrom |= s->comeFrom();
738 return comefrom;
742 /**************************** UnrolledLoopStatement ***************************/
744 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
745 : Statement(loc)
747 statements = s;
750 Statement *UnrolledLoopStatement::syntaxCopy()
752 Statements *a = new Statements();
753 a->setDim(statements->dim);
754 for (size_t i = 0; i < statements->dim; i++)
755 { Statement *s = (Statement *)statements->data[i];
756 if (s)
757 s = s->syntaxCopy();
758 a->data[i] = s;
760 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
761 return cs;
765 Statement *UnrolledLoopStatement::semantic(Scope *sc)
767 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
769 sc->noctor++;
770 Scope *scd = sc->push();
771 scd->sbreak = this;
772 scd->scontinue = this;
774 for (size_t i = 0; i < statements->dim; i++)
776 Statement *s = (Statement *) statements->data[i];
777 if (s)
779 s = s->semantic(scd);
780 statements->data[i] = s;
784 scd->pop();
785 sc->noctor--;
786 return this;
789 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
791 buf->writestring("unrolled {");
792 buf->writenl();
794 for (size_t i = 0; i < statements->dim; i++)
795 { Statement *s;
797 s = (Statement *) statements->data[i];
798 if (s)
799 s->toCBuffer(buf, hgs);
802 buf->writeByte('}');
803 buf->writenl();
806 int UnrolledLoopStatement::hasBreak()
808 return TRUE;
811 int UnrolledLoopStatement::hasContinue()
813 return TRUE;
816 int UnrolledLoopStatement::usesEH()
818 for (size_t i = 0; i < statements->dim; i++)
819 { Statement *s = (Statement *) statements->data[i];
820 if (s && s->usesEH())
821 return TRUE;
823 return FALSE;
826 int UnrolledLoopStatement::blockExit()
828 int result = BEfallthru;
829 for (size_t i = 0; i < statements->dim; i++)
830 { Statement *s = (Statement *) statements->data[i];
831 if (s)
833 int r = s->blockExit();
834 result |= r & ~(BEbreak | BEcontinue);
837 return result;
840 int UnrolledLoopStatement::fallOffEnd()
842 //printf("UnrolledLoopStatement::fallOffEnd()\n");
843 for (size_t i = 0; i < statements->dim; i++)
844 { Statement *s = (Statement *)statements->data[i];
846 if (s)
847 s->fallOffEnd();
849 return TRUE;
852 int UnrolledLoopStatement::comeFrom()
853 { int comefrom = FALSE;
855 //printf("UnrolledLoopStatement::comeFrom()\n");
856 for (size_t i = 0; i < statements->dim; i++)
857 { Statement *s = (Statement *)statements->data[i];
859 if (!s)
860 continue;
862 comefrom |= s->comeFrom();
864 return comefrom;
868 /******************************** ScopeStatement ***************************/
870 ScopeStatement::ScopeStatement(Loc loc, Statement *s)
871 : Statement(loc)
873 this->statement = s;
876 Statement *ScopeStatement::syntaxCopy()
878 Statement *s;
880 s = statement ? statement->syntaxCopy() : NULL;
881 s = new ScopeStatement(loc, s);
882 return s;
886 Statement *ScopeStatement::semantic(Scope *sc)
887 { ScopeDsymbol *sym;
889 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
890 if (statement)
891 { Statements *a;
893 sym = new ScopeDsymbol();
894 sym->parent = sc->scopesym;
895 sc = sc->push(sym);
897 a = statement->flatten(sc);
898 if (a)
900 statement = new CompoundStatement(loc, a);
903 statement = statement->semantic(sc);
904 if (statement)
906 Statement *sentry;
907 Statement *sexception;
908 Statement *sfinally;
910 statement->scopeCode(sc, &sentry, &sexception, &sfinally);
911 if (sfinally)
913 //printf("adding sfinally\n");
914 statement = new CompoundStatement(loc, statement, sfinally);
918 sc->pop();
920 return this;
923 int ScopeStatement::hasBreak()
925 //printf("ScopeStatement::hasBreak() %s\n", toChars());
926 return statement ? statement->hasBreak() : FALSE;
929 int ScopeStatement::hasContinue()
931 return statement ? statement->hasContinue() : FALSE;
934 int ScopeStatement::usesEH()
936 return statement ? statement->usesEH() : FALSE;
939 int ScopeStatement::blockExit()
941 //printf("ScopeStatement::blockExit(%p)\n", statement);
942 return statement ? statement->blockExit() : BEfallthru;
945 int ScopeStatement::fallOffEnd()
947 return statement ? statement->fallOffEnd() : TRUE;
950 int ScopeStatement::comeFrom()
952 //printf("ScopeStatement::comeFrom()\n");
953 return statement ? statement->comeFrom() : FALSE;
956 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
958 buf->writeByte('{');
959 buf->writenl();
961 if (statement)
962 statement->toCBuffer(buf, hgs);
964 buf->writeByte('}');
965 buf->writenl();
968 /******************************** WhileStatement ***************************/
970 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
971 : Statement(loc)
973 condition = c;
974 body = b;
977 Statement *WhileStatement::syntaxCopy()
979 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
980 return s;
984 Statement *WhileStatement::semantic(Scope *sc)
986 #if 0
987 if (condition->op == TOKmatch)
989 /* Rewrite while (condition) body as:
990 * if (condition)
991 * do
992 * body
993 * while ((_match = _match.opNext), _match);
996 Expression *ew = new IdentifierExp(0, Id::_match);
997 ew = new DotIdExp(0, ew, Id::next);
998 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
999 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
1000 Expression *ev = new IdentifierExp(0, Id::_match);
1001 //ev = new CastExp(0, ev, Type::tvoidptr);
1002 ew = new CommaExp(0, ew, ev);
1003 Statement *sw = new DoStatement(loc, body, ew);
1004 Statement *si = new IfStatement(loc, condition, sw, NULL);
1005 return si->semantic(sc);
1007 #endif
1009 condition = condition->semantic(sc);
1010 condition = resolveProperties(sc, condition);
1011 condition = condition->optimize(WANTvalue);
1012 condition = condition->checkToBoolean();
1014 sc->noctor++;
1016 Scope *scd = sc->push();
1017 scd->sbreak = this;
1018 scd->scontinue = this;
1019 if (body)
1020 body = body->semantic(scd);
1021 scd->pop();
1023 sc->noctor--;
1025 return this;
1028 int WhileStatement::hasBreak()
1030 return TRUE;
1033 int WhileStatement::hasContinue()
1035 return TRUE;
1038 int WhileStatement::usesEH()
1040 return body ? body->usesEH() : 0;
1043 int WhileStatement::blockExit()
1045 //printf("WhileStatement::blockExit(%p)\n", this);
1047 int result = BEnone;
1048 if (condition->canThrow())
1049 result |= BEthrow;
1050 if (body)
1051 { result |= body->blockExit();
1052 if (result & BEbreak)
1053 result |= BEfallthru;
1054 result &= ~(BEbreak | BEcontinue);
1056 else
1057 result |= BEfallthru;
1058 return result;
1061 int WhileStatement::fallOffEnd()
1063 if (body)
1064 body->fallOffEnd();
1065 return TRUE;
1068 int WhileStatement::comeFrom()
1070 if (body)
1071 return body->comeFrom();
1072 return FALSE;
1075 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1077 buf->writestring("while (");
1078 condition->toCBuffer(buf, hgs);
1079 buf->writebyte(')');
1080 buf->writenl();
1081 if (body)
1082 body->toCBuffer(buf, hgs);
1085 /******************************** DoStatement ***************************/
1087 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
1088 : Statement(loc)
1090 body = b;
1091 condition = c;
1094 Statement *DoStatement::syntaxCopy()
1096 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
1097 return s;
1101 Statement *DoStatement::semantic(Scope *sc)
1103 sc->noctor++;
1104 if (body)
1105 body = body->semanticScope(sc, this, this);
1106 sc->noctor--;
1107 condition = condition->semantic(sc);
1108 condition = resolveProperties(sc, condition);
1109 condition = condition->optimize(WANTvalue);
1111 condition = condition->checkToBoolean();
1113 return this;
1116 int DoStatement::hasBreak()
1118 return TRUE;
1121 int DoStatement::hasContinue()
1123 return TRUE;
1126 int DoStatement::usesEH()
1128 return body ? body->usesEH() : 0;
1131 int DoStatement::blockExit()
1132 { int result;
1134 if (body)
1135 { result = body->blockExit();
1136 if (result & BEbreak)
1138 if (result == BEbreak)
1139 return BEfallthru;
1140 result |= BEfallthru;
1142 if (result & BEcontinue)
1143 result |= BEfallthru;
1144 result &= ~(BEbreak | BEcontinue);
1146 else
1147 result = BEfallthru;
1148 if (result & BEfallthru && condition->canThrow())
1149 result |= BEthrow;
1150 return result;
1153 int DoStatement::fallOffEnd()
1155 if (body)
1156 body->fallOffEnd();
1157 return TRUE;
1160 int DoStatement::comeFrom()
1162 if (body)
1163 return body->comeFrom();
1164 return FALSE;
1167 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1169 buf->writestring("do");
1170 buf->writenl();
1171 if (body)
1172 body->toCBuffer(buf, hgs);
1173 buf->writestring("while (");
1174 condition->toCBuffer(buf, hgs);
1175 buf->writebyte(')');
1178 /******************************** ForStatement ***************************/
1180 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
1181 : Statement(loc)
1183 this->init = init;
1184 this->condition = condition;
1185 this->increment = increment;
1186 this->body = body;
1189 Statement *ForStatement::syntaxCopy()
1191 Statement *i = NULL;
1192 if (init)
1193 i = init->syntaxCopy();
1194 Expression *c = NULL;
1195 if (condition)
1196 c = condition->syntaxCopy();
1197 Expression *inc = NULL;
1198 if (increment)
1199 inc = increment->syntaxCopy();
1200 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
1201 return s;
1204 Statement *ForStatement::semantic(Scope *sc)
1206 ScopeDsymbol *sym = new ScopeDsymbol();
1207 sym->parent = sc->scopesym;
1208 sc = sc->push(sym);
1209 if (init)
1210 init = init->semantic(sc);
1211 sc->noctor++;
1212 if (condition)
1214 condition = condition->semantic(sc);
1215 condition = resolveProperties(sc, condition);
1216 condition = condition->optimize(WANTvalue);
1217 condition = condition->checkToBoolean();
1219 if (increment)
1220 increment = increment->semantic(sc);
1222 sc->sbreak = this;
1223 sc->scontinue = this;
1224 body = body->semantic(sc);
1225 sc->noctor--;
1227 sc->pop();
1228 return this;
1231 void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
1233 //printf("ForStatement::scopeCode()\n");
1234 //print();
1235 if (init)
1236 init->scopeCode(sc, sentry, sexception, sfinally);
1237 else
1238 Statement::scopeCode(sc, sentry, sexception, sfinally);
1241 int ForStatement::hasBreak()
1243 //printf("ForStatement::hasBreak()\n");
1244 return TRUE;
1247 int ForStatement::hasContinue()
1249 return TRUE;
1252 int ForStatement::usesEH()
1254 return (init && init->usesEH()) || body->usesEH();
1257 int ForStatement::blockExit()
1258 { int result = BEfallthru;
1260 if (init)
1261 { result = init->blockExit();
1262 if (!(result & BEfallthru))
1263 return result;
1265 if (condition)
1266 { if (condition->canThrow())
1267 result |= BEthrow;
1269 else
1270 result &= ~BEfallthru; // the body must do the exiting
1271 if (body)
1272 { int r = body->blockExit();
1273 if (r & BEbreak)
1274 result |= BEfallthru;
1275 result |= r & ~(BEbreak | BEcontinue);
1277 if (increment && increment->canThrow())
1278 result |= BEthrow;
1279 return result;
1282 int ForStatement::fallOffEnd()
1284 if (body)
1285 body->fallOffEnd();
1286 return TRUE;
1289 int ForStatement::comeFrom()
1291 //printf("ForStatement::comeFrom()\n");
1292 if (body)
1293 { int result = body->comeFrom();
1294 //printf("result = %d\n", result);
1295 return result;
1297 return FALSE;
1300 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1302 buf->writestring("for (");
1303 if (init)
1305 hgs->FLinit.init++;
1306 hgs->FLinit.decl = 0;
1307 init->toCBuffer(buf, hgs);
1308 if (hgs->FLinit.decl > 0)
1309 buf->writebyte(';');
1310 hgs->FLinit.decl = 0;
1311 hgs->FLinit.init--;
1313 else
1314 buf->writebyte(';');
1315 if (condition)
1316 { buf->writebyte(' ');
1317 condition->toCBuffer(buf, hgs);
1319 buf->writebyte(';');
1320 if (increment)
1321 { buf->writebyte(' ');
1322 increment->toCBuffer(buf, hgs);
1324 buf->writebyte(')');
1325 buf->writenl();
1326 buf->writebyte('{');
1327 buf->writenl();
1328 body->toCBuffer(buf, hgs);
1329 buf->writebyte('}');
1330 buf->writenl();
1333 /******************************** ForeachStatement ***************************/
1335 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
1336 Expression *aggr, Statement *body)
1337 : Statement(loc)
1339 this->op = op;
1340 this->arguments = arguments;
1341 this->aggr = aggr;
1342 this->body = body;
1344 this->key = NULL;
1345 this->value = NULL;
1347 this->func = NULL;
1350 Statement *ForeachStatement::syntaxCopy()
1352 Arguments *args = Argument::arraySyntaxCopy(arguments);
1353 Expression *exp = aggr->syntaxCopy();
1354 ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
1355 body ? body->syntaxCopy() : NULL);
1356 return s;
1359 Statement *ForeachStatement::semantic(Scope *sc)
1361 //printf("ForeachStatement::semantic() %p\n", this);
1362 ScopeDsymbol *sym;
1363 Statement *s = this;
1364 int dim = arguments->dim;
1365 int i;
1366 TypeAArray *taa = NULL;
1368 Type *tn = NULL;
1369 Type *tnv = NULL;
1371 func = sc->func;
1372 if (func->fes)
1373 func = func->fes->func;
1375 aggr = aggr->semantic(sc);
1376 aggr = resolveProperties(sc, aggr);
1377 aggr = aggr->optimize(WANTvalue);
1378 if (!aggr->type)
1380 error("invalid foreach aggregate %s", aggr->toChars());
1381 return this;
1384 inferApplyArgTypes(op, arguments, aggr);
1386 /* Check for inference errors
1388 if (dim != arguments->dim)
1390 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1391 error("cannot uniquely infer foreach argument types");
1392 return this;
1395 Type *tab = aggr->type->toBasetype();
1397 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
1399 if (dim < 1 || dim > 2)
1401 error("only one (value) or two (key,value) arguments for tuple foreach");
1402 return s;
1405 TypeTuple *tuple = (TypeTuple *)tab;
1406 Statements *statements = new Statements();
1407 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1408 size_t n;
1409 TupleExp *te = NULL;
1410 if (aggr->op == TOKtuple) // expression tuple
1411 { te = (TupleExp *)aggr;
1412 n = te->exps->dim;
1414 else if (aggr->op == TOKtype) // type tuple
1416 n = Argument::dim(tuple->arguments);
1418 else
1419 assert(0);
1420 for (size_t j = 0; j < n; j++)
1421 { size_t k = (op == TOKforeach) ? j : n - 1 - j;
1422 Expression *e;
1423 Type *t;
1424 if (te)
1425 e = (Expression *)te->exps->data[k];
1426 else
1427 t = Argument::getNth(tuple->arguments, k)->type;
1428 Argument *arg = (Argument *)arguments->data[0];
1429 Statements *st = new Statements();
1431 if (dim == 2)
1432 { // Declare key
1433 if (arg->storageClass & (STCout | STCref | STClazy))
1434 error("no storage class for key %s", arg->ident->toChars());
1435 TY keyty = arg->type->ty;
1436 if ((keyty != Tint32 && keyty != Tuns32) &&
1437 (! global.params.isX86_64 ||
1438 (keyty != Tint64 && keyty != Tuns64))
1441 error("foreach: key type must be int or uint, not %s", arg->type->toChars());
1443 Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
1444 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
1445 var->storage_class |= STCmanifest;
1446 DeclarationExp *de = new DeclarationExp(loc, var);
1447 st->push(new ExpStatement(loc, de));
1448 arg = (Argument *)arguments->data[1]; // value
1450 // Declare value
1451 if (arg->storageClass & (STCout | STCref | STClazy))
1452 error("no storage class for value %s", arg->ident->toChars());
1453 Dsymbol *var;
1454 if (te)
1455 { Type *tb = e->type->toBasetype();
1456 if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
1457 { VarExp *ve = (VarExp *)e;
1458 var = new AliasDeclaration(loc, arg->ident, ve->var);
1460 else
1462 arg->type = e->type;
1463 Initializer *ie = new ExpInitializer(0, e);
1464 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
1465 if (e->isConst())
1466 v->storage_class |= STCconst;
1467 var = v;
1470 else
1472 var = new AliasDeclaration(loc, arg->ident, t);
1474 DeclarationExp *de = new DeclarationExp(loc, var);
1475 st->push(new ExpStatement(loc, de));
1477 st->push(body->syntaxCopy());
1478 s = new CompoundStatement(loc, st);
1479 s = new ScopeStatement(loc, s);
1480 statements->push(s);
1483 s = new UnrolledLoopStatement(loc, statements);
1484 s = s->semantic(sc);
1485 return s;
1488 for (i = 0; i < dim; i++)
1489 { Argument *arg = (Argument *)arguments->data[i];
1490 if (!arg->type)
1492 error("cannot infer type for %s", arg->ident->toChars());
1493 return this;
1497 sym = new ScopeDsymbol();
1498 sym->parent = sc->scopesym;
1499 sc = sc->push(sym);
1501 sc->noctor++;
1503 switch (tab->ty)
1505 case Tarray:
1506 case Tsarray:
1507 if (dim < 1 || dim > 2)
1509 error("only one or two arguments for array foreach");
1510 break;
1513 /* Look for special case of parsing char types out of char type
1514 * array.
1516 tn = tab->nextOf()->toBasetype();
1517 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
1518 { Argument *arg;
1520 i = (dim == 1) ? 0 : 1; // index of value
1521 arg = (Argument *)arguments->data[i];
1522 arg->type = arg->type->semantic(loc, sc);
1523 tnv = arg->type->toBasetype();
1524 if (tnv->ty != tn->ty &&
1525 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
1527 if (arg->storageClass & STCref)
1528 error("foreach: value of UTF conversion cannot be ref");
1529 if (dim == 2)
1530 { arg = (Argument *)arguments->data[0];
1531 if (arg->storageClass & STCref)
1532 error("foreach: key cannot be ref");
1534 goto Lapply;
1538 for (i = 0; i < dim; i++)
1539 { // Declare args
1540 Argument *arg = (Argument *)arguments->data[i];
1541 VarDeclaration *var;
1543 var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1544 var->storage_class |= STCforeach;
1545 var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant);
1546 if (dim == 2 && i == 0)
1547 { key = var;
1548 //var->storage_class |= STCfinal;
1550 else
1551 { //if (!(arg->storageClass & STCref))
1552 //var->storage_class |= STCfinal;
1553 value = var;
1555 #if 1
1556 DeclarationExp *de = new DeclarationExp(loc, var);
1557 de->semantic(sc);
1558 #else
1559 var->semantic(sc);
1560 if (!sc->insert(var))
1561 error("%s already defined", var->ident->toChars());
1562 #endif
1565 sc->sbreak = this;
1566 sc->scontinue = this;
1567 body = body->semantic(sc);
1569 if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst)
1571 if (aggr->op == TOKstring)
1572 aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
1573 else
1574 error("foreach: %s is not an array of %s",
1575 tab->toChars(), value->type->toChars());
1578 if (key &&
1579 ((key->type->ty != Tint32 && key->type->ty != Tuns32) &&
1580 (! global.params.isX86_64 ||
1581 (key->type->ty != Tint64 && key->type->ty != Tuns64))
1585 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1588 if (key && key->storage_class & (STCout | STCref))
1589 error("foreach: key cannot be out or ref");
1590 break;
1592 case Taarray:
1593 taa = (TypeAArray *)tab;
1594 if (dim < 1 || dim > 2)
1596 error("only one or two arguments for associative array foreach");
1597 break;
1599 if (op == TOKforeach_reverse)
1601 error("no reverse iteration on associative arrays");
1603 goto Lapply;
1605 case Tclass:
1606 case Tstruct:
1607 case Tdelegate:
1608 Lapply:
1609 { FuncDeclaration *fdapply;
1610 Arguments *args;
1611 Expression *ec;
1612 Expression *e;
1613 FuncLiteralDeclaration *fld;
1614 Argument *a;
1615 Type *t;
1616 Expression *flde;
1617 Identifier *id;
1618 Type *tret;
1620 tret = func->type->nextOf();
1622 // Need a variable to hold value from any return statements in body.
1623 if (!sc->func->vresult && tret && tret != Type::tvoid)
1624 { VarDeclaration *v;
1626 v = new VarDeclaration(loc, tret, Id::result, NULL);
1627 v->noauto = 1;
1628 v->semantic(sc);
1629 if (!sc->insert(v))
1630 assert(0);
1631 v->parent = sc->func;
1632 sc->func->vresult = v;
1635 /* Turn body into the function literal:
1636 * int delegate(ref T arg) { body }
1638 args = new Arguments();
1639 for (i = 0; i < dim; i++)
1640 { Argument *arg = (Argument *)arguments->data[i];
1642 arg->type = arg->type->semantic(loc, sc);
1643 if (arg->storageClass & STCref)
1644 id = arg->ident;
1645 else
1646 { // Make a copy of the ref argument so it isn't
1647 // a reference.
1648 VarDeclaration *v;
1649 Initializer *ie;
1651 id = Lexer::uniqueId("__applyArg", i);
1653 ie = new ExpInitializer(0, new IdentifierExp(0, id));
1654 v = new VarDeclaration(0, arg->type, arg->ident, ie);
1655 s = new DeclarationStatement(0, v);
1656 body = new CompoundStatement(loc, s, body);
1658 a = new Argument(STCref, arg->type, id, NULL);
1659 args->push(a);
1661 t = new TypeFunction(args, Type::tint32, 0, LINKd);
1662 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
1663 fld->fbody = body;
1664 flde = new FuncExp(loc, fld);
1665 flde = flde->semantic(sc);
1666 fld->tookAddressOf = 0;
1668 // Resolve any forward referenced goto's
1669 for (int i = 0; i < gotos.dim; i++)
1670 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
1671 GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
1673 if (!gs->label->statement)
1674 { // 'Promote' it to this scope, and replace with a return
1675 cases.push(gs);
1676 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
1677 cs->statements->data[0] = (void *)s;
1681 if (tab->ty == Taarray)
1683 // Check types
1684 Argument *arg = (Argument *)arguments->data[0];
1685 if (dim == 2)
1687 if (arg->storageClass & STCref)
1688 error("foreach: index cannot be ref");
1689 if (!arg->type->equals(taa->index))
1690 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
1691 arg = (Argument *)arguments->data[1];
1693 if (!arg->type->equals(taa->nextOf()))
1694 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
1696 /* Call:
1697 * _aaApply(aggr, keysize, flde)
1699 if (dim == 2)
1700 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply2",
1701 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic
1702 else
1703 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply",
1704 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic);
1705 ec = new VarExp(0, fdapply);
1706 Expressions *exps = new Expressions();
1707 exps->push(aggr);
1708 size_t keysize = taa->index->size();
1709 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
1710 exps->push(new IntegerExp(0, keysize, Type::tsize_t));
1711 exps->push(flde);
1712 e = new CallExp(loc, ec, exps);
1713 e->type = Type::tint32; // don't run semantic() on e
1715 else if (tab->ty == Tarray || tab->ty == Tsarray)
1717 /* Call:
1718 * _aApply(aggr, flde)
1720 static char fntab[9][3] =
1721 { "cc","cw","cd",
1722 "wc","cc","wd",
1723 "dc","dw","dd"
1725 char fdname[7+1+2+ sizeof(dim)*3 + 1];
1726 int flag;
1728 switch (tn->ty)
1730 case Tchar: flag = 0; break;
1731 case Twchar: flag = 3; break;
1732 case Tdchar: flag = 6; break;
1733 default: assert(0);
1735 switch (tnv->ty)
1737 case Tchar: flag += 0; break;
1738 case Twchar: flag += 1; break;
1739 case Tdchar: flag += 2; break;
1740 default: assert(0);
1742 const char *r = (op == TOKforeach_reverse) ? "R" : "";
1743 int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
1744 assert(j < sizeof(fdname));
1745 fdapply = FuncDeclaration::genCfunc(Type::tint32, fdname,
1746 Type::tvoid->arrayOf(), flde->type); // flde->type is not generic
1748 ec = new VarExp(0, fdapply);
1749 Expressions *exps = new Expressions();
1750 if (tab->ty == Tsarray)
1751 aggr = aggr->castTo(sc, tn->arrayOf());
1752 exps->push(aggr);
1753 exps->push(flde);
1754 e = new CallExp(loc, ec, exps);
1755 e->type = Type::tint32; // don't run semantic() on e
1757 else if (tab->ty == Tdelegate)
1759 /* Call:
1760 * aggr(flde)
1762 Expressions *exps = new Expressions();
1763 exps->push(flde);
1764 e = new CallExp(loc, aggr, exps);
1765 e = e->semantic(sc);
1766 if (e->type != Type::tint32)
1767 error("opApply() function for %s must return an int", tab->toChars());
1769 else
1771 /* Call:
1772 * aggr.apply(flde)
1774 ec = new DotIdExp(loc, aggr,
1775 (op == TOKforeach_reverse) ? Id::applyReverse
1776 : Id::apply);
1777 Expressions *exps = new Expressions();
1778 exps->push(flde);
1779 e = new CallExp(loc, ec, exps);
1780 e = e->semantic(sc);
1781 if (e->type != Type::tint32)
1782 error("opApply() function for %s must return an int", tab->toChars());
1785 if (!cases.dim)
1786 // Easy case, a clean exit from the loop
1787 s = new ExpStatement(loc, e);
1788 else
1789 { // Construct a switch statement around the return value
1790 // of the apply function.
1791 Statements *a = new Statements();
1793 // default: break; takes care of cases 0 and 1
1794 s = new BreakStatement(0, NULL);
1795 s = new DefaultStatement(0, s);
1796 a->push(s);
1798 // cases 2...
1799 for (int i = 0; i < cases.dim; i++)
1801 s = (Statement *)cases.data[i];
1802 s = new CaseStatement(0, new IntegerExp(i + 2), s);
1803 a->push(s);
1806 s = new CompoundStatement(loc, a);
1807 s = new SwitchStatement(loc, e, s);
1808 s = s->semantic(sc);
1810 break;
1813 default:
1814 error("foreach: %s is not an aggregate type", aggr->type->toChars());
1815 break;
1817 sc->noctor--;
1818 sc->pop();
1819 return s;
1822 int ForeachStatement::hasBreak()
1824 return TRUE;
1827 int ForeachStatement::hasContinue()
1829 return TRUE;
1832 int ForeachStatement::usesEH()
1834 return body->usesEH();
1837 int ForeachStatement::blockExit()
1838 { int result = BEfallthru;
1840 if (aggr->canThrow())
1841 result |= BEthrow;
1843 if (body)
1845 result |= body->blockExit() & ~(BEbreak | BEcontinue);
1847 return result;
1850 int ForeachStatement::fallOffEnd()
1852 if (body)
1853 body->fallOffEnd();
1854 return TRUE;
1857 int ForeachStatement::comeFrom()
1859 if (body)
1860 return body->comeFrom();
1861 return FALSE;
1864 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1866 buf->writestring(Token::toChars(op));
1867 buf->writestring(" (");
1868 for (int i = 0; i < arguments->dim; i++)
1870 Argument *a = (Argument *)arguments->data[i];
1871 if (i)
1872 buf->writestring(", ");
1873 if (a->storageClass & STCref)
1874 buf->writestring((global.params.Dversion == 1)
1875 ? (char*)"inout " : (char*)"ref ");
1876 if (a->type)
1877 a->type->toCBuffer(buf, a->ident, hgs);
1878 else
1879 buf->writestring(a->ident->toChars());
1881 buf->writestring("; ");
1882 aggr->toCBuffer(buf, hgs);
1883 buf->writebyte(')');
1884 buf->writenl();
1885 buf->writebyte('{');
1886 buf->writenl();
1887 if (body)
1888 body->toCBuffer(buf, hgs);
1889 buf->writebyte('}');
1890 buf->writenl();
1893 /**************************** ForeachRangeStatement ***************************/
1895 ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg,
1896 Expression *lwr, Expression *upr, Statement *body)
1897 : Statement(loc)
1899 this->op = op;
1900 this->arg = arg;
1901 this->lwr = lwr;
1902 this->upr = upr;
1903 this->body = body;
1905 this->key = NULL;
1908 Statement *ForeachRangeStatement::syntaxCopy()
1910 ForeachRangeStatement *s = new ForeachRangeStatement(loc, op,
1911 arg->syntaxCopy(),
1912 lwr->syntaxCopy(),
1913 upr->syntaxCopy(),
1914 body ? body->syntaxCopy() : NULL);
1915 return s;
1918 Statement *ForeachRangeStatement::semantic(Scope *sc)
1920 //printf("ForeachRangeStatement::semantic() %p\n", this);
1921 ScopeDsymbol *sym;
1922 Statement *s = this;
1924 lwr = lwr->semantic(sc);
1925 lwr = resolveProperties(sc, lwr);
1926 lwr = lwr->optimize(WANTvalue);
1927 if (!lwr->type)
1929 error("invalid range lower bound %s", lwr->toChars());
1930 return this;
1933 upr = upr->semantic(sc);
1934 upr = resolveProperties(sc, upr);
1935 upr = upr->optimize(WANTvalue);
1936 if (!upr->type)
1938 error("invalid range upper bound %s", upr->toChars());
1939 return this;
1942 if (arg->type)
1944 lwr = lwr->implicitCastTo(sc, arg->type);
1945 upr = upr->implicitCastTo(sc, arg->type);
1947 else
1949 /* Must infer types from lwr and upr
1951 AddExp ea(loc, lwr, upr);
1952 ea.typeCombine(sc);
1953 arg->type = ea.type;
1954 lwr = ea.e1;
1955 upr = ea.e2;
1957 if (!arg->type->isscalar())
1958 error("%s is not a scalar type", arg->type->toChars());
1960 sym = new ScopeDsymbol();
1961 sym->parent = sc->scopesym;
1962 sc = sc->push(sym);
1964 sc->noctor++;
1966 key = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1967 DeclarationExp *de = new DeclarationExp(loc, key);
1968 de->semantic(sc);
1970 if (key->storage_class)
1971 error("foreach range: key cannot have storage class");
1973 sc->sbreak = this;
1974 sc->scontinue = this;
1975 body = body->semantic(sc);
1977 sc->noctor--;
1978 sc->pop();
1979 return s;
1982 int ForeachRangeStatement::hasBreak()
1984 return TRUE;
1987 int ForeachRangeStatement::hasContinue()
1989 return TRUE;
1992 int ForeachRangeStatement::usesEH()
1994 return body->usesEH();
1997 int ForeachRangeStatement::blockExit()
1998 { int result = BEfallthru;
2000 if (lwr && lwr->canThrow())
2001 result |= BEthrow;
2002 else if (upr && upr->canThrow())
2003 result |= BEthrow;
2005 if (body)
2007 result |= body->blockExit() & ~(BEbreak | BEcontinue);
2009 return result;
2012 int ForeachRangeStatement::fallOffEnd()
2014 if (body)
2015 body->fallOffEnd();
2016 return TRUE;
2019 int ForeachRangeStatement::comeFrom()
2021 if (body)
2022 return body->comeFrom();
2023 return FALSE;
2026 void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2028 buf->writestring(Token::toChars(op));
2029 buf->writestring(" (");
2031 if (arg->type)
2032 arg->type->toCBuffer(buf, arg->ident, hgs);
2033 else
2034 buf->writestring(arg->ident->toChars());
2036 buf->writestring("; ");
2037 lwr->toCBuffer(buf, hgs);
2038 buf->writestring(" .. ");
2039 upr->toCBuffer(buf, hgs);
2040 buf->writebyte(')');
2041 buf->writenl();
2042 buf->writebyte('{');
2043 buf->writenl();
2044 if (body)
2045 body->toCBuffer(buf, hgs);
2046 buf->writebyte('}');
2047 buf->writenl();
2050 /******************************** IfStatement ***************************/
2052 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
2053 : Statement(loc)
2055 this->arg = arg;
2056 this->condition = condition;
2057 this->ifbody = ifbody;
2058 this->elsebody = elsebody;
2059 this->match = NULL;
2062 Statement *IfStatement::syntaxCopy()
2064 Statement *i = NULL;
2065 if (ifbody)
2066 i = ifbody->syntaxCopy();
2068 Statement *e = NULL;
2069 if (elsebody)
2070 e = elsebody->syntaxCopy();
2072 Argument *a = arg ? arg->syntaxCopy() : NULL;
2073 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
2074 return s;
2077 Statement *IfStatement::semantic(Scope *sc)
2079 condition = condition->semantic(sc);
2080 condition = resolveProperties(sc, condition);
2081 condition = condition->checkToBoolean();
2083 // If we can short-circuit evaluate the if statement, don't do the
2084 // semantic analysis of the skipped code.
2085 // This feature allows a limited form of conditional compilation.
2086 condition = condition->optimize(WANTflags);
2088 // Evaluate at runtime
2089 unsigned cs0 = sc->callSuper;
2090 unsigned cs1;
2092 Scope *scd;
2093 if (arg)
2094 { /* Declare arg, which we will set to be the
2095 * result of condition.
2097 ScopeDsymbol *sym = new ScopeDsymbol();
2098 sym->parent = sc->scopesym;
2099 scd = sc->push(sym);
2101 Type *t = arg->type ? arg->type : condition->type;
2102 match = new VarDeclaration(loc, t->maybe(true), arg->ident, NULL);
2103 match->noauto = 1;
2104 match->semantic(scd);
2105 if (!scd->insert(match))
2106 assert(0);
2107 match->parent = sc->func;
2109 /* Generate:
2110 * (arg = condition)
2112 VarExp *v = new VarExp(0, match);
2113 condition = new AssignExp(loc, v, condition);
2114 condition = condition->semantic(scd);
2116 if (match && match->type->ty == Tmaybe)
2118 // Matched object cannot be null in the then block
2119 // (and isn't in scope in the else)
2120 match->type = match->type->nextOf();
2123 else
2124 scd = sc->push();
2125 ifbody = ifbody->semantic(scd);
2126 scd->pop();
2128 cs1 = sc->callSuper;
2129 sc->callSuper = cs0;
2130 if (elsebody)
2131 elsebody = elsebody->semanticScope(sc, NULL, NULL);
2132 sc->mergeCallSuper(loc, cs1);
2134 return this;
2137 int IfStatement::usesEH()
2139 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2142 int IfStatement::blockExit()
2144 //printf("IfStatement::blockExit(%p)\n", this);
2146 int result = BEnone;
2147 if (condition->canThrow())
2148 result |= BEthrow;
2149 if (ifbody)
2150 result |= ifbody->blockExit();
2151 else
2152 result |= BEfallthru;
2153 if (elsebody)
2154 result |= elsebody->blockExit();
2155 else
2156 result |= BEfallthru;
2157 //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
2158 return result;
2161 int IfStatement::fallOffEnd()
2163 if (!ifbody || ifbody->fallOffEnd() ||
2164 !elsebody || elsebody->fallOffEnd())
2165 return TRUE;
2166 return FALSE;
2170 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2172 buf->writestring("if (");
2173 if (arg)
2175 if (arg->type)
2176 arg->type->toCBuffer(buf, arg->ident, hgs);
2177 else
2178 buf->writestring(arg->ident->toChars());
2179 buf->writebyte(';');
2181 condition->toCBuffer(buf, hgs);
2182 buf->writebyte(')');
2183 buf->writenl();
2184 ifbody->toCBuffer(buf, hgs);
2185 if (elsebody)
2186 { buf->writestring("else");
2187 buf->writenl();
2188 elsebody->toCBuffer(buf, hgs);
2192 /******************************** ConditionalStatement ***************************/
2194 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
2195 : Statement(loc)
2197 this->condition = condition;
2198 this->ifbody = ifbody;
2199 this->elsebody = elsebody;
2202 Statement *ConditionalStatement::syntaxCopy()
2204 Statement *e = NULL;
2205 if (elsebody)
2206 e = elsebody->syntaxCopy();
2207 ConditionalStatement *s = new ConditionalStatement(loc,
2208 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
2209 return s;
2212 Statement *ConditionalStatement::semantic(Scope *sc)
2214 //printf("ConditionalStatement::semantic()\n");
2216 // If we can short-circuit evaluate the if statement, don't do the
2217 // semantic analysis of the skipped code.
2218 // This feature allows a limited form of conditional compilation.
2219 if (condition->include(sc, NULL))
2221 ifbody = ifbody->semantic(sc);
2222 return ifbody;
2224 else
2226 if (elsebody)
2227 elsebody = elsebody->semantic(sc);
2228 return elsebody;
2232 Statements *ConditionalStatement::flatten(Scope *sc)
2234 Statement *s;
2236 if (condition->include(sc, NULL))
2237 s = ifbody;
2238 else
2239 s = elsebody;
2241 Statements *a = new Statements();
2242 a->push(s);
2243 return a;
2246 int ConditionalStatement::usesEH()
2248 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2251 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2253 condition->toCBuffer(buf, hgs);
2254 buf->writenl();
2255 if (ifbody)
2256 ifbody->toCBuffer(buf, hgs);
2257 if (elsebody)
2259 buf->writestring("else");
2260 buf->writenl();
2261 elsebody->toCBuffer(buf, hgs);
2263 buf->writenl();
2267 /******************************** PragmaStatement ***************************/
2269 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
2270 : Statement(loc)
2272 this->ident = ident;
2273 this->args = args;
2274 this->body = body;
2277 Statement *PragmaStatement::syntaxCopy()
2279 Statement *b = NULL;
2280 if (body)
2281 b = body->syntaxCopy();
2282 PragmaStatement *s = new PragmaStatement(loc,
2283 ident, Expression::arraySyntaxCopy(args), b);
2284 return s;
2287 Statement *PragmaStatement::semantic(Scope *sc)
2288 { // Should be merged with PragmaDeclaration
2289 //printf("PragmaStatement::semantic() %s\n", toChars());
2290 //printf("body = %p\n", body);
2291 if (ident == Id::msg)
2293 if (args)
2295 for (size_t i = 0; i < args->dim; i++)
2297 Expression *e = (Expression *)args->data[i];
2299 e = e->semantic(sc);
2300 e = e->optimize(WANTvalue | WANTinterpret);
2301 if (e->op == TOKstring)
2303 StringExp *se = (StringExp *)e;
2304 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
2306 else
2307 error("string expected for message, not '%s'", e->toChars());
2309 fprintf(stdmsg, "\n");
2312 else if (ident == Id::lib)
2314 if (!args || args->dim != 1)
2315 error("string expected for library name");
2316 else
2318 Expression *e = (Expression *)args->data[0];
2320 e = e->semantic(sc);
2321 e = e->optimize(WANTvalue | WANTinterpret);
2322 args->data[0] = (void *)e;
2323 if (e->op != TOKstring)
2324 error("string expected for library name, not '%s'", e->toChars());
2325 else if (global.params.verbose)
2327 StringExp *se = (StringExp *)e;
2328 char *name = (char *)mem.malloc(se->len + 1);
2329 memcpy(name, se->string, se->len);
2330 name[se->len] = 0;
2331 printf("library %s\n", name);
2332 mem.free(name);
2336 else if (ident == Id::startaddress)
2338 if (!args || args->dim != 1)
2339 error("function name expected for start address");
2340 else
2342 Expression *e = (Expression *)args->data[0];
2343 e = e->semantic(sc);
2344 e = e->optimize(WANTvalue | WANTinterpret);
2345 args->data[0] = (void *)e;
2346 Dsymbol *sa = getDsymbol(e);
2347 if (!sa || !sa->isFuncDeclaration())
2348 error("function name expected for start address, not '%s'", e->toChars());
2349 if (body)
2351 body = body->semantic(sc);
2353 return this;
2356 else
2357 error("unrecognized pragma(%s)", ident->toChars());
2359 if (body)
2361 body = body->semantic(sc);
2363 return body;
2366 int PragmaStatement::usesEH()
2368 return body && body->usesEH();
2371 int PragmaStatement::blockExit()
2373 int result = BEfallthru;
2374 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru
2375 if (arrayExpressionCanThrow(args))
2376 result |= BEthrow;
2377 if (body)
2378 result |= body->blockExit();
2379 #endif
2380 return result;
2383 int PragmaStatement::fallOffEnd()
2385 if (body)
2386 return body->fallOffEnd();
2387 return TRUE;
2390 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2392 buf->writestring("pragma (");
2393 buf->writestring(ident->toChars());
2394 if (args && args->dim)
2396 buf->writestring(", ");
2397 argsToCBuffer(buf, args, hgs);
2399 buf->writeByte(')');
2400 if (body)
2402 buf->writenl();
2403 buf->writeByte('{');
2404 buf->writenl();
2406 body->toCBuffer(buf, hgs);
2408 buf->writeByte('}');
2409 buf->writenl();
2411 else
2413 buf->writeByte(';');
2414 buf->writenl();
2419 /******************************** LogStatement ***************************/
2421 LogStatement::LogStatement(Loc loc, int level, Expressions *args)
2422 : Statement(loc)
2424 this->level = level;
2425 this->args = args;
2428 Statement *LogStatement::syntaxCopy()
2430 Expressions *copied_args = Expression::arraySyntaxCopy(args);
2431 LogStatement *s = new LogStatement(loc, level, copied_args);
2432 return s;
2435 Statement *LogStatement::semantic(Scope *sc)
2437 Expression *logger = new GetLoggerExp(loc);
2438 Type *type = NULL;
2440 for (Dsymbol *s = sc->parent; s; s = s->parent)
2442 ClassDeclaration *cd;
2443 StructDeclaration *sd;
2445 cd = s->isClassDeclaration();
2446 if (cd)
2448 type = cd->type;
2449 break;
2453 if (type == NULL) {
2454 // We're a top-level function. Generate log messages from the module
2455 args->shift(new StringExp(loc, strdup(sc->module->ident->string)));
2456 } else {
2457 args->shift(new StringExp(loc, type->toChars()));
2460 args->shift(new IntegerExp(loc, level, Type::tint32));
2461 Expression *callLogger = new CallExp(loc, logger, args);
2463 Statement *s = new ExpStatement(loc, callLogger);
2465 return s->semantic(sc);
2468 void LogStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2470 char *l;
2471 switch (level) {
2472 case 0: l = "log_debug"; break;
2473 case 1: l = "log_info"; break;
2474 case 2: l = "log_warning"; break;
2475 case 3: l = "log_error"; break;
2476 default:
2477 error("Unknown log level %d", level);
2478 l = "log_UNKNOWN";
2480 buf->writestring(l);
2481 buf->writeByte('(');
2482 argsToCBuffer(buf, args, hgs);
2483 buf->writeByte(')');
2484 buf->writenl();
2487 /******************************** StaticAssertStatement ***************************/
2489 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2490 : Statement(sa->loc)
2492 this->sa = sa;
2495 Statement *StaticAssertStatement::syntaxCopy()
2497 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2498 return s;
2501 Statement *StaticAssertStatement::semantic(Scope *sc)
2503 sa->semantic2(sc);
2504 return NULL;
2507 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2509 sa->toCBuffer(buf, hgs);
2513 /******************************** SwitchStatement ***************************/
2515 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2516 : Statement(loc)
2518 condition = c;
2519 body = b;
2520 sdefault = NULL;
2521 tf = NULL;
2522 cases = NULL;
2523 hasNoDefault = 0;
2524 hasVars = 0;
2527 Statement *SwitchStatement::syntaxCopy()
2529 SwitchStatement *s = new SwitchStatement(loc,
2530 condition->syntaxCopy(), body->syntaxCopy());
2531 return s;
2534 Statement *SwitchStatement::semantic(Scope *sc)
2536 //printf("SwitchStatement::semantic(%p)\n", this);
2537 tf = sc->tf;
2538 assert(!cases); // ensure semantic() is only run once
2539 condition = condition->semantic(sc);
2540 condition = resolveProperties(sc, condition);
2541 if (condition->type->isString())
2543 // If it's not an array, cast it to one
2544 if (condition->type->ty != Tarray)
2546 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2548 condition->type = condition->type->constOf();
2550 else
2551 { condition = condition->integralPromotions(sc);
2552 condition->checkIntegral();
2554 condition = condition->optimize(WANTvalue);
2556 sc = sc->push();
2557 sc->sbreak = this;
2558 sc->sw = this;
2560 cases = new Array();
2561 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2562 body = body->semantic(sc);
2563 sc->noctor--;
2565 // Resolve any goto case's with exp
2566 for (int i = 0; i < gotoCases.dim; i++)
2568 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2570 if (!gcs->exp)
2572 gcs->error("no case statement following goto case;");
2573 break;
2576 for (Scope *scx = sc; scx; scx = scx->enclosing)
2578 if (!scx->sw)
2579 continue;
2580 for (int j = 0; j < scx->sw->cases->dim; j++)
2582 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2584 if (cs->exp->equals(gcs->exp))
2586 gcs->cs = cs;
2587 goto Lfoundcase;
2591 gcs->error("case %s not found", gcs->exp->toChars());
2593 Lfoundcase:
2597 if (!sc->sw->sdefault)
2598 { hasNoDefault = 1;
2600 if (global.params.warnings)
2601 { fprintf(stdmsg, "warning - ");
2602 error("switch statement has no default");
2605 // Generate runtime error if the default is hit
2606 Statements *a = new Statements();
2607 CompoundStatement *cs;
2608 Statement *s;
2610 if (global.params.useSwitchError)
2611 s = new SwitchErrorStatement(loc);
2612 else
2613 { Expression *e = new HaltExp(loc);
2614 s = new ExpStatement(loc, e);
2617 a->reserve(4);
2618 a->push(body);
2619 a->push(new BreakStatement(loc, NULL));
2620 sc->sw->sdefault = new DefaultStatement(loc, s);
2621 a->push(sc->sw->sdefault);
2622 cs = new CompoundStatement(loc, a);
2623 body = cs;
2626 sc->pop();
2627 return this;
2630 int SwitchStatement::hasBreak()
2632 return TRUE;
2635 int SwitchStatement::usesEH()
2637 return body ? body->usesEH() : 0;
2640 int SwitchStatement::blockExit()
2641 { int result = BEnone;
2642 if (condition->canThrow())
2643 result |= BEthrow;
2645 if (body)
2646 { result |= body->blockExit();
2647 if (result & BEbreak)
2648 { result |= BEfallthru;
2649 result &= ~BEbreak;
2652 else
2653 result |= BEfallthru;
2655 return result;
2658 int SwitchStatement::fallOffEnd()
2660 if (body)
2661 body->fallOffEnd();
2662 return TRUE; // need to do this better
2665 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2667 buf->writestring("switch (");
2668 condition->toCBuffer(buf, hgs);
2669 buf->writebyte(')');
2670 buf->writenl();
2671 if (body)
2673 if (!body->isScopeStatement())
2674 { buf->writebyte('{');
2675 buf->writenl();
2676 body->toCBuffer(buf, hgs);
2677 buf->writebyte('}');
2678 buf->writenl();
2680 else
2682 body->toCBuffer(buf, hgs);
2687 /******************************** CaseStatement ***************************/
2689 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2690 : Statement(loc)
2692 this->exp = exp;
2693 this->statement = s;
2694 index = 0;
2695 cblock = NULL;
2698 Statement *CaseStatement::syntaxCopy()
2700 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2701 return s;
2704 Statement *CaseStatement::semantic(Scope *sc)
2705 { SwitchStatement *sw = sc->sw;
2707 //printf("CaseStatement::semantic() %s\n", toChars());
2708 exp = exp->semantic(sc);
2709 if (sw)
2711 exp = exp->implicitCastTo(sc, sw->condition->type);
2712 exp = exp->optimize(WANTvalue | WANTinterpret);
2714 /* This is where variables are allowed as case expressions.
2716 if (exp->op == TOKvar)
2717 { VarExp *ve = (VarExp *)exp;
2718 VarDeclaration *v = ve->var->isVarDeclaration();
2719 Type *t = exp->type->toBasetype();
2720 if (v && (t->isintegral() || t->ty == Tclass))
2721 { /* Flag that we need to do special code generation
2722 * for this, i.e. generate a sequence of if-then-else
2724 sw->hasVars = 1;
2725 goto L1;
2729 if (exp->op != TOKstring && exp->op != TOKint64)
2731 error("case must be a string or an integral constant, not %s", exp->toChars());
2732 exp = new IntegerExp(0);
2736 for (int i = 0; i < sw->cases->dim; i++)
2738 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2740 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2741 if (cs->exp->equals(exp))
2742 { error("duplicate case %s in switch statement", exp->toChars());
2743 break;
2747 sw->cases->push(this);
2749 // Resolve any goto case's with no exp to this case statement
2750 for (int i = 0; i < sw->gotoCases.dim; i++)
2752 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2754 if (!gcs->exp)
2756 gcs->cs = this;
2757 sw->gotoCases.remove(i); // remove from array
2761 if (sc->sw->tf != sc->tf)
2762 error("switch and case are in different finally blocks");
2764 else
2765 error("case not in switch statement");
2766 statement = statement->semantic(sc);
2767 return this;
2770 int CaseStatement::compare(Object *obj)
2772 // Sort cases so we can do an efficient lookup
2773 CaseStatement *cs2 = (CaseStatement *)(obj);
2775 return exp->compare(cs2->exp);
2778 int CaseStatement::usesEH()
2780 return statement->usesEH();
2783 int CaseStatement::blockExit()
2785 // Assume the worst
2786 return BEany;
2789 int CaseStatement::fallOffEnd()
2791 return statement->fallOffEnd();
2794 int CaseStatement::comeFrom()
2796 return TRUE;
2799 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2801 buf->writestring("case ");
2802 exp->toCBuffer(buf, hgs);
2803 buf->writebyte(':');
2804 buf->writenl();
2805 statement->toCBuffer(buf, hgs);
2808 /******************************** DefaultStatement ***************************/
2810 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2811 : Statement(loc)
2813 this->statement = s;
2814 #if IN_GCC
2815 cblock = NULL;
2816 #endif
2819 Statement *DefaultStatement::syntaxCopy()
2821 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2822 return s;
2825 Statement *DefaultStatement::semantic(Scope *sc)
2827 //printf("DefaultStatement::semantic()\n");
2828 if (sc->sw)
2830 if (sc->sw->sdefault)
2832 error("switch statement already has a default");
2834 sc->sw->sdefault = this;
2836 if (sc->sw->tf != sc->tf)
2837 error("switch and default are in different finally blocks");
2839 else
2840 error("default not in switch statement");
2841 statement = statement->semantic(sc);
2842 return this;
2845 int DefaultStatement::usesEH()
2847 return statement->usesEH();
2850 int DefaultStatement::blockExit()
2852 // Assume the worst
2853 return BEany;
2856 int DefaultStatement::fallOffEnd()
2858 return statement->fallOffEnd();
2861 int DefaultStatement::comeFrom()
2863 return TRUE;
2866 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2868 buf->writestring("default:\n");
2869 statement->toCBuffer(buf, hgs);
2872 /******************************** GotoDefaultStatement ***************************/
2874 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2875 : Statement(loc)
2877 sw = NULL;
2880 Statement *GotoDefaultStatement::syntaxCopy()
2882 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2883 return s;
2886 Statement *GotoDefaultStatement::semantic(Scope *sc)
2888 sw = sc->sw;
2889 if (!sw)
2890 error("goto default not in switch statement");
2891 return this;
2894 int GotoDefaultStatement::blockExit()
2896 return BEgoto;
2899 int GotoDefaultStatement::fallOffEnd()
2901 return FALSE;
2904 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2906 buf->writestring("goto default;\n");
2909 /******************************** GotoCaseStatement ***************************/
2911 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2912 : Statement(loc)
2914 cs = NULL;
2915 this->exp = exp;
2918 Statement *GotoCaseStatement::syntaxCopy()
2920 Expression *e = exp ? exp->syntaxCopy() : NULL;
2921 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2922 return s;
2925 Statement *GotoCaseStatement::semantic(Scope *sc)
2927 if (exp)
2928 exp = exp->semantic(sc);
2930 if (!sc->sw)
2931 error("goto case not in switch statement");
2932 else
2934 sc->sw->gotoCases.push(this);
2935 if (exp)
2937 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2938 exp = exp->optimize(WANTvalue);
2941 return this;
2944 int GotoCaseStatement::blockExit()
2946 return BEgoto;
2949 int GotoCaseStatement::fallOffEnd()
2951 return FALSE;
2954 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2956 buf->writestring("goto case");
2957 if (exp)
2958 { buf->writebyte(' ');
2959 exp->toCBuffer(buf, hgs);
2961 buf->writebyte(';');
2962 buf->writenl();
2965 /******************************** SwitchErrorStatement ***************************/
2967 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2968 : Statement(loc)
2972 int SwitchErrorStatement::blockExit()
2974 return BEthrow;
2977 int SwitchErrorStatement::fallOffEnd()
2979 return FALSE;
2982 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2984 buf->writestring("SwitchErrorStatement::toCBuffer()");
2985 buf->writenl();
2988 /******************************** ReturnStatement ***************************/
2990 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2991 : Statement(loc)
2993 this->exp = exp;
2996 Statement *ReturnStatement::syntaxCopy()
2998 Expression *e = NULL;
2999 if (exp)
3000 e = exp->syntaxCopy();
3001 ReturnStatement *s = new ReturnStatement(loc, e);
3002 return s;
3005 Statement *ReturnStatement::semantic(Scope *sc)
3007 //printf("ReturnStatement::semantic() %s\n", toChars());
3009 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3010 Scope *scx = sc;
3011 int implicit0 = 0;
3013 if (sc->fes)
3015 // Find scope of function foreach is in
3016 for (; 1; scx = scx->enclosing)
3018 assert(scx);
3019 if (scx->func != fd)
3020 { fd = scx->func; // fd is now function enclosing foreach
3021 break;
3026 Type *tret = fd->type->nextOf();
3027 if (fd->tintro)
3028 tret = fd->tintro->nextOf();
3029 Type *tbret = NULL;
3031 if (tret)
3032 tbret = tret->toBasetype();
3034 // main() returns 0, even if it returns void
3035 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
3036 { implicit0 = 1;
3037 exp = new IntegerExp(0);
3040 if (sc->incontract || scx->incontract)
3041 error("return statements cannot be in contracts");
3042 if (sc->tf || scx->tf)
3043 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
3045 if (fd->isCtorDeclaration())
3047 // Constructors implicitly do:
3048 // return this;
3049 if (exp && exp->op != TOKthis)
3050 error("cannot return expression from constructor");
3051 exp = new ThisExp(0);
3054 if (!exp)
3055 fd->nrvo_can = 0;
3057 if (exp)
3059 fd->hasReturnExp |= 1;
3061 exp = exp->semantic(sc);
3062 exp = resolveProperties(sc, exp);
3063 exp = exp->optimize(WANTvalue);
3065 if (fd->nrvo_can && exp->op == TOKvar)
3066 { VarExp *ve = (VarExp *)exp;
3067 VarDeclaration *v = ve->var->isVarDeclaration();
3069 if (!v || v->isOut() || v->isRef())
3070 fd->nrvo_can = 0;
3071 else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor)
3072 // Struct being returned has destructors
3073 fd->nrvo_can = 0;
3074 else if (fd->nrvo_var == NULL)
3075 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
3076 { //printf("Setting nrvo to %s\n", v->toChars());
3077 fd->nrvo_var = v;
3079 else
3080 fd->nrvo_can = 0;
3082 else if (fd->nrvo_var != v)
3083 fd->nrvo_can = 0;
3085 else
3086 fd->nrvo_can = 0;
3088 if (fd->returnLabel && tbret->ty != Tvoid)
3091 else if (fd->inferRetType)
3093 if (fd->type->nextOf())
3095 if (!exp->type->equals(fd->type->nextOf()))
3096 error("mismatched function return type inference of %s and %s",
3097 exp->type->toChars(), fd->type->nextOf()->toChars());
3099 else
3101 ((TypeFunction *)fd->type)->next = exp->type;
3102 fd->type = fd->type->semantic(loc, sc);
3103 if (!fd->tintro)
3104 { tret = fd->type->nextOf();
3105 tbret = tret->toBasetype();
3109 else if (tbret->ty != Tvoid)
3111 exp = exp->implicitCastTo(sc, tret);
3113 else if (exp->type->ty != Tvoid)
3115 error("attempt to return %s from a function declared to return void", exp->type->toChars());
3118 else if (fd->inferRetType)
3120 if (fd->type->nextOf())
3122 if (fd->type->nextOf()->ty != Tvoid)
3123 error("mismatched function return type inference of void and %s",
3124 fd->type->nextOf()->toChars());
3126 else
3128 ((TypeFunction *)fd->type)->next = Type::tvoid;
3129 fd->type = fd->type->semantic(loc, sc);
3130 if (!fd->tintro)
3131 { tret = Type::tvoid;
3132 tbret = tret;
3136 else if (tbret->ty != Tvoid) // if non-void return
3137 error("return expression expected");
3139 if (sc->fes)
3141 Statement *s;
3143 if (exp && !implicit0)
3145 exp = exp->implicitCastTo(sc, tret);
3147 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
3148 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
3149 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
3150 exp->op == TOKstring)
3152 sc->fes->cases.push(this);
3153 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3155 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
3157 Statement *s1;
3158 Statement *s2;
3160 s = new ReturnStatement(0, NULL);
3161 sc->fes->cases.push(s);
3163 // Construct: { exp; return cases.dim + 1; }
3164 s1 = new ExpStatement(loc, exp);
3165 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3166 s = new CompoundStatement(loc, s1, s2);
3168 else
3170 VarExp *v;
3171 Statement *s1;
3172 Statement *s2;
3174 // Construct: return vresult;
3175 if (!fd->vresult)
3176 { VarDeclaration *v;
3178 v = new VarDeclaration(loc, tret, Id::result, NULL);
3179 v->noauto = 1;
3180 v->semantic(scx);
3181 if (!scx->insert(v))
3182 assert(0);
3183 v->parent = fd;
3184 fd->vresult = v;
3187 v = new VarExp(0, fd->vresult);
3188 s = new ReturnStatement(0, v);
3189 sc->fes->cases.push(s);
3191 // Construct: { vresult = exp; return cases.dim + 1; }
3192 v = new VarExp(0, fd->vresult);
3193 exp = new AssignExp(loc, v, exp);
3194 exp = exp->semantic(sc);
3195 s1 = new ExpStatement(loc, exp);
3196 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3197 s = new CompoundStatement(loc, s1, s2);
3199 return s;
3202 if (exp)
3204 if (fd->returnLabel && tbret->ty != Tvoid)
3206 assert(fd->vresult);
3207 VarExp *v = new VarExp(0, fd->vresult);
3209 exp = new AssignExp(loc, v, exp);
3210 exp = exp->semantic(sc);
3212 //exp->dump(0);
3213 //exp->print();
3214 exp->checkEscape();
3217 /* BUG: need to issue an error on:
3218 * this
3219 * { if (x) return;
3220 * super();
3224 if (sc->callSuper & CSXany_ctor &&
3225 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
3226 error("return without calling constructor");
3228 sc->callSuper |= CSXreturn;
3230 // See if all returns are instead to be replaced with a goto returnLabel;
3231 if (fd->returnLabel)
3233 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
3235 gs->label = fd->returnLabel;
3236 if (exp)
3237 { Statement *s;
3239 s = new ExpStatement(0, exp);
3240 return new CompoundStatement(loc, s, gs);
3242 return gs;
3245 if (exp && tbret->ty == Tvoid && !fd->isMain())
3246 { Statement *s;
3248 s = new ExpStatement(loc, exp);
3249 loc = 0;
3250 exp = NULL;
3251 return new CompoundStatement(loc, s, this);
3254 return this;
3257 int ReturnStatement::blockExit()
3258 { int result = BEreturn;
3260 if (exp && exp->canThrow())
3261 result |= BEthrow;
3262 return result;
3265 int ReturnStatement::fallOffEnd()
3267 return FALSE;
3270 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3272 buf->printf("return ");
3273 if (exp)
3274 exp->toCBuffer(buf, hgs);
3275 buf->writeByte(';');
3276 buf->writenl();
3279 /******************************** BreakStatement ***************************/
3281 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
3282 : Statement(loc)
3284 this->ident = ident;
3287 Statement *BreakStatement::syntaxCopy()
3289 BreakStatement *s = new BreakStatement(loc, ident);
3290 return s;
3293 Statement *BreakStatement::semantic(Scope *sc)
3295 //printf("BreakStatement::semantic()\n");
3296 // If:
3297 // break Identifier;
3298 if (ident)
3300 Scope *scx;
3301 FuncDeclaration *thisfunc = sc->func;
3303 for (scx = sc; scx; scx = scx->enclosing)
3305 LabelStatement *ls;
3307 if (scx->func != thisfunc) // if in enclosing function
3309 if (sc->fes) // if this is the body of a foreach
3311 /* Post this statement to the fes, and replace
3312 * it with a return value that caller will put into
3313 * a switch. Caller will figure out where the break
3314 * label actually is.
3315 * Case numbers start with 2, not 0, as 0 is continue
3316 * and 1 is break.
3318 Statement *s;
3319 sc->fes->cases.push(this);
3320 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3321 return s;
3323 break; // can't break to it
3326 ls = scx->slabel;
3327 if (ls && ls->ident == ident)
3329 Statement *s = ls->statement;
3331 if (!s->hasBreak())
3332 error("label '%s' has no break", ident->toChars());
3333 if (ls->tf != sc->tf)
3334 error("cannot break out of finally block");
3335 return this;
3338 error("enclosing label '%s' for break not found", ident->toChars());
3340 else if (!sc->sbreak)
3342 if (sc->fes)
3343 { Statement *s;
3345 // Replace break; with return 1;
3346 s = new ReturnStatement(0, new IntegerExp(1));
3347 return s;
3349 error("break is not inside a loop or switch");
3351 return this;
3354 int BreakStatement::blockExit()
3356 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
3357 return ident ? BEgoto : BEbreak;
3360 int BreakStatement::fallOffEnd()
3362 return FALSE;
3365 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3367 buf->writestring("break");
3368 if (ident)
3369 { buf->writebyte(' ');
3370 buf->writestring(ident->toChars());
3372 buf->writebyte(';');
3373 buf->writenl();
3376 /******************************** ContinueStatement ***************************/
3378 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
3379 : Statement(loc)
3381 this->ident = ident;
3384 Statement *ContinueStatement::syntaxCopy()
3386 ContinueStatement *s = new ContinueStatement(loc, ident);
3387 return s;
3390 Statement *ContinueStatement::semantic(Scope *sc)
3392 //printf("ContinueStatement::semantic() %p\n", this);
3393 if (ident)
3395 Scope *scx;
3396 FuncDeclaration *thisfunc = sc->func;
3398 for (scx = sc; scx; scx = scx->enclosing)
3400 LabelStatement *ls;
3402 if (scx->func != thisfunc) // if in enclosing function
3404 if (sc->fes) // if this is the body of a foreach
3406 for (; scx; scx = scx->enclosing)
3408 ls = scx->slabel;
3409 if (ls && ls->ident == ident && ls->statement == sc->fes)
3411 // Replace continue ident; with return 0;
3412 return new ReturnStatement(0, new IntegerExp(0));
3416 /* Post this statement to the fes, and replace
3417 * it with a return value that caller will put into
3418 * a switch. Caller will figure out where the break
3419 * label actually is.
3420 * Case numbers start with 2, not 0, as 0 is continue
3421 * and 1 is break.
3423 Statement *s;
3424 sc->fes->cases.push(this);
3425 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3426 return s;
3428 break; // can't continue to it
3431 ls = scx->slabel;
3432 if (ls && ls->ident == ident)
3434 Statement *s = ls->statement;
3436 if (!s->hasContinue())
3437 error("label '%s' has no continue", ident->toChars());
3438 if (ls->tf != sc->tf)
3439 error("cannot continue out of finally block");
3440 return this;
3443 error("enclosing label '%s' for continue not found", ident->toChars());
3445 else if (!sc->scontinue)
3447 if (sc->fes)
3448 { Statement *s;
3450 // Replace continue; with return 0;
3451 s = new ReturnStatement(0, new IntegerExp(0));
3452 return s;
3454 error("continue is not inside a loop");
3456 return this;
3459 int ContinueStatement::blockExit()
3461 return ident ? BEgoto : BEcontinue;
3464 int ContinueStatement::fallOffEnd()
3466 return FALSE;
3469 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3471 buf->writestring("continue");
3472 if (ident)
3473 { buf->writebyte(' ');
3474 buf->writestring(ident->toChars());
3476 buf->writebyte(';');
3477 buf->writenl();
3480 /******************************** SynchronizedStatement ***************************/
3482 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
3483 : Statement(loc)
3485 this->exp = exp;
3486 this->body = body;
3487 this->esync = NULL;
3490 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
3491 : Statement(loc)
3493 this->exp = NULL;
3494 this->body = body;
3495 this->esync = esync;
3498 Statement *SynchronizedStatement::syntaxCopy()
3500 Expression *e = exp ? exp->syntaxCopy() : NULL;
3501 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
3502 return s;
3505 Statement *SynchronizedStatement::semantic(Scope *sc)
3507 if (exp)
3508 { ClassDeclaration *cd;
3510 exp = exp->semantic(sc);
3511 exp = resolveProperties(sc, exp);
3512 cd = exp->type->isClassHandle();
3513 if (!cd)
3514 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
3515 else if (cd->isInterfaceDeclaration())
3516 { Type *t = new TypeIdentifier(0, Id::Object);
3518 t = t->semantic(0, sc);
3519 exp = new CastExp(loc, exp, t);
3520 exp = exp->semantic(sc);
3523 if (body)
3524 body = body->semantic(sc);
3525 return this;
3528 int SynchronizedStatement::hasBreak()
3530 return FALSE; //TRUE;
3533 int SynchronizedStatement::hasContinue()
3535 return FALSE; //TRUE;
3538 int SynchronizedStatement::usesEH()
3540 return TRUE;
3543 int SynchronizedStatement::blockExit()
3545 return body ? body->blockExit() : BEfallthru;
3548 int SynchronizedStatement::fallOffEnd()
3550 return body ? body->fallOffEnd() : TRUE;
3553 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3555 buf->writestring("synchronized");
3556 if (exp)
3557 { buf->writebyte('(');
3558 exp->toCBuffer(buf, hgs);
3559 buf->writebyte(')');
3561 if (body)
3563 buf->writebyte(' ');
3564 body->toCBuffer(buf, hgs);
3568 /******************************** WithStatement ***************************/
3570 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
3571 : Statement(loc)
3573 this->exp = exp;
3574 this->body = body;
3575 wthis = NULL;
3578 Statement *WithStatement::syntaxCopy()
3580 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3581 return s;
3584 Statement *WithStatement::semantic(Scope *sc)
3585 { ScopeDsymbol *sym;
3586 Initializer *init;
3588 //printf("WithStatement::semantic()\n");
3589 exp = exp->semantic(sc);
3590 exp = resolveProperties(sc, exp);
3591 if (exp->op == TOKimport)
3592 { ScopeExp *es = (ScopeExp *)exp;
3594 sym = es->sds;
3596 else if (exp->op == TOKtype)
3597 { TypeExp *es = (TypeExp *)exp;
3599 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3600 if (!sym)
3601 { error("%s has no members", es->toChars());
3602 body = body->semantic(sc);
3603 return this;
3606 else
3607 { Type *t = exp->type;
3609 assert(t);
3610 t = t->toBasetype();
3611 if (t->isClassHandle())
3613 init = new ExpInitializer(loc, exp);
3614 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3615 wthis->semantic(sc);
3617 sym = new WithScopeSymbol(this);
3618 sym->parent = sc->scopesym;
3620 else if (t->ty == Tstruct)
3622 Expression *e = exp->addressOf(sc);
3623 init = new ExpInitializer(loc, e);
3624 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3625 wthis->semantic(sc);
3626 sym = new WithScopeSymbol(this);
3627 sym->parent = sc->scopesym;
3629 else
3630 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3631 return NULL;
3634 sc = sc->push(sym);
3636 if (body)
3637 body = body->semantic(sc);
3639 sc->pop();
3641 return this;
3644 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3646 buf->writestring("with (");
3647 exp->toCBuffer(buf, hgs);
3648 buf->writestring(")\n");
3649 if (body)
3650 body->toCBuffer(buf, hgs);
3653 int WithStatement::usesEH()
3655 return body ? body->usesEH() : 0;
3658 int WithStatement::blockExit()
3660 int result = BEnone;
3661 if (exp->canThrow())
3662 result = BEthrow;
3663 if (body)
3664 result |= body->blockExit();
3665 else
3666 result |= BEfallthru;
3667 return result;
3670 int WithStatement::fallOffEnd()
3672 return body ? body->fallOffEnd() : TRUE;
3675 /******************************** TryCatchStatement ***************************/
3677 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3678 : Statement(loc)
3680 this->body = body;
3681 this->catches = catches;
3684 Statement *TryCatchStatement::syntaxCopy()
3686 Array *a = new Array();
3687 a->setDim(catches->dim);
3688 for (int i = 0; i < a->dim; i++)
3689 { Catch *c;
3691 c = (Catch *)catches->data[i];
3692 c = c->syntaxCopy();
3693 a->data[i] = c;
3695 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3696 return s;
3699 Statement *TryCatchStatement::semantic(Scope *sc)
3701 body = body->semanticScope(sc, NULL /*this*/, NULL);
3703 /* Even if body is NULL, still do semantic analysis on catches
3705 for (size_t i = 0; i < catches->dim; i++)
3706 { Catch *c = (Catch *)catches->data[i];
3707 c->semantic(sc);
3709 // Determine if current catch 'hides' any previous catches
3710 for (size_t j = 0; j < i; j++)
3711 { Catch *cj = (Catch *)catches->data[j];
3712 char *si = c->loc.toChars();
3713 char *sj = cj->loc.toChars();
3715 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3716 error("catch at %s hides catch at %s", sj, si);
3720 if (!body)
3721 return NULL;
3723 return this;
3726 int TryCatchStatement::hasBreak()
3728 return FALSE; //TRUE;
3731 int TryCatchStatement::usesEH()
3733 return TRUE;
3736 int TryCatchStatement::blockExit()
3737 { int result;
3739 assert(body);
3740 result = body->blockExit();
3742 for (size_t i = 0; i < catches->dim; i++)
3744 Catch *c = (Catch *)catches->data[i];
3745 result |= c->blockExit();
3747 return result;
3750 int TryCatchStatement::fallOffEnd()
3752 int result = FALSE;
3754 if (body)
3755 result = body->fallOffEnd();
3756 for (int i = 0; i < catches->dim; i++)
3757 { Catch *c;
3759 c = (Catch *)catches->data[i];
3760 if (c->handler)
3761 result |= c->handler->fallOffEnd();
3763 return result;
3766 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3768 buf->writestring("try");
3769 buf->writenl();
3770 if (body)
3771 body->toCBuffer(buf, hgs);
3772 for (size_t i = 0; i < catches->dim; i++)
3774 Catch *c = (Catch *)catches->data[i];
3775 c->toCBuffer(buf, hgs);
3779 /******************************** Catch ***************************/
3781 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3783 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3784 this->loc = loc;
3785 this->type = t;
3786 this->ident = id;
3787 this->handler = handler;
3788 var = NULL;
3791 Catch *Catch::syntaxCopy()
3793 Catch *c = new Catch(loc,
3794 (type ? type->syntaxCopy() : NULL),
3795 ident,
3796 (handler ? handler->syntaxCopy() : NULL));
3797 return c;
3800 void Catch::semantic(Scope *sc)
3801 { ScopeDsymbol *sym;
3803 //printf("Catch::semantic(%s)\n", ident->toChars());
3805 #ifndef IN_GCC
3806 if (sc->tf)
3808 /* This is because the _d_local_unwind() gets the stack munged
3809 * up on this. The workaround is to place any try-catches into
3810 * a separate function, and call that.
3811 * To fix, have the compiler automatically convert the finally
3812 * body into a nested function.
3814 error(loc, "cannot put catch statement inside finally block");
3816 #endif
3818 sym = new ScopeDsymbol();
3819 sym->parent = sc->scopesym;
3820 sc = sc->push(sym);
3822 if (!type)
3823 type = new TypeIdentifier(0, Id::Object);
3824 type = type->semantic(loc, sc);
3825 if (!type->toBasetype()->isClassHandle())
3826 error("can only catch class objects, not '%s'", type->toChars());
3827 else if (ident)
3829 var = new VarDeclaration(loc, type, ident, NULL);
3830 var->parent = sc->parent;
3831 sc->insert(var);
3833 handler = handler->semantic(sc);
3835 sc->pop();
3838 int Catch::blockExit()
3840 return handler ? handler->blockExit() : BEfallthru;
3843 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3845 buf->writestring("catch");
3846 if (type)
3847 { buf->writebyte('(');
3848 type->toCBuffer(buf, ident, hgs);
3849 buf->writebyte(')');
3851 buf->writenl();
3852 buf->writebyte('{');
3853 buf->writenl();
3854 if (handler)
3855 handler->toCBuffer(buf, hgs);
3856 buf->writebyte('}');
3857 buf->writenl();
3860 /****************************** TryFinallyStatement ***************************/
3862 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3863 : Statement(loc)
3865 this->body = body;
3866 this->finalbody = finalbody;
3869 Statement *TryFinallyStatement::syntaxCopy()
3871 TryFinallyStatement *s = new TryFinallyStatement(loc,
3872 body->syntaxCopy(), finalbody->syntaxCopy());
3873 return s;
3876 Statement *TryFinallyStatement::semantic(Scope *sc)
3878 //printf("TryFinallyStatement::semantic()\n");
3879 body = body->semantic(sc);
3880 sc = sc->push();
3881 sc->tf = this;
3882 sc->sbreak = NULL;
3883 sc->scontinue = NULL; // no break or continue out of finally block
3884 finalbody = finalbody->semantic(sc);
3885 sc->pop();
3886 if (!body)
3887 return finalbody;
3888 if (!finalbody)
3889 return body;
3890 if (body->blockExit() == BEfallthru)
3891 { Statement *s = new CompoundStatement(loc, body, finalbody);
3892 return s;
3894 return this;
3897 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3899 buf->printf("try\n{\n");
3900 body->toCBuffer(buf, hgs);
3901 buf->printf("}\nfinally\n{\n");
3902 finalbody->toCBuffer(buf, hgs);
3903 buf->writeByte('}');
3904 buf->writenl();
3907 int TryFinallyStatement::hasBreak()
3909 return FALSE; //TRUE;
3912 int TryFinallyStatement::hasContinue()
3914 return FALSE; //TRUE;
3917 int TryFinallyStatement::usesEH()
3919 return TRUE;
3922 int TryFinallyStatement::blockExit()
3924 int result = body->blockExit();
3925 return result;
3928 int TryFinallyStatement::fallOffEnd()
3929 { int result;
3931 result = body->fallOffEnd();
3932 // if (finalbody)
3933 // result = finalbody->fallOffEnd();
3934 return result;
3937 /****************************** OnScopeStatement ***************************/
3939 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3940 : Statement(loc)
3942 this->tok = tok;
3943 this->statement = statement;
3946 Statement *OnScopeStatement::syntaxCopy()
3948 OnScopeStatement *s = new OnScopeStatement(loc,
3949 tok, statement->syntaxCopy());
3950 return s;
3953 Statement *OnScopeStatement::semantic(Scope *sc)
3955 /* semantic is called on results of scopeCode() */
3956 return this;
3959 int OnScopeStatement::blockExit()
3960 { // At this point, this statement is just an empty placeholder
3961 return BEfallthru;
3964 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3966 buf->writestring(Token::toChars(tok));
3967 buf->writebyte(' ');
3968 statement->toCBuffer(buf, hgs);
3971 int OnScopeStatement::usesEH()
3973 return 1;
3976 void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
3978 //printf("OnScopeStatement::scopeCode()\n");
3979 //print();
3980 *sentry = NULL;
3981 *sexception = NULL;
3982 *sfinally = NULL;
3983 switch (tok)
3985 case TOKon_scope_exit:
3986 *sfinally = statement;
3987 break;
3989 case TOKon_scope_failure:
3990 *sexception = statement;
3991 break;
3993 case TOKon_scope_success:
3995 /* Create:
3996 * sentry: int x = 0;
3997 * sexception: x = 1;
3998 * sfinally: if (!x) statement;
4000 Identifier *id = Lexer::uniqueId("__os");
4002 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
4003 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
4004 *sentry = new DeclarationStatement(loc, v);
4006 Expression *e = new IntegerExp(1);
4007 e = new AssignExp(0, new VarExp(0, v), e);
4008 *sexception = new ExpStatement(0, e);
4010 e = new VarExp(0, v);
4011 e = new NotExp(0, e);
4012 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
4014 break;
4017 default:
4018 assert(0);
4022 /******************************** ThrowStatement ***************************/
4024 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
4025 : Statement(loc)
4027 this->exp = exp;
4030 Statement *ThrowStatement::syntaxCopy()
4032 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
4033 return s;
4036 Statement *ThrowStatement::semantic(Scope *sc)
4038 //printf("ThrowStatement::semantic()\n");
4040 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4041 fd->hasReturnExp |= 2;
4043 if (sc->incontract)
4044 error("Throw statements cannot be in contracts");
4045 exp = exp->semantic(sc);
4046 exp = resolveProperties(sc, exp);
4047 if (!exp->type->toBasetype()->isClassHandle())
4048 error("can only throw class objects, not type %s", exp->type->toChars());
4049 return this;
4052 int ThrowStatement::blockExit()
4054 return BEthrow; // obviously
4057 int ThrowStatement::fallOffEnd()
4059 return FALSE;
4062 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4064 buf->printf("throw ");
4065 exp->toCBuffer(buf, hgs);
4066 buf->writeByte(';');
4067 buf->writenl();
4070 /******************************** VolatileStatement **************************/
4072 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
4073 : Statement(loc)
4075 this->statement = statement;
4078 Statement *VolatileStatement::syntaxCopy()
4080 VolatileStatement *s = new VolatileStatement(loc,
4081 statement ? statement->syntaxCopy() : NULL);
4082 return s;
4085 Statement *VolatileStatement::semantic(Scope *sc)
4087 if (statement)
4088 statement = statement->semantic(sc);
4089 return this;
4092 Statements *VolatileStatement::flatten(Scope *sc)
4094 Statements *a;
4096 a = statement ? statement->flatten(sc) : NULL;
4097 if (a)
4098 { for (int i = 0; i < a->dim; i++)
4099 { Statement *s = (Statement *)a->data[i];
4101 s = new VolatileStatement(loc, s);
4102 a->data[i] = s;
4106 return a;
4109 int VolatileStatement::blockExit()
4111 return statement ? statement->blockExit() : BEfallthru;
4114 int VolatileStatement::fallOffEnd()
4116 return statement ? statement->fallOffEnd() : TRUE;
4119 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4121 buf->writestring("volatile");
4122 if (statement)
4123 { if (statement->isScopeStatement())
4124 buf->writenl();
4125 else
4126 buf->writebyte(' ');
4127 statement->toCBuffer(buf, hgs);
4132 /******************************** GotoStatement ***************************/
4134 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
4135 : Statement(loc)
4137 this->ident = ident;
4138 this->label = NULL;
4139 this->tf = NULL;
4142 Statement *GotoStatement::syntaxCopy()
4144 GotoStatement *s = new GotoStatement(loc, ident);
4145 return s;
4148 Statement *GotoStatement::semantic(Scope *sc)
4149 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4151 //printf("GotoStatement::semantic()\n");
4152 tf = sc->tf;
4153 label = fd->searchLabel(ident);
4154 if (!label->statement && sc->fes)
4156 /* Either the goto label is forward referenced or it
4157 * is in the function that the enclosing foreach is in.
4158 * Can't know yet, so wrap the goto in a compound statement
4159 * so we can patch it later, and add it to a 'look at this later'
4160 * list.
4162 Statements *a = new Statements();
4163 Statement *s;
4165 a->push(this);
4166 s = new CompoundStatement(loc, a);
4167 sc->fes->gotos.push(s); // 'look at this later' list
4168 return s;
4170 if (label->statement && label->statement->tf != sc->tf)
4171 error("cannot goto in or out of finally block");
4172 return this;
4175 int GotoStatement::blockExit()
4177 //printf("GotoStatement::blockExit(%p)\n", this);
4178 return BEgoto;
4181 int GotoStatement::fallOffEnd()
4183 return FALSE;
4186 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4188 buf->writestring("goto ");
4189 buf->writestring(ident->toChars());
4190 buf->writebyte(';');
4191 buf->writenl();
4194 /******************************** LabelStatement ***************************/
4196 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
4197 : Statement(loc)
4199 this->ident = ident;
4200 this->statement = statement;
4201 this->tf = NULL;
4202 this->lblock = NULL;
4203 this->isReturnLabel = 0;
4206 Statement *LabelStatement::syntaxCopy()
4208 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
4209 return s;
4212 Statement *LabelStatement::semantic(Scope *sc)
4213 { LabelDsymbol *ls;
4214 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4216 //printf("LabelStatement::semantic()\n");
4217 ls = fd->searchLabel(ident);
4218 if (ls->statement)
4219 error("Label '%s' already defined", ls->toChars());
4220 else
4221 ls->statement = this;
4222 tf = sc->tf;
4223 sc = sc->push();
4224 sc->scopesym = sc->enclosing->scopesym;
4225 sc->callSuper |= CSXlabel;
4226 sc->slabel = this;
4227 if (statement)
4228 statement = statement->semantic(sc);
4229 sc->pop();
4230 return this;
4233 Statements *LabelStatement::flatten(Scope *sc)
4235 Statements *a = NULL;
4237 if (statement)
4239 a = statement->flatten(sc);
4240 if (a)
4242 if (!a->dim)
4244 a->push(new ExpStatement(loc, NULL));
4246 Statement *s = (Statement *)a->data[0];
4248 s = new LabelStatement(loc, ident, s);
4249 a->data[0] = s;
4253 return a;
4257 int LabelStatement::usesEH()
4259 return statement ? statement->usesEH() : FALSE;
4262 int LabelStatement::blockExit()
4264 //printf("LabelStatement::blockExit(%p)\n", this);
4265 return statement ? statement->blockExit() : BEfallthru;
4268 int LabelStatement::fallOffEnd()
4270 return statement ? statement->fallOffEnd() : TRUE;
4273 int LabelStatement::comeFrom()
4275 //printf("LabelStatement::comeFrom()\n");
4276 return TRUE;
4279 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4281 buf->writestring(ident->toChars());
4282 buf->writebyte(':');
4283 buf->writenl();
4284 if (statement)
4285 statement->toCBuffer(buf, hgs);
4289 /******************************** LabelDsymbol ***************************/
4291 LabelDsymbol::LabelDsymbol(Identifier *ident)
4292 : Dsymbol(ident)
4294 statement = NULL;
4295 #if IN_GCC
4296 asmLabelNum = 0;
4297 #endif
4300 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
4302 return this;