Makefile.in: host_alias to host
[delight/core.git] / dmd2 / statement.c
blob95107b122a8a5460b0d6ed46db915182f43a9519
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->noauto = 1;
2078 match->semantic(scd);
2079 if (!scd->insert(match))
2080 assert(0);
2081 match->parent = sc->func;
2083 /* Generate:
2084 * (arg = condition)
2086 VarExp *v = new VarExp(0, match);
2087 condition = new AssignExp(loc, v, condition);
2088 condition = condition->semantic(scd);
2090 if (match && match->type->ty == Tmaybe)
2092 // Matched object cannot be null in the then block
2093 // (and isn't in scope in the else)
2094 match->type = match->type->nextOf();
2097 else
2098 scd = sc->push();
2099 ifbody = ifbody->semantic(scd);
2100 scd->pop();
2102 cs1 = sc->callSuper;
2103 sc->callSuper = cs0;
2104 if (elsebody)
2105 elsebody = elsebody->semanticScope(sc, NULL, NULL);
2106 sc->mergeCallSuper(loc, cs1);
2108 return this;
2111 int IfStatement::usesEH()
2113 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2116 int IfStatement::blockExit()
2118 //printf("IfStatement::blockExit(%p)\n", this);
2120 int result = BEnone;
2121 if (condition->canThrow())
2122 result |= BEthrow;
2123 if (ifbody)
2124 result |= ifbody->blockExit();
2125 else
2126 result |= BEfallthru;
2127 if (elsebody)
2128 result |= elsebody->blockExit();
2129 else
2130 result |= BEfallthru;
2131 //printf("IfStatement::blockExit(%p) = x%x\n", this, result);
2132 return result;
2135 int IfStatement::fallOffEnd()
2137 if (!ifbody || ifbody->fallOffEnd() ||
2138 !elsebody || elsebody->fallOffEnd())
2139 return TRUE;
2140 return FALSE;
2144 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2146 buf->writestring("if (");
2147 if (arg)
2149 if (arg->type)
2150 arg->type->toCBuffer(buf, arg->ident, hgs);
2151 else
2152 buf->writestring(arg->ident->toChars());
2153 buf->writebyte(';');
2155 condition->toCBuffer(buf, hgs);
2156 buf->writebyte(')');
2157 buf->writenl();
2158 ifbody->toCBuffer(buf, hgs);
2159 if (elsebody)
2160 { buf->writestring("else");
2161 buf->writenl();
2162 elsebody->toCBuffer(buf, hgs);
2166 /******************************** ConditionalStatement ***************************/
2168 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
2169 : Statement(loc)
2171 this->condition = condition;
2172 this->ifbody = ifbody;
2173 this->elsebody = elsebody;
2176 Statement *ConditionalStatement::syntaxCopy()
2178 Statement *e = NULL;
2179 if (elsebody)
2180 e = elsebody->syntaxCopy();
2181 ConditionalStatement *s = new ConditionalStatement(loc,
2182 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
2183 return s;
2186 Statement *ConditionalStatement::semantic(Scope *sc)
2188 //printf("ConditionalStatement::semantic()\n");
2190 // If we can short-circuit evaluate the if statement, don't do the
2191 // semantic analysis of the skipped code.
2192 // This feature allows a limited form of conditional compilation.
2193 if (condition->include(sc, NULL))
2195 ifbody = ifbody->semantic(sc);
2196 return ifbody;
2198 else
2200 if (elsebody)
2201 elsebody = elsebody->semantic(sc);
2202 return elsebody;
2206 Statements *ConditionalStatement::flatten(Scope *sc)
2208 Statement *s;
2210 if (condition->include(sc, NULL))
2211 s = ifbody;
2212 else
2213 s = elsebody;
2215 Statements *a = new Statements();
2216 a->push(s);
2217 return a;
2220 int ConditionalStatement::usesEH()
2222 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
2225 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2227 condition->toCBuffer(buf, hgs);
2228 buf->writenl();
2229 if (ifbody)
2230 ifbody->toCBuffer(buf, hgs);
2231 if (elsebody)
2233 buf->writestring("else");
2234 buf->writenl();
2235 elsebody->toCBuffer(buf, hgs);
2237 buf->writenl();
2241 /******************************** PragmaStatement ***************************/
2243 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
2244 : Statement(loc)
2246 this->ident = ident;
2247 this->args = args;
2248 this->body = body;
2251 Statement *PragmaStatement::syntaxCopy()
2253 Statement *b = NULL;
2254 if (body)
2255 b = body->syntaxCopy();
2256 PragmaStatement *s = new PragmaStatement(loc,
2257 ident, Expression::arraySyntaxCopy(args), b);
2258 return s;
2261 Statement *PragmaStatement::semantic(Scope *sc)
2262 { // Should be merged with PragmaDeclaration
2263 //printf("PragmaStatement::semantic() %s\n", toChars());
2264 //printf("body = %p\n", body);
2265 if (ident == Id::msg)
2267 if (args)
2269 for (size_t i = 0; i < args->dim; i++)
2271 Expression *e = (Expression *)args->data[i];
2273 e = e->semantic(sc);
2274 e = e->optimize(WANTvalue | WANTinterpret);
2275 if (e->op == TOKstring)
2277 StringExp *se = (StringExp *)e;
2278 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
2280 else
2281 error("string expected for message, not '%s'", e->toChars());
2283 fprintf(stdmsg, "\n");
2286 else if (ident == Id::lib)
2288 if (!args || args->dim != 1)
2289 error("string expected for library name");
2290 else
2292 Expression *e = (Expression *)args->data[0];
2294 e = e->semantic(sc);
2295 e = e->optimize(WANTvalue | WANTinterpret);
2296 args->data[0] = (void *)e;
2297 if (e->op != TOKstring)
2298 error("string expected for library name, not '%s'", e->toChars());
2299 else if (global.params.verbose)
2301 StringExp *se = (StringExp *)e;
2302 char *name = (char *)mem.malloc(se->len + 1);
2303 memcpy(name, se->string, se->len);
2304 name[se->len] = 0;
2305 printf("library %s\n", name);
2306 mem.free(name);
2310 else if (ident == Id::startaddress)
2312 if (!args || args->dim != 1)
2313 error("function name expected for start address");
2314 else
2316 Expression *e = (Expression *)args->data[0];
2317 e = e->semantic(sc);
2318 e = e->optimize(WANTvalue | WANTinterpret);
2319 args->data[0] = (void *)e;
2320 Dsymbol *sa = getDsymbol(e);
2321 if (!sa || !sa->isFuncDeclaration())
2322 error("function name expected for start address, not '%s'", e->toChars());
2323 if (body)
2325 body = body->semantic(sc);
2327 return this;
2330 else
2331 error("unrecognized pragma(%s)", ident->toChars());
2333 if (body)
2335 body = body->semantic(sc);
2337 return body;
2340 int PragmaStatement::usesEH()
2342 return body && body->usesEH();
2345 int PragmaStatement::blockExit()
2347 int result = BEfallthru;
2348 #if 0 // currently, no code is generated for Pragma's, so it's just fallthru
2349 if (arrayExpressionCanThrow(args))
2350 result |= BEthrow;
2351 if (body)
2352 result |= body->blockExit();
2353 #endif
2354 return result;
2357 int PragmaStatement::fallOffEnd()
2359 if (body)
2360 return body->fallOffEnd();
2361 return TRUE;
2364 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2366 buf->writestring("pragma (");
2367 buf->writestring(ident->toChars());
2368 if (args && args->dim)
2370 buf->writestring(", ");
2371 argsToCBuffer(buf, args, hgs);
2373 buf->writeByte(')');
2374 if (body)
2376 buf->writenl();
2377 buf->writeByte('{');
2378 buf->writenl();
2380 body->toCBuffer(buf, hgs);
2382 buf->writeByte('}');
2383 buf->writenl();
2385 else
2387 buf->writeByte(';');
2388 buf->writenl();
2393 /******************************** LogStatement ***************************/
2395 LogStatement::LogStatement(Loc loc, int level, Expressions *args)
2396 : Statement(loc)
2398 this->level = level;
2399 this->args = args;
2402 Statement *LogStatement::syntaxCopy()
2404 Expressions *copied_args = Expression::arraySyntaxCopy(args);
2405 LogStatement *s = new LogStatement(loc, level, copied_args);
2406 return s;
2409 Statement *LogStatement::semantic(Scope *sc)
2411 Expression *logger = new GetLoggerExp(loc);
2412 Type *type = NULL;
2414 for (Dsymbol *s = sc->parent; s; s = s->parent)
2416 ClassDeclaration *cd;
2417 StructDeclaration *sd;
2419 cd = s->isClassDeclaration();
2420 if (cd)
2422 type = cd->type;
2423 break;
2427 if (type == NULL) {
2428 // We're a top-level function. Generate log messages from the module
2429 args->shift(new StringExp(loc, strdup(sc->module->ident->string)));
2430 } else {
2431 args->shift(new StringExp(loc, type->toChars()));
2434 args->shift(new IntegerExp(loc, level, Type::tint32));
2435 Expression *callLogger = new CallExp(loc, logger, args);
2437 Statement *s = new ExpStatement(loc, callLogger);
2439 return s->semantic(sc);
2442 void LogStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2444 char *l;
2445 switch (level) {
2446 case 10: l = "log_debug"; break;
2447 case 20: l = "log_info"; break;
2448 case 30: l = "log_warning"; break;
2449 case 40: l = "log_error"; break;
2450 default:
2451 error("Unknown log level %d", level);
2452 l = "log_UNKNOWN";
2454 buf->writestring(l);
2455 buf->writeByte('(');
2456 argsToCBuffer(buf, args, hgs);
2457 buf->writeByte(')');
2458 buf->writenl();
2461 /******************************** StaticAssertStatement ***************************/
2463 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2464 : Statement(sa->loc)
2466 this->sa = sa;
2469 Statement *StaticAssertStatement::syntaxCopy()
2471 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2472 return s;
2475 Statement *StaticAssertStatement::semantic(Scope *sc)
2477 sa->semantic2(sc);
2478 return NULL;
2481 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2483 sa->toCBuffer(buf, hgs);
2487 /******************************** SwitchStatement ***************************/
2489 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2490 : Statement(loc)
2492 condition = c;
2493 body = b;
2494 sdefault = NULL;
2495 tf = NULL;
2496 cases = NULL;
2497 hasNoDefault = 0;
2498 hasVars = 0;
2501 Statement *SwitchStatement::syntaxCopy()
2503 SwitchStatement *s = new SwitchStatement(loc,
2504 condition->syntaxCopy(), body->syntaxCopy());
2505 return s;
2508 Statement *SwitchStatement::semantic(Scope *sc)
2510 //printf("SwitchStatement::semantic(%p)\n", this);
2511 tf = sc->tf;
2512 assert(!cases); // ensure semantic() is only run once
2513 condition = condition->semantic(sc);
2514 condition = resolveProperties(sc, condition);
2515 if (condition->type->isString())
2517 // If it's not an array, cast it to one
2518 if (condition->type->ty != Tarray)
2520 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2522 condition->type = condition->type->constOf();
2524 else
2525 { condition = condition->integralPromotions(sc);
2526 condition->checkIntegral();
2528 condition = condition->optimize(WANTvalue);
2530 sc = sc->push();
2531 sc->sbreak = this;
2532 sc->sw = this;
2534 cases = new Array();
2535 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2536 body = body->semantic(sc);
2537 sc->noctor--;
2539 // Resolve any goto case's with exp
2540 for (int i = 0; i < gotoCases.dim; i++)
2542 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2544 if (!gcs->exp)
2546 gcs->error("no case statement following goto case;");
2547 break;
2550 for (Scope *scx = sc; scx; scx = scx->enclosing)
2552 if (!scx->sw)
2553 continue;
2554 for (int j = 0; j < scx->sw->cases->dim; j++)
2556 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2558 if (cs->exp->equals(gcs->exp))
2560 gcs->cs = cs;
2561 goto Lfoundcase;
2565 gcs->error("case %s not found", gcs->exp->toChars());
2567 Lfoundcase:
2571 if (!sc->sw->sdefault)
2572 { hasNoDefault = 1;
2574 if (global.params.warnings)
2575 { fprintf(stdmsg, "warning - ");
2576 error("switch statement has no default");
2579 // Generate runtime error if the default is hit
2580 Statements *a = new Statements();
2581 CompoundStatement *cs;
2582 Statement *s;
2584 if (global.params.useSwitchError)
2585 s = new SwitchErrorStatement(loc);
2586 else
2587 { Expression *e = new HaltExp(loc);
2588 s = new ExpStatement(loc, e);
2591 a->reserve(4);
2592 a->push(body);
2593 a->push(new BreakStatement(loc, NULL));
2594 sc->sw->sdefault = new DefaultStatement(loc, s);
2595 a->push(sc->sw->sdefault);
2596 cs = new CompoundStatement(loc, a);
2597 body = cs;
2600 sc->pop();
2601 return this;
2604 int SwitchStatement::hasBreak()
2606 return TRUE;
2609 int SwitchStatement::usesEH()
2611 return body ? body->usesEH() : 0;
2614 int SwitchStatement::blockExit()
2615 { int result = BEnone;
2616 if (condition->canThrow())
2617 result |= BEthrow;
2619 if (body)
2620 { result |= body->blockExit();
2621 if (result & BEbreak)
2622 { result |= BEfallthru;
2623 result &= ~BEbreak;
2626 else
2627 result |= BEfallthru;
2629 return result;
2632 int SwitchStatement::fallOffEnd()
2634 if (body)
2635 body->fallOffEnd();
2636 return TRUE; // need to do this better
2639 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2641 buf->writestring("switch (");
2642 condition->toCBuffer(buf, hgs);
2643 buf->writebyte(')');
2644 buf->writenl();
2645 if (body)
2647 if (!body->isScopeStatement())
2648 { buf->writebyte('{');
2649 buf->writenl();
2650 body->toCBuffer(buf, hgs);
2651 buf->writebyte('}');
2652 buf->writenl();
2654 else
2656 body->toCBuffer(buf, hgs);
2661 /******************************** CaseStatement ***************************/
2663 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2664 : Statement(loc)
2666 this->exp = exp;
2667 this->statement = s;
2668 index = 0;
2669 cblock = NULL;
2672 Statement *CaseStatement::syntaxCopy()
2674 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2675 return s;
2678 Statement *CaseStatement::semantic(Scope *sc)
2679 { SwitchStatement *sw = sc->sw;
2681 //printf("CaseStatement::semantic() %s\n", toChars());
2682 exp = exp->semantic(sc);
2683 if (sw)
2685 exp = exp->implicitCastTo(sc, sw->condition->type);
2686 exp = exp->optimize(WANTvalue | WANTinterpret);
2688 /* This is where variables are allowed as case expressions.
2690 if (exp->op == TOKvar)
2691 { VarExp *ve = (VarExp *)exp;
2692 VarDeclaration *v = ve->var->isVarDeclaration();
2693 Type *t = exp->type->toBasetype();
2694 if (v && (t->isintegral() || t->ty == Tclass))
2695 { /* Flag that we need to do special code generation
2696 * for this, i.e. generate a sequence of if-then-else
2698 sw->hasVars = 1;
2699 goto L1;
2703 if (exp->op != TOKstring && exp->op != TOKint64)
2705 error("case must be a string or an integral constant, not %s", exp->toChars());
2706 exp = new IntegerExp(0);
2710 for (int i = 0; i < sw->cases->dim; i++)
2712 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2714 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2715 if (cs->exp->equals(exp))
2716 { error("duplicate case %s in switch statement", exp->toChars());
2717 break;
2721 sw->cases->push(this);
2723 // Resolve any goto case's with no exp to this case statement
2724 for (int i = 0; i < sw->gotoCases.dim; i++)
2726 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2728 if (!gcs->exp)
2730 gcs->cs = this;
2731 sw->gotoCases.remove(i); // remove from array
2735 if (sc->sw->tf != sc->tf)
2736 error("switch and case are in different finally blocks");
2738 else
2739 error("case not in switch statement");
2740 statement = statement->semantic(sc);
2741 return this;
2744 int CaseStatement::compare(Object *obj)
2746 // Sort cases so we can do an efficient lookup
2747 CaseStatement *cs2 = (CaseStatement *)(obj);
2749 return exp->compare(cs2->exp);
2752 int CaseStatement::usesEH()
2754 return statement->usesEH();
2757 int CaseStatement::blockExit()
2759 // Assume the worst
2760 return BEany;
2763 int CaseStatement::fallOffEnd()
2765 return statement->fallOffEnd();
2768 int CaseStatement::comeFrom()
2770 return TRUE;
2773 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2775 buf->writestring("case ");
2776 exp->toCBuffer(buf, hgs);
2777 buf->writebyte(':');
2778 buf->writenl();
2779 statement->toCBuffer(buf, hgs);
2782 /******************************** DefaultStatement ***************************/
2784 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2785 : Statement(loc)
2787 this->statement = s;
2788 #if IN_GCC
2789 cblock = NULL;
2790 #endif
2793 Statement *DefaultStatement::syntaxCopy()
2795 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2796 return s;
2799 Statement *DefaultStatement::semantic(Scope *sc)
2801 //printf("DefaultStatement::semantic()\n");
2802 if (sc->sw)
2804 if (sc->sw->sdefault)
2806 error("switch statement already has a default");
2808 sc->sw->sdefault = this;
2810 if (sc->sw->tf != sc->tf)
2811 error("switch and default are in different finally blocks");
2813 else
2814 error("default not in switch statement");
2815 statement = statement->semantic(sc);
2816 return this;
2819 int DefaultStatement::usesEH()
2821 return statement->usesEH();
2824 int DefaultStatement::blockExit()
2826 // Assume the worst
2827 return BEany;
2830 int DefaultStatement::fallOffEnd()
2832 return statement->fallOffEnd();
2835 int DefaultStatement::comeFrom()
2837 return TRUE;
2840 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2842 buf->writestring("default:\n");
2843 statement->toCBuffer(buf, hgs);
2846 /******************************** GotoDefaultStatement ***************************/
2848 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2849 : Statement(loc)
2851 sw = NULL;
2854 Statement *GotoDefaultStatement::syntaxCopy()
2856 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2857 return s;
2860 Statement *GotoDefaultStatement::semantic(Scope *sc)
2862 sw = sc->sw;
2863 if (!sw)
2864 error("goto default not in switch statement");
2865 return this;
2868 int GotoDefaultStatement::blockExit()
2870 return BEgoto;
2873 int GotoDefaultStatement::fallOffEnd()
2875 return FALSE;
2878 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2880 buf->writestring("goto default;\n");
2883 /******************************** GotoCaseStatement ***************************/
2885 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2886 : Statement(loc)
2888 cs = NULL;
2889 this->exp = exp;
2892 Statement *GotoCaseStatement::syntaxCopy()
2894 Expression *e = exp ? exp->syntaxCopy() : NULL;
2895 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2896 return s;
2899 Statement *GotoCaseStatement::semantic(Scope *sc)
2901 if (exp)
2902 exp = exp->semantic(sc);
2904 if (!sc->sw)
2905 error("goto case not in switch statement");
2906 else
2908 sc->sw->gotoCases.push(this);
2909 if (exp)
2911 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2912 exp = exp->optimize(WANTvalue);
2915 return this;
2918 int GotoCaseStatement::blockExit()
2920 return BEgoto;
2923 int GotoCaseStatement::fallOffEnd()
2925 return FALSE;
2928 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2930 buf->writestring("goto case");
2931 if (exp)
2932 { buf->writebyte(' ');
2933 exp->toCBuffer(buf, hgs);
2935 buf->writebyte(';');
2936 buf->writenl();
2939 /******************************** SwitchErrorStatement ***************************/
2941 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2942 : Statement(loc)
2946 int SwitchErrorStatement::blockExit()
2948 return BEthrow;
2951 int SwitchErrorStatement::fallOffEnd()
2953 return FALSE;
2956 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2958 buf->writestring("SwitchErrorStatement::toCBuffer()");
2959 buf->writenl();
2962 /******************************** ReturnStatement ***************************/
2964 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2965 : Statement(loc)
2967 this->exp = exp;
2970 Statement *ReturnStatement::syntaxCopy()
2972 Expression *e = NULL;
2973 if (exp)
2974 e = exp->syntaxCopy();
2975 ReturnStatement *s = new ReturnStatement(loc, e);
2976 return s;
2979 Statement *ReturnStatement::semantic(Scope *sc)
2981 //printf("ReturnStatement::semantic() %s\n", toChars());
2983 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
2984 Scope *scx = sc;
2985 int implicit0 = 0;
2987 if (sc->fes)
2989 // Find scope of function foreach is in
2990 for (; 1; scx = scx->enclosing)
2992 assert(scx);
2993 if (scx->func != fd)
2994 { fd = scx->func; // fd is now function enclosing foreach
2995 break;
3000 Type *tret = fd->type->nextOf();
3001 if (fd->tintro)
3002 tret = fd->tintro->nextOf();
3003 Type *tbret = NULL;
3005 if (tret)
3006 tbret = tret->toBasetype();
3008 // main() returns 0, even if it returns void
3009 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
3010 { implicit0 = 1;
3011 exp = new IntegerExp(0);
3014 if (sc->incontract || scx->incontract)
3015 error("return statements cannot be in contracts");
3016 if (sc->tf || scx->tf)
3017 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
3019 if (fd->isCtorDeclaration())
3021 // Constructors implicitly do:
3022 // return this;
3023 if (exp && exp->op != TOKthis)
3024 error("cannot return expression from constructor");
3025 exp = new ThisExp(0);
3028 if (!exp)
3029 fd->nrvo_can = 0;
3031 if (exp)
3033 fd->hasReturnExp |= 1;
3035 exp = exp->semantic(sc);
3036 exp = resolveProperties(sc, exp);
3037 exp = exp->optimize(WANTvalue);
3039 if (fd->nrvo_can && exp->op == TOKvar)
3040 { VarExp *ve = (VarExp *)exp;
3041 VarDeclaration *v = ve->var->isVarDeclaration();
3043 if (!v || v->isOut() || v->isRef())
3044 fd->nrvo_can = 0;
3045 else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor)
3046 // Struct being returned has destructors
3047 fd->nrvo_can = 0;
3048 else if (fd->nrvo_var == NULL)
3049 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
3050 { //printf("Setting nrvo to %s\n", v->toChars());
3051 fd->nrvo_var = v;
3053 else
3054 fd->nrvo_can = 0;
3056 else if (fd->nrvo_var != v)
3057 fd->nrvo_can = 0;
3059 else
3060 fd->nrvo_can = 0;
3062 if (fd->returnLabel && tbret->ty != Tvoid)
3065 else if (fd->inferRetType)
3067 if (fd->type->nextOf())
3069 if (!exp->type->equals(fd->type->nextOf()))
3070 error("mismatched function return type inference of %s and %s",
3071 exp->type->toChars(), fd->type->nextOf()->toChars());
3073 else
3075 ((TypeFunction *)fd->type)->next = exp->type;
3076 fd->type = fd->type->semantic(loc, sc);
3077 if (!fd->tintro)
3078 { tret = fd->type->nextOf();
3079 tbret = tret->toBasetype();
3083 else if (tbret->ty != Tvoid)
3085 exp = exp->implicitCastTo(sc, tret);
3088 else if (fd->inferRetType)
3090 if (fd->type->nextOf())
3092 if (fd->type->nextOf()->ty != Tvoid)
3093 error("mismatched function return type inference of void and %s",
3094 fd->type->nextOf()->toChars());
3096 else
3098 ((TypeFunction *)fd->type)->next = Type::tvoid;
3099 fd->type = fd->type->semantic(loc, sc);
3100 if (!fd->tintro)
3101 { tret = Type::tvoid;
3102 tbret = tret;
3106 else if (tbret->ty != Tvoid) // if non-void return
3107 error("return expression expected");
3109 if (sc->fes)
3111 Statement *s;
3113 if (exp && !implicit0)
3115 exp = exp->implicitCastTo(sc, tret);
3117 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
3118 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
3119 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
3120 exp->op == TOKstring)
3122 sc->fes->cases.push(this);
3123 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3125 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
3127 Statement *s1;
3128 Statement *s2;
3130 s = new ReturnStatement(0, NULL);
3131 sc->fes->cases.push(s);
3133 // Construct: { exp; return cases.dim + 1; }
3134 s1 = new ExpStatement(loc, exp);
3135 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3136 s = new CompoundStatement(loc, s1, s2);
3138 else
3140 VarExp *v;
3141 Statement *s1;
3142 Statement *s2;
3144 // Construct: return vresult;
3145 if (!fd->vresult)
3146 { VarDeclaration *v;
3148 v = new VarDeclaration(loc, tret, Id::result, NULL);
3149 v->noauto = 1;
3150 v->semantic(scx);
3151 if (!scx->insert(v))
3152 assert(0);
3153 v->parent = fd;
3154 fd->vresult = v;
3157 v = new VarExp(0, fd->vresult);
3158 s = new ReturnStatement(0, v);
3159 sc->fes->cases.push(s);
3161 // Construct: { vresult = exp; return cases.dim + 1; }
3162 v = new VarExp(0, fd->vresult);
3163 exp = new AssignExp(loc, v, exp);
3164 exp = exp->semantic(sc);
3165 s1 = new ExpStatement(loc, exp);
3166 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3167 s = new CompoundStatement(loc, s1, s2);
3169 return s;
3172 if (exp)
3174 if (fd->returnLabel && tbret->ty != Tvoid)
3176 assert(fd->vresult);
3177 VarExp *v = new VarExp(0, fd->vresult);
3179 exp = new AssignExp(loc, v, exp);
3180 exp = exp->semantic(sc);
3182 //exp->dump(0);
3183 //exp->print();
3184 exp->checkEscape();
3187 /* BUG: need to issue an error on:
3188 * this
3189 * { if (x) return;
3190 * super();
3194 if (sc->callSuper & CSXany_ctor &&
3195 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
3196 error("return without calling constructor");
3198 sc->callSuper |= CSXreturn;
3200 // See if all returns are instead to be replaced with a goto returnLabel;
3201 if (fd->returnLabel)
3203 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
3205 gs->label = fd->returnLabel;
3206 if (exp)
3207 { Statement *s;
3209 s = new ExpStatement(0, exp);
3210 return new CompoundStatement(loc, s, gs);
3212 return gs;
3215 if (exp && tbret->ty == Tvoid && !fd->isMain())
3216 { Statement *s;
3218 s = new ExpStatement(loc, exp);
3219 loc = 0;
3220 exp = NULL;
3221 return new CompoundStatement(loc, s, this);
3224 return this;
3227 int ReturnStatement::blockExit()
3228 { int result = BEreturn;
3230 if (exp && exp->canThrow())
3231 result |= BEthrow;
3232 return result;
3235 int ReturnStatement::fallOffEnd()
3237 return FALSE;
3240 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3242 buf->printf("return ");
3243 if (exp)
3244 exp->toCBuffer(buf, hgs);
3245 buf->writeByte(';');
3246 buf->writenl();
3249 /******************************** BreakStatement ***************************/
3251 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
3252 : Statement(loc)
3254 this->ident = ident;
3257 Statement *BreakStatement::syntaxCopy()
3259 BreakStatement *s = new BreakStatement(loc, ident);
3260 return s;
3263 Statement *BreakStatement::semantic(Scope *sc)
3265 //printf("BreakStatement::semantic()\n");
3266 // If:
3267 // break Identifier;
3268 if (ident)
3270 Scope *scx;
3271 FuncDeclaration *thisfunc = sc->func;
3273 for (scx = sc; scx; scx = scx->enclosing)
3275 LabelStatement *ls;
3277 if (scx->func != thisfunc) // if in enclosing function
3279 if (sc->fes) // if this is the body of a foreach
3281 /* Post this statement to the fes, and replace
3282 * it with a return value that caller will put into
3283 * a switch. Caller will figure out where the break
3284 * label actually is.
3285 * Case numbers start with 2, not 0, as 0 is continue
3286 * and 1 is break.
3288 Statement *s;
3289 sc->fes->cases.push(this);
3290 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3291 return s;
3293 break; // can't break to it
3296 ls = scx->slabel;
3297 if (ls && ls->ident == ident)
3299 Statement *s = ls->statement;
3301 if (!s->hasBreak())
3302 error("label '%s' has no break", ident->toChars());
3303 if (ls->tf != sc->tf)
3304 error("cannot break out of finally block");
3305 return this;
3308 error("enclosing label '%s' for break not found", ident->toChars());
3310 else if (!sc->sbreak)
3312 if (sc->fes)
3313 { Statement *s;
3315 // Replace break; with return 1;
3316 s = new ReturnStatement(0, new IntegerExp(1));
3317 return s;
3319 error("break is not inside a loop or switch");
3321 return this;
3324 int BreakStatement::blockExit()
3326 //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak);
3327 return ident ? BEgoto : BEbreak;
3330 int BreakStatement::fallOffEnd()
3332 return FALSE;
3335 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3337 buf->writestring("break");
3338 if (ident)
3339 { buf->writebyte(' ');
3340 buf->writestring(ident->toChars());
3342 buf->writebyte(';');
3343 buf->writenl();
3346 /******************************** ContinueStatement ***************************/
3348 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
3349 : Statement(loc)
3351 this->ident = ident;
3354 Statement *ContinueStatement::syntaxCopy()
3356 ContinueStatement *s = new ContinueStatement(loc, ident);
3357 return s;
3360 Statement *ContinueStatement::semantic(Scope *sc)
3362 //printf("ContinueStatement::semantic() %p\n", this);
3363 if (ident)
3365 Scope *scx;
3366 FuncDeclaration *thisfunc = sc->func;
3368 for (scx = sc; scx; scx = scx->enclosing)
3370 LabelStatement *ls;
3372 if (scx->func != thisfunc) // if in enclosing function
3374 if (sc->fes) // if this is the body of a foreach
3376 for (; scx; scx = scx->enclosing)
3378 ls = scx->slabel;
3379 if (ls && ls->ident == ident && ls->statement == sc->fes)
3381 // Replace continue ident; with return 0;
3382 return new ReturnStatement(0, new IntegerExp(0));
3386 /* Post this statement to the fes, and replace
3387 * it with a return value that caller will put into
3388 * a switch. Caller will figure out where the break
3389 * label actually is.
3390 * Case numbers start with 2, not 0, as 0 is continue
3391 * and 1 is break.
3393 Statement *s;
3394 sc->fes->cases.push(this);
3395 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
3396 return s;
3398 break; // can't continue to it
3401 ls = scx->slabel;
3402 if (ls && ls->ident == ident)
3404 Statement *s = ls->statement;
3406 if (!s->hasContinue())
3407 error("label '%s' has no continue", ident->toChars());
3408 if (ls->tf != sc->tf)
3409 error("cannot continue out of finally block");
3410 return this;
3413 error("enclosing label '%s' for continue not found", ident->toChars());
3415 else if (!sc->scontinue)
3417 if (sc->fes)
3418 { Statement *s;
3420 // Replace continue; with return 0;
3421 s = new ReturnStatement(0, new IntegerExp(0));
3422 return s;
3424 error("continue is not inside a loop");
3426 return this;
3429 int ContinueStatement::blockExit()
3431 return ident ? BEgoto : BEcontinue;
3434 int ContinueStatement::fallOffEnd()
3436 return FALSE;
3439 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3441 buf->writestring("continue");
3442 if (ident)
3443 { buf->writebyte(' ');
3444 buf->writestring(ident->toChars());
3446 buf->writebyte(';');
3447 buf->writenl();
3450 /******************************** SynchronizedStatement ***************************/
3452 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
3453 : Statement(loc)
3455 this->exp = exp;
3456 this->body = body;
3457 this->esync = NULL;
3460 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
3461 : Statement(loc)
3463 this->exp = NULL;
3464 this->body = body;
3465 this->esync = esync;
3468 Statement *SynchronizedStatement::syntaxCopy()
3470 Expression *e = exp ? exp->syntaxCopy() : NULL;
3471 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
3472 return s;
3475 Statement *SynchronizedStatement::semantic(Scope *sc)
3477 if (exp)
3478 { ClassDeclaration *cd;
3480 exp = exp->semantic(sc);
3481 exp = resolveProperties(sc, exp);
3482 cd = exp->type->isClassHandle();
3483 if (!cd)
3484 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
3485 else if (cd->isInterfaceDeclaration())
3486 { Type *t = new TypeIdentifier(0, Id::Object);
3488 t = t->semantic(0, sc);
3489 exp = new CastExp(loc, exp, t);
3490 exp = exp->semantic(sc);
3493 if (body)
3494 body = body->semantic(sc);
3495 return this;
3498 int SynchronizedStatement::hasBreak()
3500 return FALSE; //TRUE;
3503 int SynchronizedStatement::hasContinue()
3505 return FALSE; //TRUE;
3508 int SynchronizedStatement::usesEH()
3510 return TRUE;
3513 int SynchronizedStatement::blockExit()
3515 return body ? body->blockExit() : BEfallthru;
3518 int SynchronizedStatement::fallOffEnd()
3520 return body ? body->fallOffEnd() : TRUE;
3523 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3525 buf->writestring("synchronized");
3526 if (exp)
3527 { buf->writebyte('(');
3528 exp->toCBuffer(buf, hgs);
3529 buf->writebyte(')');
3531 if (body)
3533 buf->writebyte(' ');
3534 body->toCBuffer(buf, hgs);
3538 /******************************** WithStatement ***************************/
3540 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
3541 : Statement(loc)
3543 this->exp = exp;
3544 this->body = body;
3545 wthis = NULL;
3548 Statement *WithStatement::syntaxCopy()
3550 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3551 return s;
3554 Statement *WithStatement::semantic(Scope *sc)
3555 { ScopeDsymbol *sym;
3556 Initializer *init;
3558 //printf("WithStatement::semantic()\n");
3559 exp = exp->semantic(sc);
3560 exp = resolveProperties(sc, exp);
3561 if (exp->op == TOKimport)
3562 { ScopeExp *es = (ScopeExp *)exp;
3564 sym = es->sds;
3566 else if (exp->op == TOKtype)
3567 { TypeExp *es = (TypeExp *)exp;
3569 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3570 if (!sym)
3571 { error("%s has no members", es->toChars());
3572 body = body->semantic(sc);
3573 return this;
3576 else
3577 { Type *t = exp->type;
3579 assert(t);
3580 t = t->toBasetype();
3581 if (t->isClassHandle())
3583 init = new ExpInitializer(loc, exp);
3584 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3585 wthis->semantic(sc);
3587 sym = new WithScopeSymbol(this);
3588 sym->parent = sc->scopesym;
3590 else if (t->ty == Tstruct)
3592 Expression *e = exp->addressOf(sc);
3593 init = new ExpInitializer(loc, e);
3594 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3595 wthis->semantic(sc);
3596 sym = new WithScopeSymbol(this);
3597 sym->parent = sc->scopesym;
3599 else
3600 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3601 return NULL;
3604 sc = sc->push(sym);
3606 if (body)
3607 body = body->semantic(sc);
3609 sc->pop();
3611 return this;
3614 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3616 buf->writestring("with (");
3617 exp->toCBuffer(buf, hgs);
3618 buf->writestring(")\n");
3619 if (body)
3620 body->toCBuffer(buf, hgs);
3623 int WithStatement::usesEH()
3625 return body ? body->usesEH() : 0;
3628 int WithStatement::blockExit()
3630 int result = BEnone;
3631 if (exp->canThrow())
3632 result = BEthrow;
3633 if (body)
3634 result |= body->blockExit();
3635 else
3636 result |= BEfallthru;
3637 return result;
3640 int WithStatement::fallOffEnd()
3642 return body ? body->fallOffEnd() : TRUE;
3645 /******************************** TryCatchStatement ***************************/
3647 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3648 : Statement(loc)
3650 this->body = body;
3651 this->catches = catches;
3654 Statement *TryCatchStatement::syntaxCopy()
3656 Array *a = new Array();
3657 a->setDim(catches->dim);
3658 for (int i = 0; i < a->dim; i++)
3659 { Catch *c;
3661 c = (Catch *)catches->data[i];
3662 c = c->syntaxCopy();
3663 a->data[i] = c;
3665 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3666 return s;
3669 Statement *TryCatchStatement::semantic(Scope *sc)
3671 body = body->semanticScope(sc, NULL /*this*/, NULL);
3673 /* Even if body is NULL, still do semantic analysis on catches
3675 for (size_t i = 0; i < catches->dim; i++)
3676 { Catch *c = (Catch *)catches->data[i];
3677 c->semantic(sc);
3679 // Determine if current catch 'hides' any previous catches
3680 for (size_t j = 0; j < i; j++)
3681 { Catch *cj = (Catch *)catches->data[j];
3682 char *si = c->loc.toChars();
3683 char *sj = cj->loc.toChars();
3685 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3686 error("catch at %s hides catch at %s", sj, si);
3690 if (!body)
3691 return NULL;
3693 return this;
3696 int TryCatchStatement::hasBreak()
3698 return FALSE; //TRUE;
3701 int TryCatchStatement::usesEH()
3703 return TRUE;
3706 int TryCatchStatement::blockExit()
3707 { int result;
3709 assert(body);
3710 result = body->blockExit();
3712 for (size_t i = 0; i < catches->dim; i++)
3714 Catch *c = (Catch *)catches->data[i];
3715 result |= c->blockExit();
3717 return result;
3720 int TryCatchStatement::fallOffEnd()
3722 int result = FALSE;
3724 if (body)
3725 result = body->fallOffEnd();
3726 for (int i = 0; i < catches->dim; i++)
3727 { Catch *c;
3729 c = (Catch *)catches->data[i];
3730 if (c->handler)
3731 result |= c->handler->fallOffEnd();
3733 return result;
3736 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3738 buf->writestring("try");
3739 buf->writenl();
3740 if (body)
3741 body->toCBuffer(buf, hgs);
3742 for (size_t i = 0; i < catches->dim; i++)
3744 Catch *c = (Catch *)catches->data[i];
3745 c->toCBuffer(buf, hgs);
3749 /******************************** Catch ***************************/
3751 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3753 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3754 this->loc = loc;
3755 this->type = t;
3756 this->ident = id;
3757 this->handler = handler;
3758 var = NULL;
3761 Catch *Catch::syntaxCopy()
3763 Catch *c = new Catch(loc,
3764 (type ? type->syntaxCopy() : NULL),
3765 ident,
3766 (handler ? handler->syntaxCopy() : NULL));
3767 return c;
3770 void Catch::semantic(Scope *sc)
3771 { ScopeDsymbol *sym;
3773 //printf("Catch::semantic(%s)\n", ident->toChars());
3775 #ifndef IN_GCC
3776 if (sc->tf)
3778 /* This is because the _d_local_unwind() gets the stack munged
3779 * up on this. The workaround is to place any try-catches into
3780 * a separate function, and call that.
3781 * To fix, have the compiler automatically convert the finally
3782 * body into a nested function.
3784 error(loc, "cannot put catch statement inside finally block");
3786 #endif
3788 sym = new ScopeDsymbol();
3789 sym->parent = sc->scopesym;
3790 sc = sc->push(sym);
3792 if (!type)
3793 type = new TypeIdentifier(0, Id::Object);
3794 type = type->semantic(loc, sc);
3795 if (!type->toBasetype()->isClassHandle())
3796 error("can only catch class objects, not '%s'", type->toChars());
3797 else if (ident)
3799 var = new VarDeclaration(loc, type, ident, NULL);
3800 var->parent = sc->parent;
3801 sc->insert(var);
3803 handler = handler->semantic(sc);
3805 sc->pop();
3808 int Catch::blockExit()
3810 return handler ? handler->blockExit() : BEfallthru;
3813 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3815 buf->writestring("catch");
3816 if (type)
3817 { buf->writebyte('(');
3818 type->toCBuffer(buf, ident, hgs);
3819 buf->writebyte(')');
3821 buf->writenl();
3822 buf->writebyte('{');
3823 buf->writenl();
3824 if (handler)
3825 handler->toCBuffer(buf, hgs);
3826 buf->writebyte('}');
3827 buf->writenl();
3830 /****************************** TryFinallyStatement ***************************/
3832 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3833 : Statement(loc)
3835 this->body = body;
3836 this->finalbody = finalbody;
3839 Statement *TryFinallyStatement::syntaxCopy()
3841 TryFinallyStatement *s = new TryFinallyStatement(loc,
3842 body->syntaxCopy(), finalbody->syntaxCopy());
3843 return s;
3846 Statement *TryFinallyStatement::semantic(Scope *sc)
3848 //printf("TryFinallyStatement::semantic()\n");
3849 body = body->semantic(sc);
3850 sc = sc->push();
3851 sc->tf = this;
3852 sc->sbreak = NULL;
3853 sc->scontinue = NULL; // no break or continue out of finally block
3854 finalbody = finalbody->semantic(sc);
3855 sc->pop();
3856 if (!body)
3857 return finalbody;
3858 if (!finalbody)
3859 return body;
3860 if (body->blockExit() == BEfallthru)
3861 { Statement *s = new CompoundStatement(loc, body, finalbody);
3862 return s;
3864 return this;
3867 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3869 buf->printf("try\n{\n");
3870 body->toCBuffer(buf, hgs);
3871 buf->printf("}\nfinally\n{\n");
3872 finalbody->toCBuffer(buf, hgs);
3873 buf->writeByte('}');
3874 buf->writenl();
3877 int TryFinallyStatement::hasBreak()
3879 return FALSE; //TRUE;
3882 int TryFinallyStatement::hasContinue()
3884 return FALSE; //TRUE;
3887 int TryFinallyStatement::usesEH()
3889 return TRUE;
3892 int TryFinallyStatement::blockExit()
3894 int result = body->blockExit();
3895 return result;
3898 int TryFinallyStatement::fallOffEnd()
3899 { int result;
3901 result = body->fallOffEnd();
3902 // if (finalbody)
3903 // result = finalbody->fallOffEnd();
3904 return result;
3907 /****************************** OnScopeStatement ***************************/
3909 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3910 : Statement(loc)
3912 this->tok = tok;
3913 this->statement = statement;
3916 Statement *OnScopeStatement::syntaxCopy()
3918 OnScopeStatement *s = new OnScopeStatement(loc,
3919 tok, statement->syntaxCopy());
3920 return s;
3923 Statement *OnScopeStatement::semantic(Scope *sc)
3925 /* semantic is called on results of scopeCode() */
3926 return this;
3929 int OnScopeStatement::blockExit()
3930 { // At this point, this statement is just an empty placeholder
3931 return BEfallthru;
3934 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3936 buf->writestring(Token::toChars(tok));
3937 buf->writebyte(' ');
3938 statement->toCBuffer(buf, hgs);
3941 int OnScopeStatement::usesEH()
3943 return 1;
3946 void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
3948 //printf("OnScopeStatement::scopeCode()\n");
3949 //print();
3950 *sentry = NULL;
3951 *sexception = NULL;
3952 *sfinally = NULL;
3953 switch (tok)
3955 case TOKon_scope_exit:
3956 *sfinally = statement;
3957 break;
3959 case TOKon_scope_failure:
3960 *sexception = statement;
3961 break;
3963 case TOKon_scope_success:
3965 /* Create:
3966 * sentry: int x = 0;
3967 * sexception: x = 1;
3968 * sfinally: if (!x) statement;
3970 Identifier *id = Lexer::uniqueId("__os");
3972 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
3973 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
3974 *sentry = new DeclarationStatement(loc, v);
3976 Expression *e = new IntegerExp(1);
3977 e = new AssignExp(0, new VarExp(0, v), e);
3978 *sexception = new ExpStatement(0, e);
3980 e = new VarExp(0, v);
3981 e = new NotExp(0, e);
3982 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
3984 break;
3987 default:
3988 assert(0);
3992 /******************************** ThrowStatement ***************************/
3994 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
3995 : Statement(loc)
3997 this->exp = exp;
4000 Statement *ThrowStatement::syntaxCopy()
4002 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
4003 return s;
4006 Statement *ThrowStatement::semantic(Scope *sc)
4008 //printf("ThrowStatement::semantic()\n");
4010 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4011 fd->hasReturnExp |= 2;
4013 if (sc->incontract)
4014 error("Throw statements cannot be in contracts");
4015 exp = exp->semantic(sc);
4016 exp = resolveProperties(sc, exp);
4017 if (!exp->type->toBasetype()->isClassHandle())
4018 error("can only throw class objects, not type %s", exp->type->toChars());
4019 return this;
4022 int ThrowStatement::blockExit()
4024 return BEthrow; // obviously
4027 int ThrowStatement::fallOffEnd()
4029 return FALSE;
4032 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4034 buf->printf("throw ");
4035 exp->toCBuffer(buf, hgs);
4036 buf->writeByte(';');
4037 buf->writenl();
4040 /******************************** VolatileStatement **************************/
4042 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
4043 : Statement(loc)
4045 this->statement = statement;
4048 Statement *VolatileStatement::syntaxCopy()
4050 VolatileStatement *s = new VolatileStatement(loc,
4051 statement ? statement->syntaxCopy() : NULL);
4052 return s;
4055 Statement *VolatileStatement::semantic(Scope *sc)
4057 if (statement)
4058 statement = statement->semantic(sc);
4059 return this;
4062 Statements *VolatileStatement::flatten(Scope *sc)
4064 Statements *a;
4066 a = statement ? statement->flatten(sc) : NULL;
4067 if (a)
4068 { for (int i = 0; i < a->dim; i++)
4069 { Statement *s = (Statement *)a->data[i];
4071 s = new VolatileStatement(loc, s);
4072 a->data[i] = s;
4076 return a;
4079 int VolatileStatement::blockExit()
4081 return statement ? statement->blockExit() : BEfallthru;
4084 int VolatileStatement::fallOffEnd()
4086 return statement ? statement->fallOffEnd() : TRUE;
4089 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4091 buf->writestring("volatile");
4092 if (statement)
4093 { if (statement->isScopeStatement())
4094 buf->writenl();
4095 else
4096 buf->writebyte(' ');
4097 statement->toCBuffer(buf, hgs);
4102 /******************************** GotoStatement ***************************/
4104 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
4105 : Statement(loc)
4107 this->ident = ident;
4108 this->label = NULL;
4109 this->tf = NULL;
4112 Statement *GotoStatement::syntaxCopy()
4114 GotoStatement *s = new GotoStatement(loc, ident);
4115 return s;
4118 Statement *GotoStatement::semantic(Scope *sc)
4119 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4121 //printf("GotoStatement::semantic()\n");
4122 tf = sc->tf;
4123 label = fd->searchLabel(ident);
4124 if (!label->statement && sc->fes)
4126 /* Either the goto label is forward referenced or it
4127 * is in the function that the enclosing foreach is in.
4128 * Can't know yet, so wrap the goto in a compound statement
4129 * so we can patch it later, and add it to a 'look at this later'
4130 * list.
4132 Statements *a = new Statements();
4133 Statement *s;
4135 a->push(this);
4136 s = new CompoundStatement(loc, a);
4137 sc->fes->gotos.push(s); // 'look at this later' list
4138 return s;
4140 if (label->statement && label->statement->tf != sc->tf)
4141 error("cannot goto in or out of finally block");
4142 return this;
4145 int GotoStatement::blockExit()
4147 //printf("GotoStatement::blockExit(%p)\n", this);
4148 return BEgoto;
4151 int GotoStatement::fallOffEnd()
4153 return FALSE;
4156 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4158 buf->writestring("goto ");
4159 buf->writestring(ident->toChars());
4160 buf->writebyte(';');
4161 buf->writenl();
4164 /******************************** LabelStatement ***************************/
4166 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
4167 : Statement(loc)
4169 this->ident = ident;
4170 this->statement = statement;
4171 this->tf = NULL;
4172 this->lblock = NULL;
4173 this->isReturnLabel = 0;
4176 Statement *LabelStatement::syntaxCopy()
4178 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
4179 return s;
4182 Statement *LabelStatement::semantic(Scope *sc)
4183 { LabelDsymbol *ls;
4184 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
4186 //printf("LabelStatement::semantic()\n");
4187 ls = fd->searchLabel(ident);
4188 if (ls->statement)
4189 error("Label '%s' already defined", ls->toChars());
4190 else
4191 ls->statement = this;
4192 tf = sc->tf;
4193 sc = sc->push();
4194 sc->scopesym = sc->enclosing->scopesym;
4195 sc->callSuper |= CSXlabel;
4196 sc->slabel = this;
4197 if (statement)
4198 statement = statement->semantic(sc);
4199 sc->pop();
4200 return this;
4203 Statements *LabelStatement::flatten(Scope *sc)
4205 Statements *a = NULL;
4207 if (statement)
4209 a = statement->flatten(sc);
4210 if (a)
4212 if (!a->dim)
4214 a->push(new ExpStatement(loc, NULL));
4216 Statement *s = (Statement *)a->data[0];
4218 s = new LabelStatement(loc, ident, s);
4219 a->data[0] = s;
4223 return a;
4227 int LabelStatement::usesEH()
4229 return statement ? statement->usesEH() : FALSE;
4232 int LabelStatement::blockExit()
4234 //printf("LabelStatement::blockExit(%p)\n", this);
4235 return statement ? statement->blockExit() : BEfallthru;
4238 int LabelStatement::fallOffEnd()
4240 return statement ? statement->fallOffEnd() : TRUE;
4243 int LabelStatement::comeFrom()
4245 //printf("LabelStatement::comeFrom()\n");
4246 return TRUE;
4249 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
4251 buf->writestring(ident->toChars());
4252 buf->writebyte(':');
4253 buf->writenl();
4254 if (statement)
4255 statement->toCBuffer(buf, hgs);
4259 /******************************** LabelDsymbol ***************************/
4261 LabelDsymbol::LabelDsymbol(Identifier *ident)
4262 : Dsymbol(ident)
4264 statement = NULL;
4265 #if IN_GCC
4266 asmLabelNum = 0;
4267 #endif
4270 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
4272 return this;