Mercurial > projects > ldc
diff dmd2/statement.c @ 1452:638d16625da2
LDC 2 compiles again.
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Sat, 30 May 2009 17:23:32 +0100 |
parents | 5fa3e0ea06e9 |
children | 54b3c1394d62 |
line wrap: on
line diff
--- a/dmd2/statement.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/statement.c Sat May 30 17:23:32 2009 +0100 @@ -1,4426 +1,4336 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "mem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "hdrgen.h" -#include "parse.h" -#include "template.h" - -/******************************** Statement ***************************/ - -Statement::Statement(Loc loc) - : loc(loc) -{ -#ifdef _DH - // If this is an in{} contract scope statement (skip for determining - // inlineStatus of a function body for header content) - incontract = 0; -#endif -} - -Statement *Statement::syntaxCopy() -{ - assert(0); - return NULL; -} - -void Statement::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Statement::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("Statement::toCBuffer()"); - buf->writenl(); -} - -Statement *Statement::semantic(Scope *sc) -{ - return this; -} - -// Same as semantic(), but do create a new scope - -Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) -{ Scope *scd; - Statement *s; - - scd = sc->push(); - if (sbreak) - scd->sbreak = sbreak; - if (scontinue) - scd->scontinue = scontinue; - s = semantic(scd); - scd->pop(); - return s; -} - -void Statement::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -int Statement::hasBreak() -{ - //printf("Statement::hasBreak()\n"); - return FALSE; -} - -int Statement::hasContinue() -{ - return FALSE; -} - -// TRUE if statement uses exception handling - -int Statement::usesEH() -{ - return FALSE; -} - -/* Only valid after semantic analysis - */ -int Statement::blockExit() -{ - printf("Statement::blockExit(%p)\n", this); - printf("%s\n", toChars()); - assert(0); - return BEany; -} - -// TRUE if statement may fall off the end without a throw or return - -int Statement::fallOffEnd() -{ - return TRUE; -} - -// TRUE if statement 'comes from' somewhere else, like a goto - -int Statement::comeFrom() -{ - //printf("Statement::comeFrom()\n"); - return FALSE; -} - -/**************************************** - * If this statement has code that needs to run in a finally clause - * at the end of the current scope, return that code in the form of - * a Statement. - * Output: - * *sentry code executed upon entry to the scope - * *sexception code executed upon exit from the scope via exception - * *sfinally code executed in finally block - */ - -void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("Statement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; -} - -/********************************* - * Flatten out the scope by presenting the statement - * as an array of statements. - * Returns NULL if no flattening necessary. - */ - -Statements *Statement::flatten(Scope *sc) -{ - return NULL; -} - - -/******************************** ExpStatement ***************************/ - -ExpStatement::ExpStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ExpStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - ExpStatement *es = new ExpStatement(loc, e); - return es; -} - -void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statement *ExpStatement::semantic(Scope *sc) -{ - if (exp) - { - //printf("ExpStatement::semantic() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp->checkSideEffect(0); - exp = exp->optimize(0); - if (exp->op == TOKdeclaration && !isDeclarationStatement()) - { Statement *s = new DeclarationStatement(loc, exp); - return s; - } - //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); - } - return this; -} - -int ExpStatement::blockExit() -{ int result = BEfallthru; - - if (exp) - { - if (exp->op == TOKhalt) - return BEhalt; - if (exp->op == TOKassert) - { AssertExp *a = (AssertExp *)exp; - - if (a->e1->isBool(FALSE)) // if it's an assert(0) - return BEhalt; - } - if (exp->canThrow()) - result |= BEthrow; - } - return result; -} - -int ExpStatement::fallOffEnd() -{ - if (exp) - { - if (exp->op == TOKassert) - { AssertExp *a = (AssertExp *)exp; - - if (a->e1->isBool(FALSE)) // if it's an assert(0) - return FALSE; - } - else if (exp->op == TOKhalt) - return FALSE; - } - return TRUE; -} - -/******************************** CompileStatement ***************************/ - -CompileStatement::CompileStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *CompileStatement::syntaxCopy() -{ - Expression *e = exp->syntaxCopy(); - CompileStatement *es = new CompileStatement(loc, e); - return es; -} - -void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statements *CompileStatement::flatten(Scope *sc) -{ - //printf("CompileStatement::flatten() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return NULL; - } - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - - Statements *a = new Statements(); - while (p.token.value != TOKeof) - { - Statement *s = p.parseStatement(PSsemi | PScurlyscope); - a->push(s); - } - return a; -} - -Statement *CompileStatement::semantic(Scope *sc) -{ - //printf("CompileStatement::semantic() %s\n", exp->toChars()); - Statements *a = flatten(sc); - if (!a) - return NULL; - Statement *s = new CompoundStatement(loc, a); - return s->semantic(sc); -} - - -/******************************** DeclarationStatement ***************************/ - -DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) - : ExpStatement(loc, new DeclarationExp(loc, declaration)) -{ -} - -DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) - : ExpStatement(loc, exp) -{ -} - -Statement *DeclarationStatement::syntaxCopy() -{ - DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); - return ds; -} - -void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("DeclarationStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v) - { Expression *e; - - e = v->callAutoDtor(sc); - if (e) - { - //printf("dtor is: "); e->print(); - *sfinally = new ExpStatement(loc, e); - } - } - } - } -} - -void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - -/******************************** CompoundStatement ***************************/ - -CompoundStatement::CompoundStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) - : Statement(loc) -{ - statements = new Statements(); - statements->reserve(2); - statements->push(s1); - statements->push(s2); -} - -Statement *CompoundStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; -} - - -Statement *CompoundStatement::semantic(Scope *sc) -{ Statement *s; - - //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); - - for (size_t i = 0; i < statements->dim; ) - { - s = (Statement *) statements->data[i]; - if (s) - { Statements *a = s->flatten(sc); - - if (a) - { - statements->remove(i); - statements->insert(i, a); - continue; - } - s = s->semantic(sc); - statements->data[i] = s; - if (s) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - s->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sentry) - { - sentry = sentry->semantic(sc); - statements->data[i] = sentry; - } - if (sexception) - { - if (i + 1 == statements->dim && !sfinally) - { -#if 1 - sexception = sexception->semantic(sc); -#else - statements->push(sexception); - if (sfinally) - // Assume sexception does not throw - statements->push(sfinally); -#endif - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; - * try { s1; s2; } - * catch (Object __o) - * { sexception; throw __o; } - */ - Statement *body; - Statements *a = new Statements(); - - for (int j = i + 1; j < statements->dim; j++) - { - a->push(statements->data[j]); - } - body = new CompoundStatement(0, a); - body = new ScopeStatement(0, body); - - Identifier *id = Lexer::uniqueId("__o"); - - Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); - handler = new CompoundStatement(0, sexception, handler); - - Array *catches = new Array(); - Catch *ctch = new Catch(0, NULL, id, handler); - catches->push(ctch); - s = new TryCatchStatement(0, body, catches); - - if (sfinally) - s = new TryFinallyStatement(0, s, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - else if (sfinally) - { - if (0 && i + 1 == statements->dim) - { - statements->push(sfinally); - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; try { s1; s2; } finally { sfinally; } - */ - Statement *body; - Statements *a = new Statements(); - - for (int j = i + 1; j < statements->dim; j++) - { - a->push(statements->data[j]); - } - body = new CompoundStatement(0, a); - s = new TryFinallyStatement(0, body, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - } - } - i++; - } - if (statements->dim == 1 && !isAsmBlockStatement()) - { - return (Statement *)statements->data[0]; - } - return this; -} - -Statements *CompoundStatement::flatten(Scope *sc) -{ - return statements; -} - -ReturnStatement *CompoundStatement::isReturnStatement() -{ - ReturnStatement *rs = NULL; - - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - rs = s->isReturnStatement(); - if (rs) - break; - } - } - return rs; -} - -void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - s->toCBuffer(buf, hgs); - } -} - -int CompoundStatement::usesEH() -{ - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int CompoundStatement::blockExit() -{ - //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { -//printf("result = x%x\n", result); -//printf("%s\n", s->toChars()); - if (!(result & BEfallthru) && !s->comeFrom()) - { - if (global.params.warnings) - { fprintf(stdmsg, "warning - "); - s->error("statement is not reachable"); - } - } - - result &= ~BEfallthru; - result |= s->blockExit(); - } - } - return result; -} - -int CompoundStatement::fallOffEnd() -{ int falloff = TRUE; - - //printf("CompoundStatement::fallOffEnd() %s\n", toChars()); - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - -#if 0 - if (!falloff && global.params.warnings && !s->comeFrom()) - { - warning("%s: statement is not reachable", s->loc.toChars()); - } -#endif - falloff = s->fallOffEnd(); - } - return falloff; -} - -int CompoundStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("CompoundStatement::comeFrom()\n"); - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/**************************** UnrolledLoopStatement ***************************/ - -UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; - enclosinghandler = NULL; -} - -Statement *UnrolledLoopStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; -} - - -Statement *UnrolledLoopStatement::semantic(Scope *sc) -{ - //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - - enclosinghandler = sc->tfOfTry; - - sc->noctor++; - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - - for (size_t i = 0; i < statements->dim; i++) - { - Statement *s = (Statement *) statements->data[i]; - if (s) - { - s = s->semantic(scd); - statements->data[i] = s; - } - } - - scd->pop(); - sc->noctor--; - return this; -} - -void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("unrolled {"); - buf->writenl(); - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s) - s->toCBuffer(buf, hgs); - } - - buf->writeByte('}'); - buf->writenl(); -} - -int UnrolledLoopStatement::hasBreak() -{ - return TRUE; -} - -int UnrolledLoopStatement::hasContinue() -{ - return TRUE; -} - -int UnrolledLoopStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int UnrolledLoopStatement::blockExit() -{ - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - int r = s->blockExit(); - result |= r & ~(BEbreak | BEcontinue); - } - } - return result; -} - -int UnrolledLoopStatement::fallOffEnd() -{ - //printf("UnrolledLoopStatement::fallOffEnd()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (s) - s->fallOffEnd(); - } - return TRUE; -} - -int UnrolledLoopStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("UnrolledLoopStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/******************************** ScopeStatement ***************************/ - -ScopeStatement::ScopeStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -} - -Statement *ScopeStatement::syntaxCopy() -{ - Statement *s; - - s = statement ? statement->syntaxCopy() : NULL; - s = new ScopeStatement(loc, s); - return s; -} - - -Statement *ScopeStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("ScopeStatement::semantic(sc = %p)\n", sc); - if (statement) - { Statements *a; - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - a = statement->flatten(sc); - if (a) - { - statement = new CompoundStatement(loc, a); - } - - statement = statement->semantic(sc); - if (statement) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - statement->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sfinally) - { - //printf("adding sfinally\n"); - statement = new CompoundStatement(loc, statement, sfinally); - } - } - - sc->pop(); - } - return this; -} - -int ScopeStatement::hasBreak() -{ - //printf("ScopeStatement::hasBreak() %s\n", toChars()); - return statement ? statement->hasBreak() : FALSE; -} - -int ScopeStatement::hasContinue() -{ - return statement ? statement->hasContinue() : FALSE; -} - -int ScopeStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int ScopeStatement::blockExit() -{ - //printf("ScopeStatement::blockExit(%p)\n", statement); - return statement ? statement->blockExit() : BEfallthru; -} - -int ScopeStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - -int ScopeStatement::comeFrom() -{ - //printf("ScopeStatement::comeFrom()\n"); - return statement ? statement->comeFrom() : FALSE; -} - -void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('{'); - buf->writenl(); - - if (statement) - statement->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); -} - -/******************************** WhileStatement ***************************/ - -WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; - enclosinghandler = NULL; -} - -Statement *WhileStatement::syntaxCopy() -{ - WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - - -Statement *WhileStatement::semantic(Scope *sc) -{ -#if 0 - if (condition->op == TOKmatch) - { - /* Rewrite while (condition) body as: - * if (condition) - * do - * body - * while ((_match = _match.opNext), _match); - */ - - Expression *ew = new IdentifierExp(0, Id::_match); - ew = new DotIdExp(0, ew, Id::next); - ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew); - ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0)); - Expression *ev = new IdentifierExp(0, Id::_match); - //ev = new CastExp(0, ev, Type::tvoidptr); - ew = new CommaExp(0, ew, ev); - Statement *sw = new DoStatement(loc, body, ew); - Statement *si = new IfStatement(loc, condition, sw, NULL); - return si->semantic(sc); - } -#endif - - enclosinghandler = sc->tfOfTry; - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - - sc->noctor++; - - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - if (body) - body = body->semantic(scd); - scd->pop(); - - sc->noctor--; - - return this; -} - -int WhileStatement::hasBreak() -{ - return TRUE; -} - -int WhileStatement::hasContinue() -{ - return TRUE; -} - -int WhileStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WhileStatement::blockExit() -{ - //printf("WhileStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (body) - { result |= body->blockExit(); - if (result & BEbreak) - result |= BEfallthru; - } - } - else if (condition->isBool(FALSE)) - { - result |= BEfallthru; - } - else - { - if (body) - result |= body->blockExit(); - result |= BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - -int WhileStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int WhileStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); -} - -/******************************** DoStatement ***************************/ - -DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) - : Statement(loc) -{ - body = b; - condition = c; - enclosinghandler = NULL; -} - -Statement *DoStatement::syntaxCopy() -{ - DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); - return s; -} - - -Statement *DoStatement::semantic(Scope *sc) -{ - enclosinghandler = sc->tfOfTry; - - sc->noctor++; - if (body) - body = body->semanticScope(sc, this, this); - sc->noctor--; - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - - condition = condition->checkToBoolean(); - - return this; -} - -int DoStatement::hasBreak() -{ - return TRUE; -} - -int DoStatement::hasContinue() -{ - return TRUE; -} - -int DoStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int DoStatement::blockExit() -{ int result; - - if (body) - { result = body->blockExit(); - if (result == BEbreak) - return BEfallthru; - if (result & BEcontinue) - result |= BEfallthru; - } - else - result = BEfallthru; - if (result & BEfallthru) - { if (condition->canThrow()) - result |= BEthrow; - if (!(result & BEbreak) && condition->isBool(TRUE)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - -int DoStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int DoStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("do"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); -} - -/******************************** ForStatement ***************************/ - -ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) - : Statement(loc) -{ - this->init = init; - this->condition = condition; - this->increment = increment; - this->body = body; - this->enclosinghandler = NULL; -} - -Statement *ForStatement::syntaxCopy() -{ - Statement *i = NULL; - if (init) - i = init->syntaxCopy(); - Expression *c = NULL; - if (condition) - c = condition->syntaxCopy(); - Expression *inc = NULL; - if (increment) - inc = increment->syntaxCopy(); - ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); - return s; -} - -Statement *ForStatement::semantic(Scope *sc) -{ - enclosinghandler = sc->tfOfTry; - - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - if (init) - init = init->semantic(sc); - sc->noctor++; - if (condition) - { - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - } - if (increment) - { increment = increment->semantic(sc); - increment = resolveProperties(sc, increment); - } - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - sc->noctor--; - - sc->pop(); - return this; -} - -void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init->scopeCode(sc, sentry, sexception, sfinally); - else - Statement::scopeCode(sc, sentry, sexception, sfinally); -} - -int ForStatement::hasBreak() -{ - //printf("ForStatement::hasBreak()\n"); - return TRUE; -} - -int ForStatement::hasContinue() -{ - return TRUE; -} - -int ForStatement::usesEH() -{ - return (init && init->usesEH()) || body->usesEH(); -} - -int ForStatement::blockExit() -{ int result = BEfallthru; - - if (init) - { result = init->blockExit(); - if (!(result & BEfallthru)) - return result; - } - if (condition) - { if (condition->canThrow()) - result |= BEthrow; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (body) - { int r = body->blockExit(); - if (r & BEbreak) - result |= BEfallthru; - result |= r & ~(BEbreak | BEcontinue); - } - if (increment && increment->canThrow()) - result |= BEthrow; - return result; -} - -int ForStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int ForStatement::comeFrom() -{ - //printf("ForStatement::comeFrom()\n"); - if (body) - { int result = body->comeFrom(); - //printf("result = %d\n", result); - return result; - } - return FALSE; -} - -void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("for ("); - if (init) - { - hgs->FLinit.init++; - hgs->FLinit.decl = 0; - init->toCBuffer(buf, hgs); - if (hgs->FLinit.decl > 0) - buf->writebyte(';'); - hgs->FLinit.decl = 0; - hgs->FLinit.init--; - } - else - buf->writebyte(';'); - if (condition) - { buf->writebyte(' '); - condition->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - if (increment) - { buf->writebyte(' '); - increment->toCBuffer(buf, hgs); - } - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** ForeachStatement ***************************/ - -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, - Expression *aggr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arguments = arguments; - this->aggr = aggr; - this->body = body; - this->enclosinghandler = NULL; - - this->key = NULL; - this->value = NULL; - - this->func = NULL; -} - -Statement *ForeachStatement::syntaxCopy() -{ - Arguments *args = Argument::arraySyntaxCopy(arguments); - Expression *exp = aggr->syntaxCopy(); - ForeachStatement *s = new ForeachStatement(loc, op, args, exp, - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachStatement::semantic(Scope *sc) -{ - //printf("ForeachStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - size_t dim = arguments->dim; - TypeAArray *taa = NULL; - - Type *tn = NULL; - Type *tnv = NULL; - - enclosinghandler = sc->tfOfTry; - - func = sc->func; - if (func->fes) - func = func->fes->func; - - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - aggr = aggr->optimize(WANTvalue); - if (!aggr->type) - { - error("invalid foreach aggregate %s", aggr->toChars()); - return this; - } - - inferApplyArgTypes(op, arguments, aggr); - - /* Check for inference errors - */ - if (dim != arguments->dim) - { - //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); - error("cannot uniquely infer foreach argument types"); - return this; - } - - Type *tab = aggr->type->toBasetype(); - - if (tab->ty == Ttuple) // don't generate new scope for tuple loops - { - if (dim < 1 || dim > 2) - { - error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; - } - - TypeTuple *tuple = (TypeTuple *)tab; - Statements *statements = new Statements(); - //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); - size_t n; - TupleExp *te = NULL; - if (aggr->op == TOKtuple) // expression tuple - { te = (TupleExp *)aggr; - n = te->exps->dim; - } - else if (aggr->op == TOKtype) // type tuple - { - n = Argument::dim(tuple->arguments); - } - else - assert(0); - for (size_t j = 0; j < n; j++) - { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; - if (te) - e = (Expression *)te->exps->data[k]; - else - t = Argument::getNth(tuple->arguments, k)->type; - Argument *arg = (Argument *)arguments->data[0]; - Statements *st = new Statements(); - - if (dim == 2) - { // Declare key - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for key %s", arg->ident->toChars()); - TY keyty = arg->type->ty; - if (global.params.is64bit) - { - if (keyty != Tint32 && keyty != Tuns32 && keyty != Tint64 && keyty != Tuns64) - { - error("foreach: key type must be int, uint, long or ulong, not %s", key->type->toChars()); - } - } - else if (keyty != Tint32 && keyty != Tuns32) - { - error("foreach: key type must be int or uint, not %s", key->type->toChars()); - } - Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); - VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); - var->storage_class |= STCmanifest; - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - arg = (Argument *)arguments->data[1]; // value - } - // Declare value - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for value %s", arg->ident->toChars()); - Dsymbol *var; - if (te) - { Type *tb = e->type->toBasetype(); - if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - var = new AliasDeclaration(loc, arg->ident, ve->var); - } - else - { - arg->type = e->type; - Initializer *ie = new ExpInitializer(0, e); - VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (e->isConst()) - v->storage_class |= STCconst; - var = v; - } - } - else - { - var = new AliasDeclaration(loc, arg->ident, t); - } - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - - st->push(body->syntaxCopy()); - s = new CompoundStatement(loc, st); - s = new ScopeStatement(loc, s); - statements->push(s); - } - - s = new UnrolledLoopStatement(loc, statements); - s = s->semantic(sc); - return s; - } - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - switch (tab->ty) - { - case Tarray: - case Tsarray: - if (!checkForArgTypes()) - return this; - - if (dim < 1 || dim > 2) - { - error("only one or two arguments for array foreach"); - break; - } - - /* Look for special case of parsing char types out of char type - * array. - */ - tn = tab->nextOf()->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { Argument *arg; - - int i = (dim == 1) ? 0 : 1; // index of value - arg = (Argument *)arguments->data[i]; - arg->type = arg->type->semantic(loc, sc); - tnv = arg->type->toBasetype(); - if (tnv->ty != tn->ty && - (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) - { - if (arg->storageClass & STCref) - error("foreach: value of UTF conversion cannot be ref"); - if (dim == 2) - { arg = (Argument *)arguments->data[0]; - if (arg->storageClass & STCref) - error("foreach: key cannot be ref"); - } - goto Lapply; - } - } - - for (size_t i = 0; i < dim; i++) - { // Declare args - Argument *arg = (Argument *)arguments->data[i]; - VarDeclaration *var; - - var = new VarDeclaration(loc, arg->type, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant); - if (dim == 2 && i == 0) - { key = var; - //var->storage_class |= STCfinal; - } - else - { - value = var; - /* Reference to immutable data should be marked as const - */ - if (var->storage_class & STCref && !tn->isMutable()) - { - var->storage_class |= STCconst; - } - } -#if 1 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#else - var->semantic(sc); - if (!sc->insert(var)) - error("%s already defined", var->ident->toChars()); -#endif - } - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst) - { - if (aggr->op == TOKstring) - aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); - else - error("foreach: %s is not an array of %s", - tab->toChars(), value->type->toChars()); - } - - if (key) - { - if (global.params.is64bit) - { - if (key->type->ty != Tint32 && key->type->ty != Tuns32 && key->type->ty != Tint64 && key->type->ty != Tuns64) - { - error("foreach: key type must be int, uint, long or ulong, not %s", key->type->toChars()); - } - } - else if (key->type->ty != Tint32 && key->type->ty != Tuns32) - { - error("foreach: key type must be int or uint, not %s", key->type->toChars()); - } - } - - if (key && key->storage_class & (STCout | STCref)) - error("foreach: key cannot be out or ref"); - break; - - case Taarray: - if (!checkForArgTypes()) - return this; - - taa = (TypeAArray *)tab; - if (dim < 1 || dim > 2) - { - error("only one or two arguments for associative array foreach"); - break; - } - if (op == TOKforeach_reverse) - { - error("no reverse iteration on associative arrays"); - } - goto Lapply; - - case Tclass: - case Tstruct: -#if DMDV2 - { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear - * foreach (e; range) { ... } - * translates to: - * for (auto __r = range; !__r.empty; __r.next) - * { auto e = __r.head; - * ... - * } - */ - if (dim != 1) // only one argument allowed with ranges - goto Lapply; - AggregateDeclaration *ad = (tab->ty == Tclass) - ? (AggregateDeclaration *)((TypeClass *)tab)->sym - : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; - if (op == TOKforeach) - { idhead = Id::Fhead; - idnext = Id::Fnext; - } - else - { idhead = Id::Ftoe; - idnext = Id::Fretreat; - } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) - goto Lapply; - - /* Generate a temporary __r and initialize it with the aggregate. - */ - Identifier *id = Identifier::generateId("__r"); - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, aggr)); - r->semantic(sc); - Statement *init = new DeclarationStatement(loc, r); - - // !__r.empty - Expression *e = new VarExp(loc, r); - e = new DotIdExp(loc, e, Id::Fempty); - Expression *condition = new NotExp(loc, e); - - // __r.next - e = new VarExp(loc, r); - Expression *increment = new DotIdExp(loc, e, idnext); - - /* Declaration statement for e: - * auto e = __r.idhead; - */ - e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); - einit = einit->semantic(sc); - Argument *arg = (Argument *)arguments->data[0]; - VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); - ve->storage_class |= STCforeach; - ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant); - - DeclarationExp *de = new DeclarationExp(loc, ve); - - Statement *body = new CompoundStatement(loc, - new DeclarationStatement(loc, de), this->body); - - s = new ForStatement(loc, init, condition, increment, body); - s = s->semantic(sc); - break; - } -#endif - case Tdelegate: - Lapply: - { FuncDeclaration *fdapply; - Arguments *args; - Expression *ec; - Expression *e; - FuncLiteralDeclaration *fld; - Argument *a; - Type *t; - Expression *flde; - Identifier *id; - Type *tret; - TypeDelegate* dgty; - TypeDelegate* dgty2; - TypeDelegate* fldeTy; - - if (!checkForArgTypes()) - return this; - - tret = func->type->nextOf(); - - // Need a variable to hold value from any return statements in body. - if (!sc->func->vresult && tret && tret != Type::tvoid) - { VarDeclaration *v; - - v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - sc->func->vresult = v; - } - - /* Turn body into the function literal: - * int delegate(ref T arg) { body } - */ - args = new Arguments(); - for (size_t i = 0; i < dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - - arg->type = arg->type->semantic(loc, sc); - if (arg->storageClass & STCref) - id = arg->ident; - else - { // Make a copy of the ref argument so it isn't - // a reference. - VarDeclaration *v; - Initializer *ie; - - id = Lexer::uniqueId("__applyArg", i); - - ie = new ExpInitializer(0, new IdentifierExp(0, id)); - v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new DeclarationStatement(0, v); - body = new CompoundStatement(loc, s, body); - } - a = new Argument(STCref, arg->type, id, NULL); - args->push(a); - } - t = new TypeFunction(args, Type::tint32, 0, LINKd); - fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); - fld->fbody = body; - flde = new FuncExp(loc, fld); - flde = flde->semantic(sc); - fld->tookAddressOf = 0; - - // Resolve any forward referenced goto's - for (int i = 0; i < gotos.dim; i++) - { CompoundStatement *cs = (CompoundStatement *)gotos.data[i]; - GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; - - if (!gs->label->statement) - { // 'Promote' it to this scope, and replace with a return - cases.push(gs); - s = new ReturnStatement(0, new IntegerExp(cases.dim + 1)); - cs->statements->data[0] = (void *)s; - } - } - - if (tab->ty == Taarray) - { - // Check types - Argument *arg = (Argument *)arguments->data[0]; - if (dim == 2) - { - if (arg->storageClass & STCref) - error("foreach: index cannot be ref"); - if (!arg->type->equals(taa->index)) - error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); - arg = (Argument *)arguments->data[1]; - } - if (!arg->type->equals(taa->nextOf())) - error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); - - /* Call: - * _aaApply(aggr, keysize, flde) - */ - //LDC: Build arguments. - static FuncDeclaration *aaApply2_fd = NULL; - static TypeDelegate* aaApply2_dg; - if(!aaApply2_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, aaApply2_dg, NULL, NULL)); - aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2"); - } - static FuncDeclaration *aaApply_fd = NULL; - static TypeDelegate* aaApply_dg; - if(!aaApply_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, aaApply_dg, NULL, NULL)); - aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply"); - } - if (dim == 2) { - fdapply = aaApply2_fd; - fldeTy = aaApply2_dg; - } else { - fdapply = aaApply_fd; - fldeTy = aaApply_dg; - } - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - exps->push(aggr); - size_t keysize = taa->index->size(); - keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); - exps->push(new IntegerExp(0, keysize, Type::tsize_t)); - - // LDC paint delegate argument to the type runtime expects - if (!fldeTy->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = fldeTy; - } - exps->push(flde); - - e = new CallExp(loc, ec, exps); - e->type = Type::tindex; // don't run semantic() on e - } - else if (tab->ty == Tarray || tab->ty == Tsarray) - { - /* Call: - * _aApply(aggr, flde) - */ - static char fntab[9][3] = - { "cc","cw","cd", - "wc","cc","wd", - "dc","dw","dd" - }; - char fdname[7+1+2+ sizeof(dim)*3 + 1]; - int flag; - - switch (tn->ty) - { - case Tchar: flag = 0; break; - case Twchar: flag = 3; break; - case Tdchar: flag = 6; break; - default: assert(0); - } - switch (tnv->ty) - { - case Tchar: flag += 0; break; - case Twchar: flag += 1; break; - case Tdchar: flag += 2; break; - default: assert(0); - } - const char *r = (op == TOKforeach_reverse) ? "R" : ""; - int j = sprintf(fdname, "_aApply%s%.*s%d", r, 2, fntab[flag], dim); - assert(j < sizeof(fdname)); - //LDC: Build arguments. - Arguments* args = new Arguments; - args->push(new Argument(STCin, tn->arrayOf(), NULL, NULL)); - if (dim == 2) { - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); - } else { - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); - } - - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - if (tab->ty == Tsarray) - aggr = aggr->castTo(sc, tn->arrayOf()); - exps->push(aggr); - - // LDC paint delegate argument to the type runtime expects - if (!dgty->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = dgty; - } - exps->push(flde); - - e = new CallExp(loc, ec, exps); - e->type = Type::tindex; // don't run semantic() on e - } - else if (tab->ty == Tdelegate) - { - /* Call: - * aggr(flde) - */ - Expressions *exps = new Expressions(); - exps->push(flde); - e = new CallExp(loc, aggr, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - else - { - assert(tab->ty == Tstruct || tab->ty == Tclass); - Identifier *idapply = (op == TOKforeach_reverse) - ? Id::applyReverse : Id::apply; - Dsymbol *sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); - Expressions *exps = new Expressions(); -#if 0 - TemplateDeclaration *td; - if (sapply && - (td = sapply->isTemplateDeclaration()) != NULL) - { /* Call: - * aggr.apply!(fld)() - */ - TemplateInstance *ti = new TemplateInstance(loc, idapply); - Objects *tiargs = new Objects(); - tiargs->push(fld); - ti->tiargs = tiargs; - ec = new DotTemplateInstanceExp(loc, aggr, ti); - } - else -#endif - { - /* Call: - * aggr.apply(flde) - */ - ec = new DotIdExp(loc, aggr, idapply); - exps->push(flde); - } - e = new CallExp(loc, ec, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - - if (!cases.dim) - // Easy case, a clean exit from the loop - s = new ExpStatement(loc, e); - else - { // Construct a switch statement around the return value - // of the apply function. - Statements *a = new Statements(); - - // default: break; takes care of cases 0 and 1 - s = new BreakStatement(0, NULL); - s = new DefaultStatement(0, s); - a->push(s); - - // cases 2... - for (int i = 0; i < cases.dim; i++) - { - s = (Statement *)cases.data[i]; - s = new CaseStatement(0, new IntegerExp(i + 2), s); - a->push(s); - } - - s = new CompoundStatement(loc, a); - s = new SwitchStatement(loc, e, s); - s = s->semantic(sc); - } - break; - } - - default: - error("foreach: %s is not an aggregate type", aggr->type->toChars()); - break; - } - sc->noctor--; - sc->pop(); - return s; -} - -bool ForeachStatement::checkForArgTypes() -{ - for (size_t i = 0; i < arguments->dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - if (!arg->type) - { - error("cannot infer type for %s", arg->ident->toChars()); - return FALSE; - } - } - return TRUE; -} - -int ForeachStatement::hasBreak() -{ - return TRUE; -} - -int ForeachStatement::hasContinue() -{ - return TRUE; -} - -int ForeachStatement::usesEH() -{ - return body->usesEH(); -} - -int ForeachStatement::blockExit() -{ int result = BEfallthru; - - if (aggr->canThrow()) - result |= BEthrow; - - if (body) - { - result |= body->blockExit() & ~(BEbreak | BEcontinue); - } - return result; -} - -int ForeachStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int ForeachStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - for (int i = 0; i < arguments->dim; i++) - { - Argument *a = (Argument *)arguments->data[i]; - if (i) - buf->writestring(", "); - if (a->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char*)"inout " : (char*)"ref "); - if (a->type) - a->type->toCBuffer(buf, a->ident, hgs); - else - buf->writestring(a->ident->toChars()); - } - buf->writestring("; "); - aggr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/**************************** ForeachRangeStatement ***************************/ - -#if DMDV2 - -ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, - Expression *lwr, Expression *upr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arg = arg; - this->lwr = lwr; - this->upr = upr; - this->body = body; - - this->enclosinghandler = NULL; - - this->key = NULL; -} - -Statement *ForeachRangeStatement::syntaxCopy() -{ - ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, - arg->syntaxCopy(), - lwr->syntaxCopy(), - upr->syntaxCopy(), - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachRangeStatement::semantic(Scope *sc) -{ - //printf("ForeachRangeStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - - enclosinghandler = sc->tfOfTry; - - lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->optimize(WANTvalue); - if (!lwr->type) - { - error("invalid range lower bound %s", lwr->toChars()); - return this; - } - - upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->optimize(WANTvalue); - if (!upr->type) - { - error("invalid range upper bound %s", upr->toChars()); - return this; - } - - if (arg->type) - { - lwr = lwr->implicitCastTo(sc, arg->type); - upr = upr->implicitCastTo(sc, arg->type); - } - else - { - /* Must infer types from lwr and upr - */ - AddExp ea(loc, lwr, upr); - ea.typeCombine(sc); - arg->type = ea.type->mutableOf(); - lwr = ea.e1; - upr = ea.e2; - } - if (!arg->type->isscalar()) - error("%s is not a scalar type", arg->type->toChars()); - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - key = new VarDeclaration(loc, arg->type, arg->ident, NULL); - DeclarationExp *de = new DeclarationExp(loc, key); - de->semantic(sc); - - if (key->storage_class) - error("foreach range: key cannot have storage class"); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - sc->noctor--; - sc->pop(); - return s; -} - -int ForeachRangeStatement::hasBreak() -{ - return TRUE; -} - -int ForeachRangeStatement::hasContinue() -{ - return TRUE; -} - -int ForeachRangeStatement::usesEH() -{ - return body->usesEH(); -} - -int ForeachRangeStatement::blockExit() -{ int result = BEfallthru; - - if (lwr && lwr->canThrow()) - result |= BEthrow; - else if (upr && upr->canThrow()) - result |= BEthrow; - - if (body) - { - result |= body->blockExit() & ~(BEbreak | BEcontinue); - } - return result; -} - -int ForeachRangeStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - -int ForeachRangeStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - buf->writestring(arg->ident->toChars()); - - buf->writestring("; "); - lwr->toCBuffer(buf, hgs); - buf->writestring(" .. "); - upr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -#endif - -/******************************** IfStatement ***************************/ - -IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->arg = arg; - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; - this->match = NULL; -} - -Statement *IfStatement::syntaxCopy() -{ - Statement *i = NULL; - if (ifbody) - i = ifbody->syntaxCopy(); - - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - - Argument *a = arg ? arg->syntaxCopy() : NULL; - IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); - return s; -} - -Statement *IfStatement::semantic(Scope *sc) -{ - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->checkToBoolean(); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - condition = condition->optimize(WANTflags); - - // Evaluate at runtime - unsigned cs0 = sc->callSuper; - unsigned cs1; - - Scope *scd; - if (arg) - { /* Declare arg, which we will set to be the - * result of condition. - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); - - Type *t = arg->type ? arg->type : condition->type; - match = new VarDeclaration(loc, t, arg->ident, NULL); - match->noauto = 1; - match->semantic(scd); - if (!scd->insert(match)) - assert(0); - match->parent = sc->func; - - /* Generate: - * (arg = condition) - */ - VarExp *v = new VarExp(0, match); - condition = new AssignExp(loc, v, condition); - condition = condition->semantic(scd); - } - - else - scd = sc->push(); - ifbody = ifbody->semantic(scd); - scd->pop(); - - cs1 = sc->callSuper; - sc->callSuper = cs0; - if (elsebody) - elsebody = elsebody->semanticScope(sc, NULL, NULL); - sc->mergeCallSuper(loc, cs1); - - return this; -} - -int IfStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int IfStatement::blockExit() -{ - //printf("IfStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (ifbody) - result |= ifbody->blockExit(); - else - result |= BEfallthru; - } - else if (condition->isBool(FALSE)) - { - if (elsebody) - result |= elsebody->blockExit(); - else - result |= BEfallthru; - } - else - { - if (ifbody) - result |= ifbody->blockExit(); - else - result |= BEfallthru; - if (elsebody) - result |= elsebody->blockExit(); - else - result |= BEfallthru; - } - //printf("IfStatement::blockExit(%p) = x%x\n", this, result); - return result; -} - -int IfStatement::fallOffEnd() -{ - if (!ifbody || ifbody->fallOffEnd() || - !elsebody || elsebody->fallOffEnd()) - return TRUE; - return FALSE; -} - - -void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("if ("); - if (arg) - { - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - { buf->writestring("auto "); - buf->writestring(arg->ident->toChars()); - } - buf->writestring(" = "); - } - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - ifbody->toCBuffer(buf, hgs); - if (elsebody) - { buf->writestring("else"); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - } -} - -/******************************** ConditionalStatement ***************************/ - -ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; -} - -Statement *ConditionalStatement::syntaxCopy() -{ - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - ConditionalStatement *s = new ConditionalStatement(loc, - condition->syntaxCopy(), ifbody->syntaxCopy(), e); - return s; -} - -Statement *ConditionalStatement::semantic(Scope *sc) -{ - //printf("ConditionalStatement::semantic()\n"); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - if (condition->include(sc, NULL)) - { - ifbody = ifbody->semantic(sc); - return ifbody; - } - else - { - if (elsebody) - elsebody = elsebody->semantic(sc); - return elsebody; - } -} - -Statements *ConditionalStatement::flatten(Scope *sc) -{ - Statement *s; - - if (condition->include(sc, NULL)) - s = ifbody; - else - s = elsebody; - - Statements *a = new Statements(); - a->push(s); - return a; -} - -int ConditionalStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int ConditionalStatement::blockExit() -{ - int result = ifbody->blockExit(); - if (elsebody) - result |= elsebody->blockExit(); - return result; -} - -void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (ifbody) - ifbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - if (elsebody) - { - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - } - buf->writenl(); -} - - -/******************************** PragmaStatement ***************************/ - -PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) - : Statement(loc) -{ - this->ident = ident; - this->args = args; - this->body = body; -} - -Statement *PragmaStatement::syntaxCopy() -{ - Statement *b = NULL; - if (body) - b = body->syntaxCopy(); - PragmaStatement *s = new PragmaStatement(loc, - ident, Expression::arraySyntaxCopy(args), b); - return s; -} - -Statement *PragmaStatement::semantic(Scope *sc) -{ // Should be merged with PragmaDeclaration - //printf("PragmaStatement::semantic() %s\n", toChars()); - //printf("body = %p\n", body); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - } - else if (ident == Id::lib) - { -#if 1 - /* Should this be allowed? - */ - error("pragma(lib) not allowed as statement"); -#else - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } -#endif - } - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - if (body) - { - body = body->semantic(sc); - } - return this; - } - } - - // LDC - else if (ident == Id::allow_inline) - { - sc->func->allowInlining = true; - } - - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (body) - { - body = body->semantic(sc); - } - return body; -} - -int PragmaStatement::usesEH() -{ - return body && body->usesEH(); -} - -int PragmaStatement::blockExit() -{ - int result = BEfallthru; -#if 0 // currently, no code is generated for Pragma's, so it's just fallthru - if (arrayExpressionCanThrow(args)) - result |= BEthrow; - if (body) - result |= body->blockExit(); -#endif - return result; -} - -int PragmaStatement::fallOffEnd() -{ - if (body) - return body->fallOffEnd(); - return TRUE; -} - -void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("pragma ("); - buf->writestring(ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - if (body) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - - body->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); - } - else - { - buf->writeByte(';'); - buf->writenl(); - } -} - - -/******************************** StaticAssertStatement ***************************/ - -StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) - : Statement(sa->loc) -{ - this->sa = sa; -} - -Statement *StaticAssertStatement::syntaxCopy() -{ - StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); - return s; -} - -Statement *StaticAssertStatement::semantic(Scope *sc) -{ - sa->semantic2(sc); - return NULL; -} - -void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - sa->toCBuffer(buf, hgs); -} - - -/******************************** SwitchStatement ***************************/ - -SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; - sdefault = NULL; - tf = NULL; - cases = NULL; - hasNoDefault = 0; - hasVars = 0; - // LDC - enclosinghandler = NULL; -} - -Statement *SwitchStatement::syntaxCopy() -{ - SwitchStatement *s = new SwitchStatement(loc, - condition->syntaxCopy(), body->syntaxCopy()); - return s; -} - -Statement *SwitchStatement::semantic(Scope *sc) -{ - //printf("SwitchStatement::semantic(%p)\n", this); - tf = sc->tf; - assert(!cases); // ensure semantic() is only run once - - enclosinghandler = sc->tfOfTry; - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - if (condition->type->isString()) - { - // If it's not an array, cast it to one - if (condition->type->ty != Tarray) - { - condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); - } - condition->type = condition->type->constOf(); - } - else - { condition = condition->integralPromotions(sc); - condition->checkIntegral(); - } - condition = condition->optimize(WANTvalue); - - sc = sc->push(); - sc->sbreak = this; - sc->sw = this; - - cases = new Array(); - sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead - body = body->semantic(sc); - sc->noctor--; - - // Resolve any goto case's with exp - for (int i = 0; i < gotoCases.dim; i++) - { - GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; - - if (!gcs->exp) - { - gcs->error("no case statement following goto case;"); - break; - } - - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (!scx->sw) - continue; - for (int j = 0; j < scx->sw->cases->dim; j++) - { - CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; - - if (cs->exp->equals(gcs->exp)) - { - gcs->cs = cs; - goto Lfoundcase; - } - } - } - gcs->error("case %s not found", gcs->exp->toChars()); - - Lfoundcase: - ; - } - - if (!sc->sw->sdefault) - { hasNoDefault = 1; - - if (global.params.warnings) - { warning("%s: switch statement has no default", loc.toChars()); - } - - // Generate runtime error if the default is hit - Statements *a = new Statements(); - CompoundStatement *cs; - Statement *s; - - if (global.params.useSwitchError) - s = new SwitchErrorStatement(loc); - else - { Expression *e = new HaltExp(loc); - s = new ExpStatement(loc, e); - } - - a->reserve(4); - a->push(body); - a->push(new BreakStatement(loc, NULL)); - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; - } - - sc->pop(); - return this; -} - -int SwitchStatement::hasBreak() -{ - return TRUE; -} - -int SwitchStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int SwitchStatement::blockExit() -{ int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - - if (body) - { result |= body->blockExit(); - if (result & BEbreak) - { result |= BEfallthru; - result &= ~BEbreak; - } - } - else - result |= BEfallthru; - - return result; -} - -int SwitchStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; // need to do this better -} - -void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("switch ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - { - if (!body->isScopeStatement()) - { buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { - body->toCBuffer(buf, hgs); - } - } -} - -/******************************** CaseStatement ***************************/ - -CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) - : Statement(loc) -{ - this->exp = exp; - this->statement = s; - index = 0; - cblock = NULL; - bodyBB = NULL; - llvmIdx = NULL; -} - -Statement *CaseStatement::syntaxCopy() -{ - CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseStatement::semantic() %s\n", toChars()); - exp = exp->semantic(sc); - if (sw) - { - exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->optimize(WANTvalue | WANTinterpret); - - /* This is where variables are allowed as case expressions. - */ - if (exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - Type *t = exp->type->toBasetype(); - if (v && (t->isintegral() || t->ty == Tclass)) - { /* Flag that we need to do special code generation - * for this, i.e. generate a sequence of if-then-else - */ - sw->hasVars = 1; - goto L1; - } - } - - if (exp->op != TOKstring && exp->op != TOKint64) - { - error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new IntegerExp(0); - } - - L1: - for (int i = 0; i < sw->cases->dim; i++) - { - CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; - - //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); - if (cs->exp->equals(exp)) - { error("duplicate case %s in switch statement", exp->toChars()); - break; - } - } - - sw->cases->push(this); - - // Resolve any goto case's with no exp to this case statement - for (int i = 0; i < sw->gotoCases.dim; i++) - { - GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; - - if (!gcs->exp) - { - gcs->cs = this; - sw->gotoCases.remove(i); // remove from array - } - } - - if (sc->sw->tf != sc->tf) - error("switch and case are in different finally blocks"); - } - else - error("case not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int CaseStatement::compare(Object *obj) -{ - // Sort cases so we can do an efficient lookup - CaseStatement *cs2 = (CaseStatement *)(obj); - - return exp->compare(cs2->exp); -} - -int CaseStatement::usesEH() -{ - return statement->usesEH(); -} - -int CaseStatement::blockExit() -{ - return statement->blockExit(); -} - -int CaseStatement::fallOffEnd() -{ - return statement->fallOffEnd(); -} - -int CaseStatement::comeFrom() -{ - return TRUE; -} - -void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - exp->toCBuffer(buf, hgs); - buf->writebyte(':'); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -/******************************** DefaultStatement ***************************/ - -DefaultStatement::DefaultStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -#if IN_GCC -+ cblock = NULL; -#endif - bodyBB = NULL; -} - -Statement *DefaultStatement::syntaxCopy() -{ - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; -} - -Statement *DefaultStatement::semantic(Scope *sc) -{ - //printf("DefaultStatement::semantic()\n"); - if (sc->sw) - { - if (sc->sw->sdefault) - { - error("switch statement already has a default"); - } - sc->sw->sdefault = this; - - if (sc->sw->tf != sc->tf) - error("switch and default are in different finally blocks"); - } - else - error("default not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int DefaultStatement::usesEH() -{ - return statement->usesEH(); -} - -int DefaultStatement::blockExit() -{ - return statement->blockExit(); -} - -int DefaultStatement::fallOffEnd() -{ - return statement->fallOffEnd(); -} - -int DefaultStatement::comeFrom() -{ - return TRUE; -} - -void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("default:\n"); - statement->toCBuffer(buf, hgs); -} - -/******************************** GotoDefaultStatement ***************************/ - -GotoDefaultStatement::GotoDefaultStatement(Loc loc) - : Statement(loc) -{ - sw = NULL; - enclosinghandler = NULL; -} - -Statement *GotoDefaultStatement::syntaxCopy() -{ - GotoDefaultStatement *s = new GotoDefaultStatement(loc); - return s; -} - -Statement *GotoDefaultStatement::semantic(Scope *sc) -{ - enclosinghandler = sc->tfOfTry; - sw = sc->sw; - if (!sw) - error("goto default not in switch statement"); - return this; -} - -int GotoDefaultStatement::blockExit() -{ - return BEgoto; -} - -int GotoDefaultStatement::fallOffEnd() -{ - return FALSE; -} - -void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto default;\n"); -} - -/******************************** GotoCaseStatement ***************************/ - -GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - cs = NULL; - this->exp = exp; - enclosinghandler = NULL; - sw = NULL; -} - -Statement *GotoCaseStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - GotoCaseStatement *s = new GotoCaseStatement(loc, e); - return s; -} - -Statement *GotoCaseStatement::semantic(Scope *sc) -{ - enclosinghandler = sc->tfOfTry; - if (exp) - exp = exp->semantic(sc); - - if (!sc->sw) - error("goto case not in switch statement"); - else - { - sw = sc->sw; - sc->sw->gotoCases.push(this); - if (exp) - { - exp = exp->implicitCastTo(sc, sc->sw->condition->type); - exp = exp->optimize(WANTvalue); - } - } - return this; -} - -int GotoCaseStatement::blockExit() -{ - return BEgoto; -} - -int GotoCaseStatement::fallOffEnd() -{ - return FALSE; -} - -void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto case"); - if (exp) - { buf->writebyte(' '); - exp->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SwitchErrorStatement ***************************/ - -SwitchErrorStatement::SwitchErrorStatement(Loc loc) - : Statement(loc) -{ -} - -int SwitchErrorStatement::blockExit() -{ - return BEthrow; -} - -int SwitchErrorStatement::fallOffEnd() -{ - return FALSE; -} - -void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("SwitchErrorStatement::toCBuffer()"); - buf->writenl(); -} - -/******************************** ReturnStatement ***************************/ - -ReturnStatement::ReturnStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; - this->enclosinghandler = NULL; -} - -Statement *ReturnStatement::syntaxCopy() -{ - Expression *e = NULL; - if (exp) - e = exp->syntaxCopy(); - ReturnStatement *s = new ReturnStatement(loc, e); - return s; -} - -Statement *ReturnStatement::semantic(Scope *sc) -{ - //printf("ReturnStatement::semantic() %s\n", toChars()); - this->enclosinghandler = sc->tfOfTry; - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - Scope *scx = sc; - int implicit0 = 0; - - if (sc->fes) - { - // Find scope of function foreach is in - for (; 1; scx = scx->enclosing) - { - assert(scx); - if (scx->func != fd) - { fd = scx->func; // fd is now function enclosing foreach - break; - } - } - } - - Type *tret = fd->type->nextOf(); - if (fd->tintro) - /* We'll be implicitly casting the return expression to tintro - */ - tret = fd->tintro->nextOf(); - Type *tbret = NULL; - - if (tret) - tbret = tret->toBasetype(); - - // main() returns 0, even if it returns void - if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) - { implicit0 = 1; - exp = new IntegerExp(0); - } - - if (sc->incontract || scx->incontract) - error("return statements cannot be in contracts"); - if (sc->tf || scx->tf) - error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); - - if (fd->isCtorDeclaration()) - { - // Constructors implicitly do: - // return this; - if (exp && exp->op != TOKthis) - error("cannot return expression from constructor"); - exp = new ThisExp(0); - } - - if (!exp) - fd->nrvo_can = 0; - - if (exp) - { - fd->hasReturnExp |= 1; - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue); - - if (fd->nrvo_can && exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (((TypeFunction *)fd->type)->isref) - // Function returns a reference - fd->nrvo_can = 0; - else if (!v || v->isOut() || v->isRef()) - fd->nrvo_can = 0; - else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor) - // Struct being returned has destructors - fd->nrvo_can = 0; - else if (fd->nrvo_var == NULL) - { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) - { //printf("Setting nrvo to %s\n", v->toChars()); - fd->nrvo_var = v; - } - else - fd->nrvo_can = 0; - } - else if (fd->nrvo_var != v) - fd->nrvo_can = 0; - } - else - fd->nrvo_can = 0; - - if (fd->returnLabel && tbret->ty != Tvoid) - { - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (!exp->type->equals(fd->type->nextOf())) - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), fd->type->nextOf()->toChars()); - } - else - { - ((TypeFunction *)fd->type)->next = exp->type; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = fd->type->nextOf(); - tbret = tret->toBasetype(); - } - } - } - else if (tbret->ty != Tvoid) - { - exp = exp->implicitCastTo(sc, tret); - } - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (fd->type->nextOf()->ty != Tvoid) - error("mismatched function return type inference of void and %s", - fd->type->nextOf()->toChars()); - } - else - { - ((TypeFunction *)fd->type)->next = Type::tvoid; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = Type::tvoid; - tbret = tret; - } - } - } - else if (tbret->ty != Tvoid) // if non-void return - error("return expression expected"); - - if (sc->fes) - { - Statement *s; - - if (exp && !implicit0) - { - exp = exp->implicitCastTo(sc, tret); - } - if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || - exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || - exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || - exp->op == TOKstring) - { - sc->fes->cases.push(this); - // Construct: return cases.dim+1; - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - } - else if (fd->type->nextOf()->toBasetype() == Type::tvoid) - { - s = new ReturnStatement(0, NULL); - sc->fes->cases.push(s); - - // Construct: { exp; return cases.dim + 1; } - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - // Construct: return vresult; - if (!fd->vresult) - { // Declare vresult - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; - v->semantic(scx); - if (!scx->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; - } - - s = new ReturnStatement(0, new VarExp(0, fd->vresult)); - sc->fes->cases.push(s); - - // Construct: { vresult = exp; return cases.dim + 1; } - exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp); - exp = exp->semantic(sc); - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - if (fd->returnLabel && tbret->ty != Tvoid) - { - assert(fd->vresult); - VarExp *v = new VarExp(0, fd->vresult); - - exp = new AssignExp(loc, v, exp); - exp = exp->semantic(sc); - } - - if (((TypeFunction *)fd->type)->isref) - { // Function returns a reference - if (tbret->isMutable()) - exp = exp->modifiableLvalue(sc, exp); - else - exp = exp->toLvalue(sc, exp); - - if (exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->isDataseg() && !(v->storage_class & (STCref | STCout))) - error("escaping reference to local variable %s", v->toChars()); - } - } - - //exp->dump(0); - //exp->print(); - exp->checkEscape(); - } - - /* BUG: need to issue an error on: - * this - * { if (x) return; - * super(); - * } - */ - - if (sc->callSuper & CSXany_ctor && - !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) - error("return without calling constructor"); - - sc->callSuper |= CSXreturn; - - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd->returnLabel) - { - GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); - - gs->label = fd->returnLabel; - if (exp) - { /* Replace: return exp; - * with: exp; goto returnLabel; - */ - Statement *s = new ExpStatement(0, exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } - - if (exp && tbret->ty == Tvoid && !fd->isMain()) - { - /* Replace: - * return exp; - * with: - * exp; return; - */ - Statement *s = new ExpStatement(loc, exp); - loc = 0; - exp = NULL; - return new CompoundStatement(loc, s, this); - } - - return this; -} - -int ReturnStatement::blockExit() -{ int result = BEreturn; - - if (exp && exp->canThrow()) - result |= BEthrow; - return result; -} - -int ReturnStatement::fallOffEnd() -{ - return FALSE; -} - -void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("return "); - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** BreakStatement ***************************/ - -BreakStatement::BreakStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; - this->enclosinghandler = NULL; -} - -Statement *BreakStatement::syntaxCopy() -{ - BreakStatement *s = new BreakStatement(loc, ident); - return s; -} - -Statement *BreakStatement::semantic(Scope *sc) -{ - //printf("BreakStatement::semantic()\n"); - enclosinghandler = sc->tfOfTry; - // If: - // break Identifier; - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases.push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - return s; - } - break; // can't break to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasBreak()) - error("label '%s' has no break", ident->toChars()); - if (ls->tf != sc->tf) - error("cannot break out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for break not found", ident->toChars()); - } - else if (!sc->sbreak) - { - if (sc->fes) - { Statement *s; - - // Replace break; with return 1; - s = new ReturnStatement(0, new IntegerExp(1)); - return s; - } - error("break is not inside a loop or switch"); - } - return this; -} - -int BreakStatement::blockExit() -{ - //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); - return ident ? BEgoto : BEbreak; -} - -int BreakStatement::fallOffEnd() -{ - return FALSE; -} - -void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("break"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** ContinueStatement ***************************/ - -ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; - this->enclosinghandler = NULL; -} - -Statement *ContinueStatement::syntaxCopy() -{ - ContinueStatement *s = new ContinueStatement(loc, ident); - return s; -} - -Statement *ContinueStatement::semantic(Scope *sc) -{ - enclosinghandler = sc->tfOfTry; - //printf("ContinueStatement::semantic() %p\n", this); - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - for (; scx; scx = scx->enclosing) - { - ls = scx->slabel; - if (ls && ls->ident == ident && ls->statement == sc->fes) - { - // Replace continue ident; with return 0; - return new ReturnStatement(0, new IntegerExp(0)); - } - } - - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases.push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - return s; - } - break; // can't continue to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasContinue()) - error("label '%s' has no continue", ident->toChars()); - if (ls->tf != sc->tf) - error("cannot continue out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for continue not found", ident->toChars()); - } - else if (!sc->scontinue) - { - if (sc->fes) - { Statement *s; - - // Replace continue; with return 0; - s = new ReturnStatement(0, new IntegerExp(0)); - return s; - } - error("continue is not inside a loop"); - } - return this; -} - -int ContinueStatement::blockExit() -{ - return ident ? BEgoto : BEcontinue; -} - -int ContinueStatement::fallOffEnd() -{ - return FALSE; -} - -void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("continue"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SynchronizedStatement ***************************/ - -SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - this->esync = NULL; - this->enclosinghandler = NULL; - // LDC - this->llsync = NULL; -} - -SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) - : Statement(loc) -{ - this->exp = NULL; - this->body = body; - this->esync = esync; - this->enclosinghandler = NULL; - // LDC - this->llsync = NULL; -} - -Statement *SynchronizedStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *SynchronizedStatement::semantic(Scope *sc) -{ - if (exp) - { ClassDeclaration *cd; - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - cd = exp->type->isClassHandle(); - if (!cd) - error("can only synchronize on class objects, not '%s'", exp->type->toChars()); - else if (cd->isInterfaceDeclaration()) - { Type *t = new TypeIdentifier(0, Id::Object); - - t = t->semantic(0, sc); - exp = new CastExp(loc, exp, t); - exp = exp->semantic(sc); - } - } - if (body) - { - enclosinghandler = sc->tfOfTry; - sc->tfOfTry = new EnclosingSynchro(this); - body = body->semantic(sc); - sc->tfOfTry = enclosinghandler; - } - return this; -} - -int SynchronizedStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::usesEH() -{ - return TRUE; -} - -int SynchronizedStatement::blockExit() -{ - return body ? body->blockExit() : BEfallthru; -} - -int SynchronizedStatement::fallOffEnd() -{ - return body ? body->fallOffEnd() : TRUE; -} - -void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("synchronized"); - if (exp) - { buf->writebyte('('); - exp->toCBuffer(buf, hgs); - buf->writebyte(')'); - } - if (body) - { - buf->writebyte(' '); - body->toCBuffer(buf, hgs); - } -} - -/******************************** WithStatement ***************************/ - -WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - wthis = NULL; -} - -Statement *WithStatement::syntaxCopy() -{ - WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *WithStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - Initializer *init; - - //printf("WithStatement::semantic()\n"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKimport) - { ScopeExp *es = (ScopeExp *)exp; - - sym = es->sds; - } - else if (exp->op == TOKtype) - { TypeExp *es = (TypeExp *)exp; - - sym = es->type->toDsymbol(sc)->isScopeDsymbol(); - if (!sym) - { error("%s has no members", es->toChars()); - body = body->semantic(sc); - return this; - } - } - else - { Type *t = exp->type; - - assert(t); - t = t->toBasetype(); - if (t->isClassHandle()) - { - init = new ExpInitializer(loc, exp); - wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); - wthis->semantic(sc); - - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else if (t->ty == Tstruct) - { - Expression *e = exp->addressOf(sc); - init = new ExpInitializer(loc, e); - wthis = new VarDeclaration(loc, e->type, Id::withSym, init); - wthis->semantic(sc); - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else - { error("with expressions must be class objects, not '%s'", exp->type->toChars()); - return NULL; - } - } - sc = sc->push(sym); - - if (body) - body = body->semantic(sc); - - sc->pop(); - - return this; -} - -void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("with ("); - exp->toCBuffer(buf, hgs); - buf->writestring(")\n"); - if (body) - body->toCBuffer(buf, hgs); -} - -int WithStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WithStatement::blockExit() -{ - int result = BEnone; - if (exp->canThrow()) - result = BEthrow; - if (body) - result |= body->blockExit(); - else - result |= BEfallthru; - return result; -} - -int WithStatement::fallOffEnd() -{ - return body ? body->fallOffEnd() : TRUE; -} - -/******************************** TryCatchStatement ***************************/ - -TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) - : Statement(loc) -{ - this->body = body; - this->catches = catches; -} - -Statement *TryCatchStatement::syntaxCopy() -{ - Array *a = new Array(); - a->setDim(catches->dim); - for (int i = 0; i < a->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - c = c->syntaxCopy(); - a->data[i] = c; - } - TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); - return s; -} - -Statement *TryCatchStatement::semantic(Scope *sc) -{ - body = body->semanticScope(sc, NULL /*this*/, NULL); - - /* Even if body is NULL, still do semantic analysis on catches - */ - for (size_t i = 0; i < catches->dim; i++) - { Catch *c = (Catch *)catches->data[i]; - c->semantic(sc); - - // Determine if current catch 'hides' any previous catches - for (size_t j = 0; j < i; j++) - { Catch *cj = (Catch *)catches->data[j]; - char *si = c->loc.toChars(); - char *sj = cj->loc.toChars(); - - if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) - error("catch at %s hides catch at %s", sj, si); - } - } - - if (!body) - return NULL; - - return this; -} - -int TryCatchStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryCatchStatement::usesEH() -{ - return TRUE; -} - -int TryCatchStatement::blockExit() -{ int result; - - assert(body); - result = body->blockExit(); - - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (Catch *)catches->data[i]; - result |= c->blockExit(); - } - return result; -} - -int TryCatchStatement::fallOffEnd() -{ - int result = FALSE; - - if (body) - result = body->fallOffEnd(); - for (int i = 0; i < catches->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - if (c->handler) - result |= c->handler->fallOffEnd(); - } - return result; -} - -void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("try"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (Catch *)catches->data[i]; - c->toCBuffer(buf, hgs); - } -} - -/******************************** Catch ***************************/ - -Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) -{ - //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); - this->loc = loc; - this->type = t; - this->ident = id; - this->handler = handler; - var = NULL; -} - -Catch *Catch::syntaxCopy() -{ - Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), - ident, - (handler ? handler->syntaxCopy() : NULL)); - return c; -} - -void Catch::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("Catch::semantic(%s)\n", ident->toChars()); - -#ifndef IN_GCC - if (sc->tf) - { - /* This is because the _d_local_unwind() gets the stack munged - * up on this. The workaround is to place any try-catches into - * a separate function, and call that. - * To fix, have the compiler automatically convert the finally - * body into a nested function. - */ - error(loc, "cannot put catch statement inside finally block"); - } -#endif - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - if (!type) - type = new TypeIdentifier(0, Id::Object); - type = type->semantic(loc, sc); - if (!type->toBasetype()->isClassHandle()) - error("can only catch class objects, not '%s'", type->toChars()); - else if (ident) - { - var = new VarDeclaration(loc, type, ident, NULL); - var->parent = sc->parent; - sc->insert(var); - } - handler = handler->semantic(sc); - - sc->pop(); -} - -int Catch::blockExit() -{ - return handler ? handler->blockExit() : BEfallthru; -} - -void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("catch"); - if (type) - { buf->writebyte('('); - type->toCBuffer(buf, ident, hgs); - buf->writebyte(')'); - } - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (handler) - handler->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/****************************** TryFinallyStatement ***************************/ - -TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) - : Statement(loc) -{ - this->body = body; - this->finalbody = finalbody; - this->enclosinghandler = NULL; -} - -Statement *TryFinallyStatement::syntaxCopy() -{ - TryFinallyStatement *s = new TryFinallyStatement(loc, - body->syntaxCopy(), finalbody->syntaxCopy()); - return s; -} - -Statement *TryFinallyStatement::semantic(Scope *sc) -{ - //printf("TryFinallyStatement::semantic()\n"); - - enclosinghandler = sc->tfOfTry; - sc->tfOfTry = new EnclosingTryFinally(this); - body = body->semantic(sc); - sc->tfOfTry = enclosinghandler; - - sc = sc->push(); - sc->tf = this; - sc->sbreak = NULL; - sc->scontinue = NULL; // no break or continue out of finally block - finalbody = finalbody->semantic(sc); - sc->pop(); - if (!body) - return finalbody; - if (!finalbody) - return body; - if (body->blockExit() == BEfallthru) - { Statement *s = new CompoundStatement(loc, body, finalbody); - return s; - } - return this; -} - -void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("try\n{\n"); - body->toCBuffer(buf, hgs); - buf->printf("}\nfinally\n{\n"); - finalbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); -} - -int TryFinallyStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::usesEH() -{ - return TRUE; -} - -int TryFinallyStatement::blockExit() -{ - int result = body->blockExit(); - return result; -} - -int TryFinallyStatement::fallOffEnd() -{ int result; - - result = body->fallOffEnd(); -// if (finalbody) -// result = finalbody->fallOffEnd(); - return result; -} - -/****************************** OnScopeStatement ***************************/ - -OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) - : Statement(loc) -{ - this->tok = tok; - this->statement = statement; -} - -Statement *OnScopeStatement::syntaxCopy() -{ - OnScopeStatement *s = new OnScopeStatement(loc, - tok, statement->syntaxCopy()); - return s; -} - -Statement *OnScopeStatement::semantic(Scope *sc) -{ - /* semantic is called on results of scopeCode() */ - return this; -} - -int OnScopeStatement::blockExit() -{ // At this point, this statement is just an empty placeholder - return BEfallthru; -} - -void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(tok)); - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); -} - -int OnScopeStatement::usesEH() -{ - return 1; -} - -void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("OnScopeStatement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - switch (tok) - { - case TOKon_scope_exit: - *sfinally = statement; - break; - - case TOKon_scope_failure: - *sexception = statement; - break; - - case TOKon_scope_success: - { - /* Create: - * sentry: int x = 0; - * sexception: x = 1; - * sfinally: if (!x) statement; - */ - Identifier *id = Lexer::uniqueId("__os"); - - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); - VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, v); - - Expression *e = new IntegerExp(1); - e = new AssignExp(0, new VarExp(0, v), e); - *sexception = new ExpStatement(0, e); - - e = new VarExp(0, v); - e = new NotExp(0, e); - *sfinally = new IfStatement(0, NULL, e, statement, NULL); - - break; - } - - default: - assert(0); - } -} - -/******************************** ThrowStatement ***************************/ - -ThrowStatement::ThrowStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ThrowStatement::syntaxCopy() -{ - ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); - return s; -} - -Statement *ThrowStatement::semantic(Scope *sc) -{ - //printf("ThrowStatement::semantic()\n"); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 2; - - if (sc->incontract) - error("Throw statements cannot be in contracts"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (!exp->type->toBasetype()->isClassHandle()) - error("can only throw class objects, not type %s", exp->type->toChars()); - return this; -} - -int ThrowStatement::blockExit() -{ - return BEthrow; // obviously -} - -int ThrowStatement::fallOffEnd() -{ - return FALSE; -} - -void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("throw "); - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** VolatileStatement **************************/ - -VolatileStatement::VolatileStatement(Loc loc, Statement *statement) - : Statement(loc) -{ - this->statement = statement; - this->enclosinghandler = NULL; -} - -Statement *VolatileStatement::syntaxCopy() -{ - VolatileStatement *s = new VolatileStatement(loc, - statement ? statement->syntaxCopy() : NULL); - return s; -} - -Statement *VolatileStatement::semantic(Scope *sc) -{ - if (statement) - { - enclosinghandler = sc->tfOfTry; - sc->tfOfTry = new EnclosingVolatile(this); - statement = statement->semantic(sc); - sc->tfOfTry = enclosinghandler; - } - return this; -} - -Statements *VolatileStatement::flatten(Scope *sc) -{ - Statements *a; - - a = statement ? statement->flatten(sc) : NULL; - if (a) - { for (int i = 0; i < a->dim; i++) - { Statement *s = (Statement *)a->data[i]; - - s = new VolatileStatement(loc, s); - a->data[i] = s; - } - } - - return a; -} - -int VolatileStatement::blockExit() -{ - return statement ? statement->blockExit() : BEfallthru; -} - -int VolatileStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - -void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("volatile"); - if (statement) - { if (statement->isScopeStatement()) - buf->writenl(); - else - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); - } -} - - -/******************************** GotoStatement ***************************/ - -GotoStatement::GotoStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; - this->label = NULL; - this->tf = NULL; - this->enclosinghandler = NULL; -} - -Statement *GotoStatement::syntaxCopy() -{ - GotoStatement *s = new GotoStatement(loc, ident); - return s; -} - -Statement *GotoStatement::semantic(Scope *sc) -{ FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("GotoStatement::semantic()\n"); - tf = sc->tf; - enclosinghandler = sc->tfOfTry; - label = fd->searchLabel(ident); - if (!label->statement && sc->fes) - { - /* Either the goto label is forward referenced or it - * is in the function that the enclosing foreach is in. - * Can't know yet, so wrap the goto in a compound statement - * so we can patch it later, and add it to a 'look at this later' - * list. - */ - Statements *a = new Statements(); - Statement *s; - - a->push(this); - s = new CompoundStatement(loc, a); - sc->fes->gotos.push(s); // 'look at this later' list - return s; - } - if (label->statement && label->statement->tf != sc->tf) - error("cannot goto in or out of finally block"); - return this; -} - -int GotoStatement::blockExit() -{ - //printf("GotoStatement::blockExit(%p)\n", this); - return BEgoto; -} - -int GotoStatement::fallOffEnd() -{ - return FALSE; -} - -void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto "); - buf->writestring(ident->toChars()); - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** LabelStatement ***************************/ - -LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) - : Statement(loc) -{ - this->ident = ident; - this->statement = statement; - this->tf = NULL; - this->enclosinghandler = NULL; - this->lblock = NULL; - this->isReturnLabel = 0; - this->asmLabel = false; -} - -Statement *LabelStatement::syntaxCopy() -{ - LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); - return s; -} - -Statement *LabelStatement::semantic(Scope *sc) -{ LabelDsymbol *ls; - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("LabelStatement::semantic()\n"); - ls = fd->searchLabel(ident); - if (ls->statement) - error("Label '%s' already defined", ls->toChars()); - else - ls->statement = this; - tf = sc->tf; - enclosinghandler = sc->tfOfTry; - sc = sc->push(); - sc->scopesym = sc->enclosing->scopesym; - sc->callSuper |= CSXlabel; - sc->slabel = this; - if (statement) - statement = statement->semantic(sc); - sc->pop(); - - // LDC put in labmap - fd->labmap[ident->toChars()] = this; - - return this; -} - -Statements *LabelStatement::flatten(Scope *sc) -{ - Statements *a = NULL; - - if (statement) - { - a = statement->flatten(sc); - if (a) - { - if (!a->dim) - { - a->push(new ExpStatement(loc, NULL)); - } - Statement *s = (Statement *)a->data[0]; - - s = new LabelStatement(loc, ident, s); - a->data[0] = s; - } - } - - return a; -} - - -int LabelStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int LabelStatement::blockExit() -{ - //printf("LabelStatement::blockExit(%p)\n", this); - return statement ? statement->blockExit() : BEfallthru; -} - -int LabelStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - -int LabelStatement::comeFrom() -{ - //printf("LabelStatement::comeFrom()\n"); - return TRUE; -} - -void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writebyte(':'); - buf->writenl(); - if (statement) - statement->toCBuffer(buf, hgs); -} - - -/******************************** LabelDsymbol ***************************/ - -LabelDsymbol::LabelDsymbol(Identifier *ident) - : Dsymbol(ident) -{ - statement = NULL; -} - -LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? -{ - return this; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "rmem.h" + +#include "statement.h" +#include "expression.h" +#include "cond.h" +#include "init.h" +#include "staticassert.h" +#include "mtype.h" +#include "scope.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" +#include "hdrgen.h" +#include "parse.h" +#include "template.h" +#include "attrib.h" + +/******************************** Statement ***************************/ + +Statement::Statement(Loc loc) + : loc(loc) +{ +#ifdef _DH + // If this is an in{} contract scope statement (skip for determining + // inlineStatus of a function body for header content) + incontract = 0; +#endif +} + +Statement *Statement::syntaxCopy() +{ + assert(0); + return NULL; +} + +void Statement::print() +{ + fprintf(stdmsg, "%s\n", toChars()); + fflush(stdmsg); +} + +char *Statement::toChars() +{ OutBuffer *buf; + HdrGenState hgs; + + buf = new OutBuffer(); + toCBuffer(buf, &hgs); + return buf->toChars(); +} + +void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("Statement::toCBuffer()"); + buf->writenl(); +} + +Statement *Statement::semantic(Scope *sc) +{ + return this; +} + +// Same as semantic(), but do create a new scope + +Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) +{ Scope *scd; + Statement *s; + + scd = sc->push(); + if (sbreak) + scd->sbreak = sbreak; + if (scontinue) + scd->scontinue = scontinue; + s = semantic(scd); + scd->pop(); + return s; +} + +void Statement::error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end( ap ); +} + +void Statement::warning(const char *format, ...) +{ + if (global.params.warnings && !global.gag) + { + va_list ap; + va_start(ap, format); + ::vwarning(loc, format, ap); + va_end( ap ); + } +} + +int Statement::hasBreak() +{ + //printf("Statement::hasBreak()\n"); + return FALSE; +} + +int Statement::hasContinue() +{ + return FALSE; +} + +// TRUE if statement uses exception handling + +int Statement::usesEH() +{ + return FALSE; +} + +/* Only valid after semantic analysis + */ +int Statement::blockExit() +{ + printf("Statement::blockExit(%p)\n", this); + printf("%s\n", toChars()); + assert(0); + return BEany; +} + +// TRUE if statement 'comes from' somewhere else, like a goto + +int Statement::comeFrom() +{ + //printf("Statement::comeFrom()\n"); + return FALSE; +} + +/**************************************** + * If this statement has code that needs to run in a finally clause + * at the end of the current scope, return that code in the form of + * a Statement. + * Output: + * *sentry code executed upon entry to the scope + * *sexception code executed upon exit from the scope via exception + * *sfinally code executed in finally block + */ + +void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("Statement::scopeCode()\n"); + //print(); + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; +} + +/********************************* + * Flatten out the scope by presenting the statement + * as an array of statements. + * Returns NULL if no flattening necessary. + */ + +Statements *Statement::flatten(Scope *sc) +{ + return NULL; +} + + +/******************************** ExpStatement ***************************/ + +ExpStatement::ExpStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ExpStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + ExpStatement *es = new ExpStatement(loc, e); + return es; +} + +void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (exp) + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); +} + +Statement *ExpStatement::semantic(Scope *sc) +{ + if (exp) + { + //printf("ExpStatement::semantic() %s\n", exp->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp->checkSideEffect(0); + exp = exp->optimize(0); + if (exp->op == TOKdeclaration && !isDeclarationStatement()) + { Statement *s = new DeclarationStatement(loc, exp); + return s; + } + //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); + } + return this; +} + +int ExpStatement::blockExit() +{ int result = BEfallthru; + + if (exp) + { + if (exp->op == TOKhalt) + return BEhalt; + if (exp->op == TOKassert) + { AssertExp *a = (AssertExp *)exp; + + if (a->e1->isBool(FALSE)) // if it's an assert(0) + return BEhalt; + } + if (exp->canThrow()) + result |= BEthrow; + } + return result; +} + + +/******************************** CompileStatement ***************************/ + +CompileStatement::CompileStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *CompileStatement::syntaxCopy() +{ + Expression *e = exp->syntaxCopy(); + CompileStatement *es = new CompileStatement(loc, e); + return es; +} + +void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + exp->toCBuffer(buf, hgs); + buf->writestring(");"); + if (!hgs->FLinit.init) + buf->writenl(); +} + +Statements *CompileStatement::flatten(Scope *sc) +{ + //printf("CompileStatement::flatten() %s\n", exp->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", exp->toChars()); + return NULL; + } + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + + Statements *a = new Statements(); + while (p.token.value != TOKeof) + { + Statement *s = p.parseStatement(PSsemi | PScurlyscope); + a->push(s); + } + return a; +} + +Statement *CompileStatement::semantic(Scope *sc) +{ + //printf("CompileStatement::semantic() %s\n", exp->toChars()); + Statements *a = flatten(sc); + if (!a) + return NULL; + Statement *s = new CompoundStatement(loc, a); + return s->semantic(sc); +} + + +/******************************** DeclarationStatement ***************************/ + +DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) + : ExpStatement(loc, new DeclarationExp(loc, declaration)) +{ +} + +DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) + : ExpStatement(loc, exp) +{ +} + +Statement *DeclarationStatement::syntaxCopy() +{ + DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); + return ds; +} + +void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("DeclarationStatement::scopeCode()\n"); + //print(); + + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + + if (exp) + { + if (exp->op == TOKdeclaration) + { + DeclarationExp *de = (DeclarationExp *)(exp); + VarDeclaration *v = de->declaration->isVarDeclaration(); + if (v) + { Expression *e; + + e = v->callAutoDtor(sc); + if (e) + { + //printf("dtor is: "); e->print(); + *sfinally = new ExpStatement(loc, e); + } + } + } + } +} + +void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + exp->toCBuffer(buf, hgs); +} + + +/******************************** CompoundStatement ***************************/ + +CompoundStatement::CompoundStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; +} + +CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) + : Statement(loc) +{ + statements = new Statements(); + statements->reserve(2); + statements->push(s1); + statements->push(s2); +} + +Statement *CompoundStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + CompoundStatement *cs = new CompoundStatement(loc, a); + return cs; +} + + +Statement *CompoundStatement::semantic(Scope *sc) +{ Statement *s; + + //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); + + for (size_t i = 0; i < statements->dim; ) + { + s = (Statement *) statements->data[i]; + if (s) + { Statements *a = s->flatten(sc); + + if (a) + { + statements->remove(i); + statements->insert(i, a); + continue; + } + s = s->semantic(sc); + statements->data[i] = s; + if (s) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + s->scopeCode(sc, &sentry, &sexception, &sfinally); + if (sentry) + { + sentry = sentry->semantic(sc); + statements->data[i] = sentry; + } + if (sexception) + { + if (i + 1 == statements->dim && !sfinally) + { +#if 1 + sexception = sexception->semantic(sc); +#else + statements->push(sexception); + if (sfinally) + // Assume sexception does not throw + statements->push(sfinally); +#endif + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; + * try { s1; s2; } + * catch (Object __o) + * { sexception; throw __o; } + */ + Statement *body; + Statements *a = new Statements(); + + for (int j = i + 1; j < statements->dim; j++) + { + a->push(statements->data[j]); + } + body = new CompoundStatement(0, a); + body = new ScopeStatement(0, body); + + Identifier *id = Lexer::uniqueId("__o"); + + Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); + handler = new CompoundStatement(0, sexception, handler); + + Array *catches = new Array(); + Catch *ctch = new Catch(0, NULL, id, handler); + catches->push(ctch); + s = new TryCatchStatement(0, body, catches); + + if (sfinally) + s = new TryFinallyStatement(0, s, sfinally); + s = s->semantic(sc); + statements->setDim(i + 1); + statements->push(s); + break; + } + } + else if (sfinally) + { + if (0 && i + 1 == statements->dim) + { + statements->push(sfinally); + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; try { s1; s2; } finally { sfinally; } + */ + Statement *body; + Statements *a = new Statements(); + + for (int j = i + 1; j < statements->dim; j++) + { + a->push(statements->data[j]); + } + body = new CompoundStatement(0, a); + s = new TryFinallyStatement(0, body, sfinally); + s = s->semantic(sc); + statements->setDim(i + 1); + statements->push(s); + break; + } + } + } + } + i++; + } + if (statements->dim == 1 && !isAsmBlockStatement()) + { + return (Statement *)statements->data[0]; + } + return this; +} + +Statements *CompoundStatement::flatten(Scope *sc) +{ + return statements; +} + +ReturnStatement *CompoundStatement::isReturnStatement() +{ + ReturnStatement *rs = NULL; + + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + rs = s->isReturnStatement(); + if (rs) + break; + } + } + return rs; +} + +void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } +} + +int CompoundStatement::usesEH() +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int CompoundStatement::blockExit() +{ + //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); + int result = BEfallthru; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { +//printf("result = x%x\n", result); +//printf("%s\n", s->toChars()); + if (!(result & BEfallthru) && !s->comeFrom()) + { + s->warning("statement is not reachable"); + } + + result &= ~BEfallthru; + result |= s->blockExit(); + } + } + return result; +} + +int CompoundStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("CompoundStatement::comeFrom()\n"); + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + + +/******************************** CompoundDeclarationStatement ***************************/ + +CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s) + : CompoundStatement(loc, s) +{ + statements = s; +} + +Statement *CompoundDeclarationStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); + return cs; +} + +void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + int nwritten = 0; + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { DeclarationStatement *ds = s->isDeclarationStatement(); + assert(ds); + DeclarationExp *de = (DeclarationExp *)ds->exp; + assert(de->op == TOKdeclaration); + Declaration *d = de->declaration->isDeclaration(); + assert(d); + VarDeclaration *v = d->isVarDeclaration(); + if (v) + { + /* This essentially copies the part of VarDeclaration::toCBuffer() + * that does not print the type. + * Should refactor this. + */ + if (nwritten) + { + buf->writeByte(','); + buf->writestring(v->ident->toChars()); + } + else + { + StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); + if (v->type) + v->type->toCBuffer(buf, v->ident, hgs); + else + buf->writestring(v->ident->toChars()); + } + + if (v->init) + { buf->writestring(" = "); +#if DMDV2 + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) + ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); + else +#endif + v->init->toCBuffer(buf, hgs); + } + } + else + d->toCBuffer(buf, hgs); + nwritten++; + } + } + buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); +} + +/**************************** UnrolledLoopStatement ***************************/ + +UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; +} + +Statement *UnrolledLoopStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); + return cs; +} + + +Statement *UnrolledLoopStatement::semantic(Scope *sc) +{ + //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); + + sc->noctor++; + Scope *scd = sc->push(); + scd->sbreak = this; + scd->scontinue = this; + + for (size_t i = 0; i < statements->dim; i++) + { + Statement *s = (Statement *) statements->data[i]; + if (s) + { + s = s->semantic(scd); + statements->data[i] = s; + } + } + + scd->pop(); + sc->noctor--; + return this; +} + +void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("unrolled {"); + buf->writenl(); + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } + + buf->writeByte('}'); + buf->writenl(); +} + +int UnrolledLoopStatement::hasBreak() +{ + return TRUE; +} + +int UnrolledLoopStatement::hasContinue() +{ + return TRUE; +} + +int UnrolledLoopStatement::usesEH() +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int UnrolledLoopStatement::blockExit() +{ + int result = BEfallthru; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + int r = s->blockExit(); + result |= r & ~(BEbreak | BEcontinue); + } + } + return result; +} + + +int UnrolledLoopStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("UnrolledLoopStatement::comeFrom()\n"); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + + +/******************************** ScopeStatement ***************************/ + +ScopeStatement::ScopeStatement(Loc loc, Statement *s) + : Statement(loc) +{ + this->statement = s; +} + +Statement *ScopeStatement::syntaxCopy() +{ + Statement *s; + + s = statement ? statement->syntaxCopy() : NULL; + s = new ScopeStatement(loc, s); + return s; +} + + +Statement *ScopeStatement::semantic(Scope *sc) +{ ScopeDsymbol *sym; + + //printf("ScopeStatement::semantic(sc = %p)\n", sc); + if (statement) + { Statements *a; + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + a = statement->flatten(sc); + if (a) + { + statement = new CompoundStatement(loc, a); + } + + statement = statement->semantic(sc); + if (statement) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + statement->scopeCode(sc, &sentry, &sexception, &sfinally); + if (sfinally) + { + //printf("adding sfinally\n"); + statement = new CompoundStatement(loc, statement, sfinally); + } + } + + sc->pop(); + } + return this; +} + +int ScopeStatement::hasBreak() +{ + //printf("ScopeStatement::hasBreak() %s\n", toChars()); + return statement ? statement->hasBreak() : FALSE; +} + +int ScopeStatement::hasContinue() +{ + return statement ? statement->hasContinue() : FALSE; +} + +int ScopeStatement::usesEH() +{ + return statement ? statement->usesEH() : FALSE; +} + +int ScopeStatement::blockExit() +{ + //printf("ScopeStatement::blockExit(%p)\n", statement); + return statement ? statement->blockExit() : BEfallthru; +} + + +int ScopeStatement::comeFrom() +{ + //printf("ScopeStatement::comeFrom()\n"); + return statement ? statement->comeFrom() : FALSE; +} + +void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('{'); + buf->writenl(); + + if (statement) + statement->toCBuffer(buf, hgs); + + buf->writeByte('}'); + buf->writenl(); +} + +/******************************** WhileStatement ***************************/ + +WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) + : Statement(loc) +{ + condition = c; + body = b; +} + +Statement *WhileStatement::syntaxCopy() +{ + WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); + return s; +} + + +Statement *WhileStatement::semantic(Scope *sc) +{ +#if 0 + if (condition->op == TOKmatch) + { + /* Rewrite while (condition) body as: + * if (condition) + * do + * body + * while ((_match = _match.opNext), _match); + */ + + Expression *ew = new IdentifierExp(0, Id::_match); + ew = new DotIdExp(0, ew, Id::next); + ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew); + ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0)); + Expression *ev = new IdentifierExp(0, Id::_match); + //ev = new CastExp(0, ev, Type::tvoidptr); + ew = new CommaExp(0, ew, ev); + Statement *sw = new DoStatement(loc, body, ew); + Statement *si = new IfStatement(loc, condition, sw, NULL); + return si->semantic(sc); + } +#endif + + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + condition = condition->checkToBoolean(); + + sc->noctor++; + + Scope *scd = sc->push(); + scd->sbreak = this; + scd->scontinue = this; + if (body) + body = body->semantic(scd); + scd->pop(); + + sc->noctor--; + + return this; +} + +int WhileStatement::hasBreak() +{ + return TRUE; +} + +int WhileStatement::hasContinue() +{ + return TRUE; +} + +int WhileStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int WhileStatement::blockExit() +{ + //printf("WhileStatement::blockExit(%p)\n", this); + + int result = BEnone; + if (condition->canThrow()) + result |= BEthrow; + if (condition->isBool(TRUE)) + { + if (body) + { result |= body->blockExit(); + if (result & BEbreak) + result |= BEfallthru; + } + } + else if (condition->isBool(FALSE)) + { + result |= BEfallthru; + } + else + { + if (body) + result |= body->blockExit(); + result |= BEfallthru; + } + result &= ~(BEbreak | BEcontinue); + return result; +} + + +int WhileStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("while ("); + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); +} + +/******************************** DoStatement ***************************/ + +DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) + : Statement(loc) +{ + body = b; + condition = c; +} + +Statement *DoStatement::syntaxCopy() +{ + DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); + return s; +} + + +Statement *DoStatement::semantic(Scope *sc) +{ + sc->noctor++; + if (body) + body = body->semanticScope(sc, this, this); + sc->noctor--; + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + + condition = condition->checkToBoolean(); + + return this; +} + +int DoStatement::hasBreak() +{ + return TRUE; +} + +int DoStatement::hasContinue() +{ + return TRUE; +} + +int DoStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int DoStatement::blockExit() +{ int result; + + if (body) + { result = body->blockExit(); + if (result == BEbreak) + return BEfallthru; + if (result & BEcontinue) + result |= BEfallthru; + } + else + result = BEfallthru; + if (result & BEfallthru) + { if (condition->canThrow()) + result |= BEthrow; + if (!(result & BEbreak) && condition->isBool(TRUE)) + result &= ~BEfallthru; + } + result &= ~(BEbreak | BEcontinue); + return result; +} + + +int DoStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("do"); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writestring("while ("); + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); +} + +/******************************** ForStatement ***************************/ + +ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) + : Statement(loc) +{ + this->init = init; + this->condition = condition; + this->increment = increment; + this->body = body; +} + +Statement *ForStatement::syntaxCopy() +{ + Statement *i = NULL; + if (init) + i = init->syntaxCopy(); + Expression *c = NULL; + if (condition) + c = condition->syntaxCopy(); + Expression *inc = NULL; + if (increment) + inc = increment->syntaxCopy(); + ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); + return s; +} + +Statement *ForStatement::semantic(Scope *sc) +{ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + if (init) + init = init->semantic(sc); + sc->noctor++; + if (condition) + { + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + condition = condition->checkToBoolean(); + } + if (increment) + { increment = increment->semantic(sc); + increment = resolveProperties(sc, increment); + } + + sc->sbreak = this; + sc->scontinue = this; + if (body) + body = body->semantic(sc); + sc->noctor--; + + sc->pop(); + return this; +} + +void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("ForStatement::scopeCode()\n"); + //print(); + if (init) + init->scopeCode(sc, sentry, sexception, sfinally); + else + Statement::scopeCode(sc, sentry, sexception, sfinally); +} + +int ForStatement::hasBreak() +{ + //printf("ForStatement::hasBreak()\n"); + return TRUE; +} + +int ForStatement::hasContinue() +{ + return TRUE; +} + +int ForStatement::usesEH() +{ + return (init && init->usesEH()) || body->usesEH(); +} + +int ForStatement::blockExit() +{ int result = BEfallthru; + + if (init) + { result = init->blockExit(); + if (!(result & BEfallthru)) + return result; + } + if (condition) + { if (condition->canThrow()) + result |= BEthrow; + } + else + result &= ~BEfallthru; // the body must do the exiting + if (body) + { int r = body->blockExit(); + if (r & (BEbreak | BEgoto)) + result |= BEfallthru; + result |= r & ~(BEfallthru | BEbreak | BEcontinue); + } + if (increment && increment->canThrow()) + result |= BEthrow; + return result; +} + + +int ForStatement::comeFrom() +{ + //printf("ForStatement::comeFrom()\n"); + if (body) + { int result = body->comeFrom(); + //printf("result = %d\n", result); + return result; + } + return FALSE; +} + +void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("for ("); + if (init) + { + hgs->FLinit.init++; + init->toCBuffer(buf, hgs); + hgs->FLinit.init--; + } + else + buf->writebyte(';'); + if (condition) + { buf->writebyte(' '); + condition->toCBuffer(buf, hgs); + } + buf->writebyte(';'); + if (increment) + { buf->writebyte(' '); + increment->toCBuffer(buf, hgs); + } + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/******************************** ForeachStatement ***************************/ + +ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, + Expression *aggr, Statement *body) + : Statement(loc) +{ + this->op = op; + this->arguments = arguments; + this->aggr = aggr; + this->body = body; + + this->key = NULL; + this->value = NULL; + + this->func = NULL; +} + +Statement *ForeachStatement::syntaxCopy() +{ + Arguments *args = Argument::arraySyntaxCopy(arguments); + Expression *exp = aggr->syntaxCopy(); + ForeachStatement *s = new ForeachStatement(loc, op, args, exp, + body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *ForeachStatement::semantic(Scope *sc) +{ + //printf("ForeachStatement::semantic() %p\n", this); + ScopeDsymbol *sym; + Statement *s = this; + size_t dim = arguments->dim; + TypeAArray *taa = NULL; + + Type *tn = NULL; + Type *tnv = NULL; + + func = sc->func; + if (func->fes) + func = func->fes->func; + + aggr = aggr->semantic(sc); + aggr = resolveProperties(sc, aggr); + aggr = aggr->optimize(WANTvalue); + if (!aggr->type) + { + error("invalid foreach aggregate %s", aggr->toChars()); + return this; + } + + inferApplyArgTypes(op, arguments, aggr, sc->module); + + /* Check for inference errors + */ + if (dim != arguments->dim) + { + //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); + error("cannot uniquely infer foreach argument types"); + return this; + } + + Type *tab = aggr->type->toBasetype(); + + if (tab->ty == Ttuple) // don't generate new scope for tuple loops + { + if (dim < 1 || dim > 2) + { + error("only one (value) or two (key,value) arguments for tuple foreach"); + return s; + } + + TypeTuple *tuple = (TypeTuple *)tab; + Statements *statements = new Statements(); + //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); + size_t n; + TupleExp *te = NULL; + if (aggr->op == TOKtuple) // expression tuple + { te = (TupleExp *)aggr; + n = te->exps->dim; + } + else if (aggr->op == TOKtype) // type tuple + { + n = Argument::dim(tuple->arguments); + } + else + assert(0); + for (size_t j = 0; j < n; j++) + { size_t k = (op == TOKforeach) ? j : n - 1 - j; + Expression *e; + Type *t; + if (te) + e = (Expression *)te->exps->data[k]; + else + t = Argument::getNth(tuple->arguments, k)->type; + Argument *arg = (Argument *)arguments->data[0]; + Statements *st = new Statements(); + + if (dim == 2) + { // Declare key + if (arg->storageClass & (STCout | STCref | STClazy)) + error("no storage class for key %s", arg->ident->toChars()); + TY keyty = arg->type->ty; + if (keyty != Tint32 && keyty != Tuns32) + { + if (global.params.is64bit) + { + if (keyty != Tint64 && keyty != Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); + } + else + error("foreach: key type must be int or uint, not %s", arg->type->toChars()); + } + Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); + VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); + var->storage_class |= STCmanifest; + DeclarationExp *de = new DeclarationExp(loc, var); + st->push(new ExpStatement(loc, de)); + arg = (Argument *)arguments->data[1]; // value + } + // Declare value + if (arg->storageClass & (STCout | STCref | STClazy)) + error("no storage class for value %s", arg->ident->toChars()); + Dsymbol *var; + if (te) + { Type *tb = e->type->toBasetype(); + if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) + { VarExp *ve = (VarExp *)e; + var = new AliasDeclaration(loc, arg->ident, ve->var); + } + else + { + arg->type = e->type; + Initializer *ie = new ExpInitializer(0, e); + VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); + if (e->isConst()) + v->storage_class |= STCconst; + var = v; + } + } + else + { + var = new AliasDeclaration(loc, arg->ident, t); + } + DeclarationExp *de = new DeclarationExp(loc, var); + st->push(new ExpStatement(loc, de)); + + st->push(body->syntaxCopy()); + s = new CompoundStatement(loc, st); + s = new ScopeStatement(loc, s); + statements->push(s); + } + + s = new UnrolledLoopStatement(loc, statements); + s = s->semantic(sc); + return s; + } + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + sc->noctor++; + + switch (tab->ty) + { + case Tarray: + case Tsarray: + if (!checkForArgTypes()) + return this; + + if (dim < 1 || dim > 2) + { + error("only one or two arguments for array foreach"); + break; + } + + /* Look for special case of parsing char types out of char type + * array. + */ + tn = tab->nextOf()->toBasetype(); + if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) + { Argument *arg; + + int i = (dim == 1) ? 0 : 1; // index of value + arg = (Argument *)arguments->data[i]; + arg->type = arg->type->semantic(loc, sc); + tnv = arg->type->toBasetype(); + if (tnv->ty != tn->ty && + (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) + { + if (arg->storageClass & STCref) + error("foreach: value of UTF conversion cannot be ref"); + if (dim == 2) + { arg = (Argument *)arguments->data[0]; + if (arg->storageClass & STCref) + error("foreach: key cannot be ref"); + } + goto Lapply; + } + } + + for (size_t i = 0; i < dim; i++) + { // Declare args + Argument *arg = (Argument *)arguments->data[i]; + VarDeclaration *var; + + var = new VarDeclaration(loc, arg->type, arg->ident, NULL); + var->storage_class |= STCforeach; + var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + if (dim == 2 && i == 0) + { key = var; + //var->storage_class |= STCfinal; + } + else + { + value = var; + /* Reference to immutable data should be marked as const + */ + if (var->storage_class & STCref && !tn->isMutable()) + { + var->storage_class |= STCconst; + } + } +#if 1 + DeclarationExp *de = new DeclarationExp(loc, var); + de->semantic(sc); +#else + var->semantic(sc); + if (!sc->insert(var)) + error("%s already defined", var->ident->toChars()); +#endif + } + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + + if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst) + { + if (aggr->op == TOKstring) + aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); + else + error("foreach: %s is not an array of %s", + tab->toChars(), value->type->toChars()); + } + + if (key && key->type->ty != Tint32 && key->type->ty != Tuns32) + { + if (global.params.is64bit) + { + if (key->type->ty != Tint64 && key->type->ty != Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); + } + else + error("foreach: key type must be int or uint, not %s", key->type->toChars()); + } + + if (key && key->storage_class & (STCout | STCref)) + error("foreach: key cannot be out or ref"); + break; + + case Taarray: + if (!checkForArgTypes()) + return this; + + taa = (TypeAArray *)tab; + if (dim < 1 || dim > 2) + { + error("only one or two arguments for associative array foreach"); + break; + } + if (op == TOKforeach_reverse) + { + error("no reverse iteration on associative arrays"); + } + goto Lapply; + + case Tclass: + case Tstruct: +#if DMDV2 + { /* Look for range iteration, i.e. the properties + * .empty, .next, .retreat, .head and .rear + * foreach (e; aggr) { ... } + * translates to: + * for (auto __r = aggr[]; !__r.empty; __r.next) + * { auto e = __r.head; + * ... + * } + */ + if (dim != 1) // only one argument allowed with ranges + goto Lapply; + AggregateDeclaration *ad = (tab->ty == Tclass) + ? (AggregateDeclaration *)((TypeClass *)tab)->sym + : (AggregateDeclaration *)((TypeStruct *)tab)->sym; + Identifier *idhead; + Identifier *idnext; + if (op == TOKforeach) + { idhead = Id::Fhead; + idnext = Id::Fnext; + } + else + { idhead = Id::Ftoe; + idnext = Id::Fretreat; + } + Dsymbol *shead = search_function(ad, idhead); + if (!shead) + goto Lapply; + + /* Generate a temporary __r and initialize it with the aggregate. + */ + Identifier *id = Identifier::generateId("__r"); + aggr = aggr->semantic(sc); + Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); + rinit = rinit->trySemantic(sc); + if (!rinit) // if application of [] failed + rinit = aggr; + VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); +// r->semantic(sc); +//printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); + Statement *init = new DeclarationStatement(loc, r); +//printf("init: %s\n", init->toChars()); + + // !__r.empty + Expression *e = new VarExp(loc, r); + e = new DotIdExp(loc, e, Id::Fempty); + Expression *condition = new NotExp(loc, e); + + // __r.next + e = new VarExp(loc, r); + Expression *increment = new DotIdExp(loc, e, idnext); + + /* Declaration statement for e: + * auto e = __r.idhead; + */ + e = new VarExp(loc, r); + Expression *einit = new DotIdExp(loc, e, idhead); +// einit = einit->semantic(sc); + Argument *arg = (Argument *)arguments->data[0]; + VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); + ve->storage_class |= STCforeach; + ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + + DeclarationExp *de = new DeclarationExp(loc, ve); + + Statement *body = new CompoundStatement(loc, + new DeclarationStatement(loc, de), this->body); + + s = new ForStatement(loc, init, condition, increment, body); +#if 0 + printf("init: %s\n", init->toChars()); + printf("condition: %s\n", condition->toChars()); + printf("increment: %s\n", increment->toChars()); + printf("body: %s\n", body->toChars()); +#endif + s = s->semantic(sc); + break; + } +#endif + case Tdelegate: + Lapply: + { FuncDeclaration *fdapply; + Arguments *args; + Expression *ec; + Expression *e; + FuncLiteralDeclaration *fld; + Argument *a; + Type *t; + Expression *flde; + Identifier *id; + Type *tret; + TypeDelegate* dgty; + TypeDelegate* dgty2; + TypeDelegate* fldeTy; + + if (!checkForArgTypes()) + { body = body->semantic(sc); + return this; + } + + tret = func->type->nextOf(); + + // Need a variable to hold value from any return statements in body. + if (!sc->func->vresult && tret && tret != Type::tvoid) + { VarDeclaration *v; + + v = new VarDeclaration(loc, tret, Id::result, NULL); + v->noauto = 1; + v->semantic(sc); + if (!sc->insert(v)) + assert(0); + v->parent = sc->func; + sc->func->vresult = v; + } + + /* Turn body into the function literal: + * int delegate(ref T arg) { body } + */ + args = new Arguments(); + for (size_t i = 0; i < dim; i++) + { Argument *arg = (Argument *)arguments->data[i]; + + arg->type = arg->type->semantic(loc, sc); + if (arg->storageClass & STCref) + id = arg->ident; + else + { // Make a copy of the ref argument so it isn't + // a reference. + VarDeclaration *v; + Initializer *ie; + + id = Lexer::uniqueId("__applyArg", i); + + ie = new ExpInitializer(0, new IdentifierExp(0, id)); + v = new VarDeclaration(0, arg->type, arg->ident, ie); + s = new DeclarationStatement(0, v); + body = new CompoundStatement(loc, s, body); + } + a = new Argument(STCref, arg->type, id, NULL); + args->push(a); + } + t = new TypeFunction(args, Type::tint32, 0, LINKd); + fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); + fld->fbody = body; + flde = new FuncExp(loc, fld); + flde = flde->semantic(sc); + fld->tookAddressOf = 0; + + // Resolve any forward referenced goto's + for (int i = 0; i < gotos.dim; i++) + { CompoundStatement *cs = (CompoundStatement *)gotos.data[i]; + GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; + + if (!gs->label->statement) + { // 'Promote' it to this scope, and replace with a return + cases.push(gs); + s = new ReturnStatement(0, new IntegerExp(cases.dim + 1)); + cs->statements->data[0] = (void *)s; + } + } + + if (tab->ty == Taarray) + { + // Check types + Argument *arg = (Argument *)arguments->data[0]; + if (dim == 2) + { + if (arg->storageClass & STCref) + error("foreach: index cannot be ref"); + if (!arg->type->equals(taa->index)) + error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); + arg = (Argument *)arguments->data[1]; + } + if (!arg->type->equals(taa->nextOf())) + error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); + + /* Call: + * _aaApply(aggr, keysize, flde) + */ + //LDC: Build arguments. + static FuncDeclaration *aaApply2_fd = NULL; + static TypeDelegate* aaApply2_dg; + if(!aaApply2_fd) { + Arguments* args = new Arguments; + args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); + args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); + Arguments* dgargs = new Arguments; + dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); + dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); + aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Argument(STCin, aaApply2_dg, NULL, NULL)); + aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2"); + } + static FuncDeclaration *aaApply_fd = NULL; + static TypeDelegate* aaApply_dg; + if(!aaApply_fd) { + Arguments* args = new Arguments; + args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); + args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); + Arguments* dgargs = new Arguments; + dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); + aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Argument(STCin, aaApply_dg, NULL, NULL)); + aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply"); + } + if (dim == 2) { + fdapply = aaApply2_fd; + fldeTy = aaApply2_dg; + } else { + fdapply = aaApply_fd; + fldeTy = aaApply_dg; + } + ec = new VarExp(0, fdapply); + Expressions *exps = new Expressions(); + exps->push(aggr); + size_t keysize = taa->index->size(); + keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); + exps->push(new IntegerExp(0, keysize, Type::tsize_t)); + + // LDC paint delegate argument to the type runtime expects + if (!fldeTy->equals(flde->type)) + { + flde = new CastExp(loc, flde, flde->type); + flde->type = fldeTy; + } + exps->push(flde); + e = new CallExp(loc, ec, exps); + e->type = Type::tindex; // don't run semantic() on e + } + else if (tab->ty == Tarray || tab->ty == Tsarray) + { + /* Call: + * _aApply(aggr, flde) + */ + static char fntab[9][3] = + { "cc","cw","cd", + "wc","cc","wd", + "dc","dw","dd" + }; + char fdname[7+1+2+ sizeof(dim)*3 + 1]; + int flag; + + switch (tn->ty) + { + case Tchar: flag = 0; break; + case Twchar: flag = 3; break; + case Tdchar: flag = 6; break; + default: assert(0); + } + switch (tnv->ty) + { + case Tchar: flag += 0; break; + case Twchar: flag += 1; break; + case Tdchar: flag += 2; break; + default: assert(0); + } + const char *r = (op == TOKforeach_reverse) ? "R" : ""; +#ifdef __MINGW32__ + int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim); +#else + int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); +#endif + assert(j < sizeof(fdname)); + //LDC: Build arguments. + Arguments* args = new Arguments; + args->push(new Argument(STCin, tn->arrayOf(), NULL, NULL)); + if (dim == 2) { + Arguments* dgargs = new Arguments; + dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); + dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); + dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Argument(STCin, dgty, NULL, NULL)); + fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); + } else { + Arguments* dgargs = new Arguments; + dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); + dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Argument(STCin, dgty, NULL, NULL)); + fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); + } + + ec = new VarExp(0, fdapply); + Expressions *exps = new Expressions(); + if (tab->ty == Tsarray) + aggr = aggr->castTo(sc, tn->arrayOf()); + exps->push(aggr); + + // LDC paint delegate argument to the type runtime expects + if (!dgty->equals(flde->type)) + { + flde = new CastExp(loc, flde, flde->type); + flde->type = dgty; + } + exps->push(flde); + e = new CallExp(loc, ec, exps); + e->type = Type::tindex; // don't run semantic() on e + } + else if (tab->ty == Tdelegate) + { + /* Call: + * aggr(flde) + */ + Expressions *exps = new Expressions(); + exps->push(flde); + e = new CallExp(loc, aggr, exps); + e = e->semantic(sc); + if (e->type != Type::tint32) + error("opApply() function for %s must return an int", tab->toChars()); + } + else + { + assert(tab->ty == Tstruct || tab->ty == Tclass); + Identifier *idapply = (op == TOKforeach_reverse) + ? Id::applyReverse : Id::apply; + Dsymbol *sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); + Expressions *exps = new Expressions(); +#if 0 + TemplateDeclaration *td; + if (sapply && + (td = sapply->isTemplateDeclaration()) != NULL) + { /* Call: + * aggr.apply!(fld)() + */ + TemplateInstance *ti = new TemplateInstance(loc, idapply); + Objects *tiargs = new Objects(); + tiargs->push(fld); + ti->tiargs = tiargs; + ec = new DotTemplateInstanceExp(loc, aggr, ti); + } + else +#endif + { + /* Call: + * aggr.apply(flde) + */ + ec = new DotIdExp(loc, aggr, idapply); + exps->push(flde); + } + e = new CallExp(loc, ec, exps); + e = e->semantic(sc); + if (e->type != Type::tint32) + error("opApply() function for %s must return an int", tab->toChars()); + } + + if (!cases.dim) + // Easy case, a clean exit from the loop + s = new ExpStatement(loc, e); + else + { // Construct a switch statement around the return value + // of the apply function. + Statements *a = new Statements(); + + // default: break; takes care of cases 0 and 1 + s = new BreakStatement(0, NULL); + s = new DefaultStatement(0, s); + a->push(s); + + // cases 2... + for (int i = 0; i < cases.dim; i++) + { + s = (Statement *)cases.data[i]; + s = new CaseStatement(0, new IntegerExp(i + 2), s); + a->push(s); + } + + s = new CompoundStatement(loc, a); + s = new SwitchStatement(loc, e, s); + s = s->semantic(sc); + } + break; + } + + default: + error("foreach: %s is not an aggregate type", aggr->type->toChars()); + s = NULL; // error recovery + break; + } + sc->noctor--; + sc->pop(); + return s; +} + +bool ForeachStatement::checkForArgTypes() +{ bool result = TRUE; + + for (size_t i = 0; i < arguments->dim; i++) + { Argument *arg = (Argument *)arguments->data[i]; + if (!arg->type) + { + error("cannot infer type for %s", arg->ident->toChars()); + arg->type = Type::terror; + result = FALSE; + } + } + return result; +} + +int ForeachStatement::hasBreak() +{ + return TRUE; +} + +int ForeachStatement::hasContinue() +{ + return TRUE; +} + +int ForeachStatement::usesEH() +{ + return body->usesEH(); +} + +int ForeachStatement::blockExit() +{ int result = BEfallthru; + + if (aggr->canThrow()) + result |= BEthrow; + + if (body) + { + result |= body->blockExit() & ~(BEbreak | BEcontinue); + } + return result; +} + + +int ForeachStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + buf->writestring(" ("); + for (int i = 0; i < arguments->dim; i++) + { + Argument *a = (Argument *)arguments->data[i]; + if (i) + buf->writestring(", "); + if (a->storageClass & STCref) + buf->writestring((global.params.Dversion == 1) + ? (char*)"inout " : (char*)"ref "); + if (a->type) + a->type->toCBuffer(buf, a->ident, hgs); + else + buf->writestring(a->ident->toChars()); + } + buf->writestring("; "); + aggr->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/**************************** ForeachRangeStatement ***************************/ + +#if DMDV2 + +ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, + Expression *lwr, Expression *upr, Statement *body) + : Statement(loc) +{ + this->op = op; + this->arg = arg; + this->lwr = lwr; + this->upr = upr; + this->body = body; + + this->key = NULL; +} + +Statement *ForeachRangeStatement::syntaxCopy() +{ + ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, + arg->syntaxCopy(), + lwr->syntaxCopy(), + upr->syntaxCopy(), + body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *ForeachRangeStatement::semantic(Scope *sc) +{ + //printf("ForeachRangeStatement::semantic() %p\n", this); + ScopeDsymbol *sym; + Statement *s = this; + + lwr = lwr->semantic(sc); + lwr = resolveProperties(sc, lwr); + lwr = lwr->optimize(WANTvalue); + if (!lwr->type) + { + error("invalid range lower bound %s", lwr->toChars()); + return this; + } + + upr = upr->semantic(sc); + upr = resolveProperties(sc, upr); + upr = upr->optimize(WANTvalue); + if (!upr->type) + { + error("invalid range upper bound %s", upr->toChars()); + return this; + } + + if (arg->type) + { + arg->type = arg->type->semantic(loc, sc); + lwr = lwr->implicitCastTo(sc, arg->type); + upr = upr->implicitCastTo(sc, arg->type); + } + else + { + /* Must infer types from lwr and upr + */ + AddExp ea(loc, lwr, upr); + ea.typeCombine(sc); + arg->type = ea.type->mutableOf(); + lwr = ea.e1; + upr = ea.e2; + } + if (!arg->type->isscalar()) + error("%s is not a scalar type", arg->type->toChars()); + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + sc->noctor++; + + key = new VarDeclaration(loc, arg->type, arg->ident, NULL); + DeclarationExp *de = new DeclarationExp(loc, key); + de->semantic(sc); + + if (key->storage_class) + error("foreach range: key cannot have storage class"); + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + + sc->noctor--; + sc->pop(); + return s; +} + +int ForeachRangeStatement::hasBreak() +{ + return TRUE; +} + +int ForeachRangeStatement::hasContinue() +{ + return TRUE; +} + +int ForeachRangeStatement::usesEH() +{ + return body->usesEH(); +} + +int ForeachRangeStatement::blockExit() +{ int result = BEfallthru; + + if (lwr && lwr->canThrow()) + result |= BEthrow; + else if (upr && upr->canThrow()) + result |= BEthrow; + + if (body) + { + result |= body->blockExit() & ~(BEbreak | BEcontinue); + } + return result; +} + + +int ForeachRangeStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + buf->writestring(" ("); + + if (arg->type) + arg->type->toCBuffer(buf, arg->ident, hgs); + else + buf->writestring(arg->ident->toChars()); + + buf->writestring("; "); + lwr->toCBuffer(buf, hgs); + buf->writestring(" .. "); + upr->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +#endif + +/******************************** IfStatement ***************************/ + +IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) + : Statement(loc) +{ + this->arg = arg; + this->condition = condition; + this->ifbody = ifbody; + this->elsebody = elsebody; + this->match = NULL; +} + +Statement *IfStatement::syntaxCopy() +{ + Statement *i = NULL; + if (ifbody) + i = ifbody->syntaxCopy(); + + Statement *e = NULL; + if (elsebody) + e = elsebody->syntaxCopy(); + + Argument *a = arg ? arg->syntaxCopy() : NULL; + IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); + return s; +} + +Statement *IfStatement::semantic(Scope *sc) +{ + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->checkToBoolean(); + + // If we can short-circuit evaluate the if statement, don't do the + // semantic analysis of the skipped code. + // This feature allows a limited form of conditional compilation. + condition = condition->optimize(WANTflags); + + // Evaluate at runtime + unsigned cs0 = sc->callSuper; + unsigned cs1; + + Scope *scd; + if (arg) + { /* Declare arg, which we will set to be the + * result of condition. + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + scd = sc->push(sym); + + Type *t = arg->type ? arg->type : condition->type; + match = new VarDeclaration(loc, t, arg->ident, NULL); + match->noauto = 1; + match->semantic(scd); + if (!scd->insert(match)) + assert(0); + match->parent = sc->func; + + /* Generate: + * (arg = condition) + */ + VarExp *v = new VarExp(0, match); + condition = new AssignExp(loc, v, condition); + condition = condition->semantic(scd); + } + else + scd = sc->push(); + ifbody = ifbody->semantic(scd); + scd->pop(); + + cs1 = sc->callSuper; + sc->callSuper = cs0; + if (elsebody) + elsebody = elsebody->semanticScope(sc, NULL, NULL); + sc->mergeCallSuper(loc, cs1); + + return this; +} + +int IfStatement::usesEH() +{ + return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); +} + +int IfStatement::blockExit() +{ + //printf("IfStatement::blockExit(%p)\n", this); + + int result = BEnone; + if (condition->canThrow()) + result |= BEthrow; + if (condition->isBool(TRUE)) + { + if (ifbody) + result |= ifbody->blockExit(); + else + result |= BEfallthru; + } + else if (condition->isBool(FALSE)) + { + if (elsebody) + result |= elsebody->blockExit(); + else + result |= BEfallthru; + } + else + { + if (ifbody) + result |= ifbody->blockExit(); + else + result |= BEfallthru; + if (elsebody) + result |= elsebody->blockExit(); + else + result |= BEfallthru; + } + //printf("IfStatement::blockExit(%p) = x%x\n", this, result); + return result; +} + + +void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("if ("); + if (arg) + { + if (arg->type) + arg->type->toCBuffer(buf, arg->ident, hgs); + else + { buf->writestring("auto "); + buf->writestring(arg->ident->toChars()); + } + buf->writestring(" = "); + } + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + ifbody->toCBuffer(buf, hgs); + if (elsebody) + { buf->writestring("else"); + buf->writenl(); + elsebody->toCBuffer(buf, hgs); + } +} + +/******************************** ConditionalStatement ***************************/ + +ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) + : Statement(loc) +{ + this->condition = condition; + this->ifbody = ifbody; + this->elsebody = elsebody; +} + +Statement *ConditionalStatement::syntaxCopy() +{ + Statement *e = NULL; + if (elsebody) + e = elsebody->syntaxCopy(); + ConditionalStatement *s = new ConditionalStatement(loc, + condition->syntaxCopy(), ifbody->syntaxCopy(), e); + return s; +} + +Statement *ConditionalStatement::semantic(Scope *sc) +{ + //printf("ConditionalStatement::semantic()\n"); + + // If we can short-circuit evaluate the if statement, don't do the + // semantic analysis of the skipped code. + // This feature allows a limited form of conditional compilation. + if (condition->include(sc, NULL)) + { + ifbody = ifbody->semantic(sc); + return ifbody; + } + else + { + if (elsebody) + elsebody = elsebody->semantic(sc); + return elsebody; + } +} + +Statements *ConditionalStatement::flatten(Scope *sc) +{ + Statement *s; + + if (condition->include(sc, NULL)) + s = ifbody; + else + s = elsebody; + + Statements *a = new Statements(); + a->push(s); + return a; +} + +int ConditionalStatement::usesEH() +{ + return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); +} + +int ConditionalStatement::blockExit() +{ + int result = ifbody->blockExit(); + if (elsebody) + result |= elsebody->blockExit(); + return result; +} + +void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + if (ifbody) + ifbody->toCBuffer(buf, hgs); + buf->writeByte('}'); + buf->writenl(); + if (elsebody) + { + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + elsebody->toCBuffer(buf, hgs); + buf->writeByte('}'); + buf->writenl(); + } + buf->writenl(); +} + + +/******************************** PragmaStatement ***************************/ + +PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) + : Statement(loc) +{ + this->ident = ident; + this->args = args; + this->body = body; +} + +Statement *PragmaStatement::syntaxCopy() +{ + Statement *b = NULL; + if (body) + b = body->syntaxCopy(); + PragmaStatement *s = new PragmaStatement(loc, + ident, Expression::arraySyntaxCopy(args), b); + return s; +} + +Statement *PragmaStatement::semantic(Scope *sc) +{ // Should be merged with PragmaDeclaration + //printf("PragmaStatement::semantic() %s\n", toChars()); + //printf("body = %p\n", body); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); + } + else + error("string expected for message, not '%s'", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + } + else if (ident == Id::lib) + { +#if 1 + /* Should this be allowed? + */ + error("pragma(lib) not allowed as statement"); +#else + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } +#endif + } + + // LDC + else if (ident == Id::allow_inline) + { + sc->func->allowInlining = true; + } + + else if (ident == Id::startaddress) + { + if (!args || args->dim != 1) + error("function name expected for start address"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + Dsymbol *sa = getDsymbol(e); + if (!sa || !sa->isFuncDeclaration()) + error("function name expected for start address, not '%s'", e->toChars()); + if (body) + { + body = body->semantic(sc); + } + return this; + } + } + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (body) + { + body = body->semantic(sc); + } + return body; +} + +int PragmaStatement::usesEH() +{ + return body && body->usesEH(); +} + +int PragmaStatement::blockExit() +{ + int result = BEfallthru; +#if 0 // currently, no code is generated for Pragma's, so it's just fallthru + if (arrayExpressionCanThrow(args)) + result |= BEthrow; + if (body) + result |= body->blockExit(); +#endif + return result; +} + + +void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("pragma ("); + buf->writestring(ident->toChars()); + if (args && args->dim) + { + buf->writestring(", "); + argsToCBuffer(buf, args, hgs); + } + buf->writeByte(')'); + if (body) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + + body->toCBuffer(buf, hgs); + + buf->writeByte('}'); + buf->writenl(); + } + else + { + buf->writeByte(';'); + buf->writenl(); + } +} + + +/******************************** StaticAssertStatement ***************************/ + +StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) + : Statement(sa->loc) +{ + this->sa = sa; +} + +Statement *StaticAssertStatement::syntaxCopy() +{ + StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); + return s; +} + +Statement *StaticAssertStatement::semantic(Scope *sc) +{ + sa->semantic2(sc); + return NULL; +} + +void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + sa->toCBuffer(buf, hgs); +} + + +/******************************** SwitchStatement ***************************/ + +SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b) + : Statement(loc) +{ + condition = c; + body = b; + sdefault = NULL; + cases = NULL; + hasNoDefault = 0; + hasVars = 0; + // LDC + enclosingScopeExit = NULL; +} + +Statement *SwitchStatement::syntaxCopy() +{ + SwitchStatement *s = new SwitchStatement(loc, + condition->syntaxCopy(), body->syntaxCopy()); + return s; +} + +Statement *SwitchStatement::semantic(Scope *sc) +{ + //printf("SwitchStatement::semantic(%p)\n", this); + assert(!cases); // ensure semantic() is only run once + + // LDC + enclosingScopeExit = sc->enclosingScopeExit; + + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + if (condition->type->isString()) + { + // If it's not an array, cast it to one + if (condition->type->ty != Tarray) + { + condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); + } + condition->type = condition->type->constOf(); + } + else + { condition = condition->integralPromotions(sc); + condition->checkIntegral(); + } + condition = condition->optimize(WANTvalue); + + sc = sc->push(); + sc->sbreak = this; + sc->sw = this; + + cases = new Array(); + sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead + body = body->semantic(sc); + sc->noctor--; + + // Resolve any goto case's with exp + for (int i = 0; i < gotoCases.dim; i++) + { + GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; + + if (!gcs->exp) + { + gcs->error("no case statement following goto case;"); + break; + } + + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (!scx->sw) + continue; + for (int j = 0; j < scx->sw->cases->dim; j++) + { + CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; + + if (cs->exp->equals(gcs->exp)) + { + gcs->cs = cs; + goto Lfoundcase; + } + } + } + gcs->error("case %s not found", gcs->exp->toChars()); + + Lfoundcase: + ; + } + + if (!sc->sw->sdefault) + { hasNoDefault = 1; + + warning("switch statement has no default"); + + // Generate runtime error if the default is hit + Statements *a = new Statements(); + CompoundStatement *cs; + Statement *s; + + if (global.params.useSwitchError) + s = new SwitchErrorStatement(loc); + else + { Expression *e = new HaltExp(loc); + s = new ExpStatement(loc, e); + } + + a->reserve(4); + a->push(body); + + // LDC needs semantic to be run on break + Statement *breakstmt = new BreakStatement(loc, NULL); + breakstmt->semantic(sc); + a->push(breakstmt); + + sc->sw->sdefault = new DefaultStatement(loc, s); + a->push(sc->sw->sdefault); + cs = new CompoundStatement(loc, a); + body = cs; + } + + sc->pop(); + return this; +} + +int SwitchStatement::hasBreak() +{ + return TRUE; +} + +int SwitchStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int SwitchStatement::blockExit() +{ int result = BEnone; + if (condition->canThrow()) + result |= BEthrow; + + if (body) + { result |= body->blockExit(); + if (result & BEbreak) + { result |= BEfallthru; + result &= ~BEbreak; + } + } + else + result |= BEfallthru; + + return result; +} + + +void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("switch ("); + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + if (body) + { + if (!body->isScopeStatement()) + { buf->writebyte('{'); + buf->writenl(); + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); + } + else + { + body->toCBuffer(buf, hgs); + } + } +} + +/******************************** CaseStatement ***************************/ + +CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) + : Statement(loc) +{ + this->exp = exp; + this->statement = s; + index = 0; + cblock = NULL; + bodyBB = NULL; + llvmIdx = NULL; + // LDC + enclosingScopeExit = NULL; +} + +Statement *CaseStatement::syntaxCopy() +{ + CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); + return s; +} + +Statement *CaseStatement::semantic(Scope *sc) +{ SwitchStatement *sw = sc->sw; + + //printf("CaseStatement::semantic() %s\n", toChars()); + exp = exp->semantic(sc); + if (sw) + { + // LDC + enclosingScopeExit = sc->enclosingScopeExit; + if (enclosingScopeExit != sw->enclosingScopeExit) + { + error("case must be inside the same try, synchronized or volatile level as switch"); + } + + exp = exp->implicitCastTo(sc, sw->condition->type); + exp = exp->optimize(WANTvalue | WANTinterpret); + + /* This is where variables are allowed as case expressions. + */ + if (exp->op == TOKvar) + { VarExp *ve = (VarExp *)exp; + VarDeclaration *v = ve->var->isVarDeclaration(); + Type *t = exp->type->toBasetype(); + if (v && (t->isintegral() || t->ty == Tclass)) + { /* Flag that we need to do special code generation + * for this, i.e. generate a sequence of if-then-else + */ + sw->hasVars = 1; + goto L1; + } + } + + if (exp->op != TOKstring && exp->op != TOKint64) + { + error("case must be a string or an integral constant, not %s", exp->toChars()); + exp = new IntegerExp(0); + } + + L1: + for (int i = 0; i < sw->cases->dim; i++) + { + CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; + + //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); + if (cs->exp->equals(exp)) + { error("duplicate case %s in switch statement", exp->toChars()); + break; + } + } + + sw->cases->push(this); + + // Resolve any goto case's with no exp to this case statement + for (int i = 0; i < sw->gotoCases.dim; i++) + { + GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; + + if (!gcs->exp) + { + gcs->cs = this; + sw->gotoCases.remove(i); // remove from array + } + } +#if IN_DMD + if (sc->sw->tf != sc->tf) + error("switch and case are in different finally blocks"); +#endif + } + else + error("case not in switch statement"); + statement = statement->semantic(sc); + return this; +} + +int CaseStatement::compare(Object *obj) +{ + // Sort cases so we can do an efficient lookup + CaseStatement *cs2 = (CaseStatement *)(obj); + + return exp->compare(cs2->exp); +} + +int CaseStatement::usesEH() +{ + return statement->usesEH(); +} + +int CaseStatement::blockExit() +{ + return statement->blockExit(); +} + + +int CaseStatement::comeFrom() +{ + return TRUE; +} + +void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("case "); + exp->toCBuffer(buf, hgs); + buf->writebyte(':'); + buf->writenl(); + statement->toCBuffer(buf, hgs); +} + +/******************************** DefaultStatement ***************************/ + +DefaultStatement::DefaultStatement(Loc loc, Statement *s) + : Statement(loc) +{ + this->statement = s; +#if IN_GCC ++ cblock = NULL; +#endif + bodyBB = NULL; + // LDC + enclosingScopeExit = NULL; +} + +Statement *DefaultStatement::syntaxCopy() +{ + DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); + return s; +} + +Statement *DefaultStatement::semantic(Scope *sc) +{ + //printf("DefaultStatement::semantic()\n"); + if (sc->sw) + { + if (sc->sw->sdefault) + { + error("switch statement already has a default"); + } + sc->sw->sdefault = this; + + // LDC + enclosingScopeExit = sc->enclosingScopeExit; + if (enclosingScopeExit != sc->sw->enclosingScopeExit) + { + error("default must be inside the same try, synchronized or volatile level as switch"); + } + } + else + error("default not in switch statement"); + statement = statement->semantic(sc); + return this; +} + +int DefaultStatement::usesEH() +{ + return statement->usesEH(); +} + +int DefaultStatement::blockExit() +{ + return statement->blockExit(); +} + + +int DefaultStatement::comeFrom() +{ + return TRUE; +} + +void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("default:\n"); + statement->toCBuffer(buf, hgs); +} + +/******************************** GotoDefaultStatement ***************************/ + +GotoDefaultStatement::GotoDefaultStatement(Loc loc) + : Statement(loc) +{ + sw = NULL; +} + +Statement *GotoDefaultStatement::syntaxCopy() +{ + GotoDefaultStatement *s = new GotoDefaultStatement(loc); + return s; +} + +Statement *GotoDefaultStatement::semantic(Scope *sc) +{ + sw = sc->sw; + if (!sw) + error("goto default not in switch statement"); + return this; +} + +int GotoDefaultStatement::blockExit() +{ + return BEgoto; +} + + +void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("goto default;\n"); +} + +/******************************** GotoCaseStatement ***************************/ + +GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + cs = NULL; + this->exp = exp; + sw = NULL; +} + +Statement *GotoCaseStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + GotoCaseStatement *s = new GotoCaseStatement(loc, e); + return s; +} + +Statement *GotoCaseStatement::semantic(Scope *sc) +{ + if (exp) + exp = exp->semantic(sc); + + if (!sc->sw) + error("goto case not in switch statement"); + else + { + sw = sc->sw; + sc->sw->gotoCases.push(this); + if (exp) + { + exp = exp->implicitCastTo(sc, sc->sw->condition->type); + exp = exp->optimize(WANTvalue); + } + } + return this; +} + +int GotoCaseStatement::blockExit() +{ + return BEgoto; +} + + +void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("goto case"); + if (exp) + { buf->writebyte(' '); + exp->toCBuffer(buf, hgs); + } + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** SwitchErrorStatement ***************************/ + +SwitchErrorStatement::SwitchErrorStatement(Loc loc) + : Statement(loc) +{ +} + +int SwitchErrorStatement::blockExit() +{ + return BEthrow; +} + + +void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("SwitchErrorStatement::toCBuffer()"); + buf->writenl(); +} + +/******************************** ReturnStatement ***************************/ + +ReturnStatement::ReturnStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ReturnStatement::syntaxCopy() +{ + Expression *e = NULL; + if (exp) + e = exp->syntaxCopy(); + ReturnStatement *s = new ReturnStatement(loc, e); + return s; +} + +Statement *ReturnStatement::semantic(Scope *sc) +{ + //printf("ReturnStatement::semantic() %s\n", toChars()); + + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + Scope *scx = sc; + int implicit0 = 0; + + if (sc->fes) + { + // Find scope of function foreach is in + for (; 1; scx = scx->enclosing) + { + assert(scx); + if (scx->func != fd) + { fd = scx->func; // fd is now function enclosing foreach + break; + } + } + } + + Type *tret = fd->type->nextOf(); + if (fd->tintro) + /* We'll be implicitly casting the return expression to tintro + */ + tret = fd->tintro->nextOf(); + Type *tbret = NULL; + + if (tret) + tbret = tret->toBasetype(); + + // main() returns 0, even if it returns void + if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) + { implicit0 = 1; + exp = new IntegerExp(0); + } + + if (sc->incontract || scx->incontract) + error("return statements cannot be in contracts"); + if (sc->enclosingFinally || scx->enclosingFinally) + error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); + + if (fd->isCtorDeclaration()) + { + // Constructors implicitly do: + // return this; + if (exp && exp->op != TOKthis) + error("cannot return expression from constructor"); + exp = new ThisExp(0); + } + + if (!exp) + fd->nrvo_can = 0; + + if (exp) + { + fd->hasReturnExp |= 1; + + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue); + + if (fd->nrvo_can && exp->op == TOKvar) + { VarExp *ve = (VarExp *)exp; + VarDeclaration *v = ve->var->isVarDeclaration(); + + if (((TypeFunction *)fd->type)->isref) + // Function returns a reference + fd->nrvo_can = 0; + else if (!v || v->isOut() || v->isRef()) + fd->nrvo_can = 0; + else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor) + // Struct being returned has destructors + fd->nrvo_can = 0; + else if (fd->nrvo_var == NULL) + { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) + { //printf("Setting nrvo to %s\n", v->toChars()); + fd->nrvo_var = v; + } + else + fd->nrvo_can = 0; + } + else if (fd->nrvo_var != v) + fd->nrvo_can = 0; + } + else + fd->nrvo_can = 0; + + if (fd->returnLabel && tbret->ty != Tvoid) + { + } + else if (fd->inferRetType) + { + if (fd->type->nextOf()) + { + if (!exp->type->equals(fd->type->nextOf())) + error("mismatched function return type inference of %s and %s", + exp->type->toChars(), fd->type->nextOf()->toChars()); + } + else + { + ((TypeFunction *)fd->type)->next = exp->type; + fd->type = fd->type->semantic(loc, sc); + if (!fd->tintro) + { tret = fd->type->nextOf(); + tbret = tret->toBasetype(); + } + } + } + else if (tbret->ty != Tvoid) + { + exp = exp->implicitCastTo(sc, tret); + exp = exp->optimize(WANTvalue); + } + } + else if (fd->inferRetType) + { + if (fd->type->nextOf()) + { + if (fd->type->nextOf()->ty != Tvoid) + error("mismatched function return type inference of void and %s", + fd->type->nextOf()->toChars()); + } + else + { + ((TypeFunction *)fd->type)->next = Type::tvoid; + fd->type = fd->type->semantic(loc, sc); + if (!fd->tintro) + { tret = Type::tvoid; + tbret = tret; + } + } + } + else if (tbret->ty != Tvoid) // if non-void return + error("return expression expected"); + + if (sc->fes) + { + Statement *s; + + if (exp && !implicit0) + { + exp = exp->implicitCastTo(sc, tret); + } + if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || + exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || + exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || + exp->op == TOKstring) + { + sc->fes->cases.push(this); + // Construct: return cases.dim+1; + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + } + else if (fd->type->nextOf()->toBasetype() == Type::tvoid) + { + s = new ReturnStatement(0, NULL); + sc->fes->cases.push(s); + + // Construct: { exp; return cases.dim + 1; } + Statement *s1 = new ExpStatement(loc, exp); + Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + else + { + // Construct: return vresult; + if (!fd->vresult) + { // Declare vresult + VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); + v->noauto = 1; + v->semantic(scx); + if (!scx->insert(v)) + assert(0); + v->parent = fd; + fd->vresult = v; + } + + s = new ReturnStatement(0, new VarExp(0, fd->vresult)); + sc->fes->cases.push(s); + + // Construct: { vresult = exp; return cases.dim + 1; } + exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp); + exp = exp->semantic(sc); + Statement *s1 = new ExpStatement(loc, exp); + Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + return s; + } + + if (exp) + { + if (fd->returnLabel && tbret->ty != Tvoid) + { + assert(fd->vresult); + VarExp *v = new VarExp(0, fd->vresult); + + exp = new AssignExp(loc, v, exp); + exp = exp->semantic(sc); + } + + if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration()) + { // Function returns a reference + if (tbret->isMutable()) + exp = exp->modifiableLvalue(sc, exp); + else + exp = exp->toLvalue(sc, exp); + + if (exp->op == TOKvar) + { VarExp *ve = (VarExp *)exp; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && !v->isDataseg() && !(v->storage_class & (STCref | STCout))) + error("escaping reference to local variable %s", v->toChars()); + } + } + + //exp->dump(0); + //exp->print(); + exp->checkEscape(); + } + + /* BUG: need to issue an error on: + * this + * { if (x) return; + * super(); + * } + */ + + if (sc->callSuper & CSXany_ctor && + !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) + error("return without calling constructor"); + + sc->callSuper |= CSXreturn; + + // See if all returns are instead to be replaced with a goto returnLabel; + if (fd->returnLabel) + { + GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); + + gs->label = fd->returnLabel; + if (exp) + { /* Replace: return exp; + * with: exp; goto returnLabel; + */ + Statement *s = new ExpStatement(0, exp); + return new CompoundStatement(loc, s, gs); + } + return gs; + } + + if (exp && tbret->ty == Tvoid && !fd->isMain()) + { + /* Replace: + * return exp; + * with: + * exp; return; + */ + Statement *s = new ExpStatement(loc, exp); + loc = 0; + exp = NULL; + return new CompoundStatement(loc, s, this); + } + + return this; +} + +int ReturnStatement::blockExit() +{ int result = BEreturn; + + if (exp && exp->canThrow()) + result |= BEthrow; + return result; +} + + +void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("return "); + if (exp) + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + buf->writenl(); +} + +/******************************** BreakStatement ***************************/ + +BreakStatement::BreakStatement(Loc loc, Identifier *ident) + : Statement(loc) +{ + this->ident = ident; +} + +Statement *BreakStatement::syntaxCopy() +{ + BreakStatement *s = new BreakStatement(loc, ident); + return s; +} + +Statement *BreakStatement::semantic(Scope *sc) +{ + //printf("BreakStatement::semantic()\n"); + // If: + // break Identifier; + if (ident) + { + Scope *scx; + FuncDeclaration *thisfunc = sc->func; + + for (scx = sc; scx; scx = scx->enclosing) + { + LabelStatement *ls; + + if (scx->func != thisfunc) // if in enclosing function + { + if (sc->fes) // if this is the body of a foreach + { + /* Post this statement to the fes, and replace + * it with a return value that caller will put into + * a switch. Caller will figure out where the break + * label actually is. + * Case numbers start with 2, not 0, as 0 is continue + * and 1 is break. + */ + Statement *s; + sc->fes->cases.push(this); + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + return s; + } + break; // can't break to it + } + + ls = scx->slabel; + if (ls && ls->ident == ident) + { + Statement *s = ls->statement; + + if (!s->hasBreak()) + error("label '%s' has no break", ident->toChars()); + if (ls->enclosingFinally != sc->enclosingFinally) + error("cannot break out of finally block"); + + this->target = ls; + return this; + } + } + error("enclosing label '%s' for break not found", ident->toChars()); + } + else if (!sc->sbreak) + { + if (sc->fes) + { Statement *s; + + // Replace break; with return 1; + s = new ReturnStatement(0, new IntegerExp(1)); + return s; + } + error("break is not inside a loop or switch"); + } + return this; +} + +int BreakStatement::blockExit() +{ + //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); + return ident ? BEgoto : BEbreak; +} + + +void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("break"); + if (ident) + { buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** ContinueStatement ***************************/ + +ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) + : Statement(loc) +{ + this->ident = ident; +} + +Statement *ContinueStatement::syntaxCopy() +{ + ContinueStatement *s = new ContinueStatement(loc, ident); + return s; +} + +Statement *ContinueStatement::semantic(Scope *sc) +{ + //printf("ContinueStatement::semantic() %p\n", this); + if (ident) + { + Scope *scx; + FuncDeclaration *thisfunc = sc->func; + + for (scx = sc; scx; scx = scx->enclosing) + { + LabelStatement *ls; + + if (scx->func != thisfunc) // if in enclosing function + { + if (sc->fes) // if this is the body of a foreach + { + for (; scx; scx = scx->enclosing) + { + ls = scx->slabel; + if (ls && ls->ident == ident && ls->statement == sc->fes) + { + // Replace continue ident; with return 0; + return new ReturnStatement(0, new IntegerExp(0)); + } + } + + /* Post this statement to the fes, and replace + * it with a return value that caller will put into + * a switch. Caller will figure out where the break + * label actually is. + * Case numbers start with 2, not 0, as 0 is continue + * and 1 is break. + */ + Statement *s; + sc->fes->cases.push(this); + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); + return s; + } + break; // can't continue to it + } + + ls = scx->slabel; + if (ls && ls->ident == ident) + { + Statement *s = ls->statement; + + if (!s->hasContinue()) + error("label '%s' has no continue", ident->toChars()); + if (ls->enclosingFinally != sc->enclosingFinally) + error("cannot continue out of finally block"); + + this->target = ls; + return this; + } + } + error("enclosing label '%s' for continue not found", ident->toChars()); + } + else if (!sc->scontinue) + { + if (sc->fes) + { Statement *s; + + // Replace continue; with return 0; + s = new ReturnStatement(0, new IntegerExp(0)); + return s; + } + error("continue is not inside a loop"); + } + return this; +} + +int ContinueStatement::blockExit() +{ + return ident ? BEgoto : BEcontinue; +} + + +void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("continue"); + if (ident) + { buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** SynchronizedStatement ***************************/ + +SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) + : Statement(loc) +{ + this->exp = exp; + this->body = body; + this->esync = NULL; + // LDC + this->llsync = NULL; +} + +SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) + : Statement(loc) +{ + this->exp = NULL; + this->body = body; + this->esync = esync; + // LDC + this->llsync = NULL; +} + +Statement *SynchronizedStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *SynchronizedStatement::semantic(Scope *sc) +{ + if (exp) + { ClassDeclaration *cd; + + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + cd = exp->type->isClassHandle(); + if (!cd) + error("can only synchronize on class objects, not '%s'", exp->type->toChars()); + else if (cd->isInterfaceDeclaration()) + { Type *t = new TypeIdentifier(0, Id::Object); + + t = t->semantic(0, sc); + exp = new CastExp(loc, exp, t); + exp = exp->semantic(sc); + } + } + if (body) + { + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + body = body->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; + } + return this; +} + +int SynchronizedStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int SynchronizedStatement::hasContinue() +{ + return FALSE; //TRUE; +} + +int SynchronizedStatement::usesEH() +{ + return TRUE; +} + +int SynchronizedStatement::blockExit() +{ + return body ? body->blockExit() : BEfallthru; +} + + +void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("synchronized"); + if (exp) + { buf->writebyte('('); + exp->toCBuffer(buf, hgs); + buf->writebyte(')'); + } + if (body) + { + buf->writebyte(' '); + body->toCBuffer(buf, hgs); + } +} + +/******************************** WithStatement ***************************/ + +WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) + : Statement(loc) +{ + this->exp = exp; + this->body = body; + wthis = NULL; +} + +Statement *WithStatement::syntaxCopy() +{ + WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *WithStatement::semantic(Scope *sc) +{ ScopeDsymbol *sym; + Initializer *init; + + //printf("WithStatement::semantic()\n"); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + if (exp->op == TOKimport) + { ScopeExp *es = (ScopeExp *)exp; + + sym = es->sds; + } + else if (exp->op == TOKtype) + { TypeExp *es = (TypeExp *)exp; + + sym = es->type->toDsymbol(sc)->isScopeDsymbol(); + if (!sym) + { error("%s has no members", es->toChars()); + body = body->semantic(sc); + return this; + } + } + else + { Type *t = exp->type; + + assert(t); + t = t->toBasetype(); + if (t->isClassHandle()) + { + init = new ExpInitializer(loc, exp); + wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); + wthis->semantic(sc); + + sym = new WithScopeSymbol(this); + sym->parent = sc->scopesym; + } + else if (t->ty == Tstruct) + { + Expression *e = exp->addressOf(sc); + init = new ExpInitializer(loc, e); + wthis = new VarDeclaration(loc, e->type, Id::withSym, init); + wthis->semantic(sc); + sym = new WithScopeSymbol(this); + sym->parent = sc->scopesym; + } + else + { error("with expressions must be class objects, not '%s'", exp->type->toChars()); + return NULL; + } + } + sc = sc->push(sym); + + if (body) + body = body->semantic(sc); + + sc->pop(); + + return this; +} + +void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("with ("); + exp->toCBuffer(buf, hgs); + buf->writestring(")\n"); + if (body) + body->toCBuffer(buf, hgs); +} + +int WithStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int WithStatement::blockExit() +{ + int result = BEnone; + if (exp->canThrow()) + result = BEthrow; + if (body) + result |= body->blockExit(); + else + result |= BEfallthru; + return result; +} + + +/******************************** TryCatchStatement ***************************/ + +TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) + : Statement(loc) +{ + this->body = body; + this->catches = catches; +} + +Statement *TryCatchStatement::syntaxCopy() +{ + Array *a = new Array(); + a->setDim(catches->dim); + for (int i = 0; i < a->dim; i++) + { Catch *c; + + c = (Catch *)catches->data[i]; + c = c->syntaxCopy(); + a->data[i] = c; + } + TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); + return s; +} + +Statement *TryCatchStatement::semantic(Scope *sc) +{ + body = body->semanticScope(sc, NULL /*this*/, NULL); + + /* Even if body is NULL, still do semantic analysis on catches + */ + for (size_t i = 0; i < catches->dim; i++) + { Catch *c = (Catch *)catches->data[i]; + c->semantic(sc); + + // Determine if current catch 'hides' any previous catches + for (size_t j = 0; j < i; j++) + { Catch *cj = (Catch *)catches->data[j]; + char *si = c->loc.toChars(); + char *sj = cj->loc.toChars(); + + if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) + error("catch at %s hides catch at %s", sj, si); + } + } + + if (!body) + return NULL; + + return this; +} + +int TryCatchStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int TryCatchStatement::usesEH() +{ + return TRUE; +} + +int TryCatchStatement::blockExit() +{ + assert(body); + int result = body->blockExit(); + + int catchresult = 0; + for (size_t i = 0; i < catches->dim; i++) + { + Catch *c = (Catch *)catches->data[i]; + catchresult |= c->blockExit(); + + /* If we're catching Object, then there is no throwing + */ + Identifier *id = c->type->toBasetype()->isClassHandle()->ident; + if (i == 0 && + (id == Id::Object || id == Id::Throwable || id == Id::Exception)) + { + result &= ~BEthrow; + } + } + return result | catchresult; +} + + +void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("try"); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + for (size_t i = 0; i < catches->dim; i++) + { + Catch *c = (Catch *)catches->data[i]; + c->toCBuffer(buf, hgs); + } +} + +/******************************** Catch ***************************/ + +Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) +{ + //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); + this->loc = loc; + this->type = t; + this->ident = id; + this->handler = handler; + var = NULL; +} + +Catch *Catch::syntaxCopy() +{ + Catch *c = new Catch(loc, + (type ? type->syntaxCopy() : NULL), + ident, + (handler ? handler->syntaxCopy() : NULL)); + return c; +} + +void Catch::semantic(Scope *sc) +{ ScopeDsymbol *sym; + + //printf("Catch::semantic(%s)\n", ident->toChars()); + +#ifndef IN_GCC + if (sc->enclosingFinally) + { + /* This is because the _d_local_unwind() gets the stack munged + * up on this. The workaround is to place any try-catches into + * a separate function, and call that. + * To fix, have the compiler automatically convert the finally + * body into a nested function. + */ + error(loc, "cannot put catch statement inside finally block"); + } +#endif + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + if (!type) + type = new TypeIdentifier(0, Id::Object); + type = type->semantic(loc, sc); + if (!type->toBasetype()->isClassHandle()) + error("can only catch class objects, not '%s'", type->toChars()); + else if (ident) + { + var = new VarDeclaration(loc, type, ident, NULL); + var->parent = sc->parent; + sc->insert(var); + } + handler = handler->semantic(sc); + + sc->pop(); +} + +int Catch::blockExit() +{ + return handler ? handler->blockExit() : BEfallthru; +} + +void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("catch"); + if (type) + { buf->writebyte('('); + type->toCBuffer(buf, ident, hgs); + buf->writebyte(')'); + } + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (handler) + handler->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/****************************** TryFinallyStatement ***************************/ + +TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) + : Statement(loc) +{ + this->body = body; + this->finalbody = finalbody; +} + +Statement *TryFinallyStatement::syntaxCopy() +{ + TryFinallyStatement *s = new TryFinallyStatement(loc, + body->syntaxCopy(), finalbody->syntaxCopy()); + return s; +} + +Statement *TryFinallyStatement::semantic(Scope *sc) +{ + //printf("TryFinallyStatement::semantic()\n"); + + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + body = body->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; + + sc = sc->push(); + sc->enclosingFinally = this; + sc->sbreak = NULL; + sc->scontinue = NULL; // no break or continue out of finally block + finalbody = finalbody->semantic(sc); + sc->pop(); + if (!body) + return finalbody; + if (!finalbody) + return body; + if (body->blockExit() == BEfallthru) + { Statement *s = new CompoundStatement(loc, body, finalbody); + return s; + } + return this; +} + +void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("try\n{\n"); + body->toCBuffer(buf, hgs); + buf->printf("}\nfinally\n{\n"); + finalbody->toCBuffer(buf, hgs); + buf->writeByte('}'); + buf->writenl(); +} + +int TryFinallyStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int TryFinallyStatement::hasContinue() +{ + return FALSE; //TRUE; +} + +int TryFinallyStatement::usesEH() +{ + return TRUE; +} + +int TryFinallyStatement::blockExit() +{ + if (body) + return body->blockExit(); + return BEfallthru; +} + + +/****************************** OnScopeStatement ***************************/ + +OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) + : Statement(loc) +{ + this->tok = tok; + this->statement = statement; +} + +Statement *OnScopeStatement::syntaxCopy() +{ + OnScopeStatement *s = new OnScopeStatement(loc, + tok, statement->syntaxCopy()); + return s; +} + +Statement *OnScopeStatement::semantic(Scope *sc) +{ + /* semantic is called on results of scopeCode() */ + return this; +} + +int OnScopeStatement::blockExit() +{ // At this point, this statement is just an empty placeholder + return BEfallthru; +} + +void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(tok)); + buf->writebyte(' '); + statement->toCBuffer(buf, hgs); +} + +int OnScopeStatement::usesEH() +{ + return 1; +} + +void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("OnScopeStatement::scopeCode()\n"); + //print(); + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + switch (tok) + { + case TOKon_scope_exit: + *sfinally = statement; + break; + + case TOKon_scope_failure: + *sexception = statement; + break; + + case TOKon_scope_success: + { + /* Create: + * sentry: int x = 0; + * sexception: x = 1; + * sfinally: if (!x) statement; + */ + Identifier *id = Lexer::uniqueId("__os"); + + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); + VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); + *sentry = new DeclarationStatement(loc, v); + + Expression *e = new IntegerExp(1); + e = new AssignExp(0, new VarExp(0, v), e); + *sexception = new ExpStatement(0, e); + + e = new VarExp(0, v); + e = new NotExp(0, e); + *sfinally = new IfStatement(0, NULL, e, statement, NULL); + + break; + } + + default: + assert(0); + } +} + +/******************************** ThrowStatement ***************************/ + +ThrowStatement::ThrowStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ThrowStatement::syntaxCopy() +{ + ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); + return s; +} + +Statement *ThrowStatement::semantic(Scope *sc) +{ + //printf("ThrowStatement::semantic()\n"); + + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + fd->hasReturnExp |= 2; + + if (sc->incontract) + error("Throw statements cannot be in contracts"); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + if (!exp->type->toBasetype()->isClassHandle()) + error("can only throw class objects, not type %s", exp->type->toChars()); + return this; +} + +int ThrowStatement::blockExit() +{ + return BEthrow; // obviously +} + + +void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("throw "); + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + buf->writenl(); +} + +/******************************** VolatileStatement **************************/ + +VolatileStatement::VolatileStatement(Loc loc, Statement *statement) + : Statement(loc) +{ + this->statement = statement; +} + +Statement *VolatileStatement::syntaxCopy() +{ + VolatileStatement *s = new VolatileStatement(loc, + statement ? statement->syntaxCopy() : NULL); + return s; +} + +Statement *VolatileStatement::semantic(Scope *sc) +{ + if (statement) + { + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + statement = statement->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; + } + return this; +} + +Statements *VolatileStatement::flatten(Scope *sc) +{ + Statements *a; + + a = statement ? statement->flatten(sc) : NULL; + if (a) + { for (int i = 0; i < a->dim; i++) + { Statement *s = (Statement *)a->data[i]; + + s = new VolatileStatement(loc, s); + a->data[i] = s; + } + } + + return a; +} + +int VolatileStatement::blockExit() +{ + return statement ? statement->blockExit() : BEfallthru; +} + + +void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("volatile"); + if (statement) + { if (statement->isScopeStatement()) + buf->writenl(); + else + buf->writebyte(' '); + statement->toCBuffer(buf, hgs); + } +} + + +/******************************** GotoStatement ***************************/ + +GotoStatement::GotoStatement(Loc loc, Identifier *ident) + : Statement(loc) +{ + this->ident = ident; + this->label = NULL; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; +} + +Statement *GotoStatement::syntaxCopy() +{ + GotoStatement *s = new GotoStatement(loc, ident); + return s; +} + +Statement *GotoStatement::semantic(Scope *sc) +{ FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + + //printf("GotoStatement::semantic()\n"); + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; + + label = fd->searchLabel(ident); + if (!label->statement && sc->fes) + { + /* Either the goto label is forward referenced or it + * is in the function that the enclosing foreach is in. + * Can't know yet, so wrap the goto in a compound statement + * so we can patch it later, and add it to a 'look at this later' + * list. + */ + Statements *a = new Statements(); + Statement *s; + + a->push(this); + s = new CompoundStatement(loc, a); + sc->fes->gotos.push(s); // 'look at this later' list + return s; + } + if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) + error("cannot goto in or out of finally block"); + return this; +} + +int GotoStatement::blockExit() +{ + //printf("GotoStatement::blockExit(%p)\n", this); + return BEgoto; +} + + +void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("goto "); + buf->writestring(ident->toChars()); + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** LabelStatement ***************************/ + +LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) + : Statement(loc) +{ + this->ident = ident; + this->statement = statement; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; + this->lblock = NULL; + this->isReturnLabel = 0; + this->asmLabel = false; +} + +Statement *LabelStatement::syntaxCopy() +{ + LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); + return s; +} + +Statement *LabelStatement::semantic(Scope *sc) +{ LabelDsymbol *ls; + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + + //printf("LabelStatement::semantic()\n"); + ls = fd->searchLabel(ident); + if (ls->statement) + error("Label '%s' already defined", ls->toChars()); + else + ls->statement = this; + + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; + + sc = sc->push(); + sc->scopesym = sc->enclosing->scopesym; + sc->callSuper |= CSXlabel; + sc->slabel = this; + if (statement) + statement = statement->semantic(sc); + sc->pop(); + + // LDC put in labmap + fd->labmap[ident->toChars()] = this; + + return this; +} + +Statements *LabelStatement::flatten(Scope *sc) +{ + Statements *a = NULL; + + if (statement) + { + a = statement->flatten(sc); + if (a) + { + if (!a->dim) + { + a->push(new ExpStatement(loc, NULL)); + } + Statement *s = (Statement *)a->data[0]; + + s = new LabelStatement(loc, ident, s); + a->data[0] = s; + } + } + + return a; +} + + +int LabelStatement::usesEH() +{ + return statement ? statement->usesEH() : FALSE; +} + +int LabelStatement::blockExit() +{ + //printf("LabelStatement::blockExit(%p)\n", this); + return statement ? statement->blockExit() : BEfallthru; +} + + +int LabelStatement::comeFrom() +{ + //printf("LabelStatement::comeFrom()\n"); + return TRUE; +} + +void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + buf->writebyte(':'); + buf->writenl(); + if (statement) + statement->toCBuffer(buf, hgs); +} + + +/******************************** LabelDsymbol ***************************/ + +LabelDsymbol::LabelDsymbol(Identifier *ident) + : Dsymbol(ident) +{ + statement = NULL; +#if IN_GCC + asmLabelNum = 0; +#endif +} + +LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? +{ + return this; +}