Modular handling of externals
[delight/core.git] / dmd2 / statement.c
blob92ee192af606f2d9b56f0969ef1b12a084e213dc
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 Expression *newMain = new NewExp(loc, NULL, NULL, mainClass->getType(),
462 ctor ? getAutoArgs(ctor->loc, ctor->arguments, sc) : NULL);
464 // Then invoke the main() method inside it
465 // mainObject.main(...)
466 Expression *mainMethod = new DotIdExp(mainDecl->loc, newMain, Id::main);
467 Expression *mainCall = new CallExp(mainMethod->loc, mainMethod,
468 getAutoArgs(mainDecl->loc,
469 ((TypeFunction *) mainDecl->type)->parameters,
470 sc));
472 Statement *body = new ExpStatement(loc, mainCall);
474 return body->semantic(sc);
477 /******************************** CompoundStatement ***************************/
479 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
480 : Statement(loc)
482 statements = s;
485 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
486 : Statement(loc)
488 statements = new Statements();
489 statements->reserve(2);
490 statements->push(s1);
491 statements->push(s2);
494 Statement *CompoundStatement::syntaxCopy()
496 Statements *a = new Statements();
497 a->setDim(statements->dim);
498 for (size_t i = 0; i < statements->dim; i++)
499 { Statement *s = (Statement *)statements->data[i];
500 if (s)
501 s = s->syntaxCopy();
502 a->data[i] = s;
504 CompoundStatement *cs = new CompoundStatement(loc, a);
505 return cs;
509 Statement *CompoundStatement::semantic(Scope *sc)
510 { Statement *s;
512 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
514 for (size_t i = 0; i < statements->dim; )
516 s = (Statement *) statements->data[i];
517 if (s)
518 { Statements *a = s->flatten(sc);
520 if (a)
522 statements->remove(i);
523 statements->insert(i, a);
524 continue;
526 s = s->semantic(sc);
527 statements->data[i] = s;
528 if (s)
530 Statement *sentry;
531 Statement *sexception;
532 Statement *sfinally;
534 s->scopeCode(sc, &sentry, &sexception, &sfinally);
535 if (sentry)
537 sentry = sentry->semantic(sc);
538 statements->data[i] = sentry;
540 if (sexception)
542 if (i + 1 == statements->dim && !sfinally)
544 #if 1
545 sexception = sexception->semantic(sc);
546 #else
547 statements->push(sexception);
548 if (sfinally)
549 // Assume sexception does not throw
550 statements->push(sfinally);
551 #endif
553 else
555 /* Rewrite:
556 * s; s1; s2;
557 * As:
558 * s;
559 * try { s1; s2; }
560 * catch (Object __o)
561 * { sexception; throw __o; }
563 Statement *body;
564 Statements *a = new Statements();
566 for (int j = i + 1; j < statements->dim; j++)
568 a->push(statements->data[j]);
570 body = new CompoundStatement(0, a);
571 body = new ScopeStatement(0, body);
573 Identifier *id = Lexer::uniqueId("__o");
575 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
576 handler = new CompoundStatement(0, sexception, handler);
578 Array *catches = new Array();
579 Catch *ctch = new Catch(0, NULL, id, handler);
580 catches->push(ctch);
581 s = new TryCatchStatement(0, body, catches);
583 if (sfinally)
584 s = new TryFinallyStatement(0, s, sfinally);
585 s = s->semantic(sc);
586 statements->setDim(i + 1);
587 statements->push(s);
588 break;
591 else if (sfinally)
593 if (0 && i + 1 == statements->dim)
595 statements->push(sfinally);
597 else
599 /* Rewrite:
600 * s; s1; s2;
601 * As:
602 * s; try { s1; s2; } finally { sfinally; }
604 Statement *body;
605 Statements *a = new Statements();
607 for (int j = i + 1; j < statements->dim; j++)
609 a->push(statements->data[j]);
611 body = new CompoundStatement(0, a);
612 s = new TryFinallyStatement(0, body, sfinally);
613 s = s->semantic(sc);
614 statements->setDim(i + 1);
615 statements->push(s);
616 break;
621 i++;
623 if (statements->dim == 1)
624 return s;
625 return this;
628 Statements *CompoundStatement::flatten(Scope *sc)
630 return statements;
633 ReturnStatement *CompoundStatement::isReturnStatement()
634 { int i;
635 ReturnStatement *rs = NULL;
637 for (i = 0; i < statements->dim; i++)
638 { Statement *s;
640 s = (Statement *) statements->data[i];
641 if (s)
643 rs = s->isReturnStatement();
644 if (rs)
645 break;
648 return rs;
651 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
652 { int i;
654 for (i = 0; i < statements->dim; i++)
655 { Statement *s;
657 s = (Statement *) statements->data[i];
658 if (s)
659 s->toCBuffer(buf, hgs);
663 int CompoundStatement::usesEH()
665 for (int i = 0; i < statements->dim; i++)
666 { Statement *s;
668 s = (Statement *) statements->data[i];
669 if (s && s->usesEH())
670 return TRUE;
672 return FALSE;
675 int CompoundStatement::blockExit()
677 //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
678 int result = BEfallthru;
679 for (size_t i = 0; i < statements->dim; i++)
680 { Statement *s = (Statement *) statements->data[i];
681 if (s)
683 //printf("result = x%x\n", result);
684 //printf("%s\n", s->toChars());
685 if (!(result & BEfallthru) && !s->comeFrom())
687 if (global.params.warnings)
688 { fprintf(stdmsg, "warning - ");
689 s->error("statement is not reachable");
693 result &= ~BEfallthru;
694 result |= s->blockExit();
697 return result;
700 int CompoundStatement::fallOffEnd()
701 { int falloff = TRUE;
703 //printf("CompoundStatement::fallOffEnd()\n");
704 for (int i = 0; i < statements->dim; i++)
705 { Statement *s = (Statement *)statements->data[i];
707 if (!s)
708 continue;
710 #if 0
711 if (!falloff && global.params.warnings && !s->comeFrom())
713 fprintf(stdmsg, "warning - ");
714 s->error("statement is not reachable");
716 #endif
717 falloff = s->fallOffEnd();
719 return falloff;
722 int CompoundStatement::comeFrom()
723 { int comefrom = FALSE;
725 //printf("CompoundStatement::comeFrom()\n");
726 for (int i = 0; i < statements->dim; i++)
727 { Statement *s = (Statement *)statements->data[i];
729 if (!s)
730 continue;
732 comefrom |= s->comeFrom();
734 return comefrom;
738 /**************************** UnrolledLoopStatement ***************************/
740 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
741 : Statement(loc)
743 statements = s;
746 Statement *UnrolledLoopStatement::syntaxCopy()
748 Statements *a = new Statements();
749 a->setDim(statements->dim);
750 for (size_t i = 0; i < statements->dim; i++)
751 { Statement *s = (Statement *)statements->data[i];
752 if (s)
753 s = s->syntaxCopy();
754 a->data[i] = s;
756 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
757 return cs;
761 Statement *UnrolledLoopStatement::semantic(Scope *sc)
763 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
765 sc->noctor++;
766 Scope *scd = sc->push();
767 scd->sbreak = this;
768 scd->scontinue = this;
770 for (size_t i = 0; i < statements->dim; i++)
772 Statement *s = (Statement *) statements->data[i];
773 if (s)
775 s = s->semantic(scd);
776 statements->data[i] = s;
780 scd->pop();
781 sc->noctor--;
782 return this;
785 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
787 buf->writestring("unrolled {");
788 buf->writenl();
790 for (size_t i = 0; i < statements->dim; i++)
791 { Statement *s;
793 s = (Statement *) statements->data[i];
794 if (s)
795 s->toCBuffer(buf, hgs);
798 buf->writeByte('}');
799 buf->writenl();
802 int UnrolledLoopStatement::hasBreak()
804 return TRUE;
807 int UnrolledLoopStatement::hasContinue()
809 return TRUE;
812 int UnrolledLoopStatement::usesEH()
814 for (size_t i = 0; i < statements->dim; i++)
815 { Statement *s = (Statement *) statements->data[i];
816 if (s && s->usesEH())
817 return TRUE;
819 return FALSE;
822 int UnrolledLoopStatement::blockExit()
824 int result = BEfallthru;
825 for (size_t i = 0; i < statements->dim; i++)
826 { Statement *s = (Statement *) statements->data[i];
827 if (s)
829 int r = s->blockExit();
830 result |= r & ~(BEbreak | BEcontinue);
833 return result;
836 int UnrolledLoopStatement::fallOffEnd()
838 //printf("UnrolledLoopStatement::fallOffEnd()\n");
839 for (size_t i = 0; i < statements->dim; i++)
840 { Statement *s = (Statement *)statements->data[i];
842 if (s)
843 s->fallOffEnd();
845 return TRUE;
848 int UnrolledLoopStatement::comeFrom()
849 { int comefrom = FALSE;
851 //printf("UnrolledLoopStatement::comeFrom()\n");
852 for (size_t i = 0; i < statements->dim; i++)
853 { Statement *s = (Statement *)statements->data[i];
855 if (!s)
856 continue;
858 comefrom |= s->comeFrom();
860 return comefrom;
864 /******************************** ScopeStatement ***************************/
866 ScopeStatement::ScopeStatement(Loc loc, Statement *s)
867 : Statement(loc)
869 this->statement = s;
872 Statement *ScopeStatement::syntaxCopy()
874 Statement *s;
876 s = statement ? statement->syntaxCopy() : NULL;
877 s = new ScopeStatement(loc, s);
878 return s;
882 Statement *ScopeStatement::semantic(Scope *sc)
883 { ScopeDsymbol *sym;
885 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
886 if (statement)
887 { Statements *a;
889 sym = new ScopeDsymbol();
890 sym->parent = sc->scopesym;
891 sc = sc->push(sym);
893 a = statement->flatten(sc);
894 if (a)
896 statement = new CompoundStatement(loc, a);
899 statement = statement->semantic(sc);
900 if (statement)
902 Statement *sentry;
903 Statement *sexception;
904 Statement *sfinally;
906 statement->scopeCode(sc, &sentry, &sexception, &sfinally);
907 if (sfinally)
909 //printf("adding sfinally\n");
910 statement = new CompoundStatement(loc, statement, sfinally);
914 sc->pop();
916 return this;
919 int ScopeStatement::hasBreak()
921 //printf("ScopeStatement::hasBreak() %s\n", toChars());
922 return statement ? statement->hasBreak() : FALSE;
925 int ScopeStatement::hasContinue()
927 return statement ? statement->hasContinue() : FALSE;
930 int ScopeStatement::usesEH()
932 return statement ? statement->usesEH() : FALSE;
935 int ScopeStatement::blockExit()
937 //printf("ScopeStatement::blockExit(%p)\n", statement);
938 return statement ? statement->blockExit() : BEfallthru;
941 int ScopeStatement::fallOffEnd()
943 return statement ? statement->fallOffEnd() : TRUE;
946 int ScopeStatement::comeFrom()
948 //printf("ScopeStatement::comeFrom()\n");
949 return statement ? statement->comeFrom() : FALSE;
952 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
954 buf->writeByte('{');
955 buf->writenl();
957 if (statement)
958 statement->toCBuffer(buf, hgs);
960 buf->writeByte('}');
961 buf->writenl();
964 /******************************** WhileStatement ***************************/
966 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
967 : Statement(loc)
969 condition = c;
970 body = b;
973 Statement *WhileStatement::syntaxCopy()
975 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
976 return s;
980 Statement *WhileStatement::semantic(Scope *sc)
982 #if 0
983 if (condition->op == TOKmatch)
985 /* Rewrite while (condition) body as:
986 * if (condition)
987 * do
988 * body
989 * while ((_match = _match.opNext), _match);
992 Expression *ew = new IdentifierExp(0, Id::_match);
993 ew = new DotIdExp(0, ew, Id::next);
994 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
995 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
996 Expression *ev = new IdentifierExp(0, Id::_match);
997 //ev = new CastExp(0, ev, Type::tvoidptr);
998 ew = new CommaExp(0, ew, ev);
999 Statement *sw = new DoStatement(loc, body, ew);
1000 Statement *si = new IfStatement(loc, condition, sw, NULL);
1001 return si->semantic(sc);
1003 #endif
1005 condition = condition->semantic(sc);
1006 condition = resolveProperties(sc, condition);
1007 condition = condition->optimize(WANTvalue);
1008 condition = condition->checkToBoolean();
1010 sc->noctor++;
1012 Scope *scd = sc->push();
1013 scd->sbreak = this;
1014 scd->scontinue = this;
1015 if (body)
1016 body = body->semantic(scd);
1017 scd->pop();
1019 sc->noctor--;
1021 return this;
1024 int WhileStatement::hasBreak()
1026 return TRUE;
1029 int WhileStatement::hasContinue()
1031 return TRUE;
1034 int WhileStatement::usesEH()
1036 return body ? body->usesEH() : 0;
1039 int WhileStatement::blockExit()
1041 //printf("WhileStatement::blockExit(%p)\n", this);
1043 int result = BEnone;
1044 if (condition->canThrow())
1045 result |= BEthrow;
1046 if (body)
1047 { result |= body->blockExit();
1048 if (result & BEbreak)
1049 result |= BEfallthru;
1050 result &= ~(BEbreak | BEcontinue);
1052 else
1053 result |= BEfallthru;
1054 return result;
1057 int WhileStatement::fallOffEnd()
1059 if (body)
1060 body->fallOffEnd();
1061 return TRUE;
1064 int WhileStatement::comeFrom()
1066 if (body)
1067 return body->comeFrom();
1068 return FALSE;
1071 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1073 buf->writestring("while (");
1074 condition->toCBuffer(buf, hgs);
1075 buf->writebyte(')');
1076 buf->writenl();
1077 if (body)
1078 body->toCBuffer(buf, hgs);
1081 /******************************** DoStatement ***************************/
1083 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
1084 : Statement(loc)
1086 body = b;
1087 condition = c;
1090 Statement *DoStatement::syntaxCopy()
1092 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
1093 return s;
1097 Statement *DoStatement::semantic(Scope *sc)
1099 sc->noctor++;
1100 if (body)
1101 body = body->semanticScope(sc, this, this);
1102 sc->noctor--;
1103 condition = condition->semantic(sc);
1104 condition = resolveProperties(sc, condition);
1105 condition = condition->optimize(WANTvalue);
1107 condition = condition->checkToBoolean();
1109 return this;
1112 int DoStatement::hasBreak()
1114 return TRUE;
1117 int DoStatement::hasContinue()
1119 return TRUE;
1122 int DoStatement::usesEH()
1124 return body ? body->usesEH() : 0;
1127 int DoStatement::blockExit()
1128 { int result;
1130 if (body)
1131 { result = body->blockExit();
1132 if (result & BEbreak)
1134 if (result == BEbreak)
1135 return BEfallthru;
1136 result |= BEfallthru;
1138 if (result & BEcontinue)
1139 result |= BEfallthru;
1140 result &= ~(BEbreak | BEcontinue);
1142 else
1143 result = BEfallthru;
1144 if (result & BEfallthru && condition->canThrow())
1145 result |= BEthrow;
1146 return result;
1149 int DoStatement::fallOffEnd()
1151 if (body)
1152 body->fallOffEnd();
1153 return TRUE;
1156 int DoStatement::comeFrom()
1158 if (body)
1159 return body->comeFrom();
1160 return FALSE;
1163 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1165 buf->writestring("do");
1166 buf->writenl();
1167 if (body)
1168 body->toCBuffer(buf, hgs);
1169 buf->writestring("while (");
1170 condition->toCBuffer(buf, hgs);
1171 buf->writebyte(')');
1174 /******************************** ForStatement ***************************/
1176 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
1177 : Statement(loc)
1179 this->init = init;
1180 this->condition = condition;
1181 this->increment = increment;
1182 this->body = body;
1185 Statement *ForStatement::syntaxCopy()
1187 Statement *i = NULL;
1188 if (init)
1189 i = init->syntaxCopy();
1190 Expression *c = NULL;
1191 if (condition)
1192 c = condition->syntaxCopy();
1193 Expression *inc = NULL;
1194 if (increment)
1195 inc = increment->syntaxCopy();
1196 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
1197 return s;
1200 Statement *ForStatement::semantic(Scope *sc)
1202 ScopeDsymbol *sym = new ScopeDsymbol();
1203 sym->parent = sc->scopesym;
1204 sc = sc->push(sym);
1205 if (init)
1206 init = init->semantic(sc);
1207 sc->noctor++;
1208 if (condition)
1210 condition = condition->semantic(sc);
1211 condition = resolveProperties(sc, condition);
1212 condition = condition->optimize(WANTvalue);
1213 condition = condition->checkToBoolean();
1215 if (increment)
1216 increment = increment->semantic(sc);
1218 sc->sbreak = this;
1219 sc->scontinue = this;
1220 body = body->semantic(sc);
1221 sc->noctor--;
1223 sc->pop();
1224 return this;
1227 void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
1229 //printf("ForStatement::scopeCode()\n");
1230 //print();
1231 if (init)
1232 init->scopeCode(sc, sentry, sexception, sfinally);
1233 else
1234 Statement::scopeCode(sc, sentry, sexception, sfinally);
1237 int ForStatement::hasBreak()
1239 //printf("ForStatement::hasBreak()\n");
1240 return TRUE;
1243 int ForStatement::hasContinue()
1245 return TRUE;
1248 int ForStatement::usesEH()
1250 return (init && init->usesEH()) || body->usesEH();
1253 int ForStatement::blockExit()
1254 { int result = BEfallthru;
1256 if (init)
1257 { result = init->blockExit();
1258 if (!(result & BEfallthru))
1259 return result;
1261 if (condition)
1262 { if (condition->canThrow())
1263 result |= BEthrow;
1265 else
1266 result &= ~BEfallthru; // the body must do the exiting
1267 if (body)
1268 { int r = body->blockExit();
1269 if (r & BEbreak)
1270 result |= BEfallthru;
1271 result |= r & ~(BEbreak | BEcontinue);
1273 if (increment && increment->canThrow())
1274 result |= BEthrow;
1275 return result;
1278 int ForStatement::fallOffEnd()
1280 if (body)
1281 body->fallOffEnd();
1282 return TRUE;
1285 int ForStatement::comeFrom()
1287 //printf("ForStatement::comeFrom()\n");
1288 if (body)
1289 { int result = body->comeFrom();
1290 //printf("result = %d\n", result);
1291 return result;
1293 return FALSE;
1296 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1298 buf->writestring("for (");
1299 if (init)
1301 hgs->FLinit.init++;
1302 hgs->FLinit.decl = 0;
1303 init->toCBuffer(buf, hgs);
1304 if (hgs->FLinit.decl > 0)
1305 buf->writebyte(';');
1306 hgs->FLinit.decl = 0;
1307 hgs->FLinit.init--;
1309 else
1310 buf->writebyte(';');
1311 if (condition)
1312 { buf->writebyte(' ');
1313 condition->toCBuffer(buf, hgs);
1315 buf->writebyte(';');
1316 if (increment)
1317 { buf->writebyte(' ');
1318 increment->toCBuffer(buf, hgs);
1320 buf->writebyte(')');
1321 buf->writenl();
1322 buf->writebyte('{');
1323 buf->writenl();
1324 body->toCBuffer(buf, hgs);
1325 buf->writebyte('}');
1326 buf->writenl();
1329 /******************************** ForeachStatement ***************************/
1331 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
1332 Expression *aggr, Statement *body)
1333 : Statement(loc)
1335 this->op = op;
1336 this->arguments = arguments;
1337 this->aggr = aggr;
1338 this->body = body;
1340 this->key = NULL;
1341 this->value = NULL;
1343 this->func = NULL;
1346 Statement *ForeachStatement::syntaxCopy()
1348 Arguments *args = Argument::arraySyntaxCopy(arguments);
1349 Expression *exp = aggr->syntaxCopy();
1350 ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
1351 body ? body->syntaxCopy() : NULL);
1352 return s;
1355 Statement *ForeachStatement::semantic(Scope *sc)
1357 //printf("ForeachStatement::semantic() %p\n", this);
1358 ScopeDsymbol *sym;
1359 Statement *s = this;
1360 int dim = arguments->dim;
1361 int i;
1362 TypeAArray *taa = NULL;
1364 Type *tn = NULL;
1365 Type *tnv = NULL;
1367 func = sc->func;
1368 if (func->fes)
1369 func = func->fes->func;
1371 aggr = aggr->semantic(sc);
1372 aggr = resolveProperties(sc, aggr);
1373 aggr = aggr->optimize(WANTvalue);
1374 if (!aggr->type)
1376 error("invalid foreach aggregate %s", aggr->toChars());
1377 return this;
1380 inferApplyArgTypes(op, arguments, aggr);
1382 /* Check for inference errors
1384 if (dim != arguments->dim)
1386 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1387 error("cannot uniquely infer foreach argument types");
1388 return this;
1391 Type *tab = aggr->type->toBasetype();
1393 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
1395 if (dim < 1 || dim > 2)
1397 error("only one (value) or two (key,value) arguments for tuple foreach");
1398 return s;
1401 TypeTuple *tuple = (TypeTuple *)tab;
1402 Statements *statements = new Statements();
1403 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1404 size_t n;
1405 TupleExp *te = NULL;
1406 if (aggr->op == TOKtuple) // expression tuple
1407 { te = (TupleExp *)aggr;
1408 n = te->exps->dim;
1410 else if (aggr->op == TOKtype) // type tuple
1412 n = Argument::dim(tuple->arguments);
1414 else
1415 assert(0);
1416 for (size_t j = 0; j < n; j++)
1417 { size_t k = (op == TOKforeach) ? j : n - 1 - j;
1418 Expression *e;
1419 Type *t;
1420 if (te)
1421 e = (Expression *)te->exps->data[k];
1422 else
1423 t = Argument::getNth(tuple->arguments, k)->type;
1424 Argument *arg = (Argument *)arguments->data[0];
1425 Statements *st = new Statements();
1427 if (dim == 2)
1428 { // Declare key
1429 if (arg->storageClass & (STCout | STCref | STClazy))
1430 error("no storage class for key %s", arg->ident->toChars());
1431 TY keyty = arg->type->ty;
1432 if ((keyty != Tint32 && keyty != Tuns32) &&
1433 (! global.params.isX86_64 ||
1434 (keyty != Tint64 && keyty != Tuns64))
1437 error("foreach: key type must be int or uint, not %s", arg->type->toChars());
1439 Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
1440 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
1441 var->storage_class |= STCmanifest;
1442 DeclarationExp *de = new DeclarationExp(loc, var);
1443 st->push(new ExpStatement(loc, de));
1444 arg = (Argument *)arguments->data[1]; // value
1446 // Declare value
1447 if (arg->storageClass & (STCout | STCref | STClazy))
1448 error("no storage class for value %s", arg->ident->toChars());
1449 Dsymbol *var;
1450 if (te)
1451 { Type *tb = e->type->toBasetype();
1452 if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
1453 { VarExp *ve = (VarExp *)e;
1454 var = new AliasDeclaration(loc, arg->ident, ve->var);
1456 else
1458 arg->type = e->type;
1459 Initializer *ie = new ExpInitializer(0, e);
1460 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
1461 if (e->isConst())
1462 v->storage_class |= STCconst;
1463 var = v;
1466 else
1468 var = new AliasDeclaration(loc, arg->ident, t);
1470 DeclarationExp *de = new DeclarationExp(loc, var);
1471 st->push(new ExpStatement(loc, de));
1473 st->push(body->syntaxCopy());
1474 s = new CompoundStatement(loc, st);
1475 s = new ScopeStatement(loc, s);
1476 statements->push(s);
1479 s = new UnrolledLoopStatement(loc, statements);
1480 s = s->semantic(sc);
1481 return s;
1484 for (i = 0; i < dim; i++)
1485 { Argument *arg = (Argument *)arguments->data[i];
1486 if (!arg->type)
1488 error("cannot infer type for %s", arg->ident->toChars());
1489 return this;
1493 sym = new ScopeDsymbol();
1494 sym->parent = sc->scopesym;
1495 sc = sc->push(sym);
1497 sc->noctor++;
1499 switch (tab->ty)
1501 case Tarray:
1502 case Tsarray:
1503 if (dim < 1 || dim > 2)
1505 error("only one or two arguments for array foreach");
1506 break;
1509 /* Look for special case of parsing char types out of char type
1510 * array.
1512 tn = tab->nextOf()->toBasetype();
1513 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
1514 { Argument *arg;
1516 i = (dim == 1) ? 0 : 1; // index of value
1517 arg = (Argument *)arguments->data[i];
1518 arg->type = arg->type->semantic(loc, sc);
1519 tnv = arg->type->toBasetype();
1520 if (tnv->ty != tn->ty &&
1521 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
1523 if (arg->storageClass & STCref)
1524 error("foreach: value of UTF conversion cannot be ref");
1525 if (dim == 2)
1526 { arg = (Argument *)arguments->data[0];
1527 if (arg->storageClass & STCref)
1528 error("foreach: key cannot be ref");
1530 goto Lapply;
1534 for (i = 0; i < dim; i++)
1535 { // Declare args
1536 Argument *arg = (Argument *)arguments->data[i];
1537 VarDeclaration *var;
1539 var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1540 var->storage_class |= STCforeach;
1541 var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant);
1542 if (dim == 2 && i == 0)
1543 { key = var;
1544 //var->storage_class |= STCfinal;
1546 else
1547 { //if (!(arg->storageClass & STCref))
1548 //var->storage_class |= STCfinal;
1549 value = var;
1551 #if 1
1552 DeclarationExp *de = new DeclarationExp(loc, var);
1553 de->semantic(sc);
1554 #else
1555 var->semantic(sc);
1556 if (!sc->insert(var))
1557 error("%s already defined", var->ident->toChars());
1558 #endif
1561 sc->sbreak = this;
1562 sc->scontinue = this;
1563 body = body->semantic(sc);
1565 if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst)
1567 if (aggr->op == TOKstring)
1568 aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
1569 else
1570 error("foreach: %s is not an array of %s",
1571 tab->toChars(), value->type->toChars());
1574 if (key &&
1575 ((key->type->ty != Tint32 && key->type->ty != Tuns32) &&
1576 (! global.params.isX86_64 ||
1577 (key->type->ty != Tint64 && key->type->ty != Tuns64))
1581 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1584 if (key && key->storage_class & (STCout | STCref))
1585 error("foreach: key cannot be out or ref");
1586 break;
1588 case Taarray:
1589 taa = (TypeAArray *)tab;
1590 if (dim < 1 || dim > 2)
1592 error("only one or two arguments for associative array foreach");
1593 break;
1595 if (op == TOKforeach_reverse)
1597 error("no reverse iteration on associative arrays");
1599 goto Lapply;
1601 case Tclass:
1602 case Tstruct:
1603 case Tdelegate:
1604 Lapply:
1605 { FuncDeclaration *fdapply;
1606 Arguments *args;
1607 Expression *ec;
1608 Expression *e;
1609 FuncLiteralDeclaration *fld;
1610 Argument *a;
1611 Type *t;
1612 Expression *flde;
1613 Identifier *id;
1614 Type *tret;
1616 tret = func->type->nextOf();
1618 // Need a variable to hold value from any return statements in body.
1619 if (!sc->func->vresult && tret && tret != Type::tvoid)
1620 { VarDeclaration *v;
1622 v = new VarDeclaration(loc, tret, Id::result, NULL);
1623 v->noauto = 1;
1624 v->semantic(sc);
1625 if (!sc->insert(v))
1626 assert(0);
1627 v->parent = sc->func;
1628 sc->func->vresult = v;
1631 /* Turn body into the function literal:
1632 * int delegate(ref T arg) { body }
1634 args = new Arguments();
1635 for (i = 0; i < dim; i++)
1636 { Argument *arg = (Argument *)arguments->data[i];
1638 arg->type = arg->type->semantic(loc, sc);
1639 if (arg->storageClass & STCref)
1640 id = arg->ident;
1641 else
1642 { // Make a copy of the ref argument so it isn't
1643 // a reference.
1644 VarDeclaration *v;
1645 Initializer *ie;
1647 id = Lexer::uniqueId("__applyArg", i);
1649 ie = new ExpInitializer(0, new IdentifierExp(0, id));
1650 v = new VarDeclaration(0, arg->type, arg->ident, ie);
1651 s = new DeclarationStatement(0, v);
1652 body = new CompoundStatement(loc, s, body);
1654 a = new Argument(STCref, arg->type, id, NULL);
1655 args->push(a);
1657 t = new TypeFunction(args, Type::tint32, 0, LINKd);
1658 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
1659 fld->fbody = body;
1660 flde = new FuncExp(loc, fld);
1661 flde = flde->semantic(sc);
1662 fld->tookAddressOf = 0;
1664 // Resolve any forward referenced goto's
1665 for (int i = 0; i < gotos.dim; i++)
1666 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
1667 GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
1669 if (!gs->label->statement)
1670 { // 'Promote' it to this scope, and replace with a return
1671 cases.push(gs);
1672 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
1673 cs->statements->data[0] = (void *)s;
1677 if (tab->ty == Taarray)
1679 // Check types
1680 Argument *arg = (Argument *)arguments->data[0];
1681 if (dim == 2)
1683 if (arg->storageClass & STCref)
1684 error("foreach: index cannot be ref");
1685 if (!arg->type->equals(taa->index))
1686 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
1687 arg = (Argument *)arguments->data[1];
1689 if (!arg->type->equals(taa->nextOf()))
1690 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
1692 /* Call:
1693 * _aaApply(aggr, keysize, flde)
1695 if (dim == 2)
1696 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply2",
1697 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic
1698 else
1699 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply",
1700 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic);
1701 ec = new VarExp(0, fdapply);
1702 Expressions *exps = new Expressions();
1703 exps->push(aggr);
1704 size_t keysize = taa->index->size();
1705 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
1706 exps->push(new IntegerExp(0, keysize, Type::tsize_t));
1707 exps->push(flde);
1708 e = new CallExp(loc, ec, exps);
1709 e->type = Type::tint32; // don't run semantic() on e
1711 else if (tab->ty == Tarray || tab->ty == Tsarray)
1713 /* Call:
1714 * _aApply(aggr, flde)
1716 static char fntab[9][3] =
1717 { "cc","cw","cd",
1718 "wc","cc","wd",
1719 "dc","dw","dd"
1721 char fdname[7+1+2+ sizeof(dim)*3 + 1];
1722 int flag;
1724 switch (tn->ty)
1726 case Tchar: flag = 0; break;
1727 case Twchar: flag = 3; break;
1728 case Tdchar: flag = 6; break;
1729 default: assert(0);
1731 switch (tnv->ty)
1733 case Tchar: flag += 0; break;
1734 case Twchar: flag += 1; break;
1735 case Tdchar: flag += 2; break;
1736 default: assert(0);
1738 const char *r = (op == TOKforeach_reverse) ? "R" : "";
1739 int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
1740 assert(j < sizeof(fdname));
1741 fdapply = FuncDeclaration::genCfunc(Type::tint32, fdname,
1742 Type::tvoid->arrayOf(), flde->type); // flde->type is not generic
1744 ec = new VarExp(0, fdapply);
1745 Expressions *exps = new Expressions();
1746 if (tab->ty == Tsarray)
1747 aggr = aggr->castTo(sc, tn->arrayOf());
1748 exps->push(aggr);
1749 exps->push(flde);
1750 e = new CallExp(loc, ec, exps);
1751 e->type = Type::tint32; // don't run semantic() on e
1753 else if (tab->ty == Tdelegate)
1755 /* Call:
1756 * aggr(flde)
1758 Expressions *exps = new Expressions();
1759 exps->push(flde);
1760 e = new CallExp(loc, aggr, exps);
1761 e = e->semantic(sc);
1762 if (e->type != Type::tint32)
1763 error("opApply() function for %s must return an int", tab->toChars());
1765 else
1767 /* Call:
1768 * aggr.apply(flde)
1770 ec = new DotIdExp(loc, aggr,
1771 (op == TOKforeach_reverse) ? Id::applyReverse
1772 : Id::apply);
1773 Expressions *exps = new Expressions();
1774 exps->push(flde);
1775 e = new CallExp(loc, ec, exps);
1776 e = e->semantic(sc);
1777 if (e->type != Type::tint32)
1778 error("opApply() function for %s must return an int", tab->toChars());
1781 if (!cases.dim)
1782 // Easy case, a clean exit from the loop
1783 s = new ExpStatement(loc, e);
1784 else
1785 { // Construct a switch statement around the return value
1786 // of the apply function.
1787 Statements *a = new Statements();
1789 // default: break; takes care of cases 0 and 1
1790 s = new BreakStatement(0, NULL);
1791 s = new DefaultStatement(0, s);
1792 a->push(s);
1794 // cases 2...
1795 for (int i = 0; i < cases.dim; i++)
1797 s = (Statement *)cases.data[i];
1798 s = new CaseStatement(0, new IntegerExp(i + 2), s);
1799 a->push(s);
1802 s = new CompoundStatement(loc, a);
1803 s = new SwitchStatement(loc, e, s);
1804 s = s->semantic(sc);
1806 break;
1809 default:
1810 error("foreach: %s is not an aggregate type", aggr->type->toChars());
1811 break;
1813 sc->noctor--;
1814 sc->pop();
1815 return s;
1818 int ForeachStatement::hasBreak()
1820 return TRUE;
1823 int ForeachStatement::hasContinue()
1825 return TRUE;
1828 int ForeachStatement::usesEH()
1830 return body->usesEH();
1833 int ForeachStatement::blockExit()
1834 { int result = BEfallthru;
1836 if (aggr->canThrow())
1837 result |= BEthrow;
1839 if (body)
1841 result |= body->blockExit() & ~(BEbreak | BEcontinue);
1843 return result;
1846 int ForeachStatement::fallOffEnd()
1848 if (body)
1849 body->fallOffEnd();
1850 return TRUE;
1853 int ForeachStatement::comeFrom()
1855 if (body)
1856 return body->comeFrom();
1857 return FALSE;
1860 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1862 buf->writestring(Token::toChars(op));
1863 buf->writestring(" (");
1864 for (int i = 0; i < arguments->dim; i++)
1866 Argument *a = (Argument *)arguments->data[i];
1867 if (i)
1868 buf->writestring(", ");
1869 if (a->storageClass & STCref)
1870 buf->writestring((global.params.Dversion == 1)
1871 ? (char*)"inout " : (char*)"ref ");
1872 if (a->type)
1873 a->type->toCBuffer(buf, a->ident, hgs);
1874 else
1875 buf->writestring(a->ident->toChars());
1877 buf->writestring("; ");
1878 aggr->toCBuffer(buf, hgs);
1879 buf->writebyte(')');
1880 buf->writenl();
1881 buf->writebyte('{');
1882 buf->writenl();
1883 if (body)
1884 body->toCBuffer(buf, hgs);
1885 buf->writebyte('}');
1886 buf->writenl();
1889 /**************************** ForeachRangeStatement ***************************/
1891 ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg,
1892 Expression *lwr, Expression *upr, Statement *body)
1893 : Statement(loc)
1895 this->op = op;
1896 this->arg = arg;
1897 this->lwr = lwr;
1898 this->upr = upr;
1899 this->body = body;
1901 this->key = NULL;
1904 Statement *ForeachRangeStatement::syntaxCopy()
1906 ForeachRangeStatement *s = new ForeachRangeStatement(loc, op,
1907 arg->syntaxCopy(),
1908 lwr->syntaxCopy(),
1909 upr->syntaxCopy(),
1910 body ? body->syntaxCopy() : NULL);
1911 return s;
1914 Statement *ForeachRangeStatement::semantic(Scope *sc)
1916 //printf("ForeachRangeStatement::semantic() %p\n", this);
1917 ScopeDsymbol *sym;
1918 Statement *s = this;
1920 lwr = lwr->semantic(sc);
1921 lwr = resolveProperties(sc, lwr);
1922 lwr = lwr->optimize(WANTvalue);
1923 if (!lwr->type)
1925 error("invalid range lower bound %s", lwr->toChars());
1926 return this;
1929 upr = upr->semantic(sc);
1930 upr = resolveProperties(sc, upr);
1931 upr = upr->optimize(WANTvalue);
1932 if (!upr->type)
1934 error("invalid range upper bound %s", upr->toChars());
1935 return this;
1938 if (arg->type)
1940 lwr = lwr->implicitCastTo(sc, arg->type);
1941 upr = upr->implicitCastTo(sc, arg->type);
1943 else
1945 /* Must infer types from lwr and upr
1947 AddExp ea(loc, lwr, upr);
1948 ea.typeCombine(sc);
1949 arg->type = ea.type;
1950 lwr = ea.e1;
1951 upr = ea.e2;
1953 if (!arg->type->isscalar())
1954 error("%s is not a scalar type", arg->type->toChars());
1956 sym = new ScopeDsymbol();
1957 sym->parent = sc->scopesym;
1958 sc = sc->push(sym);
1960 sc->noctor++;
1962 key = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1963 DeclarationExp *de = new DeclarationExp(loc, key);
1964 de->semantic(sc);
1966 if (key->storage_class)
1967 error("foreach range: key cannot have storage class");
1969 sc->sbreak = this;
1970 sc->scontinue = this;
1971 body = body->semantic(sc);
1973 sc->noctor--;
1974 sc->pop();
1975 return s;
1978 int ForeachRangeStatement::hasBreak()
1980 return TRUE;
1983 int ForeachRangeStatement::hasContinue()
1985 return TRUE;
1988 int ForeachRangeStatement::usesEH()
1990 return body->usesEH();
1993 int ForeachRangeStatement::blockExit()
1994 { int result = BEfallthru;
1996 if (lwr && lwr->canThrow())
1997 result |= BEthrow;
1998 else if (upr && upr->canThrow())
1999 result |= BEthrow;
2001 if (body)
2003 result |= body->blockExit() & ~(BEbreak | BEcontinue);
2005 return result;
2008 int ForeachRangeStatement::fallOffEnd()
2010 if (body)
2011 body->fallOffEnd();
2012 return TRUE;
2015 int ForeachRangeStatement::comeFrom()
2017 if (body)
2018 return body->comeFrom();
2019 return FALSE;
2022 void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2024 buf->writestring(Token::toChars(op));
2025 buf->writestring(" (");
2027 if (arg->type)
2028 arg->type->toCBuffer(buf, arg->ident, hgs);
2029 else
2030 buf->writestring(arg->ident->toChars());
2032 buf->writestring("; ");
2033 lwr->toCBuffer(buf, hgs);
2034 buf->writestring(" .. ");
2035 upr->toCBuffer(buf, hgs);
2036 buf->writebyte(')');
2037 buf->writenl();
2038 buf->writebyte('{');
2039 buf->writenl();
2040 if (body)
2041 body->toCBuffer(buf, hgs);
2042 buf->writebyte('}');
2043 buf->writenl();
2046 /******************************** IfStatement ***************************/
2048 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
2049 : Statement(loc)
2051 this->arg = arg;
2052 this->condition = condition;
2053 this->ifbody = ifbody;
2054 this->elsebody = elsebody;
2055 this->match = NULL;
2058 Statement *IfStatement::syntaxCopy()
2060 Statement *i = NULL;
2061 if (ifbody)
2062 i = ifbody->syntaxCopy();
2064 Statement *e = NULL;
2065 if (elsebody)
2066 e = elsebody->syntaxCopy();
2068 Argument *a = arg ? arg->syntaxCopy() : NULL;
2069 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
2070 return s;
2073 Statement *IfStatement::semantic(Scope *sc)
2075 condition = condition->semantic(sc);
2076 condition = resolveProperties(sc, condition);
2077 condition = condition->checkToBoolean();
2079 // If we can short-circuit evaluate the if statement, don't do the
2080 // semantic analysis of the skipped code.
2081 // This feature allows a limited form of conditional compilation.
2082 condition = condition->optimize(WANTflags);
2084 // Evaluate at runtime
2085 unsigned cs0 = sc->callSuper;
2086 unsigned cs1;
2088 Scope *scd;
2089 if (arg)
2090 { /* Declare arg, which we will set to be the
2091 * result of condition.
2093 ScopeDsymbol *sym = new ScopeDsymbol();
2094 sym->parent = sc->scopesym;
2095 scd = sc->push(sym);
2097 Type *t = arg->type ? arg->type : condition->type;
2098 match = new VarDeclaration(loc, t->maybe(true), arg->ident, NULL);
2099 match->noauto = 1;
2100 match->semantic(scd);
2101 if (!scd->insert(match))
2102 assert(0);
2103 match->parent = sc->func;
2105 /* Generate:
2106 * (arg = condition)
2108 VarExp *v = new VarExp(0, match);
2109 condition = new AssignExp(loc, v, condition);
2110 condition = condition->semantic(scd);
2112 if (match && match->type->ty == Tmaybe)
2114 // Matched object cannot be null in the then block
2115 // (and isn't in scope in the else)
2116 match->type = match->type->nextOf();
2119 else
2120 scd = sc->push();
2121 ifbody = ifbody->semantic(scd);
2122 scd->pop();
2124 cs1 = sc->callSuper;
2125 sc->callSuper = cs0;
2126 if (elsebody)
2127 elsebody = elsebody->semanticScope(sc, NULL, NULL);
2128 sc->mergeCallSuper(loc, cs1);
2130 return this;
2133 int IfStatement::usesEH()
2135 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2138 int IfStatement::blockExit()
2140 //printf("IfStatement::blockExit(%p)\n", this);
2142 int result = BEnone;
2143 if (condition->canThrow())
2144 result |= BEthrow;
2145 if (ifbody)
2146 result |= ifbody->blockExit();
2147 else
2148 result |= BEfallthru;
2149 if (elsebody)
2150 result |= elsebody->blockExit();
2151 else
2152 result |= BEfallthru;
2153 //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
2154 return result;
2157 int IfStatement::fallOffEnd()
2159 if (!ifbody || ifbody->fallOffEnd() ||
2160 !elsebody || elsebody->fallOffEnd())
2161 return TRUE;
2162 return FALSE;
2166 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2168 buf->writestring("if (");
2169 if (arg)
2171 if (arg->type)
2172 arg->type->toCBuffer(buf, arg->ident, hgs);
2173 else
2174 buf->writestring(arg->ident->toChars());
2175 buf->writebyte(';');
2177 condition->toCBuffer(buf, hgs);
2178 buf->writebyte(')');
2179 buf->writenl();
2180 ifbody->toCBuffer(buf, hgs);
2181 if (elsebody)
2182 { buf->writestring("else");
2183 buf->writenl();
2184 elsebody->toCBuffer(buf, hgs);
2188 /******************************** ConditionalStatement ***************************/
2190 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
2191 : Statement(loc)
2193 this->condition = condition;
2194 this->ifbody = ifbody;
2195 this->elsebody = elsebody;
2198 Statement *ConditionalStatement::syntaxCopy()
2200 Statement *e = NULL;
2201 if (elsebody)
2202 e = elsebody->syntaxCopy();
2203 ConditionalStatement *s = new ConditionalStatement(loc,
2204 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
2205 return s;
2208 Statement *ConditionalStatement::semantic(Scope *sc)
2210 //printf("ConditionalStatement::semantic()\n");
2212 // If we can short-circuit evaluate the if statement, don't do the
2213 // semantic analysis of the skipped code.
2214 // This feature allows a limited form of conditional compilation.
2215 if (condition->include(sc, NULL))
2217 ifbody = ifbody->semantic(sc);
2218 return ifbody;
2220 else
2222 if (elsebody)
2223 elsebody = elsebody->semantic(sc);
2224 return elsebody;
2228 Statements *ConditionalStatement::flatten(Scope *sc)
2230 Statement *s;
2232 if (condition->include(sc, NULL))
2233 s = ifbody;
2234 else
2235 s = elsebody;
2237 Statements *a = new Statements();
2238 a->push(s);
2239 return a;
2242 int ConditionalStatement::usesEH()
2244 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2247 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2249 condition->toCBuffer(buf, hgs);
2250 buf->writenl();
2251 if (ifbody)
2252 ifbody->toCBuffer(buf, hgs);
2253 if (elsebody)
2255 buf->writestring("else");
2256 buf->writenl();
2257 elsebody->toCBuffer(buf, hgs);
2259 buf->writenl();
2263 /******************************** PragmaStatement ***************************/
2265 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
2266 : Statement(loc)
2268 this->ident = ident;
2269 this->args = args;
2270 this->body = body;
2273 Statement *PragmaStatement::syntaxCopy()
2275 Statement *b = NULL;
2276 if (body)
2277 b = body->syntaxCopy();
2278 PragmaStatement *s = new PragmaStatement(loc,
2279 ident, Expression::arraySyntaxCopy(args), b);
2280 return s;
2283 Statement *PragmaStatement::semantic(Scope *sc)
2284 { // Should be merged with PragmaDeclaration
2285 //printf("PragmaStatement::semantic() %s\n", toChars());
2286 //printf("body = %p\n", body);
2287 if (ident == Id::msg)
2289 if (args)
2291 for (size_t i = 0; i < args->dim; i++)
2293 Expression *e = (Expression *)args->data[i];
2295 e = e->semantic(sc);
2296 e = e->optimize(WANTvalue | WANTinterpret);
2297 if (e->op == TOKstring)
2299 StringExp *se = (StringExp *)e;
2300 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
2302 else
2303 error("string expected for message, not '%s'", e->toChars());
2305 fprintf(stdmsg, "\n");
2308 else if (ident == Id::lib)
2310 if (!args || args->dim != 1)
2311 error("string expected for library name");
2312 else
2314 Expression *e = (Expression *)args->data[0];
2316 e = e->semantic(sc);
2317 e = e->optimize(WANTvalue | WANTinterpret);
2318 args->data[0] = (void *)e;
2319 if (e->op != TOKstring)
2320 error("string expected for library name, not '%s'", e->toChars());
2321 else if (global.params.verbose)
2323 StringExp *se = (StringExp *)e;
2324 char *name = (char *)mem.malloc(se->len + 1);
2325 memcpy(name, se->string, se->len);
2326 name[se->len] = 0;
2327 printf("library %s\n", name);
2328 mem.free(name);
2332 else if (ident == Id::startaddress)
2334 if (!args || args->dim != 1)
2335 error("function name expected for start address");
2336 else
2338 Expression *e = (Expression *)args->data[0];
2339 e = e->semantic(sc);
2340 e = e->optimize(WANTvalue | WANTinterpret);
2341 args->data[0] = (void *)e;
2342 Dsymbol *sa = getDsymbol(e);
2343 if (!sa || !sa->isFuncDeclaration())
2344 error("function name expected for start address, not '%s'", e->toChars());
2345 if (body)
2347 body = body->semantic(sc);
2349 return this;
2352 else
2353 error("unrecognized pragma(%s)", ident->toChars());
2355 if (body)
2357 body = body->semantic(sc);
2359 return body;
2362 int PragmaStatement::usesEH()
2364 return body && body->usesEH();
2367 int PragmaStatement::blockExit()
2369 int result = BEfallthru;
2370 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru
2371 if (arrayExpressionCanThrow(args))
2372 result |= BEthrow;
2373 if (body)
2374 result |= body->blockExit();
2375 #endif
2376 return result;
2379 int PragmaStatement::fallOffEnd()
2381 if (body)
2382 return body->fallOffEnd();
2383 return TRUE;
2386 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2388 buf->writestring("pragma (");
2389 buf->writestring(ident->toChars());
2390 if (args && args->dim)
2392 buf->writestring(", ");
2393 argsToCBuffer(buf, args, hgs);
2395 buf->writeByte(')');
2396 if (body)
2398 buf->writenl();
2399 buf->writeByte('{');
2400 buf->writenl();
2402 body->toCBuffer(buf, hgs);
2404 buf->writeByte('}');
2405 buf->writenl();
2407 else
2409 buf->writeByte(';');
2410 buf->writenl();
2415 /******************************** LogStatement ***************************/
2417 LogStatement::LogStatement(Loc loc, int level, Expressions *args)
2418 : Statement(loc)
2420 this->level = level;
2421 this->args = args;
2424 Statement *LogStatement::syntaxCopy()
2426 Expressions *copied_args = Expression::arraySyntaxCopy(args);
2427 LogStatement *s = new LogStatement(loc, level, copied_args);
2428 return s;
2431 Statement *LogStatement::semantic(Scope *sc)
2433 Expression *logger = new GetLoggerExp(loc);
2434 Type *type = NULL;
2436 for (Dsymbol *s = sc->parent; s; s = s->parent)
2438 ClassDeclaration *cd;
2439 StructDeclaration *sd;
2441 cd = s->isClassDeclaration();
2442 if (cd)
2444 type = cd->type;
2445 break;
2449 if (type == NULL) {
2450 // We're a top-level function. Generate log messages from the module
2451 args->shift(new StringExp(loc, strdup(sc->module->ident->string)));
2452 } else {
2453 args->shift(new StringExp(loc, type->toChars()));
2456 args->shift(new IntegerExp(loc, level, Type::tint32));
2457 Expression *callLogger = new CallExp(loc, logger, args);
2459 Statement *s = new ExpStatement(loc, callLogger);
2461 return s->semantic(sc);
2464 void LogStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2466 char *l;
2467 switch (level) {
2468 case 0: l = "log_debug"; break;
2469 case 1: l = "log_info"; break;
2470 case 2: l = "log_warning"; break;
2471 case 3: l = "log_error"; break;
2472 default:
2473 error("Unknown log level %d", level);
2474 l = "log_UNKNOWN";
2476 buf->writestring(l);
2477 buf->writeByte('(');
2478 argsToCBuffer(buf, args, hgs);
2479 buf->writeByte(')');
2480 buf->writenl();
2483 /******************************** StaticAssertStatement ***************************/
2485 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2486 : Statement(sa->loc)
2488 this->sa = sa;
2491 Statement *StaticAssertStatement::syntaxCopy()
2493 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2494 return s;
2497 Statement *StaticAssertStatement::semantic(Scope *sc)
2499 sa->semantic2(sc);
2500 return NULL;
2503 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2505 sa->toCBuffer(buf, hgs);
2509 /******************************** SwitchStatement ***************************/
2511 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2512 : Statement(loc)
2514 condition = c;
2515 body = b;
2516 sdefault = NULL;
2517 tf = NULL;
2518 cases = NULL;
2519 hasNoDefault = 0;
2520 hasVars = 0;
2523 Statement *SwitchStatement::syntaxCopy()
2525 SwitchStatement *s = new SwitchStatement(loc,
2526 condition->syntaxCopy(), body->syntaxCopy());
2527 return s;
2530 Statement *SwitchStatement::semantic(Scope *sc)
2532 //printf("SwitchStatement::semantic(%p)\n", this);
2533 tf = sc->tf;
2534 assert(!cases); // ensure semantic() is only run once
2535 condition = condition->semantic(sc);
2536 condition = resolveProperties(sc, condition);
2537 if (condition->type->isString())
2539 // If it's not an array, cast it to one
2540 if (condition->type->ty != Tarray)
2542 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2544 condition->type = condition->type->constOf();
2546 else
2547 { condition = condition->integralPromotions(sc);
2548 condition->checkIntegral();
2550 condition = condition->optimize(WANTvalue);
2552 sc = sc->push();
2553 sc->sbreak = this;
2554 sc->sw = this;
2556 cases = new Array();
2557 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2558 body = body->semantic(sc);
2559 sc->noctor--;
2561 // Resolve any goto case's with exp
2562 for (int i = 0; i < gotoCases.dim; i++)
2564 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2566 if (!gcs->exp)
2568 gcs->error("no case statement following goto case;");
2569 break;
2572 for (Scope *scx = sc; scx; scx = scx->enclosing)
2574 if (!scx->sw)
2575 continue;
2576 for (int j = 0; j < scx->sw->cases->dim; j++)
2578 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2580 if (cs->exp->equals(gcs->exp))
2582 gcs->cs = cs;
2583 goto Lfoundcase;
2587 gcs->error("case %s not found", gcs->exp->toChars());
2589 Lfoundcase:
2593 if (!sc->sw->sdefault)
2594 { hasNoDefault = 1;
2596 if (global.params.warnings)
2597 { fprintf(stdmsg, "warning - ");
2598 error("switch statement has no default");
2601 // Generate runtime error if the default is hit
2602 Statements *a = new Statements();
2603 CompoundStatement *cs;
2604 Statement *s;
2606 if (global.params.useSwitchError)
2607 s = new SwitchErrorStatement(loc);
2608 else
2609 { Expression *e = new HaltExp(loc);
2610 s = new ExpStatement(loc, e);
2613 a->reserve(4);
2614 a->push(body);
2615 a->push(new BreakStatement(loc, NULL));
2616 sc->sw->sdefault = new DefaultStatement(loc, s);
2617 a->push(sc->sw->sdefault);
2618 cs = new CompoundStatement(loc, a);
2619 body = cs;
2622 sc->pop();
2623 return this;
2626 int SwitchStatement::hasBreak()
2628 return TRUE;
2631 int SwitchStatement::usesEH()
2633 return body ? body->usesEH() : 0;
2636 int SwitchStatement::blockExit()
2637 { int result = BEnone;
2638 if (condition->canThrow())
2639 result |= BEthrow;
2641 if (body)
2642 { result |= body->blockExit();
2643 if (result & BEbreak)
2644 { result |= BEfallthru;
2645 result &= ~BEbreak;
2648 else
2649 result |= BEfallthru;
2651 return result;
2654 int SwitchStatement::fallOffEnd()
2656 if (body)
2657 body->fallOffEnd();
2658 return TRUE; // need to do this better
2661 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2663 buf->writestring("switch (");
2664 condition->toCBuffer(buf, hgs);
2665 buf->writebyte(')');
2666 buf->writenl();
2667 if (body)
2669 if (!body->isScopeStatement())
2670 { buf->writebyte('{');
2671 buf->writenl();
2672 body->toCBuffer(buf, hgs);
2673 buf->writebyte('}');
2674 buf->writenl();
2676 else
2678 body->toCBuffer(buf, hgs);
2683 /******************************** CaseStatement ***************************/
2685 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2686 : Statement(loc)
2688 this->exp = exp;
2689 this->statement = s;
2690 index = 0;
2691 cblock = NULL;
2694 Statement *CaseStatement::syntaxCopy()
2696 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2697 return s;
2700 Statement *CaseStatement::semantic(Scope *sc)
2701 { SwitchStatement *sw = sc->sw;
2703 //printf("CaseStatement::semantic() %s\n", toChars());
2704 exp = exp->semantic(sc);
2705 if (sw)
2707 exp = exp->implicitCastTo(sc, sw->condition->type);
2708 exp = exp->optimize(WANTvalue | WANTinterpret);
2710 /* This is where variables are allowed as case expressions.
2712 if (exp->op == TOKvar)
2713 { VarExp *ve = (VarExp *)exp;
2714 VarDeclaration *v = ve->var->isVarDeclaration();
2715 Type *t = exp->type->toBasetype();
2716 if (v && (t->isintegral() || t->ty == Tclass))
2717 { /* Flag that we need to do special code generation
2718 * for this, i.e. generate a sequence of if-then-else
2720 sw->hasVars = 1;
2721 goto L1;
2725 if (exp->op != TOKstring && exp->op != TOKint64)
2727 error("case must be a string or an integral constant, not %s", exp->toChars());
2728 exp = new IntegerExp(0);
2732 for (int i = 0; i < sw->cases->dim; i++)
2734 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2736 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2737 if (cs->exp->equals(exp))
2738 { error("duplicate case %s in switch statement", exp->toChars());
2739 break;
2743 sw->cases->push(this);
2745 // Resolve any goto case's with no exp to this case statement
2746 for (int i = 0; i < sw->gotoCases.dim; i++)
2748 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2750 if (!gcs->exp)
2752 gcs->cs = this;
2753 sw->gotoCases.remove(i); // remove from array
2757 if (sc->sw->tf != sc->tf)
2758 error("switch and case are in different finally blocks");
2760 else
2761 error("case not in switch statement");
2762 statement = statement->semantic(sc);
2763 return this;
2766 int CaseStatement::compare(Object *obj)
2768 // Sort cases so we can do an efficient lookup
2769 CaseStatement *cs2 = (CaseStatement *)(obj);
2771 return exp->compare(cs2->exp);
2774 int CaseStatement::usesEH()
2776 return statement->usesEH();
2779 int CaseStatement::blockExit()
2781 // Assume the worst
2782 return BEany;
2785 int CaseStatement::fallOffEnd()
2787 return statement->fallOffEnd();
2790 int CaseStatement::comeFrom()
2792 return TRUE;
2795 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2797 buf->writestring("case ");
2798 exp->toCBuffer(buf, hgs);
2799 buf->writebyte(':');
2800 buf->writenl();
2801 statement->toCBuffer(buf, hgs);
2804 /******************************** DefaultStatement ***************************/
2806 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2807 : Statement(loc)
2809 this->statement = s;
2810 #if IN_GCC
2811 cblock = NULL;
2812 #endif
2815 Statement *DefaultStatement::syntaxCopy()
2817 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2818 return s;
2821 Statement *DefaultStatement::semantic(Scope *sc)
2823 //printf("DefaultStatement::semantic()\n");
2824 if (sc->sw)
2826 if (sc->sw->sdefault)
2828 error("switch statement already has a default");
2830 sc->sw->sdefault = this;
2832 if (sc->sw->tf != sc->tf)
2833 error("switch and default are in different finally blocks");
2835 else
2836 error("default not in switch statement");
2837 statement = statement->semantic(sc);
2838 return this;
2841 int DefaultStatement::usesEH()
2843 return statement->usesEH();
2846 int DefaultStatement::blockExit()
2848 // Assume the worst
2849 return BEany;
2852 int DefaultStatement::fallOffEnd()
2854 return statement->fallOffEnd();
2857 int DefaultStatement::comeFrom()
2859 return TRUE;
2862 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2864 buf->writestring("default:\n");
2865 statement->toCBuffer(buf, hgs);
2868 /******************************** GotoDefaultStatement ***************************/
2870 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2871 : Statement(loc)
2873 sw = NULL;
2876 Statement *GotoDefaultStatement::syntaxCopy()
2878 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2879 return s;
2882 Statement *GotoDefaultStatement::semantic(Scope *sc)
2884 sw = sc->sw;
2885 if (!sw)
2886 error("goto default not in switch statement");
2887 return this;
2890 int GotoDefaultStatement::blockExit()
2892 return BEgoto;
2895 int GotoDefaultStatement::fallOffEnd()
2897 return FALSE;
2900 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2902 buf->writestring("goto default;\n");
2905 /******************************** GotoCaseStatement ***************************/
2907 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2908 : Statement(loc)
2910 cs = NULL;
2911 this->exp = exp;
2914 Statement *GotoCaseStatement::syntaxCopy()
2916 Expression *e = exp ? exp->syntaxCopy() : NULL;
2917 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2918 return s;
2921 Statement *GotoCaseStatement::semantic(Scope *sc)
2923 if (exp)
2924 exp = exp->semantic(sc);
2926 if (!sc->sw)
2927 error("goto case not in switch statement");
2928 else
2930 sc->sw->gotoCases.push(this);
2931 if (exp)
2933 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2934 exp = exp->optimize(WANTvalue);
2937 return this;
2940 int GotoCaseStatement::blockExit()
2942 return BEgoto;
2945 int GotoCaseStatement::fallOffEnd()
2947 return FALSE;
2950 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2952 buf->writestring("goto case");
2953 if (exp)
2954 { buf->writebyte(' ');
2955 exp->toCBuffer(buf, hgs);
2957 buf->writebyte(';');
2958 buf->writenl();
2961 /******************************** SwitchErrorStatement ***************************/
2963 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2964 : Statement(loc)
2968 int SwitchErrorStatement::blockExit()
2970 return BEthrow;
2973 int SwitchErrorStatement::fallOffEnd()
2975 return FALSE;
2978 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2980 buf->writestring("SwitchErrorStatement::toCBuffer()");
2981 buf->writenl();
2984 /******************************** ReturnStatement ***************************/
2986 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2987 : Statement(loc)
2989 this->exp = exp;
2992 Statement *ReturnStatement::syntaxCopy()
2994 Expression *e = NULL;
2995 if (exp)
2996 e = exp->syntaxCopy();
2997 ReturnStatement *s = new ReturnStatement(loc, e);
2998 return s;
3001 Statement *ReturnStatement::semantic(Scope *sc)
3003 //printf("ReturnStatement::semantic() %s\n", toChars());
3005 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3006 Scope *scx = sc;
3007 int implicit0 = 0;
3009 if (sc->fes)
3011 // Find scope of function foreach is in
3012 for (; 1; scx = scx->enclosing)
3014 assert(scx);
3015 if (scx->func != fd)
3016 { fd = scx->func; // fd is now function enclosing foreach
3017 break;
3022 Type *tret = fd->type->nextOf();
3023 if (fd->tintro)
3024 tret = fd->tintro->nextOf();
3025 Type *tbret = NULL;
3027 if (tret)
3028 tbret = tret->toBasetype();
3030 // main() returns 0, even if it returns void
3031 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
3032 { implicit0 = 1;
3033 exp = new IntegerExp(0);
3036 if (sc->incontract || scx->incontract)
3037 error("return statements cannot be in contracts");
3038 if (sc->tf || scx->tf)
3039 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
3041 if (fd->isCtorDeclaration())
3043 // Constructors implicitly do:
3044 // return this;
3045 if (exp && exp->op != TOKthis)
3046 error("cannot return expression from constructor");
3047 exp = new ThisExp(0);
3050 if (!exp)
3051 fd->nrvo_can = 0;
3053 if (exp)
3055 fd->hasReturnExp |= 1;
3057 exp = exp->semantic(sc);
3058 exp = resolveProperties(sc, exp);
3059 exp = exp->optimize(WANTvalue);
3061 if (fd->nrvo_can && exp->op == TOKvar)
3062 { VarExp *ve = (VarExp *)exp;
3063 VarDeclaration *v = ve->var->isVarDeclaration();
3065 if (!v || v->isOut() || v->isRef())
3066 fd->nrvo_can = 0;
3067 else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor)
3068 // Struct being returned has destructors
3069 fd->nrvo_can = 0;
3070 else if (fd->nrvo_var == NULL)
3071 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
3072 { //printf("Setting nrvo to %s\n", v->toChars());
3073 fd->nrvo_var = v;
3075 else
3076 fd->nrvo_can = 0;
3078 else if (fd->nrvo_var != v)
3079 fd->nrvo_can = 0;
3081 else
3082 fd->nrvo_can = 0;
3084 if (fd->returnLabel && tbret->ty != Tvoid)
3087 else if (fd->inferRetType)
3089 if (fd->type->nextOf())
3091 if (!exp->type->equals(fd->type->nextOf()))
3092 error("mismatched function return type inference of %s and %s",
3093 exp->type->toChars(), fd->type->nextOf()->toChars());
3095 else
3097 ((TypeFunction *)fd->type)->next = exp->type;
3098 fd->type = fd->type->semantic(loc, sc);
3099 if (!fd->tintro)
3100 { tret = fd->type->nextOf();
3101 tbret = tret->toBasetype();
3105 else if (tbret->ty != Tvoid)
3107 exp = exp->implicitCastTo(sc, tret);
3110 else if (fd->inferRetType)
3112 if (fd->type->nextOf())
3114 if (fd->type->nextOf()->ty != Tvoid)
3115 error("mismatched function return type inference of void and %s",
3116 fd->type->nextOf()->toChars());
3118 else
3120 ((TypeFunction *)fd->type)->next = Type::tvoid;
3121 fd->type = fd->type->semantic(loc, sc);
3122 if (!fd->tintro)
3123 { tret = Type::tvoid;
3124 tbret = tret;
3128 else if (tbret->ty != Tvoid) // if non-void return
3129 error("return expression expected");
3131 if (sc->fes)
3133 Statement *s;
3135 if (exp && !implicit0)
3137 exp = exp->implicitCastTo(sc, tret);
3139 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
3140 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
3141 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
3142 exp->op == TOKstring)
3144 sc->fes->cases.push(this);
3145 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3147 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
3149 Statement *s1;
3150 Statement *s2;
3152 s = new ReturnStatement(0, NULL);
3153 sc->fes->cases.push(s);
3155 // Construct: { exp; return cases.dim + 1; }
3156 s1 = new ExpStatement(loc, exp);
3157 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3158 s = new CompoundStatement(loc, s1, s2);
3160 else
3162 VarExp *v;
3163 Statement *s1;
3164 Statement *s2;
3166 // Construct: return vresult;
3167 if (!fd->vresult)
3168 { VarDeclaration *v;
3170 v = new VarDeclaration(loc, tret, Id::result, NULL);
3171 v->noauto = 1;
3172 v->semantic(scx);
3173 if (!scx->insert(v))
3174 assert(0);
3175 v->parent = fd;
3176 fd->vresult = v;
3179 v = new VarExp(0, fd->vresult);
3180 s = new ReturnStatement(0, v);
3181 sc->fes->cases.push(s);
3183 // Construct: { vresult = exp; return cases.dim + 1; }
3184 v = new VarExp(0, fd->vresult);
3185 exp = new AssignExp(loc, v, exp);
3186 exp = exp->semantic(sc);
3187 s1 = new ExpStatement(loc, exp);
3188 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3189 s = new CompoundStatement(loc, s1, s2);
3191 return s;
3194 if (exp)
3196 if (fd->returnLabel && tbret->ty != Tvoid)
3198 assert(fd->vresult);
3199 VarExp *v = new VarExp(0, fd->vresult);
3201 exp = new AssignExp(loc, v, exp);
3202 exp = exp->semantic(sc);
3204 //exp->dump(0);
3205 //exp->print();
3206 exp->checkEscape();
3209 /* BUG: need to issue an error on:
3210 * this
3211 * { if (x) return;
3212 * super();
3216 if (sc->callSuper & CSXany_ctor &&
3217 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
3218 error("return without calling constructor");
3220 sc->callSuper |= CSXreturn;
3222 // See if all returns are instead to be replaced with a goto returnLabel;
3223 if (fd->returnLabel)
3225 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
3227 gs->label = fd->returnLabel;
3228 if (exp)
3229 { Statement *s;
3231 s = new ExpStatement(0, exp);
3232 return new CompoundStatement(loc, s, gs);
3234 return gs;
3237 if (exp && tbret->ty == Tvoid && !fd->isMain())
3238 { Statement *s;
3240 s = new ExpStatement(loc, exp);
3241 loc = 0;
3242 exp = NULL;
3243 return new CompoundStatement(loc, s, this);
3246 return this;
3249 int ReturnStatement::blockExit()
3250 { int result = BEreturn;
3252 if (exp && exp->canThrow())
3253 result |= BEthrow;
3254 return result;
3257 int ReturnStatement::fallOffEnd()
3259 return FALSE;
3262 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3264 buf->printf("return ");
3265 if (exp)
3266 exp->toCBuffer(buf, hgs);
3267 buf->writeByte(';');
3268 buf->writenl();
3271 /******************************** BreakStatement ***************************/
3273 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
3274 : Statement(loc)
3276 this->ident = ident;
3279 Statement *BreakStatement::syntaxCopy()
3281 BreakStatement *s = new BreakStatement(loc, ident);
3282 return s;
3285 Statement *BreakStatement::semantic(Scope *sc)
3287 //printf("BreakStatement::semantic()\n");
3288 // If:
3289 // break Identifier;
3290 if (ident)
3292 Scope *scx;
3293 FuncDeclaration *thisfunc = sc->func;
3295 for (scx = sc; scx; scx = scx->enclosing)
3297 LabelStatement *ls;
3299 if (scx->func != thisfunc) // if in enclosing function
3301 if (sc->fes) // if this is the body of a foreach
3303 /* Post this statement to the fes, and replace
3304 * it with a return value that caller will put into
3305 * a switch. Caller will figure out where the break
3306 * label actually is.
3307 * Case numbers start with 2, not 0, as 0 is continue
3308 * and 1 is break.
3310 Statement *s;
3311 sc->fes->cases.push(this);
3312 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3313 return s;
3315 break; // can't break to it
3318 ls = scx->slabel;
3319 if (ls && ls->ident == ident)
3321 Statement *s = ls->statement;
3323 if (!s->hasBreak())
3324 error("label '%s' has no break", ident->toChars());
3325 if (ls->tf != sc->tf)
3326 error("cannot break out of finally block");
3327 return this;
3330 error("enclosing label '%s' for break not found", ident->toChars());
3332 else if (!sc->sbreak)
3334 if (sc->fes)
3335 { Statement *s;
3337 // Replace break; with return 1;
3338 s = new ReturnStatement(0, new IntegerExp(1));
3339 return s;
3341 error("break is not inside a loop or switch");
3343 return this;
3346 int BreakStatement::blockExit()
3348 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
3349 return ident ? BEgoto : BEbreak;
3352 int BreakStatement::fallOffEnd()
3354 return FALSE;
3357 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3359 buf->writestring("break");
3360 if (ident)
3361 { buf->writebyte(' ');
3362 buf->writestring(ident->toChars());
3364 buf->writebyte(';');
3365 buf->writenl();
3368 /******************************** ContinueStatement ***************************/
3370 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
3371 : Statement(loc)
3373 this->ident = ident;
3376 Statement *ContinueStatement::syntaxCopy()
3378 ContinueStatement *s = new ContinueStatement(loc, ident);
3379 return s;
3382 Statement *ContinueStatement::semantic(Scope *sc)
3384 //printf("ContinueStatement::semantic() %p\n", this);
3385 if (ident)
3387 Scope *scx;
3388 FuncDeclaration *thisfunc = sc->func;
3390 for (scx = sc; scx; scx = scx->enclosing)
3392 LabelStatement *ls;
3394 if (scx->func != thisfunc) // if in enclosing function
3396 if (sc->fes) // if this is the body of a foreach
3398 for (; scx; scx = scx->enclosing)
3400 ls = scx->slabel;
3401 if (ls && ls->ident == ident && ls->statement == sc->fes)
3403 // Replace continue ident; with return 0;
3404 return new ReturnStatement(0, new IntegerExp(0));
3408 /* Post this statement to the fes, and replace
3409 * it with a return value that caller will put into
3410 * a switch. Caller will figure out where the break
3411 * label actually is.
3412 * Case numbers start with 2, not 0, as 0 is continue
3413 * and 1 is break.
3415 Statement *s;
3416 sc->fes->cases.push(this);
3417 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3418 return s;
3420 break; // can't continue to it
3423 ls = scx->slabel;
3424 if (ls && ls->ident == ident)
3426 Statement *s = ls->statement;
3428 if (!s->hasContinue())
3429 error("label '%s' has no continue", ident->toChars());
3430 if (ls->tf != sc->tf)
3431 error("cannot continue out of finally block");
3432 return this;
3435 error("enclosing label '%s' for continue not found", ident->toChars());
3437 else if (!sc->scontinue)
3439 if (sc->fes)
3440 { Statement *s;
3442 // Replace continue; with return 0;
3443 s = new ReturnStatement(0, new IntegerExp(0));
3444 return s;
3446 error("continue is not inside a loop");
3448 return this;
3451 int ContinueStatement::blockExit()
3453 return ident ? BEgoto : BEcontinue;
3456 int ContinueStatement::fallOffEnd()
3458 return FALSE;
3461 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3463 buf->writestring("continue");
3464 if (ident)
3465 { buf->writebyte(' ');
3466 buf->writestring(ident->toChars());
3468 buf->writebyte(';');
3469 buf->writenl();
3472 /******************************** SynchronizedStatement ***************************/
3474 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
3475 : Statement(loc)
3477 this->exp = exp;
3478 this->body = body;
3479 this->esync = NULL;
3482 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
3483 : Statement(loc)
3485 this->exp = NULL;
3486 this->body = body;
3487 this->esync = esync;
3490 Statement *SynchronizedStatement::syntaxCopy()
3492 Expression *e = exp ? exp->syntaxCopy() : NULL;
3493 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
3494 return s;
3497 Statement *SynchronizedStatement::semantic(Scope *sc)
3499 if (exp)
3500 { ClassDeclaration *cd;
3502 exp = exp->semantic(sc);
3503 exp = resolveProperties(sc, exp);
3504 cd = exp->type->isClassHandle();
3505 if (!cd)
3506 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
3507 else if (cd->isInterfaceDeclaration())
3508 { Type *t = new TypeIdentifier(0, Id::Object);
3510 t = t->semantic(0, sc);
3511 exp = new CastExp(loc, exp, t);
3512 exp = exp->semantic(sc);
3515 if (body)
3516 body = body->semantic(sc);
3517 return this;
3520 int SynchronizedStatement::hasBreak()
3522 return FALSE; //TRUE;
3525 int SynchronizedStatement::hasContinue()
3527 return FALSE; //TRUE;
3530 int SynchronizedStatement::usesEH()
3532 return TRUE;
3535 int SynchronizedStatement::blockExit()
3537 return body ? body->blockExit() : BEfallthru;
3540 int SynchronizedStatement::fallOffEnd()
3542 return body ? body->fallOffEnd() : TRUE;
3545 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3547 buf->writestring("synchronized");
3548 if (exp)
3549 { buf->writebyte('(');
3550 exp->toCBuffer(buf, hgs);
3551 buf->writebyte(')');
3553 if (body)
3555 buf->writebyte(' ');
3556 body->toCBuffer(buf, hgs);
3560 /******************************** WithStatement ***************************/
3562 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
3563 : Statement(loc)
3565 this->exp = exp;
3566 this->body = body;
3567 wthis = NULL;
3570 Statement *WithStatement::syntaxCopy()
3572 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3573 return s;
3576 Statement *WithStatement::semantic(Scope *sc)
3577 { ScopeDsymbol *sym;
3578 Initializer *init;
3580 //printf("WithStatement::semantic()\n");
3581 exp = exp->semantic(sc);
3582 exp = resolveProperties(sc, exp);
3583 if (exp->op == TOKimport)
3584 { ScopeExp *es = (ScopeExp *)exp;
3586 sym = es->sds;
3588 else if (exp->op == TOKtype)
3589 { TypeExp *es = (TypeExp *)exp;
3591 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3592 if (!sym)
3593 { error("%s has no members", es->toChars());
3594 body = body->semantic(sc);
3595 return this;
3598 else
3599 { Type *t = exp->type;
3601 assert(t);
3602 t = t->toBasetype();
3603 if (t->isClassHandle())
3605 init = new ExpInitializer(loc, exp);
3606 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3607 wthis->semantic(sc);
3609 sym = new WithScopeSymbol(this);
3610 sym->parent = sc->scopesym;
3612 else if (t->ty == Tstruct)
3614 Expression *e = exp->addressOf(sc);
3615 init = new ExpInitializer(loc, e);
3616 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3617 wthis->semantic(sc);
3618 sym = new WithScopeSymbol(this);
3619 sym->parent = sc->scopesym;
3621 else
3622 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3623 return NULL;
3626 sc = sc->push(sym);
3628 if (body)
3629 body = body->semantic(sc);
3631 sc->pop();
3633 return this;
3636 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3638 buf->writestring("with (");
3639 exp->toCBuffer(buf, hgs);
3640 buf->writestring(")\n");
3641 if (body)
3642 body->toCBuffer(buf, hgs);
3645 int WithStatement::usesEH()
3647 return body ? body->usesEH() : 0;
3650 int WithStatement::blockExit()
3652 int result = BEnone;
3653 if (exp->canThrow())
3654 result = BEthrow;
3655 if (body)
3656 result |= body->blockExit();
3657 else
3658 result |= BEfallthru;
3659 return result;
3662 int WithStatement::fallOffEnd()
3664 return body ? body->fallOffEnd() : TRUE;
3667 /******************************** TryCatchStatement ***************************/
3669 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3670 : Statement(loc)
3672 this->body = body;
3673 this->catches = catches;
3676 Statement *TryCatchStatement::syntaxCopy()
3678 Array *a = new Array();
3679 a->setDim(catches->dim);
3680 for (int i = 0; i < a->dim; i++)
3681 { Catch *c;
3683 c = (Catch *)catches->data[i];
3684 c = c->syntaxCopy();
3685 a->data[i] = c;
3687 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3688 return s;
3691 Statement *TryCatchStatement::semantic(Scope *sc)
3693 body = body->semanticScope(sc, NULL /*this*/, NULL);
3695 /* Even if body is NULL, still do semantic analysis on catches
3697 for (size_t i = 0; i < catches->dim; i++)
3698 { Catch *c = (Catch *)catches->data[i];
3699 c->semantic(sc);
3701 // Determine if current catch 'hides' any previous catches
3702 for (size_t j = 0; j < i; j++)
3703 { Catch *cj = (Catch *)catches->data[j];
3704 char *si = c->loc.toChars();
3705 char *sj = cj->loc.toChars();
3707 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3708 error("catch at %s hides catch at %s", sj, si);
3712 if (!body)
3713 return NULL;
3715 return this;
3718 int TryCatchStatement::hasBreak()
3720 return FALSE; //TRUE;
3723 int TryCatchStatement::usesEH()
3725 return TRUE;
3728 int TryCatchStatement::blockExit()
3729 { int result;
3731 assert(body);
3732 result = body->blockExit();
3734 for (size_t i = 0; i < catches->dim; i++)
3736 Catch *c = (Catch *)catches->data[i];
3737 result |= c->blockExit();
3739 return result;
3742 int TryCatchStatement::fallOffEnd()
3744 int result = FALSE;
3746 if (body)
3747 result = body->fallOffEnd();
3748 for (int i = 0; i < catches->dim; i++)
3749 { Catch *c;
3751 c = (Catch *)catches->data[i];
3752 if (c->handler)
3753 result |= c->handler->fallOffEnd();
3755 return result;
3758 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3760 buf->writestring("try");
3761 buf->writenl();
3762 if (body)
3763 body->toCBuffer(buf, hgs);
3764 for (size_t i = 0; i < catches->dim; i++)
3766 Catch *c = (Catch *)catches->data[i];
3767 c->toCBuffer(buf, hgs);
3771 /******************************** Catch ***************************/
3773 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3775 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3776 this->loc = loc;
3777 this->type = t;
3778 this->ident = id;
3779 this->handler = handler;
3780 var = NULL;
3783 Catch *Catch::syntaxCopy()
3785 Catch *c = new Catch(loc,
3786 (type ? type->syntaxCopy() : NULL),
3787 ident,
3788 (handler ? handler->syntaxCopy() : NULL));
3789 return c;
3792 void Catch::semantic(Scope *sc)
3793 { ScopeDsymbol *sym;
3795 //printf("Catch::semantic(%s)\n", ident->toChars());
3797 #ifndef IN_GCC
3798 if (sc->tf)
3800 /* This is because the _d_local_unwind() gets the stack munged
3801 * up on this. The workaround is to place any try-catches into
3802 * a separate function, and call that.
3803 * To fix, have the compiler automatically convert the finally
3804 * body into a nested function.
3806 error(loc, "cannot put catch statement inside finally block");
3808 #endif
3810 sym = new ScopeDsymbol();
3811 sym->parent = sc->scopesym;
3812 sc = sc->push(sym);
3814 if (!type)
3815 type = new TypeIdentifier(0, Id::Object);
3816 type = type->semantic(loc, sc);
3817 if (!type->toBasetype()->isClassHandle())
3818 error("can only catch class objects, not '%s'", type->toChars());
3819 else if (ident)
3821 var = new VarDeclaration(loc, type, ident, NULL);
3822 var->parent = sc->parent;
3823 sc->insert(var);
3825 handler = handler->semantic(sc);
3827 sc->pop();
3830 int Catch::blockExit()
3832 return handler ? handler->blockExit() : BEfallthru;
3835 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3837 buf->writestring("catch");
3838 if (type)
3839 { buf->writebyte('(');
3840 type->toCBuffer(buf, ident, hgs);
3841 buf->writebyte(')');
3843 buf->writenl();
3844 buf->writebyte('{');
3845 buf->writenl();
3846 if (handler)
3847 handler->toCBuffer(buf, hgs);
3848 buf->writebyte('}');
3849 buf->writenl();
3852 /****************************** TryFinallyStatement ***************************/
3854 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3855 : Statement(loc)
3857 this->body = body;
3858 this->finalbody = finalbody;
3861 Statement *TryFinallyStatement::syntaxCopy()
3863 TryFinallyStatement *s = new TryFinallyStatement(loc,
3864 body->syntaxCopy(), finalbody->syntaxCopy());
3865 return s;
3868 Statement *TryFinallyStatement::semantic(Scope *sc)
3870 //printf("TryFinallyStatement::semantic()\n");
3871 body = body->semantic(sc);
3872 sc = sc->push();
3873 sc->tf = this;
3874 sc->sbreak = NULL;
3875 sc->scontinue = NULL; // no break or continue out of finally block
3876 finalbody = finalbody->semantic(sc);
3877 sc->pop();
3878 if (!body)
3879 return finalbody;
3880 if (!finalbody)
3881 return body;
3882 if (body->blockExit() == BEfallthru)
3883 { Statement *s = new CompoundStatement(loc, body, finalbody);
3884 return s;
3886 return this;
3889 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3891 buf->printf("try\n{\n");
3892 body->toCBuffer(buf, hgs);
3893 buf->printf("}\nfinally\n{\n");
3894 finalbody->toCBuffer(buf, hgs);
3895 buf->writeByte('}');
3896 buf->writenl();
3899 int TryFinallyStatement::hasBreak()
3901 return FALSE; //TRUE;
3904 int TryFinallyStatement::hasContinue()
3906 return FALSE; //TRUE;
3909 int TryFinallyStatement::usesEH()
3911 return TRUE;
3914 int TryFinallyStatement::blockExit()
3916 int result = body->blockExit();
3917 return result;
3920 int TryFinallyStatement::fallOffEnd()
3921 { int result;
3923 result = body->fallOffEnd();
3924 // if (finalbody)
3925 // result = finalbody->fallOffEnd();
3926 return result;
3929 /****************************** OnScopeStatement ***************************/
3931 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3932 : Statement(loc)
3934 this->tok = tok;
3935 this->statement = statement;
3938 Statement *OnScopeStatement::syntaxCopy()
3940 OnScopeStatement *s = new OnScopeStatement(loc,
3941 tok, statement->syntaxCopy());
3942 return s;
3945 Statement *OnScopeStatement::semantic(Scope *sc)
3947 /* semantic is called on results of scopeCode() */
3948 return this;
3951 int OnScopeStatement::blockExit()
3952 { // At this point, this statement is just an empty placeholder
3953 return BEfallthru;
3956 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3958 buf->writestring(Token::toChars(tok));
3959 buf->writebyte(' ');
3960 statement->toCBuffer(buf, hgs);
3963 int OnScopeStatement::usesEH()
3965 return 1;
3968 void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
3970 //printf("OnScopeStatement::scopeCode()\n");
3971 //print();
3972 *sentry = NULL;
3973 *sexception = NULL;
3974 *sfinally = NULL;
3975 switch (tok)
3977 case TOKon_scope_exit:
3978 *sfinally = statement;
3979 break;
3981 case TOKon_scope_failure:
3982 *sexception = statement;
3983 break;
3985 case TOKon_scope_success:
3987 /* Create:
3988 * sentry: int x = 0;
3989 * sexception: x = 1;
3990 * sfinally: if (!x) statement;
3992 Identifier *id = Lexer::uniqueId("__os");
3994 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
3995 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
3996 *sentry = new DeclarationStatement(loc, v);
3998 Expression *e = new IntegerExp(1);
3999 e = new AssignExp(0, new VarExp(0, v), e);
4000 *sexception = new ExpStatement(0, e);
4002 e = new VarExp(0, v);
4003 e = new NotExp(0, e);
4004 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
4006 break;
4009 default:
4010 assert(0);
4014 /******************************** ThrowStatement ***************************/
4016 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
4017 : Statement(loc)
4019 this->exp = exp;
4022 Statement *ThrowStatement::syntaxCopy()
4024 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
4025 return s;
4028 Statement *ThrowStatement::semantic(Scope *sc)
4030 //printf("ThrowStatement::semantic()\n");
4032 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4033 fd->hasReturnExp |= 2;
4035 if (sc->incontract)
4036 error("Throw statements cannot be in contracts");
4037 exp = exp->semantic(sc);
4038 exp = resolveProperties(sc, exp);
4039 if (!exp->type->toBasetype()->isClassHandle())
4040 error("can only throw class objects, not type %s", exp->type->toChars());
4041 return this;
4044 int ThrowStatement::blockExit()
4046 return BEthrow; // obviously
4049 int ThrowStatement::fallOffEnd()
4051 return FALSE;
4054 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4056 buf->printf("throw ");
4057 exp->toCBuffer(buf, hgs);
4058 buf->writeByte(';');
4059 buf->writenl();
4062 /******************************** VolatileStatement **************************/
4064 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
4065 : Statement(loc)
4067 this->statement = statement;
4070 Statement *VolatileStatement::syntaxCopy()
4072 VolatileStatement *s = new VolatileStatement(loc,
4073 statement ? statement->syntaxCopy() : NULL);
4074 return s;
4077 Statement *VolatileStatement::semantic(Scope *sc)
4079 if (statement)
4080 statement = statement->semantic(sc);
4081 return this;
4084 Statements *VolatileStatement::flatten(Scope *sc)
4086 Statements *a;
4088 a = statement ? statement->flatten(sc) : NULL;
4089 if (a)
4090 { for (int i = 0; i < a->dim; i++)
4091 { Statement *s = (Statement *)a->data[i];
4093 s = new VolatileStatement(loc, s);
4094 a->data[i] = s;
4098 return a;
4101 int VolatileStatement::blockExit()
4103 return statement ? statement->blockExit() : BEfallthru;
4106 int VolatileStatement::fallOffEnd()
4108 return statement ? statement->fallOffEnd() : TRUE;
4111 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4113 buf->writestring("volatile");
4114 if (statement)
4115 { if (statement->isScopeStatement())
4116 buf->writenl();
4117 else
4118 buf->writebyte(' ');
4119 statement->toCBuffer(buf, hgs);
4124 /******************************** GotoStatement ***************************/
4126 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
4127 : Statement(loc)
4129 this->ident = ident;
4130 this->label = NULL;
4131 this->tf = NULL;
4134 Statement *GotoStatement::syntaxCopy()
4136 GotoStatement *s = new GotoStatement(loc, ident);
4137 return s;
4140 Statement *GotoStatement::semantic(Scope *sc)
4141 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4143 //printf("GotoStatement::semantic()\n");
4144 tf = sc->tf;
4145 label = fd->searchLabel(ident);
4146 if (!label->statement && sc->fes)
4148 /* Either the goto label is forward referenced or it
4149 * is in the function that the enclosing foreach is in.
4150 * Can't know yet, so wrap the goto in a compound statement
4151 * so we can patch it later, and add it to a 'look at this later'
4152 * list.
4154 Statements *a = new Statements();
4155 Statement *s;
4157 a->push(this);
4158 s = new CompoundStatement(loc, a);
4159 sc->fes->gotos.push(s); // 'look at this later' list
4160 return s;
4162 if (label->statement && label->statement->tf != sc->tf)
4163 error("cannot goto in or out of finally block");
4164 return this;
4167 int GotoStatement::blockExit()
4169 //printf("GotoStatement::blockExit(%p)\n", this);
4170 return BEgoto;
4173 int GotoStatement::fallOffEnd()
4175 return FALSE;
4178 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4180 buf->writestring("goto ");
4181 buf->writestring(ident->toChars());
4182 buf->writebyte(';');
4183 buf->writenl();
4186 /******************************** LabelStatement ***************************/
4188 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
4189 : Statement(loc)
4191 this->ident = ident;
4192 this->statement = statement;
4193 this->tf = NULL;
4194 this->lblock = NULL;
4195 this->isReturnLabel = 0;
4198 Statement *LabelStatement::syntaxCopy()
4200 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
4201 return s;
4204 Statement *LabelStatement::semantic(Scope *sc)
4205 { LabelDsymbol *ls;
4206 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4208 //printf("LabelStatement::semantic()\n");
4209 ls = fd->searchLabel(ident);
4210 if (ls->statement)
4211 error("Label '%s' already defined", ls->toChars());
4212 else
4213 ls->statement = this;
4214 tf = sc->tf;
4215 sc = sc->push();
4216 sc->scopesym = sc->enclosing->scopesym;
4217 sc->callSuper |= CSXlabel;
4218 sc->slabel = this;
4219 if (statement)
4220 statement = statement->semantic(sc);
4221 sc->pop();
4222 return this;
4225 Statements *LabelStatement::flatten(Scope *sc)
4227 Statements *a = NULL;
4229 if (statement)
4231 a = statement->flatten(sc);
4232 if (a)
4234 if (!a->dim)
4236 a->push(new ExpStatement(loc, NULL));
4238 Statement *s = (Statement *)a->data[0];
4240 s = new LabelStatement(loc, ident, s);
4241 a->data[0] = s;
4245 return a;
4249 int LabelStatement::usesEH()
4251 return statement ? statement->usesEH() : FALSE;
4254 int LabelStatement::blockExit()
4256 //printf("LabelStatement::blockExit(%p)\n", this);
4257 return statement ? statement->blockExit() : BEfallthru;
4260 int LabelStatement::fallOffEnd()
4262 return statement ? statement->fallOffEnd() : TRUE;
4265 int LabelStatement::comeFrom()
4267 //printf("LabelStatement::comeFrom()\n");
4268 return TRUE;
4271 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4273 buf->writestring(ident->toChars());
4274 buf->writebyte(':');
4275 buf->writenl();
4276 if (statement)
4277 statement->toCBuffer(buf, hgs);
4281 /******************************** LabelDsymbol ***************************/
4283 LabelDsymbol::LabelDsymbol(Identifier *ident)
4284 : Dsymbol(ident)
4286 statement = NULL;
4287 #if IN_GCC
4288 asmLabelNum = 0;
4289 #endif
4292 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
4294 return this;