Delay auto-generating the main function until the end of the first semantic pass
[delight/core.git] / dmd / statement.c
blob784c5f43fda999d310c7d1df6215c81b8a5e039f
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 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"
36 /******************************** Statement ***************************/
38 Statement::Statement(Loc loc)
39 : loc(loc)
41 #ifdef _DH
42 // If this is an in{} contract scope statement (skip for determining
43 // inlineStatus of a function body for header content)
44 incontract = 0;
45 #endif
48 Statement *Statement::syntaxCopy()
50 assert(0);
51 return NULL;
54 void Statement::print()
56 fprintf(stdmsg, "%s\n", toChars());
57 fflush(stdmsg);
60 char *Statement::toChars()
61 { OutBuffer *buf;
62 HdrGenState hgs;
64 buf = new OutBuffer();
65 toCBuffer(buf, &hgs);
66 return buf->toChars();
69 void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
71 buf->printf("Statement::toCBuffer()");
72 buf->writenl();
75 Statement *Statement::semantic(Scope *sc)
77 return this;
80 // Same as semantic(), but do create a new scope
82 Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
83 { Scope *scd;
84 Statement *s;
86 scd = sc->push();
87 if (sbreak)
88 scd->sbreak = sbreak;
89 if (scontinue)
90 scd->scontinue = scontinue;
91 s = semantic(scd);
92 scd->pop();
93 return s;
96 void Statement::error(const char *format, ...)
98 va_list ap;
99 va_start(ap, format);
100 ::verror(loc, format, ap);
101 va_end( ap );
104 int Statement::hasBreak()
106 //printf("Statement::hasBreak()\n");
107 return FALSE;
110 int Statement::hasContinue()
112 return FALSE;
115 // TRUE if statement uses exception handling
117 int Statement::usesEH()
119 return FALSE;
122 // TRUE if statement may fall off the end without a throw or return
124 int Statement::fallOffEnd()
126 return TRUE;
129 // TRUE if statement 'comes from' somewhere else, like a goto
131 int Statement::comeFrom()
133 //printf("Statement::comeFrom()\n");
134 return FALSE;
137 /****************************************
138 * If this statement has code that needs to run in a finally clause
139 * at the end of the current scope, return that code in the form of
140 * a Statement.
141 * Output:
142 * *sentry code executed upon entry to the scope
143 * *sexception code executed upon exit from the scope via exception
144 * *sfinally code executed in finally block
147 void Statement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
149 //printf("Statement::scopeCode()\n");
150 //print();
151 *sentry = NULL;
152 *sexception = NULL;
153 *sfinally = NULL;
156 /*********************************
157 * Flatten out the scope by presenting the statement
158 * as an array of statements.
159 * Returns NULL if no flattening necessary.
162 Statements *Statement::flatten(Scope *sc)
164 return NULL;
168 /******************************** ExpStatement ***************************/
170 ExpStatement::ExpStatement(Loc loc, Expression *exp)
171 : Statement(loc)
173 this->exp = exp;
176 Statement *ExpStatement::syntaxCopy()
178 Expression *e = exp ? exp->syntaxCopy() : NULL;
179 ExpStatement *es = new ExpStatement(loc, e);
180 return es;
183 void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
185 if (exp)
186 exp->toCBuffer(buf, hgs);
187 buf->writeByte(';');
188 if (!hgs->FLinit.init)
189 buf->writenl();
192 Statement *ExpStatement::semantic(Scope *sc)
194 if (exp)
196 //printf("ExpStatement::semantic() %s\n", exp->toChars());
197 exp = exp->semantic(sc);
198 exp = resolveProperties(sc, exp);
199 exp->checkSideEffect(0);
200 exp = exp->optimize(0);
201 //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0);
203 return this;
206 int ExpStatement::fallOffEnd()
208 if (exp)
210 if (exp->op == TOKassert)
211 { AssertExp *a = (AssertExp *)exp;
213 if (a->e1->isBool(FALSE)) // if it's an assert(0)
214 return FALSE;
216 else if (exp->op == TOKhalt)
217 return FALSE;
219 return TRUE;
222 /******************************** CompileStatement ***************************/
224 CompileStatement::CompileStatement(Loc loc, Expression *exp)
225 : Statement(loc)
227 this->exp = exp;
230 Statement *CompileStatement::syntaxCopy()
232 Expression *e = exp->syntaxCopy();
233 CompileStatement *es = new CompileStatement(loc, e);
234 return es;
237 void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
239 buf->writestring("mixin(");
240 exp->toCBuffer(buf, hgs);
241 buf->writestring(");");
242 if (!hgs->FLinit.init)
243 buf->writenl();
246 Statement *CompileStatement::semantic(Scope *sc)
248 //printf("CompileStatement::semantic() %s\n", exp->toChars());
249 exp = exp->semantic(sc);
250 exp = resolveProperties(sc, exp);
251 exp = exp->optimize(WANTvalue | WANTinterpret);
252 if (exp->op != TOKstring)
253 { error("argument to mixin must be a string, not (%s)", exp->toChars());
254 return this;
256 StringExp *se = (StringExp *)exp;
257 se = se->toUTF8(sc);
258 Parser p(sc->module, (unsigned char *)se->string, se->len, 0);
259 p.loc = loc;
260 p.nextToken();
262 Statements *statements = new Statements();
263 while (p.token.value != TOKeof)
265 Statement *s = p.parseStatement(PSsemi | PScurlyscope);
266 statements->push(s);
269 Statement *s = new CompoundStatement(loc, statements);
270 return s->semantic(sc);
274 /******************************** DeclarationStatement ***************************/
276 DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration)
277 : ExpStatement(loc, new DeclarationExp(loc, declaration))
281 DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp)
282 : ExpStatement(loc, exp)
286 Statement *DeclarationStatement::syntaxCopy()
288 DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy());
289 return ds;
292 void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
294 //printf("DeclarationStatement::scopeCode()\n");
295 //print();
297 *sentry = NULL;
298 *sexception = NULL;
299 *sfinally = NULL;
301 if (exp)
303 if (exp->op == TOKdeclaration)
305 DeclarationExp *de = (DeclarationExp *)(exp);
306 VarDeclaration *v = de->declaration->isVarDeclaration();
307 if (v)
308 { Expression *e;
310 e = v->callAutoDtor();
311 if (e)
313 //printf("dtor is: "); e->print();
314 *sfinally = new ExpStatement(loc, e);
321 void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
323 exp->toCBuffer(buf, hgs);
327 /******************************** InjectorMainBody ***************************/
329 static Expressions *getAutoArgs(Loc loc, Arguments *arguments) {
330 Expressions *args = new Expressions();
332 Expression *externals = new IdentifierExp(loc, Id::externals);
333 // Collect all the objects we need for the constructor's arguments
334 for (int i = 0; i < arguments->dim; i++) {
335 Argument *arg = (Argument *) arguments->data[i];
336 if (arg->ident == Id::args) {
337 // For 'args', just pass through the string[] passed to main()
338 args->push(new IdentifierExp(loc, arg->ident));
339 } else {
340 // For everything else, call a getter in the _externals module
341 Expression *getter = new DotIdExp(loc, externals, arg->ident);
342 args->push(getter);
346 return args;
349 InjectorMainBody::InjectorMainBody(Loc loc, ClassDeclaration *mainClass)
350 : Statement(loc), mainClass(mainClass)
354 Statement *InjectorMainBody::semantic(Scope *sc)
356 // Find the constructor and the main method
357 CtorDeclaration *ctor = NULL;
358 FuncDeclaration *mainDecl = NULL;
359 for (int i = 0; i < mainClass->members->dim; i++) {
360 Dsymbol *s;
362 s = (Dsymbol *)mainClass->members->data[i];
364 CtorDeclaration *thisCtor = s->isCtorDeclaration();
365 if (thisCtor) {
366 if (ctor) {
367 error("Multiple constructors for Main class!");
368 return NULL;
369 } else {
370 ctor = thisCtor;
374 FuncDeclaration *thisMethod = s->isFuncDeclaration();
375 if (thisMethod && thisMethod->ident == Id::main) {
376 if (mainDecl) {
377 error("Multiple main methods for Main class!");
378 return NULL;
379 } else {
380 mainDecl = thisMethod;
385 if (mainDecl == NULL) {
386 error("No main method in Main class!");
387 return NULL;
390 // Externals externals = new _externals.Externals()
391 TypeIdentifier *extType = new TypeIdentifier(loc, Id::_externals);
392 extType->addIdent(Id::Externals);
394 Expression *newExt = new NewExp(loc, NULL, NULL, extType, NULL);
395 VarDeclaration *v = new VarDeclaration(loc, extType, Id::externals,
396 new ExpInitializer(loc, newExt));
397 Statement *assignExt = new DeclarationStatement(loc, v);
398 Expression *newMain = new NewExp(loc, NULL, NULL, mainClass->getType(),
399 ctor ? getAutoArgs(ctor->loc, ctor->arguments) : NULL);
401 // Then invoke the main() method inside it
402 // mainObject.main(...)
403 Expression *mainMethod = new DotIdExp(mainDecl->loc, newMain, Id::main);
404 Expression *mainCall = new CallExp(mainMethod->loc, mainMethod,
405 getAutoArgs(mainDecl->loc,
406 ((TypeFunction *) mainDecl->type)->parameters));
408 Statement *s = new ExpStatement(loc, mainCall);
409 Statement *body = new CompoundStatement(loc, assignExt, s);
411 return body->semantic(sc);
414 /******************************** CompoundStatement ***************************/
416 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
417 : Statement(loc)
419 statements = s;
422 CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
423 : Statement(loc)
425 statements = new Statements();
426 statements->reserve(2);
427 statements->push(s1);
428 statements->push(s2);
431 Statement *CompoundStatement::syntaxCopy()
433 Statements *a = new Statements();
434 a->setDim(statements->dim);
435 for (size_t i = 0; i < statements->dim; i++)
436 { Statement *s = (Statement *)statements->data[i];
437 if (s)
438 s = s->syntaxCopy();
439 a->data[i] = s;
441 CompoundStatement *cs = new CompoundStatement(loc, a);
442 return cs;
446 Statement *CompoundStatement::semantic(Scope *sc)
447 { Statement *s;
449 //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc);
451 for (size_t i = 0; i < statements->dim; )
453 s = (Statement *) statements->data[i];
454 if (s)
455 { Statements *a = s->flatten(sc);
457 if (a)
459 statements->remove(i);
460 statements->insert(i, a);
461 continue;
463 s = s->semantic(sc);
464 statements->data[i] = s;
465 if (s)
467 Statement *sentry;
468 Statement *sexception;
469 Statement *sfinally;
471 s->scopeCode(&sentry, &sexception, &sfinally);
472 if (sentry)
474 sentry = sentry->semantic(sc);
475 statements->data[i] = sentry;
477 if (sexception)
479 if (i + 1 == statements->dim && !sfinally)
481 #if 1
482 sexception = sexception->semantic(sc);
483 #else
484 statements->push(sexception);
485 if (sfinally)
486 // Assume sexception does not throw
487 statements->push(sfinally);
488 #endif
490 else
492 /* Rewrite:
493 * s; s1; s2;
494 * As:
495 * s;
496 * try { s1; s2; }
497 * catch (Object __o)
498 * { sexception; throw __o; }
500 Statement *body;
501 Statements *a = new Statements();
503 for (int j = i + 1; j < statements->dim; j++)
505 a->push(statements->data[j]);
507 body = new CompoundStatement(0, a);
508 body = new ScopeStatement(0, body);
510 static int num;
511 char name[3 + sizeof(num) * 3 + 1];
512 sprintf(name, "__o%d", ++num);
513 Identifier *id = Lexer::idPool(name);
515 Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id));
516 handler = new CompoundStatement(0, sexception, handler);
518 Array *catches = new Array();
519 Catch *ctch = new Catch(0, NULL, id, handler);
520 catches->push(ctch);
521 s = new TryCatchStatement(0, body, catches);
523 if (sfinally)
524 s = new TryFinallyStatement(0, s, sfinally);
525 s = s->semantic(sc);
526 statements->setDim(i + 1);
527 statements->push(s);
528 break;
531 else if (sfinally)
533 if (0 && i + 1 == statements->dim)
535 statements->push(sfinally);
537 else
539 /* Rewrite:
540 * s; s1; s2;
541 * As:
542 * s; try { s1; s2; } finally { sfinally; }
544 Statement *body;
545 Statements *a = new Statements();
547 for (int j = i + 1; j < statements->dim; j++)
549 a->push(statements->data[j]);
551 body = new CompoundStatement(0, a);
552 s = new TryFinallyStatement(0, body, sfinally);
553 s = s->semantic(sc);
554 statements->setDim(i + 1);
555 statements->push(s);
556 break;
561 i++;
563 if (statements->dim == 1)
564 return s;
565 return this;
568 Statements *CompoundStatement::flatten(Scope *sc)
570 return statements;
573 ReturnStatement *CompoundStatement::isReturnStatement()
574 { int i;
575 ReturnStatement *rs = NULL;
577 for (i = 0; i < statements->dim; i++)
578 { Statement *s;
580 s = (Statement *) statements->data[i];
581 if (s)
583 rs = s->isReturnStatement();
584 if (rs)
585 break;
588 return rs;
591 void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
592 { int i;
594 for (i = 0; i < statements->dim; i++)
595 { Statement *s;
597 s = (Statement *) statements->data[i];
598 if (s)
599 s->toCBuffer(buf, hgs);
603 int CompoundStatement::usesEH()
605 for (int i = 0; i < statements->dim; i++)
606 { Statement *s;
608 s = (Statement *) statements->data[i];
609 if (s && s->usesEH())
610 return TRUE;
612 return FALSE;
615 int CompoundStatement::fallOffEnd()
616 { int falloff = TRUE;
618 //printf("CompoundStatement::fallOffEnd() %s\n", toChars());
619 for (int i = 0; i < statements->dim; i++)
620 { Statement *s = (Statement *)statements->data[i];
622 if (!s)
623 continue;
625 if (!falloff && global.params.warnings && !s->comeFrom())
627 fprintf(stdmsg, "warning - ");
628 s->error("statement is not reachable");
630 falloff = s->fallOffEnd();
632 return falloff;
635 int CompoundStatement::comeFrom()
636 { int comefrom = FALSE;
638 //printf("CompoundStatement::comeFrom()\n");
639 for (int i = 0; i < statements->dim; i++)
640 { Statement *s = (Statement *)statements->data[i];
642 if (!s)
643 continue;
645 comefrom |= s->comeFrom();
647 return comefrom;
651 /**************************** UnrolledLoopStatement ***************************/
653 UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
654 : Statement(loc)
656 statements = s;
659 Statement *UnrolledLoopStatement::syntaxCopy()
661 Statements *a = new Statements();
662 a->setDim(statements->dim);
663 for (size_t i = 0; i < statements->dim; i++)
664 { Statement *s = (Statement *)statements->data[i];
665 if (s)
666 s = s->syntaxCopy();
667 a->data[i] = s;
669 UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a);
670 return cs;
674 Statement *UnrolledLoopStatement::semantic(Scope *sc)
676 //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
678 sc->noctor++;
679 Scope *scd = sc->push();
680 scd->sbreak = this;
681 scd->scontinue = this;
683 for (size_t i = 0; i < statements->dim; i++)
685 Statement *s = (Statement *) statements->data[i];
686 if (s)
688 s = s->semantic(scd);
689 statements->data[i] = s;
693 scd->pop();
694 sc->noctor--;
695 return this;
698 void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
700 buf->writestring("unrolled {");
701 buf->writenl();
703 for (size_t i = 0; i < statements->dim; i++)
704 { Statement *s;
706 s = (Statement *) statements->data[i];
707 if (s)
708 s->toCBuffer(buf, hgs);
711 buf->writeByte('}');
712 buf->writenl();
715 int UnrolledLoopStatement::hasBreak()
717 return TRUE;
720 int UnrolledLoopStatement::hasContinue()
722 return TRUE;
725 int UnrolledLoopStatement::usesEH()
727 for (size_t i = 0; i < statements->dim; i++)
728 { Statement *s;
730 s = (Statement *) statements->data[i];
731 if (s && s->usesEH())
732 return TRUE;
734 return FALSE;
737 int UnrolledLoopStatement::fallOffEnd()
739 //printf("UnrolledLoopStatement::fallOffEnd()\n");
740 for (size_t i = 0; i < statements->dim; i++)
741 { Statement *s = (Statement *)statements->data[i];
743 if (s)
744 s->fallOffEnd();
746 return TRUE;
750 int UnrolledLoopStatement::comeFrom()
751 { int comefrom = FALSE;
753 //printf("UnrolledLoopStatement::comeFrom()\n");
754 for (size_t i = 0; i < statements->dim; i++)
755 { Statement *s = (Statement *)statements->data[i];
757 if (!s)
758 continue;
760 comefrom |= s->comeFrom();
762 return comefrom;
766 /******************************** ScopeStatement ***************************/
768 ScopeStatement::ScopeStatement(Loc loc, Statement *s)
769 : Statement(loc)
771 this->statement = s;
774 Statement *ScopeStatement::syntaxCopy()
776 Statement *s;
778 s = statement ? statement->syntaxCopy() : NULL;
779 s = new ScopeStatement(loc, s);
780 return s;
784 Statement *ScopeStatement::semantic(Scope *sc)
785 { ScopeDsymbol *sym;
787 //printf("ScopeStatement::semantic(sc = %p)\n", sc);
788 if (statement)
789 { Statements *a;
791 sym = new ScopeDsymbol();
792 sym->parent = sc->scopesym;
793 sc = sc->push(sym);
795 a = statement->flatten(sc);
796 if (a)
798 statement = new CompoundStatement(loc, a);
801 statement = statement->semantic(sc);
802 if (statement)
804 Statement *sentry;
805 Statement *sexception;
806 Statement *sfinally;
808 statement->scopeCode(&sentry, &sexception, &sfinally);
809 if (sfinally)
811 //printf("adding sfinally\n");
812 statement = new CompoundStatement(loc, statement, sfinally);
816 sc->pop();
818 return this;
821 int ScopeStatement::hasBreak()
823 //printf("ScopeStatement::hasBreak() %s\n", toChars());
824 return statement ? statement->hasBreak() : FALSE;
827 int ScopeStatement::hasContinue()
829 return statement ? statement->hasContinue() : FALSE;
832 int ScopeStatement::usesEH()
834 return statement ? statement->usesEH() : FALSE;
837 int ScopeStatement::fallOffEnd()
839 return statement ? statement->fallOffEnd() : TRUE;
842 int ScopeStatement::comeFrom()
844 //printf("ScopeStatement::comeFrom()\n");
845 return statement ? statement->comeFrom() : FALSE;
848 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
850 buf->writeByte('{');
851 buf->writenl();
853 if (statement)
854 statement->toCBuffer(buf, hgs);
856 buf->writeByte('}');
857 buf->writenl();
860 /******************************** WhileStatement ***************************/
862 WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b)
863 : Statement(loc)
865 condition = c;
866 body = b;
869 Statement *WhileStatement::syntaxCopy()
871 WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL);
872 return s;
876 Statement *WhileStatement::semantic(Scope *sc)
878 #if 0
879 if (condition->op == TOKmatch)
881 /* Rewrite while (condition) body as:
882 * if (condition)
883 * do
884 * body
885 * while ((_match = _match.opNext), _match);
888 Expression *ew = new IdentifierExp(0, Id::_match);
889 ew = new DotIdExp(0, ew, Id::next);
890 ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
891 ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
892 Expression *ev = new IdentifierExp(0, Id::_match);
893 //ev = new CastExp(0, ev, Type::tvoidptr);
894 ew = new CommaExp(0, ew, ev);
895 Statement *sw = new DoStatement(loc, body, ew);
896 Statement *si = new IfStatement(loc, condition, sw, NULL);
897 return si->semantic(sc);
899 #endif
901 condition = condition->semantic(sc);
902 condition = resolveProperties(sc, condition);
903 condition = condition->optimize(WANTvalue);
904 condition = condition->checkToBoolean();
906 sc->noctor++;
908 Scope *scd = sc->push();
909 scd->sbreak = this;
910 scd->scontinue = this;
911 if (body)
912 body = body->semantic(scd);
913 scd->pop();
915 sc->noctor--;
917 return this;
920 int WhileStatement::hasBreak()
922 return TRUE;
925 int WhileStatement::hasContinue()
927 return TRUE;
930 int WhileStatement::usesEH()
932 return body ? body->usesEH() : 0;
935 int WhileStatement::fallOffEnd()
937 if (body)
938 body->fallOffEnd();
939 return TRUE;
942 int WhileStatement::comeFrom()
944 if (body)
945 return body->comeFrom();
946 return FALSE;
949 void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
951 buf->writestring("while (");
952 condition->toCBuffer(buf, hgs);
953 buf->writebyte(')');
954 buf->writenl();
955 if (body)
956 body->toCBuffer(buf, hgs);
959 /******************************** DoStatement ***************************/
961 DoStatement::DoStatement(Loc loc, Statement *b, Expression *c)
962 : Statement(loc)
964 body = b;
965 condition = c;
968 Statement *DoStatement::syntaxCopy()
970 DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy());
971 return s;
975 Statement *DoStatement::semantic(Scope *sc)
977 sc->noctor++;
978 if (body)
979 body = body->semanticScope(sc, this, this);
980 sc->noctor--;
981 condition = condition->semantic(sc);
982 condition = resolveProperties(sc, condition);
983 condition = condition->optimize(WANTvalue);
985 condition = condition->checkToBoolean();
987 return this;
990 int DoStatement::hasBreak()
992 return TRUE;
995 int DoStatement::hasContinue()
997 return TRUE;
1000 int DoStatement::usesEH()
1002 return body ? body->usesEH() : 0;
1005 int DoStatement::fallOffEnd()
1007 if (body)
1008 body->fallOffEnd();
1009 return TRUE;
1012 int DoStatement::comeFrom()
1014 if (body)
1015 return body->comeFrom();
1016 return FALSE;
1019 void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1021 buf->writestring("do");
1022 buf->writenl();
1023 if (body)
1024 body->toCBuffer(buf, hgs);
1025 buf->writestring("while (");
1026 condition->toCBuffer(buf, hgs);
1027 buf->writebyte(')');
1030 /******************************** ForStatement ***************************/
1032 ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body)
1033 : Statement(loc)
1035 this->init = init;
1036 this->condition = condition;
1037 this->increment = increment;
1038 this->body = body;
1041 Statement *ForStatement::syntaxCopy()
1043 Statement *i = NULL;
1044 if (init)
1045 i = init->syntaxCopy();
1046 Expression *c = NULL;
1047 if (condition)
1048 c = condition->syntaxCopy();
1049 Expression *inc = NULL;
1050 if (increment)
1051 inc = increment->syntaxCopy();
1052 ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy());
1053 return s;
1056 Statement *ForStatement::semantic(Scope *sc)
1058 ScopeDsymbol *sym = new ScopeDsymbol();
1059 sym->parent = sc->scopesym;
1060 sc = sc->push(sym);
1061 if (init)
1062 init = init->semantic(sc);
1063 if (!condition)
1064 // Use a default value
1065 condition = new IntegerExp(loc, 1, Type::tboolean);
1066 sc->noctor++;
1067 condition = condition->semantic(sc);
1068 condition = resolveProperties(sc, condition);
1069 condition = condition->optimize(WANTvalue);
1070 condition = condition->checkToBoolean();
1071 if (increment)
1072 increment = increment->semantic(sc);
1074 sc->sbreak = this;
1075 sc->scontinue = this;
1076 body = body->semantic(sc);
1077 sc->noctor--;
1079 sc->pop();
1080 return this;
1083 void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
1085 //printf("ForStatement::scopeCode()\n");
1086 //print();
1087 if (init)
1088 init->scopeCode(sentry, sexception, sfinally);
1089 else
1090 Statement::scopeCode(sentry, sexception, sfinally);
1093 int ForStatement::hasBreak()
1095 //printf("ForStatement::hasBreak()\n");
1096 return TRUE;
1099 int ForStatement::hasContinue()
1101 return TRUE;
1104 int ForStatement::usesEH()
1106 return (init && init->usesEH()) || body->usesEH();
1109 int ForStatement::fallOffEnd()
1111 if (body)
1112 body->fallOffEnd();
1113 return TRUE;
1116 int ForStatement::comeFrom()
1118 //printf("ForStatement::comeFrom()\n");
1119 if (body)
1120 { int result = body->comeFrom();
1121 //printf("result = %d\n", result);
1122 return result;
1124 return FALSE;
1127 void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1129 buf->writestring("for (");
1130 if (init)
1132 hgs->FLinit.init++;
1133 hgs->FLinit.decl = 0;
1134 init->toCBuffer(buf, hgs);
1135 if (hgs->FLinit.decl > 0)
1136 buf->writebyte(';');
1137 hgs->FLinit.decl = 0;
1138 hgs->FLinit.init--;
1140 else
1141 buf->writebyte(';');
1142 if (condition)
1143 { buf->writebyte(' ');
1144 condition->toCBuffer(buf, hgs);
1146 buf->writebyte(';');
1147 if (increment)
1148 { buf->writebyte(' ');
1149 increment->toCBuffer(buf, hgs);
1151 buf->writebyte(')');
1152 buf->writenl();
1153 buf->writebyte('{');
1154 buf->writenl();
1155 body->toCBuffer(buf, hgs);
1156 buf->writebyte('}');
1157 buf->writenl();
1160 /******************************** ForeachStatement ***************************/
1162 ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments,
1163 Expression *aggr, Statement *body)
1164 : Statement(loc)
1166 this->op = op;
1167 this->arguments = arguments;
1168 this->aggr = aggr;
1169 this->body = body;
1171 this->key = NULL;
1172 this->value = NULL;
1174 this->func = NULL;
1177 Statement *ForeachStatement::syntaxCopy()
1179 Arguments *args = Argument::arraySyntaxCopy(arguments);
1180 Expression *exp = aggr->syntaxCopy();
1181 ForeachStatement *s = new ForeachStatement(loc, op, args, exp,
1182 body ? body->syntaxCopy() : NULL);
1183 return s;
1186 Statement *ForeachStatement::semantic(Scope *sc)
1188 //printf("ForeachStatement::semantic() %p\n", this);
1189 ScopeDsymbol *sym;
1190 Statement *s = this;
1191 int dim = arguments->dim;
1192 int i;
1193 TypeAArray *taa = NULL;
1195 Type *tn = NULL;
1196 Type *tnv = NULL;
1198 func = sc->func;
1199 if (func->fes)
1200 func = func->fes->func;
1202 aggr = aggr->semantic(sc);
1203 aggr = resolveProperties(sc, aggr);
1204 if (!aggr->type)
1206 error("invalid foreach aggregate %s", aggr->toChars());
1207 return this;
1210 inferApplyArgTypes(op, arguments, aggr);
1212 /* Check for inference errors
1214 if (dim != arguments->dim)
1216 //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim);
1217 error("cannot uniquely infer foreach argument types");
1218 return this;
1221 Type *tab = aggr->type->toBasetype();
1223 if (tab->ty == Ttuple) // don't generate new scope for tuple loops
1225 if (dim < 1 || dim > 2)
1227 error("only one (value) or two (key,value) arguments for tuple foreach");
1228 return s;
1231 TypeTuple *tuple = (TypeTuple *)tab;
1232 Statements *statements = new Statements();
1233 //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars());
1234 size_t n;
1235 TupleExp *te = NULL;
1236 if (aggr->op == TOKtuple) // expression tuple
1237 { te = (TupleExp *)aggr;
1238 n = te->exps->dim;
1240 else if (aggr->op == TOKtype) // type tuple
1242 n = Argument::dim(tuple->arguments);
1244 else
1245 assert(0);
1246 for (size_t j = 0; j < n; j++)
1247 { size_t k = (op == TOKforeach) ? j : n - 1 - j;
1248 Expression *e;
1249 Type *t;
1250 if (te)
1251 e = (Expression *)te->exps->data[k];
1252 else
1253 t = Argument::getNth(tuple->arguments, k)->type;
1254 Argument *arg = (Argument *)arguments->data[0];
1255 Statements *st = new Statements();
1257 if (dim == 2)
1258 { // Declare key
1259 if (arg->storageClass & (STCout | STCref | STClazy))
1260 error("no storage class for key %s", arg->ident->toChars());
1261 TY keyty = arg->type->ty;
1262 if ((keyty != Tint32 && keyty != Tuns32) &&
1263 (! global.params.isX86_64 ||
1264 (keyty != Tint64 && keyty != Tuns64))
1267 error("foreach: key type must be int or uint, not %s", arg->type->toChars());
1269 Initializer *ie = new ExpInitializer(0, new IntegerExp(k));
1270 VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie);
1271 var->storage_class |= STCconst;
1272 DeclarationExp *de = new DeclarationExp(loc, var);
1273 st->push(new ExpStatement(loc, de));
1274 arg = (Argument *)arguments->data[1]; // value
1276 // Declare value
1277 if (arg->storageClass & (STCout | STCref | STClazy))
1278 error("no storage class for value %s", arg->ident->toChars());
1279 Dsymbol *var;
1280 if (te)
1282 if (e->type->toBasetype()->ty == Tfunction &&
1283 e->op == TOKvar)
1284 { VarExp *ve = (VarExp *)e;
1285 var = new AliasDeclaration(loc, arg->ident, ve->var);
1287 else
1289 arg->type = e->type;
1290 Initializer *ie = new ExpInitializer(0, e);
1291 VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
1292 if (e->isConst())
1293 v->storage_class |= STCconst;
1294 #if V2
1295 else
1296 v->storage_class |= STCfinal;
1297 #endif
1298 var = v;
1301 else
1303 var = new AliasDeclaration(loc, arg->ident, t);
1305 DeclarationExp *de = new DeclarationExp(loc, var);
1306 st->push(new ExpStatement(loc, de));
1308 st->push(body->syntaxCopy());
1309 s = new CompoundStatement(loc, st);
1310 s = new ScopeStatement(loc, s);
1311 statements->push(s);
1314 s = new UnrolledLoopStatement(loc, statements);
1315 s = s->semantic(sc);
1316 return s;
1319 for (i = 0; i < dim; i++)
1320 { Argument *arg = (Argument *)arguments->data[i];
1321 if (!arg->type)
1323 error("cannot infer type for %s", arg->ident->toChars());
1324 return this;
1328 sym = new ScopeDsymbol();
1329 sym->parent = sc->scopesym;
1330 sc = sc->push(sym);
1332 sc->noctor++;
1334 switch (tab->ty)
1336 case Tarray:
1337 case Tsarray:
1338 if (dim < 1 || dim > 2)
1340 error("only one or two arguments for array foreach");
1341 break;
1344 /* Look for special case of parsing char types out of char type
1345 * array.
1347 tn = tab->nextOf()->toBasetype();
1348 if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
1349 { Argument *arg;
1351 i = (dim == 1) ? 0 : 1; // index of value
1352 arg = (Argument *)arguments->data[i];
1353 arg->type = arg->type->semantic(loc, sc);
1354 tnv = arg->type->toBasetype();
1355 if (tnv->ty != tn->ty &&
1356 (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
1358 if (arg->storageClass & STCref)
1359 error("foreach: value of UTF conversion cannot be ref");
1360 if (dim == 2)
1361 { arg = (Argument *)arguments->data[0];
1362 if (arg->storageClass & STCref)
1363 error("foreach: key cannot be ref");
1365 goto Lapply;
1369 for (i = 0; i < dim; i++)
1370 { // Declare args
1371 Argument *arg = (Argument *)arguments->data[i];
1372 VarDeclaration *var;
1374 var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
1375 var->storage_class |= STCforeach;
1376 var->storage_class |= arg->storageClass & (STCin | STCout | STCref);
1377 #if 1
1378 DeclarationExp *de = new DeclarationExp(loc, var);
1379 de->semantic(sc);
1380 #else
1381 var->semantic(sc);
1382 if (!sc->insert(var))
1383 error("%s already defined", var->ident->toChars());
1384 #endif
1385 if (dim == 2 && i == 0)
1386 key = var;
1387 else
1388 value = var;
1391 sc->sbreak = this;
1392 sc->scontinue = this;
1393 body = body->semantic(sc);
1395 if (!value->type->equals(tab->next))
1397 if (aggr->op == TOKstring)
1398 aggr = aggr->implicitCastTo(sc, value->type->arrayOf());
1399 else
1400 error("foreach: %s is not an array of %s", tab->toChars(), value->type->toChars());
1403 if (key &&
1404 ((key->type->ty != Tint32 && key->type->ty != Tuns32) &&
1405 (! global.params.isX86_64 ||
1406 (key->type->ty != Tint64 && key->type->ty != Tuns64))
1410 error("foreach: key type must be int or uint, not %s", key->type->toChars());
1413 if (key && key->storage_class & (STCout | STCref))
1414 error("foreach: key cannot be out or ref");
1415 break;
1417 case Taarray:
1418 taa = (TypeAArray *)tab;
1419 if (dim < 1 || dim > 2)
1421 error("only one or two arguments for associative array foreach");
1422 break;
1424 if (op == TOKforeach_reverse)
1426 error("no reverse iteration on associative arrays");
1428 goto Lapply;
1430 case Tclass:
1431 case Tstruct:
1432 case Tdelegate:
1433 Lapply:
1434 { FuncDeclaration *fdapply;
1435 Arguments *args;
1436 Expression *ec;
1437 Expression *e;
1438 FuncLiteralDeclaration *fld;
1439 Argument *a;
1440 Type *t;
1441 Expression *flde;
1442 Identifier *id;
1443 Type *tret;
1445 tret = func->type->nextOf();
1447 // Need a variable to hold value from any return statements in body.
1448 if (!sc->func->vresult && tret && tret != Type::tvoid)
1449 { VarDeclaration *v;
1451 v = new VarDeclaration(loc, tret, Id::result, NULL);
1452 v->noauto = 1;
1453 v->semantic(sc);
1454 if (!sc->insert(v))
1455 assert(0);
1456 v->parent = sc->func;
1457 sc->func->vresult = v;
1460 /* Turn body into the function literal:
1461 * int delegate(ref T arg) { body }
1463 args = new Arguments();
1464 for (i = 0; i < dim; i++)
1465 { Argument *arg = (Argument *)arguments->data[i];
1467 arg->type = arg->type->semantic(loc, sc);
1468 if (arg->storageClass & STCref)
1469 id = arg->ident;
1470 else
1471 { // Make a copy of the ref argument so it isn't
1472 // a reference.
1473 VarDeclaration *v;
1474 Initializer *ie;
1475 char applyArg[10 + sizeof(i)*3 + 1];
1477 sprintf(applyArg, "__applyArg%d", i);
1478 id = Lexer::idPool(applyArg);
1480 ie = new ExpInitializer(0, new IdentifierExp(0, id));
1481 v = new VarDeclaration(0, arg->type, arg->ident, ie);
1482 s = new DeclarationStatement(0, v);
1483 body = new CompoundStatement(loc, s, body);
1485 a = new Argument(STCref, arg->type, id, NULL);
1486 args->push(a);
1488 t = new TypeFunction(args, Type::tint32, 0, LINKd);
1489 fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
1490 fld->fbody = body;
1491 flde = new FuncExp(loc, fld);
1492 flde = flde->semantic(sc);
1494 // Resolve any forward referenced goto's
1495 for (int i = 0; i < gotos.dim; i++)
1496 { CompoundStatement *cs = (CompoundStatement *)gotos.data[i];
1497 GotoStatement *gs = (GotoStatement *)cs->statements->data[0];
1499 if (!gs->label->statement)
1500 { // 'Promote' it to this scope, and replace with a return
1501 cases.push(gs);
1502 s = new ReturnStatement(0, new IntegerExp(cases.dim + 1));
1503 cs->statements->data[0] = (void *)s;
1507 if (tab->ty == Taarray)
1509 // Check types
1510 Argument *arg = (Argument *)arguments->data[0];
1511 if (dim == 2)
1513 if (arg->storageClass & STCref)
1514 error("foreach: index cannot be ref");
1515 if (!arg->type->equals(taa->index))
1516 error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
1517 arg = (Argument *)arguments->data[1];
1519 if (!arg->type->equals(taa->nextOf()))
1520 error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
1522 /* Call:
1523 * _aaApply(aggr, keysize, flde)
1525 if (dim == 2)
1526 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply2",
1527 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic
1528 else
1529 fdapply = FuncDeclaration::genCfunc(Type::tint32, "_aaApply",
1530 Type::tvoid->arrayOf(), Type::tsize_t, flde->type); // flde->type is not generic);
1531 ec = new VarExp(0, fdapply);
1532 Expressions *exps = new Expressions();
1533 exps->push(aggr);
1534 size_t keysize = taa->key->size();
1535 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
1536 exps->push(new IntegerExp(0, keysize, Type::tsize_t));
1537 exps->push(flde);
1538 e = new CallExp(loc, ec, exps);
1539 e->type = Type::tint32; // don't run semantic() on e
1541 else if (tab->ty == Tarray || tab->ty == Tsarray)
1543 /* Call:
1544 * _aApply(aggr, flde)
1546 static char fntab[9][3] =
1547 { "cc","cw","cd",
1548 "wc","cc","wd",
1549 "dc","dw","dd"
1551 char fdname[7+1+2+ sizeof(dim)*3 + 1];
1552 int flag;
1554 switch (tn->ty)
1556 case Tchar: flag = 0; break;
1557 case Twchar: flag = 3; break;
1558 case Tdchar: flag = 6; break;
1559 default: assert(0);
1561 switch (tnv->ty)
1563 case Tchar: flag += 0; break;
1564 case Twchar: flag += 1; break;
1565 case Tdchar: flag += 2; break;
1566 default: assert(0);
1568 const char *r = (op == TOKforeach_reverse) ? "R" : "";
1569 int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim);
1570 assert(j < sizeof(fdname));
1571 fdapply = FuncDeclaration::genCfunc(Type::tint32, fdname,
1572 Type::tvoid->arrayOf(), flde->type); // flde->type is not generic
1574 ec = new VarExp(0, fdapply);
1575 Expressions *exps = new Expressions();
1576 if (tab->ty == Tsarray)
1577 aggr = aggr->castTo(sc, tn->arrayOf());
1578 exps->push(aggr);
1579 exps->push(flde);
1580 e = new CallExp(loc, ec, exps);
1581 e->type = Type::tint32; // don't run semantic() on e
1583 else if (tab->ty == Tdelegate)
1585 /* Call:
1586 * aggr(flde)
1588 Expressions *exps = new Expressions();
1589 exps->push(flde);
1590 e = new CallExp(loc, aggr, exps);
1591 e = e->semantic(sc);
1592 if (e->type != Type::tint32)
1593 error("opApply() function for %s must return an int", tab->toChars());
1595 else
1597 /* Call:
1598 * aggr.apply(flde)
1600 ec = new DotIdExp(loc, aggr,
1601 (op == TOKforeach_reverse) ? Id::applyReverse
1602 : Id::apply);
1603 Expressions *exps = new Expressions();
1604 exps->push(flde);
1605 e = new CallExp(loc, ec, exps);
1606 e = e->semantic(sc);
1607 if (e->type != Type::tint32)
1608 error("opApply() function for %s must return an int", tab->toChars());
1611 if (!cases.dim)
1612 // Easy case, a clean exit from the loop
1613 s = new ExpStatement(loc, e);
1614 else
1615 { // Construct a switch statement around the return value
1616 // of the apply function.
1617 Statements *a = new Statements();
1619 // default: break; takes care of cases 0 and 1
1620 s = new BreakStatement(0, NULL);
1621 s = new DefaultStatement(0, s);
1622 a->push(s);
1624 // cases 2...
1625 for (int i = 0; i < cases.dim; i++)
1627 s = (Statement *)cases.data[i];
1628 s = new CaseStatement(0, new IntegerExp(i + 2), s);
1629 a->push(s);
1632 s = new CompoundStatement(loc, a);
1633 s = new SwitchStatement(loc, e, s);
1634 s = s->semantic(sc);
1636 break;
1639 default:
1640 error("foreach: %s is not an aggregate type", aggr->type->toChars());
1641 break;
1643 sc->noctor--;
1644 sc->pop();
1645 return s;
1648 int ForeachStatement::hasBreak()
1650 return TRUE;
1653 int ForeachStatement::hasContinue()
1655 return TRUE;
1658 int ForeachStatement::usesEH()
1660 return body->usesEH();
1663 int ForeachStatement::fallOffEnd()
1665 if (body)
1666 body->fallOffEnd();
1667 return TRUE;
1670 int ForeachStatement::comeFrom()
1672 if (body)
1673 return body->comeFrom();
1674 return FALSE;
1677 void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1679 buf->writestring(Token::toChars(op));
1680 buf->writestring(" (");
1681 int i;
1682 for (int i = 0; i < arguments->dim; i++)
1684 Argument *a = (Argument *)arguments->data[i];
1685 if (i)
1686 buf->writestring(", ");
1687 if (a->storageClass & STCref)
1688 buf->writestring((global.params.Dversion == 1)
1689 ? (char*)"inout " : (char*)"ref ");
1690 if (a->type)
1691 a->type->toCBuffer(buf, a->ident, hgs);
1692 else
1693 buf->writestring(a->ident->toChars());
1695 buf->writestring("; ");
1696 aggr->toCBuffer(buf, hgs);
1697 buf->writebyte(')');
1698 buf->writenl();
1699 buf->writebyte('{');
1700 buf->writenl();
1701 if (body)
1702 body->toCBuffer(buf, hgs);
1703 buf->writebyte('}');
1704 buf->writenl();
1707 /******************************** IfStatement ***************************/
1709 IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody)
1710 : Statement(loc)
1712 this->arg = arg;
1713 this->condition = condition;
1714 this->ifbody = ifbody;
1715 this->elsebody = elsebody;
1716 this->match = NULL;
1719 Statement *IfStatement::syntaxCopy()
1721 Statement *i = NULL;
1722 if (ifbody)
1723 i = ifbody->syntaxCopy();
1725 Statement *e = NULL;
1726 if (elsebody)
1727 e = elsebody->syntaxCopy();
1729 Argument *a = arg ? arg->syntaxCopy() : NULL;
1730 IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e);
1731 return s;
1734 Statement *IfStatement::semantic(Scope *sc)
1736 condition = condition->semantic(sc);
1737 condition = resolveProperties(sc, condition);
1738 condition = condition->checkToBoolean();
1740 // If we can short-circuit evaluate the if statement, don't do the
1741 // semantic analysis of the skipped code.
1742 // This feature allows a limited form of conditional compilation.
1743 condition = condition->optimize(WANTflags);
1745 // Evaluate at runtime
1746 unsigned cs0 = sc->callSuper;
1747 unsigned cs1;
1749 Scope *scd;
1750 if (arg)
1751 { /* Declare arg, which we will set to be the
1752 * result of condition.
1754 ScopeDsymbol *sym = new ScopeDsymbol();
1755 sym->parent = sc->scopesym;
1756 scd = sc->push(sym);
1758 Type *t = arg->type ? arg->type : condition->type;
1759 match = new VarDeclaration(loc, t, arg->ident, NULL);
1760 match->noauto = 1;
1761 match->semantic(scd);
1762 if (!scd->insert(match))
1763 assert(0);
1764 match->parent = sc->func;
1766 /* Generate:
1767 * (arg = condition)
1769 VarExp *v = new VarExp(0, match);
1770 condition = new AssignExp(loc, v, condition);
1771 condition = condition->semantic(scd);
1773 else
1774 scd = sc->push();
1775 ifbody = ifbody->semantic(scd);
1776 scd->pop();
1778 cs1 = sc->callSuper;
1779 sc->callSuper = cs0;
1780 if (elsebody)
1781 elsebody = elsebody->semanticScope(sc, NULL, NULL);
1782 sc->mergeCallSuper(loc, cs1);
1784 return this;
1787 int IfStatement::usesEH()
1789 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
1792 int IfStatement::fallOffEnd()
1794 if (!ifbody || ifbody->fallOffEnd() ||
1795 !elsebody || elsebody->fallOffEnd())
1796 return TRUE;
1797 return FALSE;
1801 void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1803 buf->writestring("if (");
1804 if (arg)
1806 if (arg->type)
1807 arg->type->toCBuffer(buf, arg->ident, hgs);
1808 else
1809 buf->writestring(arg->ident->toChars());
1810 buf->writebyte(';');
1812 condition->toCBuffer(buf, hgs);
1813 buf->writebyte(')');
1814 buf->writenl();
1815 ifbody->toCBuffer(buf, hgs);
1816 if (elsebody)
1817 { buf->writestring("else");
1818 buf->writenl();
1819 elsebody->toCBuffer(buf, hgs);
1823 /******************************** ConditionalStatement ***************************/
1825 ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
1826 : Statement(loc)
1828 this->condition = condition;
1829 this->ifbody = ifbody;
1830 this->elsebody = elsebody;
1833 Statement *ConditionalStatement::syntaxCopy()
1835 Statement *e = NULL;
1836 if (elsebody)
1837 e = elsebody->syntaxCopy();
1838 ConditionalStatement *s = new ConditionalStatement(loc,
1839 condition->syntaxCopy(), ifbody->syntaxCopy(), e);
1840 return s;
1843 Statement *ConditionalStatement::semantic(Scope *sc)
1845 //printf("ConditionalStatement::semantic()\n");
1847 // If we can short-circuit evaluate the if statement, don't do the
1848 // semantic analysis of the skipped code.
1849 // This feature allows a limited form of conditional compilation.
1850 if (condition->include(sc, NULL))
1852 ifbody = ifbody->semantic(sc);
1853 return ifbody;
1855 else
1857 if (elsebody)
1858 elsebody = elsebody->semantic(sc);
1859 return elsebody;
1863 Statements *ConditionalStatement::flatten(Scope *sc)
1865 Statement *s;
1867 if (condition->include(sc, NULL))
1868 s = ifbody;
1869 else
1870 s = elsebody;
1872 Statements *a = new Statements();
1873 a->push(s);
1874 return a;
1877 int ConditionalStatement::usesEH()
1879 return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH());
1882 void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1884 condition->toCBuffer(buf, hgs);
1885 buf->writenl();
1886 if (ifbody)
1887 ifbody->toCBuffer(buf, hgs);
1888 if (elsebody)
1890 buf->writestring("else");
1891 buf->writenl();
1892 elsebody->toCBuffer(buf, hgs);
1894 buf->writenl();
1898 /******************************** PragmaStatement ***************************/
1900 PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
1901 : Statement(loc)
1903 this->ident = ident;
1904 this->args = args;
1905 this->body = body;
1908 Statement *PragmaStatement::syntaxCopy()
1910 Statement *b = NULL;
1911 if (body)
1912 b = body->syntaxCopy();
1913 PragmaStatement *s = new PragmaStatement(loc,
1914 ident, Expression::arraySyntaxCopy(args), b);
1915 return s;
1918 Statement *PragmaStatement::semantic(Scope *sc)
1919 { // Should be merged with PragmaDeclaration
1920 //printf("PragmaStatement::semantic() %s\n", toChars());
1921 //printf("body = %p\n", body);
1922 if (ident == Id::msg)
1924 if (args)
1926 for (size_t i = 0; i < args->dim; i++)
1928 Expression *e = (Expression *)args->data[i];
1930 e = e->semantic(sc);
1931 e = e->optimize(WANTvalue | WANTinterpret);
1932 if (e->op == TOKstring)
1934 StringExp *se = (StringExp *)e;
1935 fprintf(stdmsg, "%.*s", (int)se->len, se->string);
1937 else
1938 error("string expected for message, not '%s'", e->toChars());
1940 fprintf(stdmsg, "\n");
1943 else if (ident == Id::lib)
1945 if (!args || args->dim != 1)
1946 error("string expected for library name");
1947 else
1949 Expression *e = (Expression *)args->data[0];
1951 e = e->semantic(sc);
1952 e = e->optimize(WANTvalue | WANTinterpret);
1953 args->data[0] = (void *)e;
1954 if (e->op != TOKstring)
1955 error("string expected for library name, not '%s'", e->toChars());
1956 else if (global.params.verbose)
1958 StringExp *se = (StringExp *)e;
1959 char *name = (char *)mem.malloc(se->len + 1);
1960 memcpy(name, se->string, se->len);
1961 name[se->len] = 0;
1962 printf("library %s\n", name);
1963 mem.free(name);
1967 else
1968 error("unrecognized pragma(%s)", ident->toChars());
1970 if (body)
1972 body = body->semantic(sc);
1974 return body;
1977 int PragmaStatement::usesEH()
1979 return body && body->usesEH();
1982 int PragmaStatement::fallOffEnd()
1984 if (body)
1985 return body->fallOffEnd();
1986 return TRUE;
1989 void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
1991 buf->writestring("pragma (");
1992 buf->writestring(ident->toChars());
1993 if (args && args->dim)
1995 buf->writestring(", ");
1996 argsToCBuffer(buf, args, hgs);
1998 buf->writeByte(')');
1999 if (body)
2001 buf->writenl();
2002 buf->writeByte('{');
2003 buf->writenl();
2005 body->toCBuffer(buf, hgs);
2007 buf->writeByte('}');
2008 buf->writenl();
2010 else
2012 buf->writeByte(';');
2013 buf->writenl();
2018 /******************************** StaticAssertStatement ***************************/
2020 StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
2021 : Statement(sa->loc)
2023 this->sa = sa;
2026 Statement *StaticAssertStatement::syntaxCopy()
2028 StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
2029 return s;
2032 Statement *StaticAssertStatement::semantic(Scope *sc)
2034 sa->semantic2(sc);
2035 return NULL;
2038 void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2040 sa->toCBuffer(buf, hgs);
2044 /******************************** SwitchStatement ***************************/
2046 SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
2047 : Statement(loc)
2049 condition = c;
2050 body = b;
2051 sdefault = NULL;
2052 cases = NULL;
2053 hasNoDefault = 0;
2056 Statement *SwitchStatement::syntaxCopy()
2058 SwitchStatement *s = new SwitchStatement(loc,
2059 condition->syntaxCopy(), body->syntaxCopy());
2060 return s;
2063 Statement *SwitchStatement::semantic(Scope *sc)
2065 //printf("SwitchStatement::semantic(%p)\n", this);
2066 assert(!cases); // ensure semantic() is only run once
2067 condition = condition->semantic(sc);
2068 condition = resolveProperties(sc, condition);
2069 if (condition->type->isString())
2071 // If it's not an array, cast it to one
2072 if (condition->type->ty != Tarray)
2074 condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf());
2077 else
2078 { condition = condition->integralPromotions(sc);
2079 condition->checkIntegral();
2081 condition = condition->optimize(WANTvalue);
2083 sc = sc->push();
2084 sc->sbreak = this;
2085 sc->sw = this;
2087 cases = new Array();
2088 sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
2089 body = body->semantic(sc);
2090 sc->noctor--;
2092 // Resolve any goto case's with exp
2093 for (int i = 0; i < gotoCases.dim; i++)
2095 GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i];
2097 if (!gcs->exp)
2099 gcs->error("no case statement following goto case;");
2100 break;
2103 for (Scope *scx = sc; scx; scx = scx->enclosing)
2105 if (!scx->sw)
2106 continue;
2107 for (int j = 0; j < scx->sw->cases->dim; j++)
2109 CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j];
2111 if (cs->exp->equals(gcs->exp))
2113 gcs->cs = cs;
2114 goto Lfoundcase;
2118 gcs->error("case %s not found", gcs->exp->toChars());
2120 Lfoundcase:
2124 if (!sc->sw->sdefault)
2125 { hasNoDefault = 1;
2127 if (global.params.warnings)
2128 { fprintf(stdmsg, "warning - ");
2129 error("switch statement has no default");
2132 // Generate runtime error if the default is hit
2133 Statements *a = new Statements();
2134 CompoundStatement *cs;
2135 Statement *s;
2137 if (global.params.useSwitchError)
2138 s = new SwitchErrorStatement(loc);
2139 else
2140 { Expression *e = new HaltExp(loc);
2141 s = new ExpStatement(loc, e);
2144 a->reserve(4);
2145 a->push(body);
2146 a->push(new BreakStatement(loc, NULL));
2147 sc->sw->sdefault = new DefaultStatement(loc, s);
2148 a->push(sc->sw->sdefault);
2149 cs = new CompoundStatement(loc, a);
2150 body = cs;
2153 sc->pop();
2154 return this;
2157 int SwitchStatement::hasBreak()
2159 return TRUE;
2162 int SwitchStatement::usesEH()
2164 return body ? body->usesEH() : 0;
2167 int SwitchStatement::fallOffEnd()
2169 if (body)
2170 body->fallOffEnd();
2171 return TRUE; // need to do this better
2174 void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2176 buf->writestring("switch (");
2177 condition->toCBuffer(buf, hgs);
2178 buf->writebyte(')');
2179 buf->writenl();
2180 if (body)
2182 if (!body->isScopeStatement())
2183 { buf->writebyte('{');
2184 buf->writenl();
2185 body->toCBuffer(buf, hgs);
2186 buf->writebyte('}');
2187 buf->writenl();
2189 else
2191 body->toCBuffer(buf, hgs);
2196 /******************************** CaseStatement ***************************/
2198 CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
2199 : Statement(loc)
2201 this->exp = exp;
2202 this->statement = s;
2203 cblock = NULL;
2206 Statement *CaseStatement::syntaxCopy()
2208 CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy());
2209 return s;
2212 Statement *CaseStatement::semantic(Scope *sc)
2213 { SwitchStatement *sw = sc->sw;
2215 //printf("CaseStatement::semantic() %s\n", toChars());
2216 exp = exp->semantic(sc);
2217 if (sw)
2218 { int i;
2220 exp = exp->implicitCastTo(sc, sw->condition->type);
2221 exp = exp->optimize(WANTvalue | WANTinterpret);
2222 if (exp->op != TOKstring && exp->op != TOKint64)
2224 error("case must be a string or an integral constant, not %s", exp->toChars());
2225 exp = new IntegerExp(0);
2228 for (i = 0; i < sw->cases->dim; i++)
2230 CaseStatement *cs = (CaseStatement *)sw->cases->data[i];
2232 //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars());
2233 if (cs->exp->equals(exp))
2234 { error("duplicate case %s in switch statement", exp->toChars());
2235 break;
2239 sw->cases->push(this);
2241 // Resolve any goto case's with no exp to this case statement
2242 for (i = 0; i < sw->gotoCases.dim; i++)
2244 GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i];
2246 if (!gcs->exp)
2248 gcs->cs = this;
2249 sw->gotoCases.remove(i); // remove from array
2253 else
2254 error("case not in switch statement");
2255 statement = statement->semantic(sc);
2256 return this;
2259 int CaseStatement::compare(Object *obj)
2261 // Sort cases so we can do an efficient lookup
2262 CaseStatement *cs2 = (CaseStatement *)(obj);
2264 return exp->compare(cs2->exp);
2267 int CaseStatement::usesEH()
2269 return statement->usesEH();
2272 int CaseStatement::fallOffEnd()
2274 return statement->fallOffEnd();
2277 int CaseStatement::comeFrom()
2279 return TRUE;
2282 void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2284 buf->writestring("case ");
2285 exp->toCBuffer(buf, hgs);
2286 buf->writebyte(':');
2287 buf->writenl();
2288 statement->toCBuffer(buf, hgs);
2291 /******************************** DefaultStatement ***************************/
2293 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
2294 : Statement(loc)
2296 this->statement = s;
2297 #if IN_GCC
2298 cblock = NULL;
2299 #endif
2302 Statement *DefaultStatement::syntaxCopy()
2304 DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy());
2305 return s;
2308 Statement *DefaultStatement::semantic(Scope *sc)
2310 if (sc->sw)
2312 if (sc->sw->sdefault)
2314 error("switch statement already has a default");
2316 sc->sw->sdefault = this;
2318 else
2319 error("default not in switch statement");
2320 statement = statement->semantic(sc);
2321 return this;
2324 int DefaultStatement::usesEH()
2326 return statement->usesEH();
2329 int DefaultStatement::fallOffEnd()
2331 return statement->fallOffEnd();
2334 int DefaultStatement::comeFrom()
2336 return TRUE;
2339 void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2341 buf->writestring("default:\n");
2342 statement->toCBuffer(buf, hgs);
2345 /******************************** GotoDefaultStatement ***************************/
2347 GotoDefaultStatement::GotoDefaultStatement(Loc loc)
2348 : Statement(loc)
2350 sw = NULL;
2353 Statement *GotoDefaultStatement::syntaxCopy()
2355 GotoDefaultStatement *s = new GotoDefaultStatement(loc);
2356 return s;
2359 Statement *GotoDefaultStatement::semantic(Scope *sc)
2361 sw = sc->sw;
2362 if (!sw)
2363 error("goto default not in switch statement");
2364 return this;
2367 int GotoDefaultStatement::fallOffEnd()
2369 return FALSE;
2372 void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2374 buf->writestring("goto default;\n");
2377 /******************************** GotoCaseStatement ***************************/
2379 GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
2380 : Statement(loc)
2382 cs = NULL;
2383 this->exp = exp;
2386 Statement *GotoCaseStatement::syntaxCopy()
2388 Expression *e = exp ? exp->syntaxCopy() : NULL;
2389 GotoCaseStatement *s = new GotoCaseStatement(loc, e);
2390 return s;
2393 Statement *GotoCaseStatement::semantic(Scope *sc)
2395 if (exp)
2396 exp = exp->semantic(sc);
2398 if (!sc->sw)
2399 error("goto case not in switch statement");
2400 else
2402 sc->sw->gotoCases.push(this);
2403 if (exp)
2405 exp = exp->implicitCastTo(sc, sc->sw->condition->type);
2406 exp = exp->optimize(WANTvalue);
2409 return this;
2412 int GotoCaseStatement::fallOffEnd()
2414 return FALSE;
2417 void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2419 buf->writestring("goto case");
2420 if (exp)
2421 { buf->writebyte(' ');
2422 exp->toCBuffer(buf, hgs);
2424 buf->writebyte(';');
2425 buf->writenl();
2428 /******************************** SwitchErrorStatement ***************************/
2430 SwitchErrorStatement::SwitchErrorStatement(Loc loc)
2431 : Statement(loc)
2435 int SwitchErrorStatement::fallOffEnd()
2437 return FALSE;
2440 void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2442 buf->writestring("SwitchErrorStatement::toCBuffer()");
2443 buf->writenl();
2446 /******************************** ReturnStatement ***************************/
2448 ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
2449 : Statement(loc)
2451 this->exp = exp;
2454 Statement *ReturnStatement::syntaxCopy()
2456 Expression *e = NULL;
2457 if (exp)
2458 e = exp->syntaxCopy();
2459 ReturnStatement *s = new ReturnStatement(loc, e);
2460 return s;
2463 Statement *ReturnStatement::semantic(Scope *sc)
2465 //printf("ReturnStatement::semantic() %s\n", toChars());
2467 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
2468 Scope *scx = sc;
2469 int implicit0 = 0;
2471 if (sc->fes)
2473 // Find scope of function foreach is in
2474 for (; 1; scx = scx->enclosing)
2476 assert(scx);
2477 if (scx->func != fd)
2478 { fd = scx->func; // fd is now function enclosing foreach
2479 break;
2484 Type *tret = fd->type->nextOf();
2485 if (fd->tintro)
2486 tret = fd->tintro->nextOf();
2487 Type *tbret = NULL;
2489 if (tret)
2490 tbret = tret->toBasetype();
2492 // main() returns 0, even if it returns void
2493 if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain())
2494 { implicit0 = 1;
2495 exp = new IntegerExp(0);
2498 if (sc->incontract || scx->incontract)
2499 error("return statements cannot be in contracts");
2500 if (sc->tf || scx->tf)
2501 error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
2503 if (fd->isCtorDeclaration())
2505 // Constructors implicitly do:
2506 // return this;
2507 if (exp && exp->op != TOKthis)
2508 error("cannot return expression from constructor");
2509 exp = new ThisExp(0);
2512 if (!exp)
2513 fd->nrvo_can = 0;
2515 if (exp)
2517 fd->hasReturnExp |= 1;
2519 exp = exp->semantic(sc);
2520 exp = resolveProperties(sc, exp);
2521 exp = exp->optimize(WANTvalue);
2523 if (fd->nrvo_can && exp->op == TOKvar)
2524 { VarExp *ve = (VarExp *)exp;
2525 VarDeclaration *v = ve->var->isVarDeclaration();
2527 if (!v || v->isOut() || v->isRef())
2528 fd->nrvo_can = 0;
2529 else if (fd->nrvo_var == NULL)
2530 { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
2531 fd->nrvo_var = v;
2532 else
2533 fd->nrvo_can = 0;
2535 else if (fd->nrvo_var != v)
2536 fd->nrvo_can = 0;
2538 else
2539 fd->nrvo_can = 0;
2541 if (fd->returnLabel && tbret->ty != Tvoid)
2544 else if (fd->inferRetType)
2546 if (fd->type->nextOf())
2548 if (!exp->type->equals(fd->type->nextOf()))
2549 error("mismatched function return type inference of %s and %s",
2550 exp->type->toChars(), fd->type->nextOf()->toChars());
2552 else
2554 fd->type->next = exp->type;
2555 fd->type = fd->type->semantic(loc, sc);
2556 if (!fd->tintro)
2557 { tret = fd->type->nextOf();
2558 tbret = tret->toBasetype();
2562 else if (tbret->ty != Tvoid)
2564 exp = exp->implicitCastTo(sc, tret);
2567 else if (fd->inferRetType)
2569 if (fd->type->nextOf())
2571 if (fd->type->nextOf()->ty != Tvoid)
2572 error("mismatched function return type inference of void and %s",
2573 fd->type->nextOf()->toChars());
2575 else
2577 fd->type->next = Type::tvoid;
2578 fd->type = fd->type->semantic(loc, sc);
2579 if (!fd->tintro)
2580 { tret = Type::tvoid;
2581 tbret = tret;
2585 else if (tbret->ty != Tvoid) // if non-void return
2586 error("return expression expected");
2588 if (sc->fes)
2590 Statement *s;
2592 if (exp && !implicit0)
2594 exp = exp->implicitCastTo(sc, tret);
2596 if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 ||
2597 exp->op == TOKimaginary80 || exp->op == TOKcomplex80 ||
2598 exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull ||
2599 exp->op == TOKstring)
2601 sc->fes->cases.push(this);
2602 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2604 else if (fd->type->nextOf()->toBasetype() == Type::tvoid)
2606 Statement *s1;
2607 Statement *s2;
2609 s = new ReturnStatement(0, NULL);
2610 sc->fes->cases.push(s);
2612 // Construct: { exp; return cases.dim + 1; }
2613 s1 = new ExpStatement(loc, exp);
2614 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2615 s = new CompoundStatement(loc, s1, s2);
2617 else
2619 VarExp *v;
2620 Statement *s1;
2621 Statement *s2;
2623 // Construct: return vresult;
2624 if (!fd->vresult)
2625 { VarDeclaration *v;
2627 v = new VarDeclaration(loc, tret, Id::result, NULL);
2628 v->noauto = 1;
2629 v->semantic(scx);
2630 if (!scx->insert(v))
2631 assert(0);
2632 v->parent = fd;
2633 fd->vresult = v;
2636 v = new VarExp(0, fd->vresult);
2637 s = new ReturnStatement(0, v);
2638 sc->fes->cases.push(s);
2640 // Construct: { vresult = exp; return cases.dim + 1; }
2641 v = new VarExp(0, fd->vresult);
2642 exp = new AssignExp(loc, v, exp);
2643 exp = exp->semantic(sc);
2644 s1 = new ExpStatement(loc, exp);
2645 s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2646 s = new CompoundStatement(loc, s1, s2);
2648 return s;
2651 if (exp)
2653 if (fd->returnLabel && tbret->ty != Tvoid)
2655 assert(fd->vresult);
2656 VarExp *v = new VarExp(0, fd->vresult);
2658 exp = new AssignExp(loc, v, exp);
2659 exp = exp->semantic(sc);
2661 //exp->dump(0);
2662 //exp->print();
2663 exp->checkEscape();
2666 /* BUG: need to issue an error on:
2667 * this
2668 * { if (x) return;
2669 * super();
2673 if (sc->callSuper & CSXany_ctor &&
2674 !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
2675 error("return without calling constructor");
2677 sc->callSuper |= CSXreturn;
2679 // See if all returns are instead to be replaced with a goto returnLabel;
2680 if (fd->returnLabel)
2682 GotoStatement *gs = new GotoStatement(loc, Id::returnLabel);
2684 gs->label = fd->returnLabel;
2685 if (exp)
2686 { Statement *s;
2688 s = new ExpStatement(0, exp);
2689 return new CompoundStatement(loc, s, gs);
2691 return gs;
2694 if (exp && tbret->ty == Tvoid && !fd->isMain())
2695 { Statement *s;
2697 s = new ExpStatement(loc, exp);
2698 loc = 0;
2699 exp = NULL;
2700 return new CompoundStatement(loc, s, this);
2703 return this;
2706 int ReturnStatement::fallOffEnd()
2708 return FALSE;
2711 void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2713 buf->printf("return ");
2714 if (exp)
2715 exp->toCBuffer(buf, hgs);
2716 buf->writeByte(';');
2717 buf->writenl();
2720 /******************************** BreakStatement ***************************/
2722 BreakStatement::BreakStatement(Loc loc, Identifier *ident)
2723 : Statement(loc)
2725 this->ident = ident;
2728 Statement *BreakStatement::syntaxCopy()
2730 BreakStatement *s = new BreakStatement(loc, ident);
2731 return s;
2734 Statement *BreakStatement::semantic(Scope *sc)
2736 // If:
2737 // break Identifier;
2738 if (ident)
2740 Scope *scx;
2741 FuncDeclaration *thisfunc = sc->func;
2743 for (scx = sc; scx; scx = scx->enclosing)
2745 LabelStatement *ls;
2747 if (scx->func != thisfunc) // if in enclosing function
2749 if (sc->fes) // if this is the body of a foreach
2751 /* Post this statement to the fes, and replace
2752 * it with a return value that caller will put into
2753 * a switch. Caller will figure out where the break
2754 * label actually is.
2755 * Case numbers start with 2, not 0, as 0 is continue
2756 * and 1 is break.
2758 Statement *s;
2759 sc->fes->cases.push(this);
2760 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2761 return s;
2763 break; // can't break to it
2766 ls = scx->slabel;
2767 if (ls && ls->ident == ident)
2769 Statement *s = ls->statement;
2771 if (!s->hasBreak())
2772 error("label '%s' has no break", ident->toChars());
2773 if (ls->tf != sc->tf)
2774 error("cannot break out of finally block");
2775 return this;
2778 error("enclosing label '%s' for break not found", ident->toChars());
2780 else if (!sc->sbreak)
2782 if (sc->fes)
2783 { Statement *s;
2785 // Replace break; with return 1;
2786 s = new ReturnStatement(0, new IntegerExp(1));
2787 return s;
2789 error("break is not inside a loop or switch");
2791 return this;
2794 int BreakStatement::fallOffEnd()
2796 return FALSE;
2799 void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2801 buf->writestring("break");
2802 if (ident)
2803 { buf->writebyte(' ');
2804 buf->writestring(ident->toChars());
2806 buf->writebyte(';');
2807 buf->writenl();
2810 /******************************** ContinueStatement ***************************/
2812 ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
2813 : Statement(loc)
2815 this->ident = ident;
2818 Statement *ContinueStatement::syntaxCopy()
2820 ContinueStatement *s = new ContinueStatement(loc, ident);
2821 return s;
2824 Statement *ContinueStatement::semantic(Scope *sc)
2826 //printf("ContinueStatement::semantic() %p\n", this);
2827 if (ident)
2829 Scope *scx;
2830 FuncDeclaration *thisfunc = sc->func;
2832 for (scx = sc; scx; scx = scx->enclosing)
2834 LabelStatement *ls;
2836 if (scx->func != thisfunc) // if in enclosing function
2838 if (sc->fes) // if this is the body of a foreach
2840 for (; scx; scx = scx->enclosing)
2842 ls = scx->slabel;
2843 if (ls && ls->ident == ident && ls->statement == sc->fes)
2845 // Replace continue ident; with return 0;
2846 return new ReturnStatement(0, new IntegerExp(0));
2850 /* Post this statement to the fes, and replace
2851 * it with a return value that caller will put into
2852 * a switch. Caller will figure out where the break
2853 * label actually is.
2854 * Case numbers start with 2, not 0, as 0 is continue
2855 * and 1 is break.
2857 Statement *s;
2858 sc->fes->cases.push(this);
2859 s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
2860 return s;
2862 break; // can't continue to it
2865 ls = scx->slabel;
2866 if (ls && ls->ident == ident)
2868 Statement *s = ls->statement;
2870 if (!s->hasContinue())
2871 error("label '%s' has no continue", ident->toChars());
2872 if (ls->tf != sc->tf)
2873 error("cannot continue out of finally block");
2874 return this;
2877 error("enclosing label '%s' for continue not found", ident->toChars());
2879 else if (!sc->scontinue)
2881 if (sc->fes)
2882 { Statement *s;
2884 // Replace continue; with return 0;
2885 s = new ReturnStatement(0, new IntegerExp(0));
2886 return s;
2888 error("continue is not inside a loop");
2890 return this;
2893 int ContinueStatement::fallOffEnd()
2895 return FALSE;
2898 void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2900 buf->writestring("continue");
2901 if (ident)
2902 { buf->writebyte(' ');
2903 buf->writestring(ident->toChars());
2905 buf->writebyte(';');
2906 buf->writenl();
2909 /******************************** SynchronizedStatement ***************************/
2911 SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
2912 : Statement(loc)
2914 this->exp = exp;
2915 this->body = body;
2916 this->esync = NULL;
2919 SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body)
2920 : Statement(loc)
2922 this->exp = NULL;
2923 this->body = body;
2924 this->esync = esync;
2927 Statement *SynchronizedStatement::syntaxCopy()
2929 Expression *e = exp ? exp->syntaxCopy() : NULL;
2930 SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL);
2931 return s;
2934 Statement *SynchronizedStatement::semantic(Scope *sc)
2936 if (exp)
2937 { ClassDeclaration *cd;
2939 exp = exp->semantic(sc);
2940 exp = resolveProperties(sc, exp);
2941 cd = exp->type->isClassHandle();
2942 if (!cd)
2943 error("can only synchronize on class objects, not '%s'", exp->type->toChars());
2944 else if (cd->isInterfaceDeclaration())
2945 { Type *t = new TypeIdentifier(0, Id::Object);
2947 t = t->semantic(0, sc);
2948 exp = new CastExp(loc, exp, t);
2949 exp = exp->semantic(sc);
2952 if (body)
2953 body = body->semantic(sc);
2954 return this;
2957 int SynchronizedStatement::hasBreak()
2959 return FALSE; //TRUE;
2962 int SynchronizedStatement::hasContinue()
2964 return FALSE; //TRUE;
2967 int SynchronizedStatement::usesEH()
2969 return TRUE;
2972 int SynchronizedStatement::fallOffEnd()
2974 return body ? body->fallOffEnd() : TRUE;
2977 void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
2979 buf->writestring("synchronized");
2980 if (exp)
2981 { buf->writebyte('(');
2982 exp->toCBuffer(buf, hgs);
2983 buf->writebyte(')');
2985 if (body)
2987 buf->writebyte(' ');
2988 body->toCBuffer(buf, hgs);
2992 /******************************** WithStatement ***************************/
2994 WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body)
2995 : Statement(loc)
2997 this->exp = exp;
2998 this->body = body;
2999 wthis = NULL;
3002 Statement *WithStatement::syntaxCopy()
3004 WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL);
3005 return s;
3008 Statement *WithStatement::semantic(Scope *sc)
3009 { ScopeDsymbol *sym;
3010 Initializer *init;
3012 //printf("WithStatement::semantic()\n");
3013 exp = exp->semantic(sc);
3014 exp = resolveProperties(sc, exp);
3015 if (exp->op == TOKimport)
3016 { ScopeExp *es = (ScopeExp *)exp;
3018 sym = es->sds;
3020 else if (exp->op == TOKtype)
3021 { TypeExp *es = (TypeExp *)exp;
3023 sym = es->type->toDsymbol(sc)->isScopeDsymbol();
3024 if (!sym)
3025 { error("%s has no members", es->toChars());
3026 body = body->semantic(sc);
3027 return this;
3030 else
3031 { Type *t = exp->type;
3033 assert(t);
3034 t = t->toBasetype();
3035 if (t->isClassHandle())
3037 init = new ExpInitializer(loc, exp);
3038 wthis = new VarDeclaration(loc, exp->type, Id::withSym, init);
3039 wthis->semantic(sc);
3041 sym = new WithScopeSymbol(this);
3042 sym->parent = sc->scopesym;
3044 else if (t->ty == Tstruct)
3046 Expression *e = exp->addressOf(sc);
3047 init = new ExpInitializer(loc, e);
3048 wthis = new VarDeclaration(loc, e->type, Id::withSym, init);
3049 wthis->semantic(sc);
3050 sym = new WithScopeSymbol(this);
3051 sym->parent = sc->scopesym;
3053 else
3054 { error("with expressions must be class objects, not '%s'", exp->type->toChars());
3055 return NULL;
3058 sc = sc->push(sym);
3060 if (body)
3061 body = body->semantic(sc);
3063 sc->pop();
3065 return this;
3068 void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3070 buf->writestring("with (");
3071 exp->toCBuffer(buf, hgs);
3072 buf->writestring(")\n");
3073 if (body)
3074 body->toCBuffer(buf, hgs);
3077 int WithStatement::usesEH()
3079 return body ? body->usesEH() : 0;
3082 int WithStatement::fallOffEnd()
3084 return body ? body->fallOffEnd() : TRUE;
3087 /******************************** TryCatchStatement ***************************/
3089 TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches)
3090 : Statement(loc)
3092 this->body = body;
3093 this->catches = catches;
3096 Statement *TryCatchStatement::syntaxCopy()
3098 Array *a = new Array();
3099 a->setDim(catches->dim);
3100 for (int i = 0; i < a->dim; i++)
3101 { Catch *c;
3103 c = (Catch *)catches->data[i];
3104 c = c->syntaxCopy();
3105 a->data[i] = c;
3107 TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a);
3108 return s;
3111 Statement *TryCatchStatement::semantic(Scope *sc)
3113 body = body->semanticScope(sc, NULL /*this*/, NULL);
3115 for (int i = 0; i < catches->dim; i++)
3116 { Catch *c;
3118 c = (Catch *)catches->data[i];
3119 c->semantic(sc);
3121 // Determine if current catch 'hides' any previous catches
3122 for (int j = 0; j < i; j++)
3123 { Catch *cj = (Catch *)catches->data[j];
3124 char *si = c->loc.toChars();
3125 char *sj = cj->loc.toChars();
3127 if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
3128 error("catch at %s hides catch at %s", sj, si);
3131 return this;
3134 int TryCatchStatement::hasBreak()
3136 return FALSE; //TRUE;
3139 int TryCatchStatement::usesEH()
3141 return TRUE;
3144 int TryCatchStatement::fallOffEnd()
3146 int result = FALSE;
3148 if (body)
3149 result = body->fallOffEnd();
3150 for (int i = 0; i < catches->dim; i++)
3151 { Catch *c;
3153 c = (Catch *)catches->data[i];
3154 if (c->handler)
3155 result |= c->handler->fallOffEnd();
3157 return result;
3160 void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3162 buf->writestring("try");
3163 buf->writenl();
3164 if (body)
3165 body->toCBuffer(buf, hgs);
3166 int i;
3167 for (i = 0; i < catches->dim; i++)
3169 Catch *c = (Catch *)catches->data[i];
3170 c->toCBuffer(buf, hgs);
3174 /******************************** Catch ***************************/
3176 Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
3178 //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
3179 this->loc = loc;
3180 this->type = t;
3181 this->ident = id;
3182 this->handler = handler;
3183 var = NULL;
3186 Catch *Catch::syntaxCopy()
3188 Catch *c = new Catch(loc,
3189 (type ? type->syntaxCopy() : NULL),
3190 ident,
3191 (handler ? handler->syntaxCopy() : NULL));
3192 return c;
3195 void Catch::semantic(Scope *sc)
3196 { ScopeDsymbol *sym;
3198 //printf("Catch::semantic(%s)\n", ident->toChars());
3200 #ifndef IN_GCC
3201 if (sc->tf)
3203 /* This is because the _d_local_unwind() gets the stack munged
3204 * up on this. The workaround is to place any try-catches into
3205 * a separate function, and call that.
3206 * To fix, have the compiler automatically convert the finally
3207 * body into a nested function.
3209 error(loc, "cannot put catch statement inside finally block");
3211 #endif
3213 sym = new ScopeDsymbol();
3214 sym->parent = sc->scopesym;
3215 sc = sc->push(sym);
3217 if (!type)
3218 type = new TypeIdentifier(0, Id::Object);
3219 type = type->semantic(loc, sc);
3220 if (!type->toBasetype()->isClassHandle())
3221 error("can only catch class objects, not '%s'", type->toChars());
3222 else if (ident)
3224 var = new VarDeclaration(loc, type, ident, NULL);
3225 var->parent = sc->parent;
3226 sc->insert(var);
3228 handler = handler->semantic(sc);
3230 sc->pop();
3233 void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3235 buf->writestring("catch");
3236 if (type)
3237 { buf->writebyte('(');
3238 type->toCBuffer(buf, ident, hgs);
3239 buf->writebyte(')');
3241 buf->writenl();
3242 buf->writebyte('{');
3243 buf->writenl();
3244 handler->toCBuffer(buf, hgs);
3245 buf->writebyte('}');
3246 buf->writenl();
3249 /****************************** TryFinallyStatement ***************************/
3251 TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
3252 : Statement(loc)
3254 this->body = body;
3255 this->finalbody = finalbody;
3258 Statement *TryFinallyStatement::syntaxCopy()
3260 TryFinallyStatement *s = new TryFinallyStatement(loc,
3261 body->syntaxCopy(), finalbody->syntaxCopy());
3262 return s;
3265 Statement *TryFinallyStatement::semantic(Scope *sc)
3267 //printf("TryFinallyStatement::semantic()\n");
3268 body = body->semantic(sc);
3269 sc = sc->push();
3270 sc->tf = this;
3271 sc->sbreak = NULL;
3272 sc->scontinue = NULL; // no break or continue out of finally block
3273 finalbody = finalbody->semantic(sc);
3274 sc->pop();
3275 return this;
3278 void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3280 buf->printf("try\n{\n");
3281 body->toCBuffer(buf, hgs);
3282 buf->printf("}\nfinally\n{\n");
3283 finalbody->toCBuffer(buf, hgs);
3284 buf->writeByte('}');
3285 buf->writenl();
3288 int TryFinallyStatement::hasBreak()
3290 return FALSE; //TRUE;
3293 int TryFinallyStatement::hasContinue()
3295 return FALSE; //TRUE;
3298 int TryFinallyStatement::usesEH()
3300 return TRUE;
3303 int TryFinallyStatement::fallOffEnd()
3304 { int result;
3306 result = body ? body->fallOffEnd() : TRUE;
3307 // if (finalbody)
3308 // result = finalbody->fallOffEnd();
3309 return result;
3312 /****************************** OnScopeStatement ***************************/
3314 OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
3315 : Statement(loc)
3317 this->tok = tok;
3318 this->statement = statement;
3321 Statement *OnScopeStatement::syntaxCopy()
3323 OnScopeStatement *s = new OnScopeStatement(loc,
3324 tok, statement->syntaxCopy());
3325 return s;
3328 Statement *OnScopeStatement::semantic(Scope *sc)
3330 /* semantic is called on results of scopeCode() */
3331 return this;
3334 void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3336 buf->writestring(Token::toChars(tok));
3337 buf->writebyte(' ');
3338 statement->toCBuffer(buf, hgs);
3341 int OnScopeStatement::usesEH()
3343 return (tok != TOKon_scope_success);
3346 void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally)
3348 //printf("OnScopeStatement::scopeCode()\n");
3349 //print();
3350 *sentry = NULL;
3351 *sexception = NULL;
3352 *sfinally = NULL;
3353 switch (tok)
3355 case TOKon_scope_exit:
3356 *sfinally = statement;
3357 break;
3359 case TOKon_scope_failure:
3360 *sexception = statement;
3361 break;
3363 case TOKon_scope_success:
3365 /* Create:
3366 * sentry: int x = 0;
3367 * sexception: x = 1;
3368 * sfinally: if (!x) statement;
3370 static int num;
3371 char name[5 + sizeof(num) * 3 + 1];
3372 sprintf(name, "__osf%d", ++num);
3373 Identifier *id = Lexer::idPool(name);
3375 ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0));
3376 VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie);
3377 *sentry = new DeclarationStatement(loc, v);
3379 Expression *e = new IntegerExp(1);
3380 e = new AssignExp(0, new VarExp(0, v), e);
3381 *sexception = new ExpStatement(0, e);
3383 e = new VarExp(0, v);
3384 e = new NotExp(0, e);
3385 *sfinally = new IfStatement(0, NULL, e, statement, NULL);
3387 break;
3390 default:
3391 assert(0);
3395 /******************************** ThrowStatement ***************************/
3397 ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
3398 : Statement(loc)
3400 this->exp = exp;
3403 Statement *ThrowStatement::syntaxCopy()
3405 ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
3406 return s;
3409 Statement *ThrowStatement::semantic(Scope *sc)
3411 //printf("ThrowStatement::semantic()\n");
3413 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3414 fd->hasReturnExp |= 2;
3416 if (sc->incontract)
3417 error("Throw statements cannot be in contracts");
3418 exp = exp->semantic(sc);
3419 exp = resolveProperties(sc, exp);
3420 if (!exp->type->toBasetype()->isClassHandle())
3421 error("can only throw class objects, not type %s", exp->type->toChars());
3422 return this;
3425 int ThrowStatement::fallOffEnd()
3427 return FALSE;
3430 void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3432 buf->printf("throw ");
3433 exp->toCBuffer(buf, hgs);
3434 buf->writeByte(';');
3435 buf->writenl();
3438 /******************************** VolatileStatement **************************/
3440 VolatileStatement::VolatileStatement(Loc loc, Statement *statement)
3441 : Statement(loc)
3443 this->statement = statement;
3446 Statement *VolatileStatement::syntaxCopy()
3448 VolatileStatement *s = new VolatileStatement(loc,
3449 statement ? statement->syntaxCopy() : NULL);
3450 return s;
3453 Statement *VolatileStatement::semantic(Scope *sc)
3455 statement = statement ? statement->semantic(sc) : NULL;
3456 return this;
3459 Statements *VolatileStatement::flatten(Scope *sc)
3461 Statements *a;
3463 a = statement ? statement->flatten(sc) : NULL;
3464 if (a)
3465 { for (int i = 0; i < a->dim; i++)
3466 { Statement *s = (Statement *)a->data[i];
3468 s = new VolatileStatement(loc, s);
3469 a->data[i] = s;
3473 return a;
3476 int VolatileStatement::fallOffEnd()
3478 return statement ? statement->fallOffEnd() : TRUE;
3481 void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3483 buf->writestring("volatile");
3484 if (statement)
3485 { if (statement->isScopeStatement())
3486 buf->writenl();
3487 else
3488 buf->writebyte(' ');
3489 statement->toCBuffer(buf, hgs);
3494 /******************************** GotoStatement ***************************/
3496 GotoStatement::GotoStatement(Loc loc, Identifier *ident)
3497 : Statement(loc)
3499 this->ident = ident;
3500 this->label = NULL;
3501 this->tf = NULL;
3504 Statement *GotoStatement::syntaxCopy()
3506 GotoStatement *s = new GotoStatement(loc, ident);
3507 return s;
3510 Statement *GotoStatement::semantic(Scope *sc)
3511 { FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3513 //printf("GotoStatement::semantic()\n");
3514 tf = sc->tf;
3515 label = fd->searchLabel(ident);
3516 if (!label->statement && sc->fes)
3518 /* Either the goto label is forward referenced or it
3519 * is in the function that the enclosing foreach is in.
3520 * Can't know yet, so wrap the goto in a compound statement
3521 * so we can patch it later, and add it to a 'look at this later'
3522 * list.
3524 Statements *a = new Statements();
3525 Statement *s;
3527 a->push(this);
3528 s = new CompoundStatement(loc, a);
3529 sc->fes->gotos.push(s); // 'look at this later' list
3530 return s;
3532 if (label->statement && label->statement->tf != sc->tf)
3533 error("cannot goto in or out of finally block");
3534 return this;
3537 int GotoStatement::fallOffEnd()
3539 return FALSE;
3542 void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3544 buf->writestring("goto ");
3545 buf->writestring(ident->toChars());
3546 buf->writebyte(';');
3547 buf->writenl();
3550 /******************************** LabelStatement ***************************/
3552 LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
3553 : Statement(loc)
3555 this->ident = ident;
3556 this->statement = statement;
3557 this->tf = NULL;
3558 this->lblock = NULL;
3559 this->isReturnLabel = 0;
3562 Statement *LabelStatement::syntaxCopy()
3564 LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy());
3565 return s;
3568 Statement *LabelStatement::semantic(Scope *sc)
3569 { LabelDsymbol *ls;
3570 FuncDeclaration *fd = sc->parent->isFuncDeclaration();
3572 //printf("LabelStatement::semantic()\n");
3573 ls = fd->searchLabel(ident);
3574 if (ls->statement)
3575 error("Label '%s' already defined", ls->toChars());
3576 else
3577 ls->statement = this;
3578 tf = sc->tf;
3579 sc = sc->push();
3580 sc->scopesym = sc->enclosing->scopesym;
3581 sc->callSuper |= CSXlabel;
3582 sc->slabel = this;
3583 if (statement)
3584 statement = statement->semantic(sc);
3585 sc->pop();
3586 return this;
3589 Statements *LabelStatement::flatten(Scope *sc)
3591 Statements *a = NULL;
3593 if (statement)
3595 a = statement->flatten(sc);
3596 if (a)
3598 if (!a->dim)
3600 a->push(new ExpStatement(loc, NULL));
3602 Statement *s = (Statement *)a->data[0];
3604 s = new LabelStatement(loc, ident, s);
3605 a->data[0] = s;
3609 return a;
3613 int LabelStatement::usesEH()
3615 return statement ? statement->usesEH() : FALSE;
3618 int LabelStatement::fallOffEnd()
3620 return statement ? statement->fallOffEnd() : TRUE;
3623 int LabelStatement::comeFrom()
3625 //printf("LabelStatement::comeFrom()\n");
3626 return TRUE;
3629 void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
3631 buf->writestring(ident->toChars());
3632 buf->writebyte(':');
3633 buf->writenl();
3634 if (statement)
3635 statement->toCBuffer(buf, hgs);
3639 /******************************** LabelDsymbol ***************************/
3641 LabelDsymbol::LabelDsymbol(Identifier *ident)
3642 : Dsymbol(ident)
3644 statement = NULL;
3645 #if IN_GCC
3646 asmLabelNum = 0;
3647 #endif
3650 LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
3652 return this;