Merged Delight changes to D1 into D2
[delight/core.git] / dmd2 / statement.c
blobde06a838bf036724d60cb98c6950234cdc6f6065
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) {
360 Expressions *args = new Expressions();
362 Expression *externals = new IdentifierExp(loc, Id::externals);
363 // Collect all the objects we need for the constructor's arguments
364 for (int i = 0; i < arguments->dim; i++) {
365 Argument *arg = (Argument *) arguments->data[i];
366 if (arg->ident == Id::args) {
367 // For 'args', just pass through the string[] passed to main()
368 args->push(new IdentifierExp(loc, arg->ident));
369 } else {
370 // For everything else, call a getter in the _externals module
371 Expression *getter = new DotIdExp(loc, externals, arg->ident);
372 args->push(getter);
376 return args;
379 InjectorMainBody::InjectorMainBody(Loc loc, ClassDeclaration *mainClass)
380 : Statement(loc), mainClass(mainClass)
384 Statement *InjectorMainBody::semantic(Scope *sc)
386 // Find the constructor and the main method
387 CtorDeclaration *ctor = NULL;
388 FuncDeclaration *mainDecl = NULL;
389 for (int i = 0; i < mainClass->members->dim; i++) {
390 Dsymbol *s;
392 s = (Dsymbol *)mainClass->members->data[i];
394 CtorDeclaration *thisCtor = s->isCtorDeclaration();
395 if (thisCtor) {
396 if (ctor) {
397 error("Multiple constructors for Main class!");
398 return NULL;
399 } else {
400 ctor = thisCtor;
404 FuncDeclaration *thisMethod = s->isFuncDeclaration();
405 if (thisMethod && thisMethod->ident == Id::main) {
406 if (mainDecl) {
407 error("Multiple main methods for Main class!");
408 return NULL;
409 } else {
410 mainDecl = thisMethod;
415 if (mainDecl == NULL) {
416 error("No main method in Main class!");
417 return NULL;
420 // Externals externals = new _externals.Externals()
421 TypeIdentifier *extType = new TypeIdentifier(loc, Id::dlt);
422 extType->addIdent(Id::_externals);
423 extType->addIdent(Id::Externals);
425 Expression *newExt = new NewExp(loc, NULL, NULL, extType, NULL);
426 VarDeclaration *v = new VarDeclaration(loc, extType, Id::externals,
427 new ExpInitializer(loc, newExt));
428 Statement *assignExt = new DeclarationStatement(loc, v);
429 Expression *newMain = new NewExp(loc, NULL, NULL, mainClass->getType(),
430 ctor ? getAutoArgs(ctor->loc, ctor->arguments) : NULL);
432 // Then invoke the main() method inside it
433 // mainObject.main(...)
434 Expression *mainMethod = new DotIdExp(mainDecl->loc, newMain, Id::main);
435 Expression *mainCall = new CallExp(mainMethod->loc, mainMethod,
436 getAutoArgs(mainDecl->loc,
437 ((TypeFunction *) mainDecl->type)->parameters));
439 Statement *s = new ExpStatement(loc, mainCall);
440 Statement *runMain = new CompoundStatement(loc, assignExt, s);
442 // catch (SystemExit)
443 Array *catches = new Array();
444 Statement *handler = new ExpStatement(loc, new CallExp(loc,
445 new DotIdExp(loc,
446 new IdentifierExp(loc, Id::externals),
447 Id::SystemExit),
448 new IdentifierExp(loc, Id::result)));
449 Catch *c = new Catch(loc, new TypeIdentifier(loc, Id::SystemExit), Id::result, handler);
450 catches->push(c);
451 Statement *body = new TryCatchStatement(loc, runMain, catches);
452 return body->semantic(sc);
455 /******************************** CompoundStatement ***************************/
457 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
458 : Statement(loc)
460 statements = s;
463 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
464 : Statement(loc)
466 statements = new Statements();
467 statements->reserve(2);
468 statements->push(s1);
469 statements->push(s2);
472 Statement *CompoundStatement::syntaxCopy()
474 Statements *a = new Statements();
475 a->setDim(statements->dim);
476 for (size_t i = 0; i < statements->dim; i++)
477 { Statement *s = (Statement *)statements->data[i];
478 if (s)
479 s = s->syntaxCopy();
480 a->data[i] = s;
482 CompoundStatement *cs = new CompoundStatement(loc, a);
483 return cs;
487 Statement *CompoundStatement::semantic(Scope *sc)
488 { Statement *s;
490 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
492 for (size_t i = 0; i < statements->dim; )
494 s = (Statement *) statements->data[i];
495 if (s)
496 { Statements *a = s->flatten(sc);
498 if (a)
500 statements->remove(i);
501 statements->insert(i, a);
502 continue;
504 s = s->semantic(sc);
505 statements->data[i] = s;
506 if (s)
508 Statement *sentry;
509 Statement *sexception;
510 Statement *sfinally;
512 s->scopeCode(sc, &sentry, &sexception, &sfinally);
513 if (sentry)
515 sentry = sentry->semantic(sc);
516 statements->data[i] = sentry;
518 if (sexception)
520 if (i + 1 == statements->dim && !sfinally)
522 #if 1
523 sexception = sexception->semantic(sc);
524 #else
525 statements->push(sexception);
526 if (sfinally)
527 // Assume sexception does not throw
528 statements->push(sfinally);
529 #endif
531 else
533 /* Rewrite:
534 * s; s1; s2;
535 * As:
536 * s;
537 * try { s1; s2; }
538 * catch (Object __o)
539 * { sexception; throw __o; }
541 Statement *body;
542 Statements *a = new Statements();
544 for (int j = i + 1; j < statements->dim; j++)
546 a->push(statements->data[j]);
548 body = new CompoundStatement(0, a);
549 body = new ScopeStatement(0, body);
551 Identifier *id = Lexer::uniqueId("__o");
553 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
554 handler = new CompoundStatement(0, sexception, handler);
556 Array *catches = new Array();
557 Catch *ctch = new Catch(0, NULL, id, handler);
558 catches->push(ctch);
559 s = new TryCatchStatement(0, body, catches);
561 if (sfinally)
562 s = new TryFinallyStatement(0, s, sfinally);
563 s = s->semantic(sc);
564 statements->setDim(i + 1);
565 statements->push(s);
566 break;
569 else if (sfinally)
571 if (0 && i + 1 == statements->dim)
573 statements->push(sfinally);
575 else
577 /* Rewrite:
578 * s; s1; s2;
579 * As:
580 * s; try { s1; s2; } finally { sfinally; }
582 Statement *body;
583 Statements *a = new Statements();
585 for (int j = i + 1; j < statements->dim; j++)
587 a->push(statements->data[j]);
589 body = new CompoundStatement(0, a);
590 s = new TryFinallyStatement(0, body, sfinally);
591 s = s->semantic(sc);
592 statements->setDim(i + 1);
593 statements->push(s);
594 break;
599 i++;
601 if (statements->dim == 1)
602 return s;
603 return this;
606 Statements *CompoundStatement::flatten(Scope *sc)
608 return statements;
611 ReturnStatement *CompoundStatement::isReturnStatement()
612 { int i;
613 ReturnStatement *rs = NULL;
615 for (i = 0; i < statements->dim; i++)
616 { Statement *s;
618 s = (Statement *) statements->data[i];
619 if (s)
621 rs = s->isReturnStatement();
622 if (rs)
623 break;
626 return rs;
629 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
630 { int i;
632 for (i = 0; i < statements->dim; i++)
633 { Statement *s;
635 s = (Statement *) statements->data[i];
636 if (s)
637 s->toCBuffer(buf, hgs);
641 int CompoundStatement::usesEH()
643 for (int i = 0; i < statements->dim; i++)
644 { Statement *s;
646 s = (Statement *) statements->data[i];
647 if (s && s->usesEH())
648 return TRUE;
650 return FALSE;
653 int CompoundStatement::blockExit()
655 //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim);
656 int result = BEfallthru;
657 for (size_t i = 0; i < statements->dim; i++)
658 { Statement *s = (Statement *) statements->data[i];
659 if (s)
661 //printf("result = x%x\n", result);
662 //printf("%s\n", s->toChars());
663 if (!(result & BEfallthru) && !s->comeFrom())
665 if (global.params.warnings)
666 { fprintf(stdmsg, "warning - ");
667 s->error("statement is not reachable");
671 result &= ~BEfallthru;
672 result |= s->blockExit();
675 return result;
678 int CompoundStatement::fallOffEnd()
679 { int falloff = TRUE;
681 //printf("CompoundStatement::fallOffEnd()\n");
682 for (int i = 0; i < statements->dim; i++)
683 { Statement *s = (Statement *)statements->data[i];
685 if (!s)
686 continue;
688 #if 0
689 if (!falloff && global.params.warnings && !s->comeFrom())
691 fprintf(stdmsg, "warning - ");
692 s->error("statement is not reachable");
694 #endif
695 falloff = s->fallOffEnd();
697 return falloff;
700 int CompoundStatement::comeFrom()
701 { int comefrom = FALSE;
703 //printf("CompoundStatement::comeFrom()\n");
704 for (int i = 0; i < statements->dim; i++)
705 { Statement *s = (Statement *)statements->data[i];
707 if (!s)
708 continue;
710 comefrom |= s->comeFrom();
712 return comefrom;
716 /**************************** UnrolledLoopStatement ***************************/
718 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
719 : Statement(loc)
721 statements = s;
724 Statement *UnrolledLoopStatement::syntaxCopy()
726 Statements *a = new Statements();
727 a->setDim(statements->dim);
728 for (size_t i = 0; i < statements->dim; i++)
729 { Statement *s = (Statement *)statements->data[i];
730 if (s)
731 s = s->syntaxCopy();
732 a->data[i] = s;
734 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
735 return cs;
739 Statement *UnrolledLoopStatement::semantic(Scope *sc)
741 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
743 sc->noctor++;
744 Scope *scd = sc->push();
745 scd->sbreak = this;
746 scd->scontinue = this;
748 for (size_t i = 0; i < statements->dim; i++)
750 Statement *s = (Statement *) statements->data[i];
751 if (s)
753 s = s->semantic(scd);
754 statements->data[i] = s;
758 scd->pop();
759 sc->noctor--;
760 return this;
763 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
765 buf->writestring("unrolled {");
766 buf->writenl();
768 for (size_t i = 0; i < statements->dim; i++)
769 { Statement *s;
771 s = (Statement *) statements->data[i];
772 if (s)
773 s->toCBuffer(buf, hgs);
776 buf->writeByte('}');
777 buf->writenl();
780 int UnrolledLoopStatement::hasBreak()
782 return TRUE;
785 int UnrolledLoopStatement::hasContinue()
787 return TRUE;
790 int UnrolledLoopStatement::usesEH()
792 for (size_t i = 0; i < statements->dim; i++)
793 { Statement *s = (Statement *) statements->data[i];
794 if (s && s->usesEH())
795 return TRUE;
797 return FALSE;
800 int UnrolledLoopStatement::blockExit()
802 int result = BEfallthru;
803 for (size_t i = 0; i < statements->dim; i++)
804 { Statement *s = (Statement *) statements->data[i];
805 if (s)
807 int r = s->blockExit();
808 result |= r & ~(BEbreak | BEcontinue);
811 return result;
814 int UnrolledLoopStatement::fallOffEnd()
816 //printf("UnrolledLoopStatement::fallOffEnd()\n");
817 for (size_t i = 0; i < statements->dim; i++)
818 { Statement *s = (Statement *)statements->data[i];
820 if (s)
821 s->fallOffEnd();
823 return TRUE;
826 int UnrolledLoopStatement::comeFrom()
827 { int comefrom = FALSE;
829 //printf("UnrolledLoopStatement::comeFrom()\n");
830 for (size_t i = 0; i < statements->dim; i++)
831 { Statement *s = (Statement *)statements->data[i];
833 if (!s)
834 continue;
836 comefrom |= s->comeFrom();
838 return comefrom;
842 /******************************** ScopeStatement ***************************/
844 ScopeStatement::ScopeStatement(Loc loc, Statement *s)
845 : Statement(loc)
847 this->statement = s;
850 Statement *ScopeStatement::syntaxCopy()
852 Statement *s;
854 s = statement ? statement->syntaxCopy() : NULL;
855 s = new ScopeStatement(loc, s);
856 return s;
860 Statement *ScopeStatement::semantic(Scope *sc)
861 { ScopeDsymbol *sym;
863 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
864 if (statement)
865 { Statements *a;
867 sym = new ScopeDsymbol();
868 sym->parent = sc->scopesym;
869 sc = sc->push(sym);
871 a = statement->flatten(sc);
872 if (a)
874 statement = new CompoundStatement(loc, a);
877 statement = statement->semantic(sc);
878 if (statement)
880 Statement *sentry;
881 Statement *sexception;
882 Statement *sfinally;
884 statement->scopeCode(sc, &sentry, &sexception, &sfinally);
885 if (sfinally)
887 //printf("adding sfinally\n");
888 statement = new CompoundStatement(loc, statement, sfinally);
892 sc->pop();
894 return this;
897 int ScopeStatement::hasBreak()
899 //printf("ScopeStatement::hasBreak() %s\n", toChars());
900 return statement ? statement->hasBreak() : FALSE;
903 int ScopeStatement::hasContinue()
905 return statement ? statement->hasContinue() : FALSE;
908 int ScopeStatement::usesEH()
910 return statement ? statement->usesEH() : FALSE;
913 int ScopeStatement::blockExit()
915 //printf("ScopeStatement::blockExit(%p)\n", statement);
916 return statement ? statement->blockExit() : BEfallthru;
919 int ScopeStatement::fallOffEnd()
921 return statement ? statement->fallOffEnd() : TRUE;
924 int ScopeStatement::comeFrom()
926 //printf("ScopeStatement::comeFrom()\n");
927 return statement ? statement->comeFrom() : FALSE;
930 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
932 buf->writeByte('{');
933 buf->writenl();
935 if (statement)
936 statement->toCBuffer(buf, hgs);
938 buf->writeByte('}');
939 buf->writenl();
942 /******************************** WhileStatement ***************************/
944 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
945 : Statement(loc)
947 condition = c;
948 body = b;
951 Statement *WhileStatement::syntaxCopy()
953 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
954 return s;
958 Statement *WhileStatement::semantic(Scope *sc)
960 #if 0
961 if (condition->op == TOKmatch)
963 /* Rewrite while (condition) body as:
964 * if (condition)
965 * do
966 * body
967 * while ((_match = _match.opNext), _match);
970 Expression *ew = new IdentifierExp(0, Id::_match);
971 ew = new DotIdExp(0, ew, Id::next);
972 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
973 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
974 Expression *ev = new IdentifierExp(0, Id::_match);
975 //ev = new CastExp(0, ev, Type::tvoidptr);
976 ew = new CommaExp(0, ew, ev);
977 Statement *sw = new DoStatement(loc, body, ew);
978 Statement *si = new IfStatement(loc, condition, sw, NULL);
979 return si->semantic(sc);
981 #endif
983 condition = condition->semantic(sc);
984 condition = resolveProperties(sc, condition);
985 condition = condition->optimize(WANTvalue);
986 condition = condition->checkToBoolean();
988 sc->noctor++;
990 Scope *scd = sc->push();
991 scd->sbreak = this;
992 scd->scontinue = this;
993 if (body)
994 body = body->semantic(scd);
995 scd->pop();
997 sc->noctor--;
999 return this;
1002 int WhileStatement::hasBreak()
1004 return TRUE;
1007 int WhileStatement::hasContinue()
1009 return TRUE;
1012 int WhileStatement::usesEH()
1014 return body ? body->usesEH() : 0;
1017 int WhileStatement::blockExit()
1019 //printf("WhileStatement::blockExit(%p)\n", this);
1021 int result = BEnone;
1022 if (condition->canThrow())
1023 result |= BEthrow;
1024 if (body)
1025 { result |= body->blockExit();
1026 if (result & BEbreak)
1027 result |= BEfallthru;
1028 result &= ~(BEbreak | BEcontinue);
1030 else
1031 result |= BEfallthru;
1032 return result;
1035 int WhileStatement::fallOffEnd()
1037 if (body)
1038 body->fallOffEnd();
1039 return TRUE;
1042 int WhileStatement::comeFrom()
1044 if (body)
1045 return body->comeFrom();
1046 return FALSE;
1049 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1051 buf->writestring("while (");
1052 condition->toCBuffer(buf, hgs);
1053 buf->writebyte(')');
1054 buf->writenl();
1055 if (body)
1056 body->toCBuffer(buf, hgs);
1059 /******************************** DoStatement ***************************/
1061 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
1062 : Statement(loc)
1064 body = b;
1065 condition = c;
1068 Statement *DoStatement::syntaxCopy()
1070 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
1071 return s;
1075 Statement *DoStatement::semantic(Scope *sc)
1077 sc->noctor++;
1078 if (body)
1079 body = body->semanticScope(sc, this, this);
1080 sc->noctor--;
1081 condition = condition->semantic(sc);
1082 condition = resolveProperties(sc, condition);
1083 condition = condition->optimize(WANTvalue);
1085 condition = condition->checkToBoolean();
1087 return this;
1090 int DoStatement::hasBreak()
1092 return TRUE;
1095 int DoStatement::hasContinue()
1097 return TRUE;
1100 int DoStatement::usesEH()
1102 return body ? body->usesEH() : 0;
1105 int DoStatement::blockExit()
1106 { int result;
1108 if (body)
1109 { result = body->blockExit();
1110 if (result & BEbreak)
1112 if (result == BEbreak)
1113 return BEfallthru;
1114 result |= BEfallthru;
1116 if (result & BEcontinue)
1117 result |= BEfallthru;
1118 result &= ~(BEbreak | BEcontinue);
1120 else
1121 result = BEfallthru;
1122 if (result & BEfallthru && condition->canThrow())
1123 result |= BEthrow;
1124 return result;
1127 int DoStatement::fallOffEnd()
1129 if (body)
1130 body->fallOffEnd();
1131 return TRUE;
1134 int DoStatement::comeFrom()
1136 if (body)
1137 return body->comeFrom();
1138 return FALSE;
1141 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1143 buf->writestring("do");
1144 buf->writenl();
1145 if (body)
1146 body->toCBuffer(buf, hgs);
1147 buf->writestring("while (");
1148 condition->toCBuffer(buf, hgs);
1149 buf->writebyte(')');
1152 /******************************** ForStatement ***************************/
1154 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
1155 : Statement(loc)
1157 this->init = init;
1158 this->condition = condition;
1159 this->increment = increment;
1160 this->body = body;
1163 Statement *ForStatement::syntaxCopy()
1165 Statement *i = NULL;
1166 if (init)
1167 i = init->syntaxCopy();
1168 Expression *c = NULL;
1169 if (condition)
1170 c = condition->syntaxCopy();
1171 Expression *inc = NULL;
1172 if (increment)
1173 inc = increment->syntaxCopy();
1174 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
1175 return s;
1178 Statement *ForStatement::semantic(Scope *sc)
1180 ScopeDsymbol *sym = new ScopeDsymbol();
1181 sym->parent = sc->scopesym;
1182 sc = sc->push(sym);
1183 if (init)
1184 init = init->semantic(sc);
1185 sc->noctor++;
1186 if (condition)
1188 condition = condition->semantic(sc);
1189 condition = resolveProperties(sc, condition);
1190 condition = condition->optimize(WANTvalue);
1191 condition = condition->checkToBoolean();
1193 if (increment)
1194 increment = increment->semantic(sc);
1196 sc->sbreak = this;
1197 sc->scontinue = this;
1198 body = body->semantic(sc);
1199 sc->noctor--;
1201 sc->pop();
1202 return this;
1205 void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
1207 //printf("ForStatement::scopeCode()\n");
1208 //print();
1209 if (init)
1210 init->scopeCode(sc, sentry, sexception, sfinally);
1211 else
1212 Statement::scopeCode(sc, sentry, sexception, sfinally);
1215 int ForStatement::hasBreak()
1217 //printf("ForStatement::hasBreak()\n");
1218 return TRUE;
1221 int ForStatement::hasContinue()
1223 return TRUE;
1226 int ForStatement::usesEH()
1228 return (init && init->usesEH()) || body->usesEH();
1231 int ForStatement::blockExit()
1232 { int result = BEfallthru;
1234 if (init)
1235 { result = init->blockExit();
1236 if (!(result & BEfallthru))
1237 return result;
1239 if (condition)
1240 { if (condition->canThrow())
1241 result |= BEthrow;
1243 else
1244 result &= ~BEfallthru; // the body must do the exiting
1245 if (body)
1246 { int r = body->blockExit();
1247 if (r & BEbreak)
1248 result |= BEfallthru;
1249 result |= r & ~(BEbreak | BEcontinue);
1251 if (increment && increment->canThrow())
1252 result |= BEthrow;
1253 return result;
1256 int ForStatement::fallOffEnd()
1258 if (body)
1259 body->fallOffEnd();
1260 return TRUE;
1263 int ForStatement::comeFrom()
1265 //printf("ForStatement::comeFrom()\n");
1266 if (body)
1267 { int result = body->comeFrom();
1268 //printf("result = %d\n", result);
1269 return result;
1271 return FALSE;
1274 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1276 buf->writestring("for (");
1277 if (init)
1279 hgs->FLinit.init++;
1280 hgs->FLinit.decl = 0;
1281 init->toCBuffer(buf, hgs);
1282 if (hgs->FLinit.decl > 0)
1283 buf->writebyte(';');
1284 hgs->FLinit.decl = 0;
1285 hgs->FLinit.init--;
1287 else
1288 buf->writebyte(';');
1289 if (condition)
1290 { buf->writebyte(' ');
1291 condition->toCBuffer(buf, hgs);
1293 buf->writebyte(';');
1294 if (increment)
1295 { buf->writebyte(' ');
1296 increment->toCBuffer(buf, hgs);
1298 buf->writebyte(')');
1299 buf->writenl();
1300 buf->writebyte('{');
1301 buf->writenl();
1302 body->toCBuffer(buf, hgs);
1303 buf->writebyte('}');
1304 buf->writenl();
1307 /******************************** ForeachStatement ***************************/
1309 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
1310 Expression *aggr, Statement *body)
1311 : Statement(loc)
1313 this->op = op;
1314 this->arguments = arguments;
1315 this->aggr = aggr;
1316 this->body = body;
1318 this->key = NULL;
1319 this->value = NULL;
1321 this->func = NULL;
1324 Statement *ForeachStatement::syntaxCopy()
1326 Arguments *args = Argument::arraySyntaxCopy(arguments);
1327 Expression *exp = aggr->syntaxCopy();
1328 ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
1329 body ? body->syntaxCopy() : NULL);
1330 return s;
1333 Statement *ForeachStatement::semantic(Scope *sc)
1335 //printf("ForeachStatement::semantic() %p\n", this);
1336 ScopeDsymbol *sym;
1337 Statement *s = this;
1338 int dim = arguments->dim;
1339 int i;
1340 TypeAArray *taa = NULL;
1342 Type *tn = NULL;
1343 Type *tnv = NULL;
1345 func = sc->func;
1346 if (func->fes)
1347 func = func->fes->func;
1349 aggr = aggr->semantic(sc);
1350 aggr = resolveProperties(sc, aggr);
1351 aggr = aggr->optimize(WANTvalue);
1352 if (!aggr->type)
1354 error("invalid foreach aggregate %s", aggr->toChars());
1355 return this;
1358 inferApplyArgTypes(op, arguments, aggr);
1360 /* Check for inference errors
1362 if (dim != arguments->dim)
1364 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1365 error("cannot uniquely infer foreach argument types");
1366 return this;
1369 Type *tab = aggr->type->toBasetype();
1371 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
1373 if (dim < 1 || dim > 2)
1375 error("only one (value) or two (key,value) arguments for tuple foreach");
1376 return s;
1379 TypeTuple *tuple = (TypeTuple *)tab;
1380 Statements *statements = new Statements();
1381 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1382 size_t n;
1383 TupleExp *te = NULL;
1384 if (aggr->op == TOKtuple) // expression tuple
1385 { te = (TupleExp *)aggr;
1386 n = te->exps->dim;
1388 else if (aggr->op == TOKtype) // type tuple
1390 n = Argument::dim(tuple->arguments);
1392 else
1393 assert(0);
1394 for (size_t j = 0; j < n; j++)
1395 { size_t k = (op == TOKforeach) ? j : n - 1 - j;
1396 Expression *e;
1397 Type *t;
1398 if (te)
1399 e = (Expression *)te->exps->data[k];
1400 else
1401 t = Argument::getNth(tuple->arguments, k)->type;
1402 Argument *arg = (Argument *)arguments->data[0];
1403 Statements *st = new Statements();
1405 if (dim == 2)
1406 { // Declare key
1407 if (arg->storageClass & (STCout | STCref | STClazy))
1408 error("no storage class for key %s", arg->ident->toChars());
1409 TY keyty = arg->type->ty;
1410 if ((keyty != Tint32 && keyty != Tuns32) &&
1411 (! global.params.isX86_64 ||
1412 (keyty != Tint64 && keyty != Tuns64))
1415 error("foreach: key type must be int or uint, not %s", arg->type->toChars());
1417 Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
1418 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
1419 var->storage_class |= STCmanifest;
1420 DeclarationExp *de = new DeclarationExp(loc, var);
1421 st->push(new ExpStatement(loc, de));
1422 arg = (Argument *)arguments->data[1]; // value
1424 // Declare value
1425 if (arg->storageClass & (STCout | STCref | STClazy))
1426 error("no storage class for value %s", arg->ident->toChars());
1427 Dsymbol *var;
1428 if (te)
1429 { Type *tb = e->type->toBasetype();
1430 if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
1431 { VarExp *ve = (VarExp *)e;
1432 var = new AliasDeclaration(loc, arg->ident, ve->var);
1434 else
1436 arg->type = e->type;
1437 Initializer *ie = new ExpInitializer(0, e);
1438 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
1439 if (e->isConst())
1440 v->storage_class |= STCconst;
1441 var = v;
1444 else
1446 var = new AliasDeclaration(loc, arg->ident, t);
1448 DeclarationExp *de = new DeclarationExp(loc, var);
1449 st->push(new ExpStatement(loc, de));
1451 st->push(body->syntaxCopy());
1452 s = new CompoundStatement(loc, st);
1453 s = new ScopeStatement(loc, s);
1454 statements->push(s);
1457 s = new UnrolledLoopStatement(loc, statements);
1458 s = s->semantic(sc);
1459 return s;
1462 for (i = 0; i < dim; i++)
1463 { Argument *arg = (Argument *)arguments->data[i];
1464 if (!arg->type)
1466 error("cannot infer type for %s", arg->ident->toChars());
1467 return this;
1471 sym = new ScopeDsymbol();
1472 sym->parent = sc->scopesym;
1473 sc = sc->push(sym);
1475 sc->noctor++;
1477 switch (tab->ty)
1479 case Tarray:
1480 case Tsarray:
1481 if (dim < 1 || dim > 2)
1483 error("only one or two arguments for array foreach");
1484 break;
1487 /* Look for special case of parsing char types out of char type
1488 * array.
1490 tn = tab->nextOf()->toBasetype();
1491 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
1492 { Argument *arg;
1494 i = (dim == 1) ? 0 : 1; // index of value
1495 arg = (Argument *)arguments->data[i];
1496 arg->type = arg->type->semantic(loc, sc);
1497 tnv = arg->type->toBasetype();
1498 if (tnv->ty != tn->ty &&
1499 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
1501 if (arg->storageClass & STCref)
1502 error("foreach: value of UTF conversion cannot be ref");
1503 if (dim == 2)
1504 { arg = (Argument *)arguments->data[0];
1505 if (arg->storageClass & STCref)
1506 error("foreach: key cannot be ref");
1508 goto Lapply;
1512 for (i = 0; i < dim; i++)
1513 { // Declare args
1514 Argument *arg = (Argument *)arguments->data[i];
1515 VarDeclaration *var;
1517 var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1518 var->storage_class |= STCforeach;
1519 var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant);
1520 if (dim == 2 && i == 0)
1521 { key = var;
1522 //var->storage_class |= STCfinal;
1524 else
1525 { //if (!(arg->storageClass & STCref))
1526 //var->storage_class |= STCfinal;
1527 value = var;
1529 #if 1
1530 DeclarationExp *de = new DeclarationExp(loc, var);
1531 de->semantic(sc);
1532 #else
1533 var->semantic(sc);
1534 if (!sc->insert(var))
1535 error("%s already defined", var->ident->toChars());
1536 #endif
1539 sc->sbreak = this;
1540 sc->scontinue = this;
1541 body = body->semantic(sc);
1543 if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst)
1545 if (aggr->op == TOKstring)
1546 aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
1547 else
1548 error("foreach: %s is not an array of %s",
1549 tab->toChars(), value->type->toChars());
1552 if (key &&
1553 ((key->type->ty != Tint32 && key->type->ty != Tuns32) &&
1554 (! global.params.isX86_64 ||
1555 (key->type->ty != Tint64 && key->type->ty != Tuns64))
1559 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1562 if (key && key->storage_class & (STCout | STCref))
1563 error("foreach: key cannot be out or ref");
1564 break;
1566 case Taarray:
1567 taa = (TypeAArray *)tab;
1568 if (dim < 1 || dim > 2)
1570 error("only one or two arguments for associative array foreach");
1571 break;
1573 if (op == TOKforeach_reverse)
1575 error("no reverse iteration on associative arrays");
1577 goto Lapply;
1579 case Tclass:
1580 case Tstruct:
1581 case Tdelegate:
1582 Lapply:
1583 { FuncDeclaration *fdapply;
1584 Arguments *args;
1585 Expression *ec;
1586 Expression *e;
1587 FuncLiteralDeclaration *fld;
1588 Argument *a;
1589 Type *t;
1590 Expression *flde;
1591 Identifier *id;
1592 Type *tret;
1594 tret = func->type->nextOf();
1596 // Need a variable to hold value from any return statements in body.
1597 if (!sc->func->vresult && tret && tret != Type::tvoid)
1598 { VarDeclaration *v;
1600 v = new VarDeclaration(loc, tret, Id::result, NULL);
1601 v->noauto = 1;
1602 v->semantic(sc);
1603 if (!sc->insert(v))
1604 assert(0);
1605 v->parent = sc->func;
1606 sc->func->vresult = v;
1609 /* Turn body into the function literal:
1610 * int delegate(ref T arg) { body }
1612 args = new Arguments();
1613 for (i = 0; i < dim; i++)
1614 { Argument *arg = (Argument *)arguments->data[i];
1616 arg->type = arg->type->semantic(loc, sc);
1617 if (arg->storageClass & STCref)
1618 id = arg->ident;
1619 else
1620 { // Make a copy of the ref argument so it isn't
1621 // a reference.
1622 VarDeclaration *v;
1623 Initializer *ie;
1625 id = Lexer::uniqueId("__applyArg", i);
1627 ie = new ExpInitializer(0, new IdentifierExp(0, id));
1628 v = new VarDeclaration(0, arg->type, arg->ident, ie);
1629 s = new DeclarationStatement(0, v);
1630 body = new CompoundStatement(loc, s, body);
1632 a = new Argument(STCref, arg->type, id, NULL);
1633 args->push(a);
1635 t = new TypeFunction(args, Type::tint32, 0, LINKd);
1636 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
1637 fld->fbody = body;
1638 flde = new FuncExp(loc, fld);
1639 flde = flde->semantic(sc);
1640 fld->tookAddressOf = 0;
1642 // Resolve any forward referenced goto's
1643 for (int i = 0; i < gotos.dim; i++)
1644 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
1645 GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
1647 if (!gs->label->statement)
1648 { // 'Promote' it to this scope, and replace with a return
1649 cases.push(gs);
1650 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
1651 cs->statements->data[0] = (void *)s;
1655 if (tab->ty == Taarray)
1657 // Check types
1658 Argument *arg = (Argument *)arguments->data[0];
1659 if (dim == 2)
1661 if (arg->storageClass & STCref)
1662 error("foreach: index cannot be ref");
1663 if (!arg->type->equals(taa->index))
1664 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
1665 arg = (Argument *)arguments->data[1];
1667 if (!arg->type->equals(taa->nextOf()))
1668 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
1670 /* Call:
1671 * _aaApply(aggr, keysize, flde)
1673 if (dim == 2)
1674 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply2",
1675 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic
1676 else
1677 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply",
1678 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic);
1679 ec = new VarExp(0, fdapply);
1680 Expressions *exps = new Expressions();
1681 exps->push(aggr);
1682 size_t keysize = taa->index->size();
1683 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
1684 exps->push(new IntegerExp(0, keysize, Type::tsize_t));
1685 exps->push(flde);
1686 e = new CallExp(loc, ec, exps);
1687 e->type = Type::tint32; // don't run semantic() on e
1689 else if (tab->ty == Tarray || tab->ty == Tsarray)
1691 /* Call:
1692 * _aApply(aggr, flde)
1694 static char fntab[9][3] =
1695 { "cc","cw","cd",
1696 "wc","cc","wd",
1697 "dc","dw","dd"
1699 char fdname[7+1+2+ sizeof(dim)*3 + 1];
1700 int flag;
1702 switch (tn->ty)
1704 case Tchar: flag = 0; break;
1705 case Twchar: flag = 3; break;
1706 case Tdchar: flag = 6; break;
1707 default: assert(0);
1709 switch (tnv->ty)
1711 case Tchar: flag += 0; break;
1712 case Twchar: flag += 1; break;
1713 case Tdchar: flag += 2; break;
1714 default: assert(0);
1716 const char *r = (op == TOKforeach_reverse) ? "R" : "";
1717 int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
1718 assert(j < sizeof(fdname));
1719 fdapply = FuncDeclaration::genCfunc(Type::tint32, fdname,
1720 Type::tvoid->arrayOf(), flde->type); // flde->type is not generic
1722 ec = new VarExp(0, fdapply);
1723 Expressions *exps = new Expressions();
1724 if (tab->ty == Tsarray)
1725 aggr = aggr->castTo(sc, tn->arrayOf());
1726 exps->push(aggr);
1727 exps->push(flde);
1728 e = new CallExp(loc, ec, exps);
1729 e->type = Type::tint32; // don't run semantic() on e
1731 else if (tab->ty == Tdelegate)
1733 /* Call:
1734 * aggr(flde)
1736 Expressions *exps = new Expressions();
1737 exps->push(flde);
1738 e = new CallExp(loc, aggr, exps);
1739 e = e->semantic(sc);
1740 if (e->type != Type::tint32)
1741 error("opApply() function for %s must return an int", tab->toChars());
1743 else
1745 /* Call:
1746 * aggr.apply(flde)
1748 ec = new DotIdExp(loc, aggr,
1749 (op == TOKforeach_reverse) ? Id::applyReverse
1750 : Id::apply);
1751 Expressions *exps = new Expressions();
1752 exps->push(flde);
1753 e = new CallExp(loc, ec, exps);
1754 e = e->semantic(sc);
1755 if (e->type != Type::tint32)
1756 error("opApply() function for %s must return an int", tab->toChars());
1759 if (!cases.dim)
1760 // Easy case, a clean exit from the loop
1761 s = new ExpStatement(loc, e);
1762 else
1763 { // Construct a switch statement around the return value
1764 // of the apply function.
1765 Statements *a = new Statements();
1767 // default: break; takes care of cases 0 and 1
1768 s = new BreakStatement(0, NULL);
1769 s = new DefaultStatement(0, s);
1770 a->push(s);
1772 // cases 2...
1773 for (int i = 0; i < cases.dim; i++)
1775 s = (Statement *)cases.data[i];
1776 s = new CaseStatement(0, new IntegerExp(i + 2), s);
1777 a->push(s);
1780 s = new CompoundStatement(loc, a);
1781 s = new SwitchStatement(loc, e, s);
1782 s = s->semantic(sc);
1784 break;
1787 default:
1788 error("foreach: %s is not an aggregate type", aggr->type->toChars());
1789 break;
1791 sc->noctor--;
1792 sc->pop();
1793 return s;
1796 int ForeachStatement::hasBreak()
1798 return TRUE;
1801 int ForeachStatement::hasContinue()
1803 return TRUE;
1806 int ForeachStatement::usesEH()
1808 return body->usesEH();
1811 int ForeachStatement::blockExit()
1812 { int result = BEfallthru;
1814 if (aggr->canThrow())
1815 result |= BEthrow;
1817 if (body)
1819 result |= body->blockExit() & ~(BEbreak | BEcontinue);
1821 return result;
1824 int ForeachStatement::fallOffEnd()
1826 if (body)
1827 body->fallOffEnd();
1828 return TRUE;
1831 int ForeachStatement::comeFrom()
1833 if (body)
1834 return body->comeFrom();
1835 return FALSE;
1838 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1840 buf->writestring(Token::toChars(op));
1841 buf->writestring(" (");
1842 for (int i = 0; i < arguments->dim; i++)
1844 Argument *a = (Argument *)arguments->data[i];
1845 if (i)
1846 buf->writestring(", ");
1847 if (a->storageClass & STCref)
1848 buf->writestring((global.params.Dversion == 1)
1849 ? (char*)"inout " : (char*)"ref ");
1850 if (a->type)
1851 a->type->toCBuffer(buf, a->ident, hgs);
1852 else
1853 buf->writestring(a->ident->toChars());
1855 buf->writestring("; ");
1856 aggr->toCBuffer(buf, hgs);
1857 buf->writebyte(')');
1858 buf->writenl();
1859 buf->writebyte('{');
1860 buf->writenl();
1861 if (body)
1862 body->toCBuffer(buf, hgs);
1863 buf->writebyte('}');
1864 buf->writenl();
1867 /**************************** ForeachRangeStatement ***************************/
1869 ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg,
1870 Expression *lwr, Expression *upr, Statement *body)
1871 : Statement(loc)
1873 this->op = op;
1874 this->arg = arg;
1875 this->lwr = lwr;
1876 this->upr = upr;
1877 this->body = body;
1879 this->key = NULL;
1882 Statement *ForeachRangeStatement::syntaxCopy()
1884 ForeachRangeStatement *s = new ForeachRangeStatement(loc, op,
1885 arg->syntaxCopy(),
1886 lwr->syntaxCopy(),
1887 upr->syntaxCopy(),
1888 body ? body->syntaxCopy() : NULL);
1889 return s;
1892 Statement *ForeachRangeStatement::semantic(Scope *sc)
1894 //printf("ForeachRangeStatement::semantic() %p\n", this);
1895 ScopeDsymbol *sym;
1896 Statement *s = this;
1898 lwr = lwr->semantic(sc);
1899 lwr = resolveProperties(sc, lwr);
1900 lwr = lwr->optimize(WANTvalue);
1901 if (!lwr->type)
1903 error("invalid range lower bound %s", lwr->toChars());
1904 return this;
1907 upr = upr->semantic(sc);
1908 upr = resolveProperties(sc, upr);
1909 upr = upr->optimize(WANTvalue);
1910 if (!upr->type)
1912 error("invalid range upper bound %s", upr->toChars());
1913 return this;
1916 if (arg->type)
1918 lwr = lwr->implicitCastTo(sc, arg->type);
1919 upr = upr->implicitCastTo(sc, arg->type);
1921 else
1923 /* Must infer types from lwr and upr
1925 AddExp ea(loc, lwr, upr);
1926 ea.typeCombine(sc);
1927 arg->type = ea.type;
1928 lwr = ea.e1;
1929 upr = ea.e2;
1931 if (!arg->type->isscalar())
1932 error("%s is not a scalar type", arg->type->toChars());
1934 sym = new ScopeDsymbol();
1935 sym->parent = sc->scopesym;
1936 sc = sc->push(sym);
1938 sc->noctor++;
1940 key = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1941 DeclarationExp *de = new DeclarationExp(loc, key);
1942 de->semantic(sc);
1944 if (key->storage_class)
1945 error("foreach range: key cannot have storage class");
1947 sc->sbreak = this;
1948 sc->scontinue = this;
1949 body = body->semantic(sc);
1951 sc->noctor--;
1952 sc->pop();
1953 return s;
1956 int ForeachRangeStatement::hasBreak()
1958 return TRUE;
1961 int ForeachRangeStatement::hasContinue()
1963 return TRUE;
1966 int ForeachRangeStatement::usesEH()
1968 return body->usesEH();
1971 int ForeachRangeStatement::blockExit()
1972 { int result = BEfallthru;
1974 if (lwr && lwr->canThrow())
1975 result |= BEthrow;
1976 else if (upr && upr->canThrow())
1977 result |= BEthrow;
1979 if (body)
1981 result |= body->blockExit() & ~(BEbreak | BEcontinue);
1983 return result;
1986 int ForeachRangeStatement::fallOffEnd()
1988 if (body)
1989 body->fallOffEnd();
1990 return TRUE;
1993 int ForeachRangeStatement::comeFrom()
1995 if (body)
1996 return body->comeFrom();
1997 return FALSE;
2000 void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2002 buf->writestring(Token::toChars(op));
2003 buf->writestring(" (");
2005 if (arg->type)
2006 arg->type->toCBuffer(buf, arg->ident, hgs);
2007 else
2008 buf->writestring(arg->ident->toChars());
2010 buf->writestring("; ");
2011 lwr->toCBuffer(buf, hgs);
2012 buf->writestring(" .. ");
2013 upr->toCBuffer(buf, hgs);
2014 buf->writebyte(')');
2015 buf->writenl();
2016 buf->writebyte('{');
2017 buf->writenl();
2018 if (body)
2019 body->toCBuffer(buf, hgs);
2020 buf->writebyte('}');
2021 buf->writenl();
2024 /******************************** IfStatement ***************************/
2026 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
2027 : Statement(loc)
2029 this->arg = arg;
2030 this->condition = condition;
2031 this->ifbody = ifbody;
2032 this->elsebody = elsebody;
2033 this->match = NULL;
2036 Statement *IfStatement::syntaxCopy()
2038 Statement *i = NULL;
2039 if (ifbody)
2040 i = ifbody->syntaxCopy();
2042 Statement *e = NULL;
2043 if (elsebody)
2044 e = elsebody->syntaxCopy();
2046 Argument *a = arg ? arg->syntaxCopy() : NULL;
2047 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
2048 return s;
2051 Statement *IfStatement::semantic(Scope *sc)
2053 condition = condition->semantic(sc);
2054 condition = resolveProperties(sc, condition);
2055 condition = condition->checkToBoolean();
2057 // If we can short-circuit evaluate the if statement, don't do the
2058 // semantic analysis of the skipped code.
2059 // This feature allows a limited form of conditional compilation.
2060 condition = condition->optimize(WANTflags);
2062 // Evaluate at runtime
2063 unsigned cs0 = sc->callSuper;
2064 unsigned cs1;
2066 Scope *scd;
2067 if (arg)
2068 { /* Declare arg, which we will set to be the
2069 * result of condition.
2071 ScopeDsymbol *sym = new ScopeDsymbol();
2072 sym->parent = sc->scopesym;
2073 scd = sc->push(sym);
2075 Type *t = arg->type ? arg->type : condition->type;
2076 match = new VarDeclaration(loc, t->maybe(true), arg->ident, NULL);
2077 match->skipnullcheck = true;
2078 match->noauto = 1;
2079 match->semantic(scd);
2080 if (!scd->insert(match))
2081 assert(0);
2082 match->parent = sc->func;
2084 /* Generate:
2085 * (arg = condition)
2087 VarExp *v = new VarExp(0, match);
2088 condition = new AssignExp(loc, v, condition);
2089 condition = condition->semantic(scd);
2091 if (match && match->type->ty == Tmaybe)
2093 // Matched object cannot be null in the then block
2094 // (and isn't in scope in the else)
2095 match->type = match->type->nextOf();
2098 else
2099 scd = sc->push();
2100 ifbody = ifbody->semantic(scd);
2101 scd->pop();
2103 cs1 = sc->callSuper;
2104 sc->callSuper = cs0;
2105 if (elsebody)
2106 elsebody = elsebody->semanticScope(sc, NULL, NULL);
2107 sc->mergeCallSuper(loc, cs1);
2109 return this;
2112 int IfStatement::usesEH()
2114 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2117 int IfStatement::blockExit()
2119 //printf("IfStatement::blockExit(%p)\n", this);
2121 int result = BEnone;
2122 if (condition->canThrow())
2123 result |= BEthrow;
2124 if (ifbody)
2125 result |= ifbody->blockExit();
2126 else
2127 result |= BEfallthru;
2128 if (elsebody)
2129 result |= elsebody->blockExit();
2130 else
2131 result |= BEfallthru;
2132 //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
2133 return result;
2136 int IfStatement::fallOffEnd()
2138 if (!ifbody || ifbody->fallOffEnd() ||
2139 !elsebody || elsebody->fallOffEnd())
2140 return TRUE;
2141 return FALSE;
2145 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2147 buf->writestring("if (");
2148 if (arg)
2150 if (arg->type)
2151 arg->type->toCBuffer(buf, arg->ident, hgs);
2152 else
2153 buf->writestring(arg->ident->toChars());
2154 buf->writebyte(';');
2156 condition->toCBuffer(buf, hgs);
2157 buf->writebyte(')');
2158 buf->writenl();
2159 ifbody->toCBuffer(buf, hgs);
2160 if (elsebody)
2161 { buf->writestring("else");
2162 buf->writenl();
2163 elsebody->toCBuffer(buf, hgs);
2167 /******************************** ConditionalStatement ***************************/
2169 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
2170 : Statement(loc)
2172 this->condition = condition;
2173 this->ifbody = ifbody;
2174 this->elsebody = elsebody;
2177 Statement *ConditionalStatement::syntaxCopy()
2179 Statement *e = NULL;
2180 if (elsebody)
2181 e = elsebody->syntaxCopy();
2182 ConditionalStatement *s = new ConditionalStatement(loc,
2183 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
2184 return s;
2187 Statement *ConditionalStatement::semantic(Scope *sc)
2189 //printf("ConditionalStatement::semantic()\n");
2191 // If we can short-circuit evaluate the if statement, don't do the
2192 // semantic analysis of the skipped code.
2193 // This feature allows a limited form of conditional compilation.
2194 if (condition->include(sc, NULL))
2196 ifbody = ifbody->semantic(sc);
2197 return ifbody;
2199 else
2201 if (elsebody)
2202 elsebody = elsebody->semantic(sc);
2203 return elsebody;
2207 Statements *ConditionalStatement::flatten(Scope *sc)
2209 Statement *s;
2211 if (condition->include(sc, NULL))
2212 s = ifbody;
2213 else
2214 s = elsebody;
2216 Statements *a = new Statements();
2217 a->push(s);
2218 return a;
2221 int ConditionalStatement::usesEH()
2223 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2226 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2228 condition->toCBuffer(buf, hgs);
2229 buf->writenl();
2230 if (ifbody)
2231 ifbody->toCBuffer(buf, hgs);
2232 if (elsebody)
2234 buf->writestring("else");
2235 buf->writenl();
2236 elsebody->toCBuffer(buf, hgs);
2238 buf->writenl();
2242 /******************************** PragmaStatement ***************************/
2244 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
2245 : Statement(loc)
2247 this->ident = ident;
2248 this->args = args;
2249 this->body = body;
2252 Statement *PragmaStatement::syntaxCopy()
2254 Statement *b = NULL;
2255 if (body)
2256 b = body->syntaxCopy();
2257 PragmaStatement *s = new PragmaStatement(loc,
2258 ident, Expression::arraySyntaxCopy(args), b);
2259 return s;
2262 Statement *PragmaStatement::semantic(Scope *sc)
2263 { // Should be merged with PragmaDeclaration
2264 //printf("PragmaStatement::semantic() %s\n", toChars());
2265 //printf("body = %p\n", body);
2266 if (ident == Id::msg)
2268 if (args)
2270 for (size_t i = 0; i < args->dim; i++)
2272 Expression *e = (Expression *)args->data[i];
2274 e = e->semantic(sc);
2275 e = e->optimize(WANTvalue | WANTinterpret);
2276 if (e->op == TOKstring)
2278 StringExp *se = (StringExp *)e;
2279 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
2281 else
2282 error("string expected for message, not '%s'", e->toChars());
2284 fprintf(stdmsg, "\n");
2287 else if (ident == Id::lib)
2289 if (!args || args->dim != 1)
2290 error("string expected for library name");
2291 else
2293 Expression *e = (Expression *)args->data[0];
2295 e = e->semantic(sc);
2296 e = e->optimize(WANTvalue | WANTinterpret);
2297 args->data[0] = (void *)e;
2298 if (e->op != TOKstring)
2299 error("string expected for library name, not '%s'", e->toChars());
2300 else if (global.params.verbose)
2302 StringExp *se = (StringExp *)e;
2303 char *name = (char *)mem.malloc(se->len + 1);
2304 memcpy(name, se->string, se->len);
2305 name[se->len] = 0;
2306 printf("library %s\n", name);
2307 mem.free(name);
2311 else if (ident == Id::startaddress)
2313 if (!args || args->dim != 1)
2314 error("function name expected for start address");
2315 else
2317 Expression *e = (Expression *)args->data[0];
2318 e = e->semantic(sc);
2319 e = e->optimize(WANTvalue | WANTinterpret);
2320 args->data[0] = (void *)e;
2321 Dsymbol *sa = getDsymbol(e);
2322 if (!sa || !sa->isFuncDeclaration())
2323 error("function name expected for start address, not '%s'", e->toChars());
2324 if (body)
2326 body = body->semantic(sc);
2328 return this;
2331 else
2332 error("unrecognized pragma(%s)", ident->toChars());
2334 if (body)
2336 body = body->semantic(sc);
2338 return body;
2341 int PragmaStatement::usesEH()
2343 return body && body->usesEH();
2346 int PragmaStatement::blockExit()
2348 int result = BEfallthru;
2349 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru
2350 if (arrayExpressionCanThrow(args))
2351 result |= BEthrow;
2352 if (body)
2353 result |= body->blockExit();
2354 #endif
2355 return result;
2358 int PragmaStatement::fallOffEnd()
2360 if (body)
2361 return body->fallOffEnd();
2362 return TRUE;
2365 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2367 buf->writestring("pragma (");
2368 buf->writestring(ident->toChars());
2369 if (args && args->dim)
2371 buf->writestring(", ");
2372 argsToCBuffer(buf, args, hgs);
2374 buf->writeByte(')');
2375 if (body)
2377 buf->writenl();
2378 buf->writeByte('{');
2379 buf->writenl();
2381 body->toCBuffer(buf, hgs);
2383 buf->writeByte('}');
2384 buf->writenl();
2386 else
2388 buf->writeByte(';');
2389 buf->writenl();
2394 /******************************** LogStatement ***************************/
2396 LogStatement::LogStatement(Loc loc, int level, Expressions *args)
2397 : Statement(loc)
2399 this->level = level;
2400 this->args = args;
2403 Statement *LogStatement::syntaxCopy()
2405 Expressions *copied_args = Expression::arraySyntaxCopy(args);
2406 LogStatement *s = new LogStatement(loc, level, copied_args);
2407 return s;
2410 Statement *LogStatement::semantic(Scope *sc)
2412 Expression *logger = new GetLoggerExp(loc);
2413 Type *type = NULL;
2415 for (Dsymbol *s = sc->parent; s; s = s->parent)
2417 ClassDeclaration *cd;
2418 StructDeclaration *sd;
2420 cd = s->isClassDeclaration();
2421 if (cd)
2423 type = cd->type;
2424 break;
2428 if (type == NULL) {
2429 // We're a top-level function. Generate log messages from the module
2430 args->shift(new StringExp(loc, strdup(sc->module->ident->string)));
2431 } else {
2432 args->shift(new StringExp(loc, type->toChars()));
2435 args->shift(new IntegerExp(loc, level, Type::tint32));
2436 Expression *callLogger = new CallExp(loc, logger, args);
2438 Statement *s = new ExpStatement(loc, callLogger);
2440 return s->semantic(sc);
2443 void LogStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2445 char *l;
2446 switch (level) {
2447 case 10: l = "log_debug"; break;
2448 case 20: l = "log_info"; break;
2449 case 30: l = "log_warning"; break;
2450 case 40: l = "log_error"; break;
2451 default:
2452 error("Unknown log level %d", level);
2453 l = "log_UNKNOWN";
2455 buf->writestring(l);
2456 buf->writeByte('(');
2457 argsToCBuffer(buf, args, hgs);
2458 buf->writeByte(')');
2459 buf->writenl();
2462 /******************************** StaticAssertStatement ***************************/
2464 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2465 : Statement(sa->loc)
2467 this->sa = sa;
2470 Statement *StaticAssertStatement::syntaxCopy()
2472 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2473 return s;
2476 Statement *StaticAssertStatement::semantic(Scope *sc)
2478 sa->semantic2(sc);
2479 return NULL;
2482 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2484 sa->toCBuffer(buf, hgs);
2488 /******************************** SwitchStatement ***************************/
2490 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2491 : Statement(loc)
2493 condition = c;
2494 body = b;
2495 sdefault = NULL;
2496 tf = NULL;
2497 cases = NULL;
2498 hasNoDefault = 0;
2499 hasVars = 0;
2502 Statement *SwitchStatement::syntaxCopy()
2504 SwitchStatement *s = new SwitchStatement(loc,
2505 condition->syntaxCopy(), body->syntaxCopy());
2506 return s;
2509 Statement *SwitchStatement::semantic(Scope *sc)
2511 //printf("SwitchStatement::semantic(%p)\n", this);
2512 tf = sc->tf;
2513 assert(!cases); // ensure semantic() is only run once
2514 condition = condition->semantic(sc);
2515 condition = resolveProperties(sc, condition);
2516 if (condition->type->isString())
2518 // If it's not an array, cast it to one
2519 if (condition->type->ty != Tarray)
2521 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2523 condition->type = condition->type->constOf();
2525 else
2526 { condition = condition->integralPromotions(sc);
2527 condition->checkIntegral();
2529 condition = condition->optimize(WANTvalue);
2531 sc = sc->push();
2532 sc->sbreak = this;
2533 sc->sw = this;
2535 cases = new Array();
2536 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2537 body = body->semantic(sc);
2538 sc->noctor--;
2540 // Resolve any goto case's with exp
2541 for (int i = 0; i < gotoCases.dim; i++)
2543 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2545 if (!gcs->exp)
2547 gcs->error("no case statement following goto case;");
2548 break;
2551 for (Scope *scx = sc; scx; scx = scx->enclosing)
2553 if (!scx->sw)
2554 continue;
2555 for (int j = 0; j < scx->sw->cases->dim; j++)
2557 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2559 if (cs->exp->equals(gcs->exp))
2561 gcs->cs = cs;
2562 goto Lfoundcase;
2566 gcs->error("case %s not found", gcs->exp->toChars());
2568 Lfoundcase:
2572 if (!sc->sw->sdefault)
2573 { hasNoDefault = 1;
2575 if (global.params.warnings)
2576 { fprintf(stdmsg, "warning - ");
2577 error("switch statement has no default");
2580 // Generate runtime error if the default is hit
2581 Statements *a = new Statements();
2582 CompoundStatement *cs;
2583 Statement *s;
2585 if (global.params.useSwitchError)
2586 s = new SwitchErrorStatement(loc);
2587 else
2588 { Expression *e = new HaltExp(loc);
2589 s = new ExpStatement(loc, e);
2592 a->reserve(4);
2593 a->push(body);
2594 a->push(new BreakStatement(loc, NULL));
2595 sc->sw->sdefault = new DefaultStatement(loc, s);
2596 a->push(sc->sw->sdefault);
2597 cs = new CompoundStatement(loc, a);
2598 body = cs;
2601 sc->pop();
2602 return this;
2605 int SwitchStatement::hasBreak()
2607 return TRUE;
2610 int SwitchStatement::usesEH()
2612 return body ? body->usesEH() : 0;
2615 int SwitchStatement::blockExit()
2616 { int result = BEnone;
2617 if (condition->canThrow())
2618 result |= BEthrow;
2620 if (body)
2621 { result |= body->blockExit();
2622 if (result & BEbreak)
2623 { result |= BEfallthru;
2624 result &= ~BEbreak;
2627 else
2628 result |= BEfallthru;
2630 return result;
2633 int SwitchStatement::fallOffEnd()
2635 if (body)
2636 body->fallOffEnd();
2637 return TRUE; // need to do this better
2640 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2642 buf->writestring("switch (");
2643 condition->toCBuffer(buf, hgs);
2644 buf->writebyte(')');
2645 buf->writenl();
2646 if (body)
2648 if (!body->isScopeStatement())
2649 { buf->writebyte('{');
2650 buf->writenl();
2651 body->toCBuffer(buf, hgs);
2652 buf->writebyte('}');
2653 buf->writenl();
2655 else
2657 body->toCBuffer(buf, hgs);
2662 /******************************** CaseStatement ***************************/
2664 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2665 : Statement(loc)
2667 this->exp = exp;
2668 this->statement = s;
2669 index = 0;
2670 cblock = NULL;
2673 Statement *CaseStatement::syntaxCopy()
2675 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2676 return s;
2679 Statement *CaseStatement::semantic(Scope *sc)
2680 { SwitchStatement *sw = sc->sw;
2682 //printf("CaseStatement::semantic() %s\n", toChars());
2683 exp = exp->semantic(sc);
2684 if (sw)
2686 exp = exp->implicitCastTo(sc, sw->condition->type);
2687 exp = exp->optimize(WANTvalue | WANTinterpret);
2689 /* This is where variables are allowed as case expressions.
2691 if (exp->op == TOKvar)
2692 { VarExp *ve = (VarExp *)exp;
2693 VarDeclaration *v = ve->var->isVarDeclaration();
2694 Type *t = exp->type->toBasetype();
2695 if (v && (t->isintegral() || t->ty == Tclass))
2696 { /* Flag that we need to do special code generation
2697 * for this, i.e. generate a sequence of if-then-else
2699 sw->hasVars = 1;
2700 goto L1;
2704 if (exp->op != TOKstring && exp->op != TOKint64)
2706 error("case must be a string or an integral constant, not %s", exp->toChars());
2707 exp = new IntegerExp(0);
2711 for (int i = 0; i < sw->cases->dim; i++)
2713 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2715 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2716 if (cs->exp->equals(exp))
2717 { error("duplicate case %s in switch statement", exp->toChars());
2718 break;
2722 sw->cases->push(this);
2724 // Resolve any goto case's with no exp to this case statement
2725 for (int i = 0; i < sw->gotoCases.dim; i++)
2727 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2729 if (!gcs->exp)
2731 gcs->cs = this;
2732 sw->gotoCases.remove(i); // remove from array
2736 if (sc->sw->tf != sc->tf)
2737 error("switch and case are in different finally blocks");
2739 else
2740 error("case not in switch statement");
2741 statement = statement->semantic(sc);
2742 return this;
2745 int CaseStatement::compare(Object *obj)
2747 // Sort cases so we can do an efficient lookup
2748 CaseStatement *cs2 = (CaseStatement *)(obj);
2750 return exp->compare(cs2->exp);
2753 int CaseStatement::usesEH()
2755 return statement->usesEH();
2758 int CaseStatement::blockExit()
2760 // Assume the worst
2761 return BEany;
2764 int CaseStatement::fallOffEnd()
2766 return statement->fallOffEnd();
2769 int CaseStatement::comeFrom()
2771 return TRUE;
2774 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2776 buf->writestring("case ");
2777 exp->toCBuffer(buf, hgs);
2778 buf->writebyte(':');
2779 buf->writenl();
2780 statement->toCBuffer(buf, hgs);
2783 /******************************** DefaultStatement ***************************/
2785 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2786 : Statement(loc)
2788 this->statement = s;
2789 #if IN_GCC
2790 cblock = NULL;
2791 #endif
2794 Statement *DefaultStatement::syntaxCopy()
2796 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2797 return s;
2800 Statement *DefaultStatement::semantic(Scope *sc)
2802 //printf("DefaultStatement::semantic()\n");
2803 if (sc->sw)
2805 if (sc->sw->sdefault)
2807 error("switch statement already has a default");
2809 sc->sw->sdefault = this;
2811 if (sc->sw->tf != sc->tf)
2812 error("switch and default are in different finally blocks");
2814 else
2815 error("default not in switch statement");
2816 statement = statement->semantic(sc);
2817 return this;
2820 int DefaultStatement::usesEH()
2822 return statement->usesEH();
2825 int DefaultStatement::blockExit()
2827 // Assume the worst
2828 return BEany;
2831 int DefaultStatement::fallOffEnd()
2833 return statement->fallOffEnd();
2836 int DefaultStatement::comeFrom()
2838 return TRUE;
2841 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2843 buf->writestring("default:\n");
2844 statement->toCBuffer(buf, hgs);
2847 /******************************** GotoDefaultStatement ***************************/
2849 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2850 : Statement(loc)
2852 sw = NULL;
2855 Statement *GotoDefaultStatement::syntaxCopy()
2857 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2858 return s;
2861 Statement *GotoDefaultStatement::semantic(Scope *sc)
2863 sw = sc->sw;
2864 if (!sw)
2865 error("goto default not in switch statement");
2866 return this;
2869 int GotoDefaultStatement::blockExit()
2871 return BEgoto;
2874 int GotoDefaultStatement::fallOffEnd()
2876 return FALSE;
2879 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2881 buf->writestring("goto default;\n");
2884 /******************************** GotoCaseStatement ***************************/
2886 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2887 : Statement(loc)
2889 cs = NULL;
2890 this->exp = exp;
2893 Statement *GotoCaseStatement::syntaxCopy()
2895 Expression *e = exp ? exp->syntaxCopy() : NULL;
2896 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2897 return s;
2900 Statement *GotoCaseStatement::semantic(Scope *sc)
2902 if (exp)
2903 exp = exp->semantic(sc);
2905 if (!sc->sw)
2906 error("goto case not in switch statement");
2907 else
2909 sc->sw->gotoCases.push(this);
2910 if (exp)
2912 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2913 exp = exp->optimize(WANTvalue);
2916 return this;
2919 int GotoCaseStatement::blockExit()
2921 return BEgoto;
2924 int GotoCaseStatement::fallOffEnd()
2926 return FALSE;
2929 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2931 buf->writestring("goto case");
2932 if (exp)
2933 { buf->writebyte(' ');
2934 exp->toCBuffer(buf, hgs);
2936 buf->writebyte(';');
2937 buf->writenl();
2940 /******************************** SwitchErrorStatement ***************************/
2942 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2943 : Statement(loc)
2947 int SwitchErrorStatement::blockExit()
2949 return BEthrow;
2952 int SwitchErrorStatement::fallOffEnd()
2954 return FALSE;
2957 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2959 buf->writestring("SwitchErrorStatement::toCBuffer()");
2960 buf->writenl();
2963 /******************************** ReturnStatement ***************************/
2965 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2966 : Statement(loc)
2968 this->exp = exp;
2971 Statement *ReturnStatement::syntaxCopy()
2973 Expression *e = NULL;
2974 if (exp)
2975 e = exp->syntaxCopy();
2976 ReturnStatement *s = new ReturnStatement(loc, e);
2977 return s;
2980 Statement *ReturnStatement::semantic(Scope *sc)
2982 //printf("ReturnStatement::semantic() %s\n", toChars());
2984 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
2985 Scope *scx = sc;
2986 int implicit0 = 0;
2988 if (sc->fes)
2990 // Find scope of function foreach is in
2991 for (; 1; scx = scx->enclosing)
2993 assert(scx);
2994 if (scx->func != fd)
2995 { fd = scx->func; // fd is now function enclosing foreach
2996 break;
3001 Type *tret = fd->type->nextOf();
3002 if (fd->tintro)
3003 tret = fd->tintro->nextOf();
3004 Type *tbret = NULL;
3006 if (tret)
3007 tbret = tret->toBasetype();
3009 // main() returns 0, even if it returns void
3010 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
3011 { implicit0 = 1;
3012 exp = new IntegerExp(0);
3015 if (sc->incontract || scx->incontract)
3016 error("return statements cannot be in contracts");
3017 if (sc->tf || scx->tf)
3018 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
3020 if (fd->isCtorDeclaration())
3022 // Constructors implicitly do:
3023 // return this;
3024 if (exp && exp->op != TOKthis)
3025 error("cannot return expression from constructor");
3026 exp = new ThisExp(0);
3029 if (!exp)
3030 fd->nrvo_can = 0;
3032 if (exp)
3034 fd->hasReturnExp |= 1;
3036 exp = exp->semantic(sc);
3037 exp = resolveProperties(sc, exp);
3038 exp = exp->optimize(WANTvalue);
3040 if (fd->nrvo_can && exp->op == TOKvar)
3041 { VarExp *ve = (VarExp *)exp;
3042 VarDeclaration *v = ve->var->isVarDeclaration();
3044 if (!v || v->isOut() || v->isRef())
3045 fd->nrvo_can = 0;
3046 else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor)
3047 // Struct being returned has destructors
3048 fd->nrvo_can = 0;
3049 else if (fd->nrvo_var == NULL)
3050 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
3051 { //printf("Setting nrvo to %s\n", v->toChars());
3052 fd->nrvo_var = v;
3054 else
3055 fd->nrvo_can = 0;
3057 else if (fd->nrvo_var != v)
3058 fd->nrvo_can = 0;
3060 else
3061 fd->nrvo_can = 0;
3063 if (fd->returnLabel && tbret->ty != Tvoid)
3066 else if (fd->inferRetType)
3068 if (fd->type->nextOf())
3070 if (!exp->type->equals(fd->type->nextOf()))
3071 error("mismatched function return type inference of %s and %s",
3072 exp->type->toChars(), fd->type->nextOf()->toChars());
3074 else
3076 ((TypeFunction *)fd->type)->next = exp->type;
3077 fd->type = fd->type->semantic(loc, sc);
3078 if (!fd->tintro)
3079 { tret = fd->type->nextOf();
3080 tbret = tret->toBasetype();
3084 else if (tbret->ty != Tvoid)
3086 exp = exp->implicitCastTo(sc, tret);
3089 else if (fd->inferRetType)
3091 if (fd->type->nextOf())
3093 if (fd->type->nextOf()->ty != Tvoid)
3094 error("mismatched function return type inference of void and %s",
3095 fd->type->nextOf()->toChars());
3097 else
3099 ((TypeFunction *)fd->type)->next = Type::tvoid;
3100 fd->type = fd->type->semantic(loc, sc);
3101 if (!fd->tintro)
3102 { tret = Type::tvoid;
3103 tbret = tret;
3107 else if (tbret->ty != Tvoid) // if non-void return
3108 error("return expression expected");
3110 if (sc->fes)
3112 Statement *s;
3114 if (exp && !implicit0)
3116 exp = exp->implicitCastTo(sc, tret);
3118 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
3119 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
3120 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
3121 exp->op == TOKstring)
3123 sc->fes->cases.push(this);
3124 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3126 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
3128 Statement *s1;
3129 Statement *s2;
3131 s = new ReturnStatement(0, NULL);
3132 sc->fes->cases.push(s);
3134 // Construct: { exp; return cases.dim + 1; }
3135 s1 = new ExpStatement(loc, exp);
3136 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3137 s = new CompoundStatement(loc, s1, s2);
3139 else
3141 VarExp *v;
3142 Statement *s1;
3143 Statement *s2;
3145 // Construct: return vresult;
3146 if (!fd->vresult)
3147 { VarDeclaration *v;
3149 v = new VarDeclaration(loc, tret, Id::result, NULL);
3150 v->noauto = 1;
3151 v->semantic(scx);
3152 if (!scx->insert(v))
3153 assert(0);
3154 v->parent = fd;
3155 fd->vresult = v;
3158 v = new VarExp(0, fd->vresult);
3159 s = new ReturnStatement(0, v);
3160 sc->fes->cases.push(s);
3162 // Construct: { vresult = exp; return cases.dim + 1; }
3163 v = new VarExp(0, fd->vresult);
3164 exp = new AssignExp(loc, v, exp);
3165 exp = exp->semantic(sc);
3166 s1 = new ExpStatement(loc, exp);
3167 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3168 s = new CompoundStatement(loc, s1, s2);
3170 return s;
3173 if (exp)
3175 if (fd->returnLabel && tbret->ty != Tvoid)
3177 assert(fd->vresult);
3178 VarExp *v = new VarExp(0, fd->vresult);
3180 exp = new AssignExp(loc, v, exp);
3181 exp = exp->semantic(sc);
3183 //exp->dump(0);
3184 //exp->print();
3185 exp->checkEscape();
3188 /* BUG: need to issue an error on:
3189 * this
3190 * { if (x) return;
3191 * super();
3195 if (sc->callSuper & CSXany_ctor &&
3196 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
3197 error("return without calling constructor");
3199 sc->callSuper |= CSXreturn;
3201 // See if all returns are instead to be replaced with a goto returnLabel;
3202 if (fd->returnLabel)
3204 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
3206 gs->label = fd->returnLabel;
3207 if (exp)
3208 { Statement *s;
3210 s = new ExpStatement(0, exp);
3211 return new CompoundStatement(loc, s, gs);
3213 return gs;
3216 if (exp && tbret->ty == Tvoid && !fd->isMain())
3217 { Statement *s;
3219 s = new ExpStatement(loc, exp);
3220 loc = 0;
3221 exp = NULL;
3222 return new CompoundStatement(loc, s, this);
3225 return this;
3228 int ReturnStatement::blockExit()
3229 { int result = BEreturn;
3231 if (exp && exp->canThrow())
3232 result |= BEthrow;
3233 return result;
3236 int ReturnStatement::fallOffEnd()
3238 return FALSE;
3241 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3243 buf->printf("return ");
3244 if (exp)
3245 exp->toCBuffer(buf, hgs);
3246 buf->writeByte(';');
3247 buf->writenl();
3250 /******************************** BreakStatement ***************************/
3252 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
3253 : Statement(loc)
3255 this->ident = ident;
3258 Statement *BreakStatement::syntaxCopy()
3260 BreakStatement *s = new BreakStatement(loc, ident);
3261 return s;
3264 Statement *BreakStatement::semantic(Scope *sc)
3266 //printf("BreakStatement::semantic()\n");
3267 // If:
3268 // break Identifier;
3269 if (ident)
3271 Scope *scx;
3272 FuncDeclaration *thisfunc = sc->func;
3274 for (scx = sc; scx; scx = scx->enclosing)
3276 LabelStatement *ls;
3278 if (scx->func != thisfunc) // if in enclosing function
3280 if (sc->fes) // if this is the body of a foreach
3282 /* Post this statement to the fes, and replace
3283 * it with a return value that caller will put into
3284 * a switch. Caller will figure out where the break
3285 * label actually is.
3286 * Case numbers start with 2, not 0, as 0 is continue
3287 * and 1 is break.
3289 Statement *s;
3290 sc->fes->cases.push(this);
3291 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3292 return s;
3294 break; // can't break to it
3297 ls = scx->slabel;
3298 if (ls && ls->ident == ident)
3300 Statement *s = ls->statement;
3302 if (!s->hasBreak())
3303 error("label '%s' has no break", ident->toChars());
3304 if (ls->tf != sc->tf)
3305 error("cannot break out of finally block");
3306 return this;
3309 error("enclosing label '%s' for break not found", ident->toChars());
3311 else if (!sc->sbreak)
3313 if (sc->fes)
3314 { Statement *s;
3316 // Replace break; with return 1;
3317 s = new ReturnStatement(0, new IntegerExp(1));
3318 return s;
3320 error("break is not inside a loop or switch");
3322 return this;
3325 int BreakStatement::blockExit()
3327 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
3328 return ident ? BEgoto : BEbreak;
3331 int BreakStatement::fallOffEnd()
3333 return FALSE;
3336 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3338 buf->writestring("break");
3339 if (ident)
3340 { buf->writebyte(' ');
3341 buf->writestring(ident->toChars());
3343 buf->writebyte(';');
3344 buf->writenl();
3347 /******************************** ContinueStatement ***************************/
3349 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
3350 : Statement(loc)
3352 this->ident = ident;
3355 Statement *ContinueStatement::syntaxCopy()
3357 ContinueStatement *s = new ContinueStatement(loc, ident);
3358 return s;
3361 Statement *ContinueStatement::semantic(Scope *sc)
3363 //printf("ContinueStatement::semantic() %p\n", this);
3364 if (ident)
3366 Scope *scx;
3367 FuncDeclaration *thisfunc = sc->func;
3369 for (scx = sc; scx; scx = scx->enclosing)
3371 LabelStatement *ls;
3373 if (scx->func != thisfunc) // if in enclosing function
3375 if (sc->fes) // if this is the body of a foreach
3377 for (; scx; scx = scx->enclosing)
3379 ls = scx->slabel;
3380 if (ls && ls->ident == ident && ls->statement == sc->fes)
3382 // Replace continue ident; with return 0;
3383 return new ReturnStatement(0, new IntegerExp(0));
3387 /* Post this statement to the fes, and replace
3388 * it with a return value that caller will put into
3389 * a switch. Caller will figure out where the break
3390 * label actually is.
3391 * Case numbers start with 2, not 0, as 0 is continue
3392 * and 1 is break.
3394 Statement *s;
3395 sc->fes->cases.push(this);
3396 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3397 return s;
3399 break; // can't continue to it
3402 ls = scx->slabel;
3403 if (ls && ls->ident == ident)
3405 Statement *s = ls->statement;
3407 if (!s->hasContinue())
3408 error("label '%s' has no continue", ident->toChars());
3409 if (ls->tf != sc->tf)
3410 error("cannot continue out of finally block");
3411 return this;
3414 error("enclosing label '%s' for continue not found", ident->toChars());
3416 else if (!sc->scontinue)
3418 if (sc->fes)
3419 { Statement *s;
3421 // Replace continue; with return 0;
3422 s = new ReturnStatement(0, new IntegerExp(0));
3423 return s;
3425 error("continue is not inside a loop");
3427 return this;
3430 int ContinueStatement::blockExit()
3432 return ident ? BEgoto : BEcontinue;
3435 int ContinueStatement::fallOffEnd()
3437 return FALSE;
3440 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3442 buf->writestring("continue");
3443 if (ident)
3444 { buf->writebyte(' ');
3445 buf->writestring(ident->toChars());
3447 buf->writebyte(';');
3448 buf->writenl();
3451 /******************************** SynchronizedStatement ***************************/
3453 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
3454 : Statement(loc)
3456 this->exp = exp;
3457 this->body = body;
3458 this->esync = NULL;
3461 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
3462 : Statement(loc)
3464 this->exp = NULL;
3465 this->body = body;
3466 this->esync = esync;
3469 Statement *SynchronizedStatement::syntaxCopy()
3471 Expression *e = exp ? exp->syntaxCopy() : NULL;
3472 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
3473 return s;
3476 Statement *SynchronizedStatement::semantic(Scope *sc)
3478 if (exp)
3479 { ClassDeclaration *cd;
3481 exp = exp->semantic(sc);
3482 exp = resolveProperties(sc, exp);
3483 cd = exp->type->isClassHandle();
3484 if (!cd)
3485 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
3486 else if (cd->isInterfaceDeclaration())
3487 { Type *t = new TypeIdentifier(0, Id::Object);
3489 t = t->semantic(0, sc);
3490 exp = new CastExp(loc, exp, t);
3491 exp = exp->semantic(sc);
3494 if (body)
3495 body = body->semantic(sc);
3496 return this;
3499 int SynchronizedStatement::hasBreak()
3501 return FALSE; //TRUE;
3504 int SynchronizedStatement::hasContinue()
3506 return FALSE; //TRUE;
3509 int SynchronizedStatement::usesEH()
3511 return TRUE;
3514 int SynchronizedStatement::blockExit()
3516 return body ? body->blockExit() : BEfallthru;
3519 int SynchronizedStatement::fallOffEnd()
3521 return body ? body->fallOffEnd() : TRUE;
3524 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3526 buf->writestring("synchronized");
3527 if (exp)
3528 { buf->writebyte('(');
3529 exp->toCBuffer(buf, hgs);
3530 buf->writebyte(')');
3532 if (body)
3534 buf->writebyte(' ');
3535 body->toCBuffer(buf, hgs);
3539 /******************************** WithStatement ***************************/
3541 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
3542 : Statement(loc)
3544 this->exp = exp;
3545 this->body = body;
3546 wthis = NULL;
3549 Statement *WithStatement::syntaxCopy()
3551 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3552 return s;
3555 Statement *WithStatement::semantic(Scope *sc)
3556 { ScopeDsymbol *sym;
3557 Initializer *init;
3559 //printf("WithStatement::semantic()\n");
3560 exp = exp->semantic(sc);
3561 exp = resolveProperties(sc, exp);
3562 if (exp->op == TOKimport)
3563 { ScopeExp *es = (ScopeExp *)exp;
3565 sym = es->sds;
3567 else if (exp->op == TOKtype)
3568 { TypeExp *es = (TypeExp *)exp;
3570 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3571 if (!sym)
3572 { error("%s has no members", es->toChars());
3573 body = body->semantic(sc);
3574 return this;
3577 else
3578 { Type *t = exp->type;
3580 assert(t);
3581 t = t->toBasetype();
3582 if (t->isClassHandle())
3584 init = new ExpInitializer(loc, exp);
3585 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3586 wthis->semantic(sc);
3588 sym = new WithScopeSymbol(this);
3589 sym->parent = sc->scopesym;
3591 else if (t->ty == Tstruct)
3593 Expression *e = exp->addressOf(sc);
3594 init = new ExpInitializer(loc, e);
3595 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3596 wthis->semantic(sc);
3597 sym = new WithScopeSymbol(this);
3598 sym->parent = sc->scopesym;
3600 else
3601 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3602 return NULL;
3605 sc = sc->push(sym);
3607 if (body)
3608 body = body->semantic(sc);
3610 sc->pop();
3612 return this;
3615 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3617 buf->writestring("with (");
3618 exp->toCBuffer(buf, hgs);
3619 buf->writestring(")\n");
3620 if (body)
3621 body->toCBuffer(buf, hgs);
3624 int WithStatement::usesEH()
3626 return body ? body->usesEH() : 0;
3629 int WithStatement::blockExit()
3631 int result = BEnone;
3632 if (exp->canThrow())
3633 result = BEthrow;
3634 if (body)
3635 result |= body->blockExit();
3636 else
3637 result |= BEfallthru;
3638 return result;
3641 int WithStatement::fallOffEnd()
3643 return body ? body->fallOffEnd() : TRUE;
3646 /******************************** TryCatchStatement ***************************/
3648 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3649 : Statement(loc)
3651 this->body = body;
3652 this->catches = catches;
3655 Statement *TryCatchStatement::syntaxCopy()
3657 Array *a = new Array();
3658 a->setDim(catches->dim);
3659 for (int i = 0; i < a->dim; i++)
3660 { Catch *c;
3662 c = (Catch *)catches->data[i];
3663 c = c->syntaxCopy();
3664 a->data[i] = c;
3666 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3667 return s;
3670 Statement *TryCatchStatement::semantic(Scope *sc)
3672 body = body->semanticScope(sc, NULL /*this*/, NULL);
3674 /* Even if body is NULL, still do semantic analysis on catches
3676 for (size_t i = 0; i < catches->dim; i++)
3677 { Catch *c = (Catch *)catches->data[i];
3678 c->semantic(sc);
3680 // Determine if current catch 'hides' any previous catches
3681 for (size_t j = 0; j < i; j++)
3682 { Catch *cj = (Catch *)catches->data[j];
3683 char *si = c->loc.toChars();
3684 char *sj = cj->loc.toChars();
3686 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3687 error("catch at %s hides catch at %s", sj, si);
3691 if (!body)
3692 return NULL;
3694 return this;
3697 int TryCatchStatement::hasBreak()
3699 return FALSE; //TRUE;
3702 int TryCatchStatement::usesEH()
3704 return TRUE;
3707 int TryCatchStatement::blockExit()
3708 { int result;
3710 assert(body);
3711 result = body->blockExit();
3713 for (size_t i = 0; i < catches->dim; i++)
3715 Catch *c = (Catch *)catches->data[i];
3716 result |= c->blockExit();
3718 return result;
3721 int TryCatchStatement::fallOffEnd()
3723 int result = FALSE;
3725 if (body)
3726 result = body->fallOffEnd();
3727 for (int i = 0; i < catches->dim; i++)
3728 { Catch *c;
3730 c = (Catch *)catches->data[i];
3731 if (c->handler)
3732 result |= c->handler->fallOffEnd();
3734 return result;
3737 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3739 buf->writestring("try");
3740 buf->writenl();
3741 if (body)
3742 body->toCBuffer(buf, hgs);
3743 for (size_t i = 0; i < catches->dim; i++)
3745 Catch *c = (Catch *)catches->data[i];
3746 c->toCBuffer(buf, hgs);
3750 /******************************** Catch ***************************/
3752 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3754 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3755 this->loc = loc;
3756 this->type = t;
3757 this->ident = id;
3758 this->handler = handler;
3759 var = NULL;
3762 Catch *Catch::syntaxCopy()
3764 Catch *c = new Catch(loc,
3765 (type ? type->syntaxCopy() : NULL),
3766 ident,
3767 (handler ? handler->syntaxCopy() : NULL));
3768 return c;
3771 void Catch::semantic(Scope *sc)
3772 { ScopeDsymbol *sym;
3774 //printf("Catch::semantic(%s)\n", ident->toChars());
3776 #ifndef IN_GCC
3777 if (sc->tf)
3779 /* This is because the _d_local_unwind() gets the stack munged
3780 * up on this. The workaround is to place any try-catches into
3781 * a separate function, and call that.
3782 * To fix, have the compiler automatically convert the finally
3783 * body into a nested function.
3785 error(loc, "cannot put catch statement inside finally block");
3787 #endif
3789 sym = new ScopeDsymbol();
3790 sym->parent = sc->scopesym;
3791 sc = sc->push(sym);
3793 if (!type)
3794 type = new TypeIdentifier(0, Id::Object);
3795 type = type->semantic(loc, sc);
3796 if (!type->toBasetype()->isClassHandle())
3797 error("can only catch class objects, not '%s'", type->toChars());
3798 else if (ident)
3800 var = new VarDeclaration(loc, type, ident, NULL);
3801 var->parent = sc->parent;
3802 sc->insert(var);
3804 handler = handler->semantic(sc);
3806 sc->pop();
3809 int Catch::blockExit()
3811 return handler ? handler->blockExit() : BEfallthru;
3814 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3816 buf->writestring("catch");
3817 if (type)
3818 { buf->writebyte('(');
3819 type->toCBuffer(buf, ident, hgs);
3820 buf->writebyte(')');
3822 buf->writenl();
3823 buf->writebyte('{');
3824 buf->writenl();
3825 if (handler)
3826 handler->toCBuffer(buf, hgs);
3827 buf->writebyte('}');
3828 buf->writenl();
3831 /****************************** TryFinallyStatement ***************************/
3833 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3834 : Statement(loc)
3836 this->body = body;
3837 this->finalbody = finalbody;
3840 Statement *TryFinallyStatement::syntaxCopy()
3842 TryFinallyStatement *s = new TryFinallyStatement(loc,
3843 body->syntaxCopy(), finalbody->syntaxCopy());
3844 return s;
3847 Statement *TryFinallyStatement::semantic(Scope *sc)
3849 //printf("TryFinallyStatement::semantic()\n");
3850 body = body->semantic(sc);
3851 sc = sc->push();
3852 sc->tf = this;
3853 sc->sbreak = NULL;
3854 sc->scontinue = NULL; // no break or continue out of finally block
3855 finalbody = finalbody->semantic(sc);
3856 sc->pop();
3857 if (!body)
3858 return finalbody;
3859 if (!finalbody)
3860 return body;
3861 if (body->blockExit() == BEfallthru)
3862 { Statement *s = new CompoundStatement(loc, body, finalbody);
3863 return s;
3865 return this;
3868 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3870 buf->printf("try\n{\n");
3871 body->toCBuffer(buf, hgs);
3872 buf->printf("}\nfinally\n{\n");
3873 finalbody->toCBuffer(buf, hgs);
3874 buf->writeByte('}');
3875 buf->writenl();
3878 int TryFinallyStatement::hasBreak()
3880 return FALSE; //TRUE;
3883 int TryFinallyStatement::hasContinue()
3885 return FALSE; //TRUE;
3888 int TryFinallyStatement::usesEH()
3890 return TRUE;
3893 int TryFinallyStatement::blockExit()
3895 int result = body->blockExit();
3896 return result;
3899 int TryFinallyStatement::fallOffEnd()
3900 { int result;
3902 result = body->fallOffEnd();
3903 // if (finalbody)
3904 // result = finalbody->fallOffEnd();
3905 return result;
3908 /****************************** OnScopeStatement ***************************/
3910 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3911 : Statement(loc)
3913 this->tok = tok;
3914 this->statement = statement;
3917 Statement *OnScopeStatement::syntaxCopy()
3919 OnScopeStatement *s = new OnScopeStatement(loc,
3920 tok, statement->syntaxCopy());
3921 return s;
3924 Statement *OnScopeStatement::semantic(Scope *sc)
3926 /* semantic is called on results of scopeCode() */
3927 return this;
3930 int OnScopeStatement::blockExit()
3931 { // At this point, this statement is just an empty placeholder
3932 return BEfallthru;
3935 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3937 buf->writestring(Token::toChars(tok));
3938 buf->writebyte(' ');
3939 statement->toCBuffer(buf, hgs);
3942 int OnScopeStatement::usesEH()
3944 return 1;
3947 void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
3949 //printf("OnScopeStatement::scopeCode()\n");
3950 //print();
3951 *sentry = NULL;
3952 *sexception = NULL;
3953 *sfinally = NULL;
3954 switch (tok)
3956 case TOKon_scope_exit:
3957 *sfinally = statement;
3958 break;
3960 case TOKon_scope_failure:
3961 *sexception = statement;
3962 break;
3964 case TOKon_scope_success:
3966 /* Create:
3967 * sentry: int x = 0;
3968 * sexception: x = 1;
3969 * sfinally: if (!x) statement;
3971 Identifier *id = Lexer::uniqueId("__os");
3973 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
3974 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
3975 *sentry = new DeclarationStatement(loc, v);
3977 Expression *e = new IntegerExp(1);
3978 e = new AssignExp(0, new VarExp(0, v), e);
3979 *sexception = new ExpStatement(0, e);
3981 e = new VarExp(0, v);
3982 e = new NotExp(0, e);
3983 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
3985 break;
3988 default:
3989 assert(0);
3993 /******************************** ThrowStatement ***************************/
3995 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
3996 : Statement(loc)
3998 this->exp = exp;
4001 Statement *ThrowStatement::syntaxCopy()
4003 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
4004 return s;
4007 Statement *ThrowStatement::semantic(Scope *sc)
4009 //printf("ThrowStatement::semantic()\n");
4011 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4012 fd->hasReturnExp |= 2;
4014 if (sc->incontract)
4015 error("Throw statements cannot be in contracts");
4016 exp = exp->semantic(sc);
4017 exp = resolveProperties(sc, exp);
4018 if (!exp->type->toBasetype()->isClassHandle())
4019 error("can only throw class objects, not type %s", exp->type->toChars());
4020 return this;
4023 int ThrowStatement::blockExit()
4025 return BEthrow; // obviously
4028 int ThrowStatement::fallOffEnd()
4030 return FALSE;
4033 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4035 buf->printf("throw ");
4036 exp->toCBuffer(buf, hgs);
4037 buf->writeByte(';');
4038 buf->writenl();
4041 /******************************** VolatileStatement **************************/
4043 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
4044 : Statement(loc)
4046 this->statement = statement;
4049 Statement *VolatileStatement::syntaxCopy()
4051 VolatileStatement *s = new VolatileStatement(loc,
4052 statement ? statement->syntaxCopy() : NULL);
4053 return s;
4056 Statement *VolatileStatement::semantic(Scope *sc)
4058 if (statement)
4059 statement = statement->semantic(sc);
4060 return this;
4063 Statements *VolatileStatement::flatten(Scope *sc)
4065 Statements *a;
4067 a = statement ? statement->flatten(sc) : NULL;
4068 if (a)
4069 { for (int i = 0; i < a->dim; i++)
4070 { Statement *s = (Statement *)a->data[i];
4072 s = new VolatileStatement(loc, s);
4073 a->data[i] = s;
4077 return a;
4080 int VolatileStatement::blockExit()
4082 return statement ? statement->blockExit() : BEfallthru;
4085 int VolatileStatement::fallOffEnd()
4087 return statement ? statement->fallOffEnd() : TRUE;
4090 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4092 buf->writestring("volatile");
4093 if (statement)
4094 { if (statement->isScopeStatement())
4095 buf->writenl();
4096 else
4097 buf->writebyte(' ');
4098 statement->toCBuffer(buf, hgs);
4103 /******************************** GotoStatement ***************************/
4105 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
4106 : Statement(loc)
4108 this->ident = ident;
4109 this->label = NULL;
4110 this->tf = NULL;
4113 Statement *GotoStatement::syntaxCopy()
4115 GotoStatement *s = new GotoStatement(loc, ident);
4116 return s;
4119 Statement *GotoStatement::semantic(Scope *sc)
4120 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4122 //printf("GotoStatement::semantic()\n");
4123 tf = sc->tf;
4124 label = fd->searchLabel(ident);
4125 if (!label->statement && sc->fes)
4127 /* Either the goto label is forward referenced or it
4128 * is in the function that the enclosing foreach is in.
4129 * Can't know yet, so wrap the goto in a compound statement
4130 * so we can patch it later, and add it to a 'look at this later'
4131 * list.
4133 Statements *a = new Statements();
4134 Statement *s;
4136 a->push(this);
4137 s = new CompoundStatement(loc, a);
4138 sc->fes->gotos.push(s); // 'look at this later' list
4139 return s;
4141 if (label->statement && label->statement->tf != sc->tf)
4142 error("cannot goto in or out of finally block");
4143 return this;
4146 int GotoStatement::blockExit()
4148 //printf("GotoStatement::blockExit(%p)\n", this);
4149 return BEgoto;
4152 int GotoStatement::fallOffEnd()
4154 return FALSE;
4157 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4159 buf->writestring("goto ");
4160 buf->writestring(ident->toChars());
4161 buf->writebyte(';');
4162 buf->writenl();
4165 /******************************** LabelStatement ***************************/
4167 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
4168 : Statement(loc)
4170 this->ident = ident;
4171 this->statement = statement;
4172 this->tf = NULL;
4173 this->lblock = NULL;
4174 this->isReturnLabel = 0;
4177 Statement *LabelStatement::syntaxCopy()
4179 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
4180 return s;
4183 Statement *LabelStatement::semantic(Scope *sc)
4184 { LabelDsymbol *ls;
4185 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4187 //printf("LabelStatement::semantic()\n");
4188 ls = fd->searchLabel(ident);
4189 if (ls->statement)
4190 error("Label '%s' already defined", ls->toChars());
4191 else
4192 ls->statement = this;
4193 tf = sc->tf;
4194 sc = sc->push();
4195 sc->scopesym = sc->enclosing->scopesym;
4196 sc->callSuper |= CSXlabel;
4197 sc->slabel = this;
4198 if (statement)
4199 statement = statement->semantic(sc);
4200 sc->pop();
4201 return this;
4204 Statements *LabelStatement::flatten(Scope *sc)
4206 Statements *a = NULL;
4208 if (statement)
4210 a = statement->flatten(sc);
4211 if (a)
4213 if (!a->dim)
4215 a->push(new ExpStatement(loc, NULL));
4217 Statement *s = (Statement *)a->data[0];
4219 s = new LabelStatement(loc, ident, s);
4220 a->data[0] = s;
4224 return a;
4228 int LabelStatement::usesEH()
4230 return statement ? statement->usesEH() : FALSE;
4233 int LabelStatement::blockExit()
4235 //printf("LabelStatement::blockExit(%p)\n", this);
4236 return statement ? statement->blockExit() : BEfallthru;
4239 int LabelStatement::fallOffEnd()
4241 return statement ? statement->fallOffEnd() : TRUE;
4244 int LabelStatement::comeFrom()
4246 //printf("LabelStatement::comeFrom()\n");
4247 return TRUE;
4250 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4252 buf->writestring(ident->toChars());
4253 buf->writebyte(':');
4254 buf->writenl();
4255 if (statement)
4256 statement->toCBuffer(buf, hgs);
4260 /******************************** LabelDsymbol ***************************/
4262 LabelDsymbol::LabelDsymbol(Identifier *ident)
4263 : Dsymbol(ident)
4265 statement = NULL;
4266 #if IN_GCC
4267 asmLabelNum = 0;
4268 #endif
4271 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
4273 return this;