/d/dmd/statement.c
C | 4560 lines | 3578 code | 633 blank | 349 comment | 668 complexity | 8cffde6f3962fa6c60ceb278ef036e82 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- // Compiler implementation of the D programming language
- // Copyright (c) 1999-2011 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.
- /* NOTE: This file has been patched from the original DMD distribution to
- work with the GDC compiler.
- Modified by Michael Parrott, September 2009
- Using David Friedman's code
- */
- #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"
- #if _WIN32
- #include <windows.h>
- #define CRITSECSIZE sizeof(CRITICAL_SECTION)
- #elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
- #include <pthread.h>
- #define CRITSECSIZE sizeof(pthread_mutex_t)
- #else
- #define CRITSECSIZE 64
- #endif
- /******************************** Statement ***************************/
- Statement::Statement(Loc loc)
- : loc(loc)
- {
- // If this is an in{} contract scope statement (skip for determining
- // inlineStatus of a function body for header content)
- incontract = 0;
- }
- 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;
- }
- Statement *Statement::semanticNoScope(Scope *sc)
- {
- //printf("Statement::semanticNoScope() %s\n", toChars());
- Statement *s = this;
- if (!s->isCompoundStatement() && !s->isScopeStatement())
- {
- s = new CompoundStatement(loc, this); // so scopeCode() gets called
- }
- s = s->semantic(sc);
- return s;
- }
- // Same as semanticNoScope(), but do create a new scope
- Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue)
- {
- Scope *scd = sc->push();
- if (sbreak)
- scd->sbreak = sbreak;
- if (scontinue)
- scd->scontinue = scontinue;
- Statement *s = semanticNoScope(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, ...)
- {
- 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(bool mustNotThrow)
- {
- 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;
- }
- // Return TRUE if statement has no code in it
- int Statement::isEmpty()
- {
- //printf("Statement::isEmpty()\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;
- }
- /******************************** PeelStatement ***************************/
- PeelStatement::PeelStatement(Statement *s)
- : Statement(s->loc)
- {
- this->s = s;
- }
- Statement *PeelStatement::semantic(Scope *sc)
- {
- /* "peel" off this wrapper, and don't run semantic()
- * on the result.
- */
- return s;
- }
- /******************************** ExpStatement ***************************/
- ExpStatement::ExpStatement(Loc loc, Expression *exp)
- : Statement(loc)
- {
- this->exp = exp;
- }
- ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration)
- : Statement(loc)
- {
- this->exp = new DeclarationExp(loc, declaration);
- }
- 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);
- if (exp->op != TOKdeclaration)
- { buf->writeByte(';');
- if (!hgs->FLinit.init)
- buf->writenl();
- }
- }
- else
- {
- 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);
- }
- return this;
- }
- int ExpStatement::blockExit(bool mustNotThrow)
- { 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::isEmpty()
- {
- return exp == NULL;
- }
- void ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
- {
- //printf("ExpStatement::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->callScopeDtor(sc);
- if (e)
- {
- //printf("dtor is: "); e->print();
- #if 0
- if (v->type->toBasetype()->ty == Tstruct)
- { /* Need a 'gate' to turn on/off destruction,
- * in case v gets moved elsewhere.
- */
- Identifier *id = Lexer::uniqueId("__runDtor");
- ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1));
- VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie);
- *sentry = new ExpStatement(loc, rd);
- v->rundtor = rd;
- /* Rewrite e as:
- * rundtor && e
- */
- Expression *ve = new VarExp(loc, v->rundtor);
- e = new AndAndExp(loc, ve, e);
- e->type = Type::tbool;
- }
- #endif
- *sfinally = new ExpStatement(loc, e);
- }
- }
- }
- }
- }
- /******************************** 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 == TOKerror)
- return NULL;
- StringExp *se = exp->toString();
- if (!se)
- { error("argument to mixin must be a string, not (%s)", exp->toChars());
- return NULL;
- }
- 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);
- if (s) // if no parsing errors
- 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);
- }
- /******************************** 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);
- }
- CompoundStatement::CompoundStatement(Loc loc, Statement *s1)
- : Statement(loc)
- {
- statements = new Statements();
- statements->push(s1);
- }
- 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 (size_t j = i + 1; j < statements->dim; j++)
- {
- a->push((*statements)[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 (size_t j = i + 1; j < statements->dim; j++)
- {
- a->push((*statements)[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)
- {
- return (*statements)[0];
- }
- return this;
- }
- Statements *CompoundStatement::flatten(Scope *sc)
- {
- return statements;
- }
- ReturnStatement *CompoundStatement::isReturnStatement()
- {
- ReturnStatement *rs = NULL;
- for (size_t i = 0; i < statements->dim; i++)
- { Statement *s = (*statements)[i];
- if (s)
- {
- rs = s->isReturnStatement();
- if (rs)
- break;
- }
- }
- return rs;
- }
- void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
- {
- for (size_t i = 0; i < statements->dim; i++)
- { Statement *s = (Statement *) statements->data[i];
- if (s)
- s->toCBuffer(buf, hgs);
- }
- }
- int CompoundStatement::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 CompoundStatement::blockExit(bool mustNotThrow)
- {
- //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 (s->blockExit(mustNotThrow) != BEhalt && !s->isEmpty())
- s->warning("statement is not reachable");
- }
- else
- {
- result &= ~BEfallthru;
- result |= s->blockExit(mustNotThrow);
- }
- }
- }
- return result;
- }
- int CompoundStatement::comeFrom()
- { int comefrom = FALSE;
- //printf("CompoundStatement::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;
- }
- int CompoundStatement::isEmpty()
- {
- for (size_t i = 0; i < statements->dim; i++)
- { Statement *s = (Statement *) statements->data[i];
- if (s && !s->isEmpty())
- return FALSE;
- }
- return TRUE;
- }
- /******************************** 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 (size_t i = 0; i < statements->dim; i++)
- { Statement *s = (Statement *) statements->data[i];
- ExpStatement *ds;
- if (s &&
- (ds = s->isExpStatement()) != NULL &&
- ds->exp->op == TOKdeclaration)
- {
- 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)
- {
- //printf("[%d]: %s\n", i, s->toChars());
- 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(bool mustNotThrow)
- {
- int result = BEfallthru;
- for (size_t i = 0; i < statements->dim; i++)
- { Statement *s = (Statement *) statements->data[i];
- if (s)
- {
- int r = s->blockExit(mustNotThrow);
- 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");
- sfinally = sfinally->semantic(sc);
- 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(bool mustNotThrow)
- {
- //printf("ScopeStatement::blockExit(%p)\n", statement);
- return statement ? statement->blockExit(mustNotThrow) : BEfallthru;
- }
- int ScopeStatement::comeFrom()
- {
- //printf("ScopeStatement::comeFrom()\n");
- return statement ? statement->comeFrom() : FALSE;
- }
- int ScopeStatement::isEmpty()
- {
- //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE);
- return statement ? statement->isEmpty() : TRUE;
- }
- 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)
- {
- /* Rewrite as a for(;condition;) loop
- */
- Statement *s = new ForStatement(loc, NULL, condition, NULL, body);
- s = s->semantic(sc);
- return s;
- }
- int WhileStatement::hasBreak()
- {
- return TRUE;
- }
- int WhileStatement::hasContinue()
- {
- return TRUE;
- }
- int WhileStatement::usesEH()
- {
- assert(0);
- return body ? body->usesEH() : 0;
- }
- int WhileStatement::blockExit(bool mustNotThrow)
- {
- assert(0);
- //printf("WhileStatement::blockExit(%p)\n", this);
- int result = BEnone;
- if (condition->canThrow())
- result |= BEthrow;
- if (condition->isBool(TRUE))
- {
- if (body)
- { result |= body->blockExit(mustNotThrow);
- if (result & BEbreak)
- result |= BEfallthru;
- }
- }
- else if (condition->isBool(FALSE))
- {
- result |= BEfallthru;
- }
- else
- {
- if (body)
- result |= body->blockExit(mustNotThrow);
- result |= BEfallthru;
- }
- result &= ~(BEbreak | BEcontinue);
- return result;
- }
- int WhileStatement::comeFrom()
- {
- assert(0);
- 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(bool mustNotThrow)
- { int result;
- if (body)
- { result = body->blockExit(mustNotThrow);
- 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);
- #if 0
- if (!condition)
- // Use a default value
- condition = new IntegerExp(loc, 1, Type::tboolean);
- #endif
- 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);
- increment = increment->optimize(0);
- }
- sc->sbreak = this;
- sc->scontinue = this;
- if (body)
- body = body->semanticNoScope(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(bool mustNotThrow)
- { int result = BEfallthru;
- if (init)
- { result = init->blockExit(mustNotThrow);
- if (!(result & BEfallthru))
- return result;
- }
- if (condition)
- { if (condition->canThrow())
- result |= BEthrow;
- if (condition->isBool(TRUE))
- result &= ~BEfallthru;
- else if (condition->isBool(FALSE))
- return result;
- }
- else
- result &= ~BEfallthru; // the body must do the exiting
- if (body)
- { int r = body->blockExit(mustNotThrow);
- 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, Parameters *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;
- this->cases = NULL;
- this->gotos = NULL;
- }
- Statement *ForeachStatement::syntaxCopy()
- {
- //printf("ForeachStatement::syntaxCopy()\n");
- Parameters *args = Parameter::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);
- /* 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 = Parameter::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 = te->exps->tdata()[k];
- else
- t = Parameter::getNth(tuple->arguments, k)->type;
- Parameter *arg = arguments->tdata()[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());
- arg->type = arg->type->semantic(loc, sc);
- 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 |= STCconst;
- DeclarationExp *de = new DeclarationExp(loc, var);
- st->push(new ExpStatement(loc, de));
- arg = (*arguments)[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();
- Dsymbol *s = NULL;
- if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
- s = ((VarExp *)e)->var;
- else if (e->op == TOKtemplate)
- s =((TemplateExp *)e)->td;
- else if (e->op == TOKimport)
- s =((ScopeExp *)e)->sds;
- if (s)
- var = new AliasDeclaration(loc, arg->ident, s);
- else
- {
- arg->type = e->type;
- Initializer *ie = new ExpInitializer(0, e);
- VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie);
- if (e->isConst() || e->op == TOKstring)
- 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;
- }
- for (size_t i = 0; i < dim; i++)
- { Parameter *arg = (Parameter *)arguments->data[i];
- if (!arg->type)
- {
- error("cannot infer type for %s", arg->ident->toChars());
- return this;
- }
- }
- sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- sc->noctor++;
- switch (tab->ty)
- {
- case Tarray:
- case Tsarray:
- 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)
- { Parameter *arg;
- int i = (dim == 1) ? 0 : 1; // index of value
- arg = (Parameter *)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 = (Parameter *)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
- Parameter *arg = (Parameter *)arguments->data[i];
- Type *argtype = arg->type->semantic(loc, sc);
- VarDeclaration *var;
- var = new VarDeclaration(loc, argtype, arg->ident, NULL);
- var->storage_class |= STCforeach;
- var->storage_class |= arg->storageClass & (STCin | STCout | STCref);
- if (dim == 2 && i == 0)
- key = var;
- else
- value = var;
- #if 0
- DeclarationExp *de = new DeclarationExp(loc, var);
- de->semantic(sc);
- #endif
- }
- #if 1
- {
- /* Convert to a ForStatement
- * foreach (key, value; a) body =>
- * for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
- * { T value = tmp[k]; body }
- *
- * foreach_reverse (key, value; a) body =>
- * for (T[] tmp = a[], size_t key = tmp.length; key--; )
- * { T value = tmp[k]; body }
- */
- Identifier *id = Lexer::uniqueId("__aggr");
- ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL));
- VarDeclaration *tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie);
- Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length);
- if (!key)
- {
- Identifier *idkey = Lexer::uniqueId("__key");
- key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL);
- }
- if (op == TOKforeach_reverse)
- key->init = new ExpInitializer(loc, tmp_length);
- else
- key->init = new ExpInitializer(loc, new IntegerExp(0));
- Statements *cs = new Statements();
- cs->push(new ExpStatement(loc, tmp));
- cs->push(new ExpStatement(loc, key));
- Statement *forinit = new CompoundDeclarationStatement(loc, cs);
- Expression *cond;
- if (op == TOKforeach_reverse)
- // key--
- cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key));
- else
- // key < tmp.length
- cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length);
- Expression *increment = NULL;
- if (op == TOKforeach)
- // key += 1
- increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
- // T value = tmp[key];
- value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key)));
- Statement *ds = new ExpStatement(loc, value);
- body = new CompoundStatement(loc, ds, body);
- ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body);
- s = fs->semantic(sc);
- break;
- }
- #else
- if (!value->type->equals(tab->next))
- {
- 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 (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->storage_class & (STCout | STCref))
- error("foreach: key cannot be out or ref");
- }
- sc->sbreak = this;
- sc->scontinue = this;
- body = body->semantic(sc);
- break;
- #endif
- case Taarray:
- 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");
- 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 ExpStatement(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);
- Parameter *arg = (Parameter *)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 ExpStatement(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:
- {
- Expression *ec;
- Expression *e;
- Parameter *a;
- Type *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 = new VarDeclaration(loc, tret, Id::result, NULL);
- v->noscope = 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 }
- */
- Parameters *args = new Parameters();
- for (size_t i = 0; i < dim; i++)
- { Parameter *arg = (Parameter *)arguments->data[i];
- Identifier *id;
- 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.
- id = Lexer::uniqueId("__applyArg", i);
- Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id));
- VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie);
- s = new ExpStatement(0, v);
- body = new CompoundStatement(loc, s, body);
- }
- a = new Parameter(STCref, arg->type, id, NULL);
- args->push(a);
- }
- Type *t = new TypeFunction(args, Type::tint32, 0, LINKd);
- cases = new Statements();
- gotos = new Array();
- FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this);
- fld->fbody = body;
- Expression *flde = new FuncExp(loc, fld);
- flde = flde->semantic(sc);
- // Resolve any forward referenced goto's
- for (size_t 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 (taa)
- {
- // Check types
- Parameter *arg = (Parameter *)arguments->data[0];
- if (dim == 2)
- {
- if (arg->storageClass & STCref)
- error("foreach: index cannot be ref");
- if (!arg->type->equals(taa->index))
- error("foreach: ind…
Large files files are truncated, but you can click here to view the full file