Mercurial > projects > ldc
diff dmd/interpret.c @ 875:330f999ade44
Merged DMD 1.038
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 06 Jan 2009 16:33:51 +0100 |
parents | 50383e476c7e |
children | 29c0d1194033 |
line wrap: on
line diff
--- a/dmd/interpret.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/interpret.c Tue Jan 06 16:33:51 2009 +0100 @@ -1,2231 +1,2304 @@ - -// 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" - -#define LOG 0 - -struct InterState -{ - InterState *caller; // calling function's InterState - FuncDeclaration *fd; // function being interpreted - Dsymbols vars; // variables used in this function - Statement *start; // if !=NULL, start execution at this statement - Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result - - InterState(); -}; - -InterState::InterState() -{ - memset(this, 0, sizeof(InterState)); -} - -Expression *interpret_aaLen(InterState *istate, Expressions *arguments); -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); -Expression *interpret_aaValues(InterState *istate, Expressions *arguments); - -/************************************* - * Attempt to interpret a function given the arguments. - * Input: - * istate state for calling function (NULL if none) - * Return result expression if successful, NULL if not. - */ - -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments) -{ -#if LOG - printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); - printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); -#endif - if (global.errors) - return NULL; - if (ident == Id::aaLen) - return interpret_aaLen(istate, arguments); - else if (ident == Id::aaKeys) - return interpret_aaKeys(istate, arguments); - else if (ident == Id::aaValues) - return interpret_aaValues(istate, arguments); - - if (cantInterpret || semanticRun == 1) - return NULL; - - if (needThis() || isNested() || !fbody) - { cantInterpret = 1; - return NULL; - } - - if (semanticRun == 0 && scope) - { - semantic3(scope); - if (global.errors) // if errors compiling this function - return NULL; - } - if (semanticRun < 2) - return NULL; - - Type *tb = type->toBasetype(); - assert(tb->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)tb; - Type *tret = tf->next->toBasetype(); - if (tf->varargs /*|| tret->ty == Tvoid*/) - { cantInterpret = 1; - return NULL; - } - - if (tf->parameters) - { size_t dim = Argument::dim(tf->parameters); - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(tf->parameters, i); - if (arg->storageClass & STClazy) - { cantInterpret = 1; - return NULL; - } - } - } - - InterState istatex; - istatex.caller = istate; - istatex.fd = this; - - Expressions vsave; // place to save previous parameter values - size_t dim = 0; - if (arguments) - { - dim = arguments->dim; - assert(!dim || parameters->dim == dim); - vsave.setDim(dim); - - /* Evaluate all the arguments to the function, - * store the results in eargs[] - */ - Expressions eargs; - eargs.setDim(dim); - - for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)arguments->data[i]; - Argument *arg = Argument::getNth(tf->parameters, i); - - if (arg->storageClass & (STCout | STCref)) - { - } - else - { /* Value parameters - */ - Type *ta = arg->type->toBasetype(); - if (ta->ty == Tsarray && earg->op == TOKaddress) - { - /* Static arrays are passed by a simple pointer. - * Skip past this to get at the actual arg. - */ - earg = ((AddrExp *)earg)->e1; - } - earg = earg->interpret(istate ? istate : &istatex); - if (earg == EXP_CANT_INTERPRET) - return NULL; - } - eargs.data[i] = earg; - } - - for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)eargs.data[i]; - Argument *arg = Argument::getNth(tf->parameters, i); - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - vsave.data[i] = v->value; -#if LOG - printf("arg[%d] = %s\n", i, earg->toChars()); -#endif - if (arg->storageClass & (STCout | STCref)) - { - /* Bind out or ref parameter to the corresponding - * variable v2 - */ - if (!istate || earg->op != TOKvar) - return NULL; // can't bind to non-interpreted vars - - VarDeclaration *v2; - while (1) - { - VarExp *ve = (VarExp *)earg; - v2 = ve->var->isVarDeclaration(); - if (!v2) - return NULL; - if (!v2->value || v2->value->op != TOKvar) - break; - earg = v2->value; - } - - v->value = new VarExp(earg->loc, v2); - - /* Don't restore the value of v2 upon function return - */ - assert(istate); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v == v2) - { istate->vars.data[i] = NULL; - break; - } - } - } - else - { /* Value parameters - */ - v->value = earg; - } -#if LOG - printf("interpreted arg[%d] = %s\n", i, earg->toChars()); -#endif - } - } - - /* Save the values of the local variables used - */ - Expressions valueSaves; - if (istate) - { - //printf("saving local variables...\n"); - valueSaves.setDim(istate->vars.dim); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { - //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - valueSaves.data[i] = v->value; - v->value = NULL; - } - } - } - - Expression *e = NULL; - - while (1) - { - e = fbody->interpret(&istatex); - if (e == EXP_CANT_INTERPRET) - { -#if LOG - printf("function body failed to interpret\n"); -#endif - e = NULL; - } - - /* This is how we deal with a recursive statement AST - * that has arbitrary goto statements in it. - * Bubble up a 'result' which is the target of the goto - * statement, then go recursively down the AST looking - * for that statement, then execute starting there. - */ - if (e == EXP_GOTO_INTERPRET) - { - istatex.start = istatex.gotoTarget; // set starting statement - istatex.gotoTarget = NULL; - } - else - break; - } - - /* Restore the parameter values - */ - for (size_t i = 0; i < dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - v->value = (Expression *)vsave.data[i]; - } - - if (istate) - { - /* Restore the variable values - */ - //printf("restoring local variables...\n"); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { v->value = (Expression *)valueSaves.data[i]; - //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - } - } - } - - return e; -} - -/******************************** Statement ***************************/ - -#define START() \ - if (istate->start) \ - { if (istate->start != this) \ - return NULL; \ - istate->start = NULL; \ - } - -/*********************************** - * Interpret the statement. - * Returns: - * NULL continue to next statement - * EXP_CANT_INTERPRET cannot interpret statement at compile time - * !NULL expression from return statement - */ - -Expression *Statement::interpret(InterState *istate) -{ -#if LOG - printf("Statement::interpret()\n"); -#endif - START() - return EXP_CANT_INTERPRET; -} - -Expression *ExpStatement::interpret(InterState *istate) -{ -#if LOG - printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (exp) - { - Expression *e = exp->interpret(istate); - if (e == EXP_CANT_INTERPRET) - { - //printf("-ExpStatement::interpret(): %p\n", e); - return EXP_CANT_INTERPRET; - } - } - return NULL; -} - -Expression *CompoundStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("CompoundStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (s) - { - e = s->interpret(istate); - if (e) - break; - } - } - } -#if LOG - printf("-CompoundStatement::interpret() %p\n", e); -#endif - return e; -} - -Expression *UnrolledLoopStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("UnrolledLoopStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - e = s->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - { e = NULL; - continue; - } - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e) - break; - } - } - return e; -} - -Expression *IfStatement::interpret(InterState *istate) -{ -#if LOG - printf("IfStatement::interpret(%s)\n", condition->toChars()); -#endif - - if (istate->start == this) - istate->start = NULL; - if (istate->start) - { - Expression *e = NULL; - if (ifbody) - e = ifbody->interpret(istate); - if (istate->start && elsebody) - e = elsebody->interpret(istate); - return e; - } - - Expression *e = condition->interpret(istate); - assert(e); - //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = ifbody ? ifbody->interpret(istate) : NULL; - else if (e->isBool(FALSE)) - e = elsebody ? elsebody->interpret(istate) : NULL; - else - { - e = EXP_CANT_INTERPRET; - } - } - return e; -} - -Expression *ScopeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ScopeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -Expression *ReturnStatement::interpret(InterState *istate) -{ -#if LOG - printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (!exp) - return EXP_VOID_INTERPRET; -#if LOG - Expression *e = exp->interpret(istate); - printf("e = %p\n", e); - return e; -#else - return exp->interpret(istate); -#endif -} - -Expression *BreakStatement::interpret(InterState *istate) -{ -#if LOG - printf("BreakStatement::interpret()\n"); -#endif - START() - if (ident) - return EXP_CANT_INTERPRET; - else - return EXP_BREAK_INTERPRET; -} - -Expression *ContinueStatement::interpret(InterState *istate) -{ -#if LOG - printf("ContinueStatement::interpret()\n"); -#endif - START() - if (ident) - return EXP_CANT_INTERPRET; - else - return EXP_CONTINUE_INTERPRET; -} - -Expression *WhileStatement::interpret(InterState *istate) -{ -#if LOG - printf("WhileStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e != EXP_CONTINUE_INTERPRET) - return e; - } - - while (1) - { - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - continue; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e) - break; - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *DoStatement::interpret(InterState *istate) -{ -#if LOG - printf("DoStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e == EXP_CONTINUE_INTERPRET) - goto Lcontinue; - if (e) - return e; - } - - while (1) - { - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - - Lcontinue: - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (init) - { - e = init->interpret(istate); - if (e == EXP_CANT_INTERPRET) - return e; - assert(!e); - } - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e == EXP_CONTINUE_INTERPRET) - goto Lcontinue; - if (e) - return e; - } - - while (1) - { - if (!condition) - goto Lhead; - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { - Lhead: - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - Lcontinue: - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForeachStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForeachStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *eaggr; - - if (value->isOut() || value->isRef()) - return EXP_CANT_INTERPRET; - - eaggr = aggr->interpret(istate); - if (eaggr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *dim = ArrayLength(Type::tsize_t, eaggr); - if (dim == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key ? key->value : NULL; - Expression *valuesave = value->value; - - uinteger_t d = dim->toUInteger(); - uinteger_t index; - - if (op == TOKforeach) - { - for (index = 0; index < d; index++) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - else // TOKforeach_reverse - { - for (index = d; index-- != 0;) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - value->value = valuesave; - if (key) - key->value = keysave; - return e; -} - -#if DMDV2 -Expression *ForeachRangeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForeachRangeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *elwr = lwr->interpret(istate); - if (elwr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *eupr = upr->interpret(istate); - if (eupr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key->value; - - if (op == TOKforeach) - { - key->value = elwr; - - while (1) - { - e = Cmp(TOKlt, key->value->type, key->value, upr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - } - } - else // TOKforeach_reverse - { - key->value = eupr; - - while (1) - { - e = Cmp(TOKgt, key->value->type, key->value, lwr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - } - } - key->value = keysave; - return e; -} -#endif - -Expression *SwitchStatement::interpret(InterState *istate) -{ -#if LOG - printf("SwitchStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e = NULL; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - return e; - } - - - Expression *econdition = condition->interpret(istate); - if (econdition == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Statement *s = NULL; - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { - CaseStatement *cs = (CaseStatement *)cases->data[i]; - e = Equal(TOKequal, Type::tint32, econdition, cs->exp); - if (e == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - if (e->isBool(TRUE)) - { s = cs; - break; - } - } - } - if (!s) - { if (hasNoDefault) - error("no default or case for %s in switch statement", econdition->toChars()); - s = sdefault; - } - - assert(s); - istate->start = s; - e = body ? body->interpret(istate) : NULL; - assert(!istate->start); - if (e == EXP_BREAK_INTERPRET) - return NULL; - return e; -} - -Expression *CaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *DefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("DefaultStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *GotoStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoStatement::interpret()\n"); -#endif - START() - assert(label && label->statement); - istate->gotoTarget = label->statement; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoCaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoCaseStatement::interpret()\n"); -#endif - START() - assert(cs); - istate->gotoTarget = cs; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoDefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoDefaultStatement::interpret()\n"); -#endif - START() - assert(sw && sw->sdefault); - istate->gotoTarget = sw->sdefault; - return EXP_GOTO_INTERPRET; -} - -Expression *LabelStatement::interpret(InterState *istate) -{ -#if LOG - printf("LabelStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -/******************************** Expression ***************************/ - -Expression *Expression::interpret(InterState *istate) -{ -#if LOG - printf("Expression::interpret() %s\n", toChars()); - printf("type = %s\n", type->toChars()); - dump(0); -#endif - return EXP_CANT_INTERPRET; -} - -Expression *NullExp::interpret(InterState *istate) -{ - return this; -} - -Expression *IntegerExp::interpret(InterState *istate) -{ -#if LOG - printf("IntegerExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *RealExp::interpret(InterState *istate) -{ -#if LOG - printf("RealExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *ComplexExp::interpret(InterState *istate) -{ - return this; -} - -Expression *StringExp::interpret(InterState *istate) -{ -#if LOG - printf("StringExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) -{ - Expression *e = EXP_CANT_INTERPRET; - VarDeclaration *v = d->isVarDeclaration(); - SymbolDeclaration *s = d->isSymbolDeclaration(); - if (v) - { -#if DMDV2 - if ((v->isConst() || v->isInvariant()) && v->init && !v->value) -#else - if (v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (e && !e->type) - e->type = v->type; - } - else - { e = v->value; - if (!e) - error(loc, "variable %s is used before initialization", v->toChars()); - else if (e != EXP_CANT_INTERPRET) - e = e->interpret(istate); - } - if (!e) - e = EXP_CANT_INTERPRET; - } - else if (s) - { - if (s->dsym->toInitializer() == s->sym) - { Expressions *exps = new Expressions(); - e = new StructLiteralExp(0, s->dsym, exps); - e = e->semantic(NULL); - } - } - return e; -} - -Expression *VarExp::interpret(InterState *istate) -{ -#if LOG - printf("VarExp::interpret() %s\n", toChars()); -#endif - return getVarExp(loc, istate, var); -} - -Expression *DeclarationExp::interpret(InterState *istate) -{ -#if LOG - printf("DeclarationExp::interpret() %s\n", toChars()); -#endif - Expression *e; - VarDeclaration *v = declaration->isVarDeclaration(); - if (v) - { - Dsymbol *s = v->toAlias(); - if (s == v && !v->isStatic() && v->init) - { - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie) - e = ie->exp->interpret(istate); - else if (v->init->isVoidInitializer()) - e = NULL; - } -#if DMDV2 - else if (s == v && (v->isConst() || v->isInvariant()) && v->init) -#else - else if (s == v && v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (!e) - e = EXP_CANT_INTERPRET; - else if (!e->type) - e->type = v->type; - } - } - else if (declaration->isAttribDeclaration() || - declaration->isTemplateMixin() || - declaration->isTupleDeclaration()) - { // These can be made to work, too lazy now - e = EXP_CANT_INTERPRET; - } - else - { // Others should not contain executable code, so are trivial to evaluate - e = NULL; - } -#if LOG - printf("-DeclarationExp::interpret(): %p\n", e); -#endif - return e; -} - -Expression *TupleExp::interpret(InterState *istate) -{ -#if LOG - printf("TupleExp::interpret() %s\n", toChars()); -#endif - Expressions *expsx = NULL; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - Expression *ex; - - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return ex; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(exps->dim); - for (size_t j = 0; j < i; j++) - { - expsx->data[j] = exps->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - if (expsx) - { TupleExp *te = new TupleExp(loc, expsx); - expandTuples(te->exps); - te->type = new TypeTuple(te->exps); - return te; - } - return this; -} - -Expression *ArrayLiteralExp::interpret(InterState *istate) -{ Expressions *expsx = NULL; - -#if LOG - printf("ArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - Expression *ex; - - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return EXP_CANT_INTERPRET; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->data[j] = elements->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); - ae->type = type; - return ae; - } - return this; -} - -Expression *AssocArrayLiteralExp::interpret(InterState *istate) -{ Expressions *keysx = keys; - Expressions *valuesx = values; - -#if LOG - printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); -#endif - for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = (Expression *)keys->data[i]; - Expression *evalue = (Expression *)values->data[i]; - Expression *ex; - - ex = ekey->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - - /* If any changes, do Copy On Write - */ - if (ex != ekey) - { - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - keysx->data[i] = (void *)ex; - } - - ex = evalue->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - - /* If any changes, do Copy On Write - */ - if (ex != evalue) - { - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - valuesx->data[i] = (void *)ex; - } - } - if (keysx != keys) - expandTuples(keysx); - if (valuesx != values) - expandTuples(valuesx); - if (keysx->dim != valuesx->dim) - goto Lerr; - - /* Remove duplicate keys - */ - for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = (Expression *)keysx->data[i - 1]; - - for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = (Expression *)keysx->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->isBool(TRUE)) // if a match - { - // Remove ekey - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - keysx->remove(i - 1); - valuesx->remove(i - 1); - i -= 1; // redo the i'th iteration - break; - } - } - } - - if (keysx != keys || valuesx != values) - { - AssocArrayLiteralExp *ae; - ae = new AssocArrayLiteralExp(loc, keysx, valuesx); - ae->type = type; - return ae; - } - return this; - -Lerr: - if (keysx != keys) - delete keysx; - if (valuesx != values) - delete values; - return EXP_CANT_INTERPRET; -} - -Expression *StructLiteralExp::interpret(InterState *istate) -{ Expressions *expsx = NULL; - -#if LOG - printf("StructLiteralExp::interpret() %s\n", toChars()); -#endif - /* We don't know how to deal with overlapping fields - */ - if (sd->hasUnions) - return EXP_CANT_INTERPRET; - - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - Expression *ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return EXP_CANT_INTERPRET; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->data[j] = elements->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); - se->type = type; - return se; - } - return this; -} - -Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) -{ Expression *e; - Expression *e1; - -#if LOG - printf("UnaExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ -} - -UNA_INTERPRET(Neg) -UNA_INTERPRET(Com) -UNA_INTERPRET(Not) -UNA_INTERPRET(Bool) - - -typedef Expression *(*fp_t)(Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - if (e2->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1, e2); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ -} - -BIN_INTERPRET(Add) -BIN_INTERPRET(Min) -BIN_INTERPRET(Mul) -BIN_INTERPRET(Div) -BIN_INTERPRET(Mod) -BIN_INTERPRET(Shl) -BIN_INTERPRET(Shr) -BIN_INTERPRET(Ushr) -BIN_INTERPRET(And) -BIN_INTERPRET(Or) -BIN_INTERPRET(Xor) - - -typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon2() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1 && - e1->op != TOKnull && - e1->op != TOKstring && - e1->op != TOKarrayliteral && - e1->op != TOKstructliteral) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - if (e2->isConst() != 1 && - e2->op != TOKnull && - e2->op != TOKstring && - e2->op != TOKarrayliteral && - e2->op != TOKstructliteral) - goto Lcant; - - e = (*fp)(op, type, e1, e2); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET2(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon2(istate, &op); \ -} - -BIN_INTERPRET2(Equal) -BIN_INTERPRET2(Identity) -BIN_INTERPRET2(Cmp) - -Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) -{ -#if LOG - printf("BinExp::interpretAssignCommon() %s\n", toChars()); -#endif - Expression *e = EXP_CANT_INTERPRET; - Expression *e1 = this->e1; - - if (fp) - { - if (e1->op == TOKcast) - { CastExp *ce = (CastExp *)e1; - e1 = ce->e1; - } - } - if (e1 == EXP_CANT_INTERPRET) - return e1; - Expression *e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - /* Assignment to variable of the form: - * v = e2 - */ - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->isDataseg()) - { - /* Chase down rebinding of out and ref - */ - if (v->value && v->value->op == TOKvar) - { - VarExp *ve2 = (VarExp *)v->value; - if (ve2->var->isSymbolDeclaration()) - { - /* This can happen if v is a struct initialized to - * 0 using an __initZ SymbolDeclaration from - * TypeStruct::defaultInit() - */ - } - else - v = ve2->var->isVarDeclaration(); - assert(v); - } - - Expression *ev = v->value; - if (fp && !ev) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - if (fp) - e2 = (*fp)(v->type, ev, e2); - else - { /* Look for special case of struct being initialized with 0. - */ - if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) - { - e2 = v->type->defaultInit(); - } - e2 = Cast(v->type, v->type, e2); - } - if (e2 != EXP_CANT_INTERPRET) - { - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - //printf("\tadding %s to istate\n", v->toChars()); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } - v->value = e2; - e = Cast(type, type, post ? ev : e2); - } - } - } - /* Assignment to struct member of the form: - * *(symoffexp) = e2 - */ - else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - - if (v->isDataseg()) - return EXP_CANT_INTERPRET; - if (fp && !v->value) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - Expression *vie = v->value; - if (vie->op == TOKvar) - { - Declaration *d = ((VarExp *)vie)->var; - vie = getVarExp(e1->loc, istate, d); - } - if (vie->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - StructLiteralExp *se = (StructLiteralExp *)vie; - int fieldi = se->getFieldIndex(type, soe->offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - Expression *ev = se->getField(type, soe->offset); - if (fp) - e2 = (*fp)(type, ev, e2); - else - e2 = Cast(type, type, e2); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } - - /* Create new struct literal reflecting updated fieldi - */ - Expressions *expsx = new Expressions(); - expsx->setDim(se->elements->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == fieldi) - expsx->data[j] = (void *)e2; - else - expsx->data[j] = se->elements->data[j]; - } - v->value = new StructLiteralExp(se->loc, se->sd, expsx); - v->value->type = se->type; - - e = Cast(type, type, post ? ev : e2); - } - /* Assignment to array element of the form: - * a[i] = e2 - */ - else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar) - { IndexExp *ie = (IndexExp *)e1; - VarExp *ve = (VarExp *)ie->e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (!v || v->isDataseg()) - return EXP_CANT_INTERPRET; - if (!v->value) - { - if (fp) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - - Type *t = v->type->toBasetype(); - if (t->ty == Tsarray) - { - /* This array was void initialized. Create a - * default initializer for it. - * What we should do is fill the array literal with - * NULL data, so use-before-initialized can be detected. - * But we're too lazy at the moment to do it, as that - * involves redoing Index() and whoever calls it. - */ - Expression *ev = v->type->defaultInit(); - size_t dim = ((TypeSArray *)t)->dim->toInteger(); - Expressions *elements = new Expressions(); - elements->setDim(dim); - for (size_t i = 0; i < dim; i++) - elements->data[i] = (void *)ev; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = v->type; - v->value = ae; - } - else - return EXP_CANT_INTERPRET; - } - - ArrayLiteralExp *ae = NULL; - AssocArrayLiteralExp *aae = NULL; - StringExp *se = NULL; - if (v->value->op == TOKarrayliteral) - ae = (ArrayLiteralExp *)v->value; - else if (v->value->op == TOKassocarrayliteral) - aae = (AssocArrayLiteralExp *)v->value; - else if (v->value->op == TOKstring) - se = (StringExp *)v->value; - else - return EXP_CANT_INTERPRET; - - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - Expression *ev; - if (fp || ae || se) // not for aae, because key might not be there - { - ev = Index(type, v->value, index); - if (ev == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - - if (fp) - e2 = (*fp)(type, ev, e2); - else - e2 = Cast(type, type, e2); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } - - if (ae) - { - /* Create new array literal reflecting updated elem - */ - int elemi = index->toInteger(); - Expressions *expsx = new Expressions(); - expsx->setDim(ae->elements->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == elemi) - expsx->data[j] = (void *)e2; - else - expsx->data[j] = ae->elements->data[j]; - } - v->value = new ArrayLiteralExp(ae->loc, expsx); - v->value->type = ae->type; - } - else if (aae) - { - /* Create new associative array literal reflecting updated key/value - */ - Expressions *keysx = aae->keys; - Expressions *valuesx = new Expressions(); - valuesx->setDim(aae->values->dim); - int updated = 0; - for (size_t j = valuesx->dim; j; ) - { j--; - Expression *ekey = (Expression *)aae->keys->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); - if (ex == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - if (ex->isBool(TRUE)) - { valuesx->data[j] = (void *)e2; - updated = 1; - } - else - valuesx->data[j] = aae->values->data[j]; - } - if (!updated) - { // Append index/e2 to keysx[]/valuesx[] - valuesx->push(e2); - keysx = (Expressions *)keysx->copy(); - keysx->push(index); - } - v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); - v->value->type = aae->type; - } - else if (se) - { - /* Create new string literal reflecting updated elem - */ - int elemi = index->toInteger(); - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - unsigned value = e2->toInteger(); - switch (se->sz) - { - case 1: s[elemi] = value; break; - case 2: ((unsigned short *)s)[elemi] = value; break; - case 4: ((unsigned *)s)[elemi] = value; break; - default: - assert(0); - break; - } - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - v->value = se2; - } - else - assert(0); - - e = Cast(type, type, post ? ev : e2); - } - else - { -#ifdef DEBUG - dump(0); -#endif - } - return e; -} - -Expression *AssignExp::interpret(InterState *istate) -{ - return interpretAssignCommon(istate, NULL); -} - -#define BIN_ASSIGN_INTERPRET(op) \ -Expression *op##AssignExp::interpret(InterState *istate) \ -{ \ - return interpretAssignCommon(istate, &op); \ -} - -BIN_ASSIGN_INTERPRET(Add) -BIN_ASSIGN_INTERPRET(Min) -BIN_ASSIGN_INTERPRET(Cat) -BIN_ASSIGN_INTERPRET(Mul) -BIN_ASSIGN_INTERPRET(Div) -BIN_ASSIGN_INTERPRET(Mod) -BIN_ASSIGN_INTERPRET(Shl) -BIN_ASSIGN_INTERPRET(Shr) -BIN_ASSIGN_INTERPRET(Ushr) -BIN_ASSIGN_INTERPRET(And) -BIN_ASSIGN_INTERPRET(Or) -BIN_ASSIGN_INTERPRET(Xor) - -Expression *PostExp::interpret(InterState *istate) -{ -#if LOG - printf("PostExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if (op == TOKplusplus) - e = interpretAssignCommon(istate, &Add, 1); - else - e = interpretAssignCommon(istate, &Min, 1); -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PostExp::interpret() CANT\n"); -#endif - return e; -} - -Expression *AndAndExp::interpret(InterState *istate) -{ -#if LOG - printf("AndAndExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - { - e = e2->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else - e = EXP_CANT_INTERPRET; - } - } - else - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *OrOrExp::interpret(InterState *istate) -{ -#if LOG - printf("OrOrExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else if (e->isBool(FALSE)) - { - e = e2->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else - e = EXP_CANT_INTERPRET; - } - } - else - e = EXP_CANT_INTERPRET; - } - return e; -} - - -Expression *CallExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("CallExp::interpret() %s\n", toChars()); -#endif - if (e1->op == TOKvar) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { -#if DMDV2 - enum BUILTIN b = fd->isBuiltin(); - if (b) - { Expressions args; - args.setDim(arguments->dim); - for (size_t i = 0; i < args.dim; i++) - { - Expression *earg = (Expression *)arguments->data[i]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return earg; - args.data[i] = (void *)earg; - } - e = eval_builtin(b, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - else -#endif - // Inline .dup - if (fd->ident == Id::adDup && arguments && arguments->dim == 2) - { - e = (Expression *)arguments->data[1]; - e = e->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - e = expType(type, e); - } - } - else - { - Expression *eresult = fd->interpret(istate, arguments); - if (eresult) - e = eresult; - else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } - return e; -} - -Expression *CommaExp::interpret(InterState *istate) -{ -#if LOG - printf("CommaExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - e = e2->interpret(istate); - return e; -} - -Expression *CondExp::interpret(InterState *istate) -{ -#if LOG - printf("CondExp::interpret() %s\n", toChars()); -#endif - Expression *e = econd->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = e1->interpret(istate); - else if (e->isBool(FALSE)) - e = e2->interpret(istate); - else - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *ArrayLengthExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("ArrayLengthExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - else if (e1->op == TOKnull) - { - e = new IntegerExp(loc, 0, type); - } - else - goto Lcant; - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *IndexExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("IndexExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - - if (e1->op == TOKstring || e1->op == TOKarrayliteral) - { - /* Set the $ variable - */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; - } - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - return Index(type, e1, e2); - -Lcant: - return EXP_CANT_INTERPRET; -} - - -Expression *SliceExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *lwr; - Expression *upr; - -#if LOG - printf("SliceExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (!this->lwr) - { - e = e1->castTo(NULL, type); - return e->interpret(istate); - } - - /* Set the $ variable - */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (lwr == EXP_CANT_INTERPRET) - goto Lcant; - upr = this->upr->interpret(istate); - if (upr == EXP_CANT_INTERPRET) - goto Lcant; - - return Slice(type, e1, lwr, upr); - -Lcant: - return EXP_CANT_INTERPRET; -} - - -Expression *CatExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("CatExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - { - goto Lcant; - } - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - return Cat(type, e1, e2); - -Lcant: -#if LOG - printf("CatExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; -} - - -Expression *CastExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("CastExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - return Cast(type, to, e1); - -Lcant: -#if LOG - printf("CastExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; -} - - -Expression *AssertExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("AssertExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isBool(TRUE)) - { - } - else if (e1->isBool(FALSE)) - { - if (msg) - { - e = msg->interpret(istate); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - error("%s", e->toChars()); - } - else - error("%s failed", toChars()); - goto Lcant; - } - else - goto Lcant; - return e1; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *PtrExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("PtrExp::interpret() %s\n", toChars()); -#endif - - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - Expression *ex = ade->e1; - ex = ex->interpret(istate); - if (ex != EXP_CANT_INTERPRET) - { - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - unsigned offset = ae->e2->toInteger(); - e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - e = Ptr(type, e1); - } - else if (e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - if (v) - { Expression *ev = getVarExp(loc, istate, v); - if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ev; - e = se->getField(type, soe->offset); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - } -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *DotVarExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - - Expression *ex = e1->interpret(istate); - - // Constant fold structliteral.member - if (ex != EXP_CANT_INTERPRET && ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - - VarDeclaration* v; - if (v = var->isVarDeclaration()) - { - e = se->getField(type, v->offset); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - - return e; -} - -/******************************* Special Functions ***************************/ - -Expression *interpret_aaLen(InterState *istate, Expressions *arguments) -{ - if (!arguments || arguments->dim != 1) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); - return e; -} - -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) -{ - //printf("interpret_aaKeys()\n"); - if (!arguments || arguments->dim != 2) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - return e; -} - -Expression *interpret_aaValues(InterState *istate, Expressions *arguments) -{ - //printf("interpret_aaValues()\n"); - if (!arguments || arguments->dim != 3) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - //printf("result is %s\n", e->toChars()); - return e; -} - + +// 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" + +#define LOG 0 + +struct InterState +{ + InterState *caller; // calling function's InterState + FuncDeclaration *fd; // function being interpreted + Dsymbols vars; // variables used in this function + Statement *start; // if !=NULL, start execution at this statement + Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result + + InterState(); +}; + +InterState::InterState() +{ + memset(this, 0, sizeof(InterState)); +} + +Expression *interpret_aaLen(InterState *istate, Expressions *arguments); +Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); +Expression *interpret_aaValues(InterState *istate, Expressions *arguments); + +/************************************* + * Attempt to interpret a function given the arguments. + * Input: + * istate state for calling function (NULL if none) + * Return result expression if successful, NULL if not. + */ + +Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments) +{ +#if LOG + printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); + printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); +#endif + if (global.errors) + return NULL; + if (ident == Id::aaLen) + return interpret_aaLen(istate, arguments); + else if (ident == Id::aaKeys) + return interpret_aaKeys(istate, arguments); + else if (ident == Id::aaValues) + return interpret_aaValues(istate, arguments); + + if (cantInterpret || semanticRun == 1) + return NULL; + + if (needThis() || isNested() || !fbody) + { cantInterpret = 1; + return NULL; + } + + if (semanticRun == 0 && scope) + { + semantic3(scope); + if (global.errors) // if errors compiling this function + return NULL; + } + if (semanticRun < 2) + return NULL; + + Type *tb = type->toBasetype(); + assert(tb->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)tb; + Type *tret = tf->next->toBasetype(); + if (tf->varargs /*|| tret->ty == Tvoid*/) + { cantInterpret = 1; + return NULL; + } + + if (tf->parameters) + { size_t dim = Argument::dim(tf->parameters); + for (size_t i = 0; i < dim; i++) + { Argument *arg = Argument::getNth(tf->parameters, i); + if (arg->storageClass & STClazy) + { cantInterpret = 1; + return NULL; + } + } + } + + InterState istatex; + istatex.caller = istate; + istatex.fd = this; + + Expressions vsave; // place to save previous parameter values + size_t dim = 0; + if (arguments) + { + dim = arguments->dim; + assert(!dim || parameters->dim == dim); + vsave.setDim(dim); + + /* Evaluate all the arguments to the function, + * store the results in eargs[] + */ + Expressions eargs; + eargs.setDim(dim); + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)arguments->data[i]; + Argument *arg = Argument::getNth(tf->parameters, i); + + if (arg->storageClass & (STCout | STCref)) + { + } + else + { /* Value parameters + */ + Type *ta = arg->type->toBasetype(); + if (ta->ty == Tsarray && earg->op == TOKaddress) + { + /* Static arrays are passed by a simple pointer. + * Skip past this to get at the actual arg. + */ + earg = ((AddrExp *)earg)->e1; + } + earg = earg->interpret(istate ? istate : &istatex); + if (earg == EXP_CANT_INTERPRET) + return NULL; + } + eargs.data[i] = earg; + } + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)eargs.data[i]; + Argument *arg = Argument::getNth(tf->parameters, i); + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + vsave.data[i] = v->value; +#if LOG + printf("arg[%d] = %s\n", i, earg->toChars()); +#endif + if (arg->storageClass & (STCout | STCref)) + { + /* Bind out or ref parameter to the corresponding + * variable v2 + */ + if (!istate || earg->op != TOKvar) + return NULL; // can't bind to non-interpreted vars + + VarDeclaration *v2; + while (1) + { + VarExp *ve = (VarExp *)earg; + v2 = ve->var->isVarDeclaration(); + if (!v2) + return NULL; + if (!v2->value || v2->value->op != TOKvar) + break; + earg = v2->value; + } + + v->value = new VarExp(earg->loc, v2); + + /* Don't restore the value of v2 upon function return + */ + assert(istate); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v == v2) + { istate->vars.data[i] = NULL; + break; + } + } + } + else + { /* Value parameters + */ + v->value = earg; + } +#if LOG + printf("interpreted arg[%d] = %s\n", i, earg->toChars()); +#endif + } + } + + /* Save the values of the local variables used + */ + Expressions valueSaves; + if (istate) + { + //printf("saving local variables...\n"); + valueSaves.setDim(istate->vars.dim); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v) + { + //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); + valueSaves.data[i] = v->value; + v->value = NULL; + } + } + } + + Expression *e = NULL; + + while (1) + { + e = fbody->interpret(&istatex); + if (e == EXP_CANT_INTERPRET) + { +#if LOG + printf("function body failed to interpret\n"); +#endif + e = NULL; + } + + /* This is how we deal with a recursive statement AST + * that has arbitrary goto statements in it. + * Bubble up a 'result' which is the target of the goto + * statement, then go recursively down the AST looking + * for that statement, then execute starting there. + */ + if (e == EXP_GOTO_INTERPRET) + { + istatex.start = istatex.gotoTarget; // set starting statement + istatex.gotoTarget = NULL; + } + else + break; + } + + /* Restore the parameter values + */ + for (size_t i = 0; i < dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + v->value = (Expression *)vsave.data[i]; + } + + if (istate) + { + /* Restore the variable values + */ + //printf("restoring local variables...\n"); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v) + { v->value = (Expression *)valueSaves.data[i]; + //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); + } + } + } + + return e; +} + +/******************************** Statement ***************************/ + +#define START() \ + if (istate->start) \ + { if (istate->start != this) \ + return NULL; \ + istate->start = NULL; \ + } + +/*********************************** + * Interpret the statement. + * Returns: + * NULL continue to next statement + * EXP_CANT_INTERPRET cannot interpret statement at compile time + * !NULL expression from return statement + */ + +Expression *Statement::interpret(InterState *istate) +{ +#if LOG + printf("Statement::interpret()\n"); +#endif + START() + return EXP_CANT_INTERPRET; +} + +Expression *ExpStatement::interpret(InterState *istate) +{ +#if LOG + printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); +#endif + START() + if (exp) + { + Expression *e = exp->interpret(istate); + if (e == EXP_CANT_INTERPRET) + { + //printf("-ExpStatement::interpret(): %p\n", e); + return EXP_CANT_INTERPRET; + } + } + return NULL; +} + +Expression *CompoundStatement::interpret(InterState *istate) +{ Expression *e = NULL; + +#if LOG + printf("CompoundStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statements) + { + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (s) + { + e = s->interpret(istate); + if (e) + break; + } + } + } +#if LOG + printf("-CompoundStatement::interpret() %p\n", e); +#endif + return e; +} + +Expression *UnrolledLoopStatement::interpret(InterState *istate) +{ Expression *e = NULL; + +#if LOG + printf("UnrolledLoopStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statements) + { + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + e = s->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_CONTINUE_INTERPRET) + { e = NULL; + continue; + } + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e) + break; + } + } + return e; +} + +Expression *IfStatement::interpret(InterState *istate) +{ +#if LOG + printf("IfStatement::interpret(%s)\n", condition->toChars()); +#endif + + if (istate->start == this) + istate->start = NULL; + if (istate->start) + { + Expression *e = NULL; + if (ifbody) + e = ifbody->interpret(istate); + if (istate->start && elsebody) + e = elsebody->interpret(istate); + return e; + } + + Expression *e = condition->interpret(istate); + assert(e); + //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = ifbody ? ifbody->interpret(istate) : NULL; + else if (e->isBool(FALSE)) + e = elsebody ? elsebody->interpret(istate) : NULL; + else + { + e = EXP_CANT_INTERPRET; + } + } + return e; +} + +Expression *ScopeStatement::interpret(InterState *istate) +{ +#if LOG + printf("ScopeStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + return statement ? statement->interpret(istate) : NULL; +} + +Expression *ReturnStatement::interpret(InterState *istate) +{ +#if LOG + printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); +#endif + START() + if (!exp) + return EXP_VOID_INTERPRET; +#if LOG + Expression *e = exp->interpret(istate); + printf("e = %p\n", e); + return e; +#else + return exp->interpret(istate); +#endif +} + +Expression *BreakStatement::interpret(InterState *istate) +{ +#if LOG + printf("BreakStatement::interpret()\n"); +#endif + START() + if (ident) + return EXP_CANT_INTERPRET; + else + return EXP_BREAK_INTERPRET; +} + +Expression *ContinueStatement::interpret(InterState *istate) +{ +#if LOG + printf("ContinueStatement::interpret()\n"); +#endif + START() + if (ident) + return EXP_CANT_INTERPRET; + else + return EXP_CONTINUE_INTERPRET; +} + +Expression *WhileStatement::interpret(InterState *istate) +{ +#if LOG + printf("WhileStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e != EXP_CONTINUE_INTERPRET) + return e; + } + + while (1) + { + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_CONTINUE_INTERPRET) + continue; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e) + break; + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *DoStatement::interpret(InterState *istate) +{ +#if LOG + printf("DoStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e == EXP_CONTINUE_INTERPRET) + goto Lcontinue; + if (e) + return e; + } + + while (1) + { + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e && e != EXP_CONTINUE_INTERPRET) + break; + + Lcontinue: + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *ForStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (init) + { + e = init->interpret(istate); + if (e == EXP_CANT_INTERPRET) + return e; + assert(!e); + } + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e == EXP_CONTINUE_INTERPRET) + goto Lcontinue; + if (e) + return e; + } + + while (1) + { + if (!condition) + goto Lhead; + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { + Lhead: + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e && e != EXP_CONTINUE_INTERPRET) + break; + Lcontinue: + if (increment) + { + e = increment->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + } + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *ForeachStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForeachStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (istate->start) + return NULL; + + Expression *e = NULL; + Expression *eaggr; + + if (value->isOut() || value->isRef()) + return EXP_CANT_INTERPRET; + + eaggr = aggr->interpret(istate); + if (eaggr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *dim = ArrayLength(Type::tsize_t, eaggr); + if (dim == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *keysave = key ? key->value : NULL; + Expression *valuesave = value->value; + + uinteger_t d = dim->toUInteger(); + uinteger_t index; + + if (op == TOKforeach) + { + for (index = 0; index < d; index++) + { + Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); + if (key) + key->value = ekey; + e = Index(value->type, eaggr, ekey); + if (e == EXP_CANT_INTERPRET) + break; + value->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == EXP_CONTINUE_INTERPRET) + e = NULL; + else if (e) + break; + } + } + else // TOKforeach_reverse + { + for (index = d; index-- != 0;) + { + Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); + if (key) + key->value = ekey; + e = Index(value->type, eaggr, ekey); + if (e == EXP_CANT_INTERPRET) + break; + value->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == EXP_CONTINUE_INTERPRET) + e = NULL; + else if (e) + break; + } + } + value->value = valuesave; + if (key) + key->value = keysave; + return e; +} + +#if DMDV2 +Expression *ForeachRangeStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForeachRangeStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (istate->start) + return NULL; + + Expression *e = NULL; + Expression *elwr = lwr->interpret(istate); + if (elwr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *eupr = upr->interpret(istate); + if (eupr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *keysave = key->value; + + if (op == TOKforeach) + { + key->value = elwr; + + while (1) + { + e = Cmp(TOKlt, key->value->type, key->value, upr); + if (e == EXP_CANT_INTERPRET) + break; + if (e->isBool(TRUE) == FALSE) + { e = NULL; + break; + } + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + } + } + else // TOKforeach_reverse + { + key->value = eupr; + + while (1) + { + e = Cmp(TOKgt, key->value->type, key->value, lwr); + if (e == EXP_CANT_INTERPRET) + break; + if (e->isBool(TRUE) == FALSE) + { e = NULL; + break; + } + + e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + } + } + key->value = keysave; + return e; +} +#endif + +Expression *SwitchStatement::interpret(InterState *istate) +{ +#if LOG + printf("SwitchStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e = NULL; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + return e; + } + + + Expression *econdition = condition->interpret(istate); + if (econdition == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Statement *s = NULL; + if (cases) + { + for (size_t i = 0; i < cases->dim; i++) + { + CaseStatement *cs = (CaseStatement *)cases->data[i]; + e = Equal(TOKequal, Type::tint32, econdition, cs->exp); + if (e == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (e->isBool(TRUE)) + { s = cs; + break; + } + } + } + if (!s) + { if (hasNoDefault) + error("no default or case for %s in switch statement", econdition->toChars()); + s = sdefault; + } + + assert(s); + istate->start = s; + e = body ? body->interpret(istate) : NULL; + assert(!istate->start); + if (e == EXP_BREAK_INTERPRET) + return NULL; + return e; +} + +Expression *CaseStatement::interpret(InterState *istate) +{ +#if LOG + printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); +#endif + if (istate->start == this) + istate->start = NULL; + if (statement) + return statement->interpret(istate); + else + return NULL; +} + +Expression *DefaultStatement::interpret(InterState *istate) +{ +#if LOG + printf("DefaultStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statement) + return statement->interpret(istate); + else + return NULL; +} + +Expression *GotoStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoStatement::interpret()\n"); +#endif + START() + assert(label && label->statement); + istate->gotoTarget = label->statement; + return EXP_GOTO_INTERPRET; +} + +Expression *GotoCaseStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoCaseStatement::interpret()\n"); +#endif + START() + assert(cs); + istate->gotoTarget = cs; + return EXP_GOTO_INTERPRET; +} + +Expression *GotoDefaultStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoDefaultStatement::interpret()\n"); +#endif + START() + assert(sw && sw->sdefault); + istate->gotoTarget = sw->sdefault; + return EXP_GOTO_INTERPRET; +} + +Expression *LabelStatement::interpret(InterState *istate) +{ +#if LOG + printf("LabelStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + return statement ? statement->interpret(istate) : NULL; +} + +/******************************** Expression ***************************/ + +Expression *Expression::interpret(InterState *istate) +{ +#if LOG + printf("Expression::interpret() %s\n", toChars()); + printf("type = %s\n", type->toChars()); + dump(0); +#endif + return EXP_CANT_INTERPRET; +} + +Expression *NullExp::interpret(InterState *istate) +{ + return this; +} + +Expression *IntegerExp::interpret(InterState *istate) +{ +#if LOG + printf("IntegerExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *RealExp::interpret(InterState *istate) +{ +#if LOG + printf("RealExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *ComplexExp::interpret(InterState *istate) +{ + return this; +} + +Expression *StringExp::interpret(InterState *istate) +{ +#if LOG + printf("StringExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) +{ + Expression *e = EXP_CANT_INTERPRET; + VarDeclaration *v = d->isVarDeclaration(); + SymbolDeclaration *s = d->isSymbolDeclaration(); + if (v) + { +#if DMDV2 + if ((v->isConst() || v->isInvariant()) && v->init && !v->value) +#else + if (v->isConst() && v->init) +#endif + { e = v->init->toExpression(); + if (e && !e->type) + e->type = v->type; + } + else + { e = v->value; + if (!e) + error(loc, "variable %s is used before initialization", v->toChars()); + else if (e != EXP_CANT_INTERPRET) + e = e->interpret(istate); + } + if (!e) + e = EXP_CANT_INTERPRET; + } + else if (s) + { + if (s->dsym->toInitializer() == s->sym) + { Expressions *exps = new Expressions(); + e = new StructLiteralExp(0, s->dsym, exps); + e = e->semantic(NULL); + } + } + return e; +} + +Expression *VarExp::interpret(InterState *istate) +{ +#if LOG + printf("VarExp::interpret() %s\n", toChars()); +#endif + return getVarExp(loc, istate, var); +} + +Expression *DeclarationExp::interpret(InterState *istate) +{ +#if LOG + printf("DeclarationExp::interpret() %s\n", toChars()); +#endif + Expression *e; + VarDeclaration *v = declaration->isVarDeclaration(); + if (v) + { + Dsymbol *s = v->toAlias(); + if (s == v && !v->isStatic() && v->init) + { + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie) + e = ie->exp->interpret(istate); + else if (v->init->isVoidInitializer()) + e = NULL; + } +#if DMDV2 + else if (s == v && (v->isConst() || v->isInvariant()) && v->init) +#else + else if (s == v && v->isConst() && v->init) +#endif + { e = v->init->toExpression(); + if (!e) + e = EXP_CANT_INTERPRET; + else if (!e->type) + e->type = v->type; + } + } + else if (declaration->isAttribDeclaration() || + declaration->isTemplateMixin() || + declaration->isTupleDeclaration()) + { // These can be made to work, too lazy now + e = EXP_CANT_INTERPRET; + } + else + { // Others should not contain executable code, so are trivial to evaluate + e = NULL; + } +#if LOG + printf("-DeclarationExp::interpret(): %p\n", e); +#endif + return e; +} + +Expression *TupleExp::interpret(InterState *istate) +{ +#if LOG + printf("TupleExp::interpret() %s\n", toChars()); +#endif + Expressions *expsx = NULL; + + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + Expression *ex; + + ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return ex; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(exps->dim); + for (size_t j = 0; j < i; j++) + { + expsx->data[j] = exps->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + if (expsx) + { TupleExp *te = new TupleExp(loc, expsx); + expandTuples(te->exps); + te->type = new TypeTuple(te->exps); + return te; + } + return this; +} + +Expression *ArrayLiteralExp::interpret(InterState *istate) +{ Expressions *expsx = NULL; + +#if LOG + printf("ArrayLiteralExp::interpret() %s\n", toChars()); +#endif + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + Expression *ex; + + ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return EXP_CANT_INTERPRET; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(elements->dim); + for (size_t j = 0; j < elements->dim; j++) + { + expsx->data[j] = elements->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + } + if (elements && expsx) + { + expandTuples(expsx); + if (expsx->dim != elements->dim) + { delete expsx; + return EXP_CANT_INTERPRET; + } + ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); + ae->type = type; + return ae; + } + return this; +} + +Expression *AssocArrayLiteralExp::interpret(InterState *istate) +{ Expressions *keysx = keys; + Expressions *valuesx = values; + +#if LOG + printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); +#endif + for (size_t i = 0; i < keys->dim; i++) + { Expression *ekey = (Expression *)keys->data[i]; + Expression *evalue = (Expression *)values->data[i]; + Expression *ex; + + ex = ekey->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + + /* If any changes, do Copy On Write + */ + if (ex != ekey) + { + if (keysx == keys) + keysx = (Expressions *)keys->copy(); + keysx->data[i] = (void *)ex; + } + + ex = evalue->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + + /* If any changes, do Copy On Write + */ + if (ex != evalue) + { + if (valuesx == values) + valuesx = (Expressions *)values->copy(); + valuesx->data[i] = (void *)ex; + } + } + if (keysx != keys) + expandTuples(keysx); + if (valuesx != values) + expandTuples(valuesx); + if (keysx->dim != valuesx->dim) + goto Lerr; + + /* Remove duplicate keys + */ + for (size_t i = 1; i < keysx->dim; i++) + { Expression *ekey = (Expression *)keysx->data[i - 1]; + + for (size_t j = i; j < keysx->dim; j++) + { Expression *ekey2 = (Expression *)keysx->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + if (ex->isBool(TRUE)) // if a match + { + // Remove ekey + if (keysx == keys) + keysx = (Expressions *)keys->copy(); + if (valuesx == values) + valuesx = (Expressions *)values->copy(); + keysx->remove(i - 1); + valuesx->remove(i - 1); + i -= 1; // redo the i'th iteration + break; + } + } + } + + if (keysx != keys || valuesx != values) + { + AssocArrayLiteralExp *ae; + ae = new AssocArrayLiteralExp(loc, keysx, valuesx); + ae->type = type; + return ae; + } + return this; + +Lerr: + if (keysx != keys) + delete keysx; + if (valuesx != values) + delete values; + return EXP_CANT_INTERPRET; +} + +Expression *StructLiteralExp::interpret(InterState *istate) +{ Expressions *expsx = NULL; + +#if LOG + printf("StructLiteralExp::interpret() %s\n", toChars()); +#endif + /* We don't know how to deal with overlapping fields + */ + if (sd->hasUnions) + return EXP_CANT_INTERPRET; + + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + + Expression *ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return EXP_CANT_INTERPRET; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(elements->dim); + for (size_t j = 0; j < elements->dim; j++) + { + expsx->data[j] = elements->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + } + if (elements && expsx) + { + expandTuples(expsx); + if (expsx->dim != elements->dim) + { delete expsx; + return EXP_CANT_INTERPRET; + } + StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); + se->type = type; + return se; + } + return this; +} + +Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) +{ Expression *e; + Expression *e1; + +#if LOG + printf("UnaExp::interpretCommon() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1) + goto Lcant; + + e = (*fp)(type, e1); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define UNA_INTERPRET(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon(istate, &op); \ +} + +UNA_INTERPRET(Neg) +UNA_INTERPRET(Com) +UNA_INTERPRET(Not) +UNA_INTERPRET(Bool) + + +typedef Expression *(*fp_t)(Type *, Expression *, Expression *); + +Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("BinExp::interpretCommon() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1) + goto Lcant; + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + if (e2->isConst() != 1) + goto Lcant; + + e = (*fp)(type, e1, e2); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define BIN_INTERPRET(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon(istate, &op); \ +} + +BIN_INTERPRET(Add) +BIN_INTERPRET(Min) +BIN_INTERPRET(Mul) +BIN_INTERPRET(Div) +BIN_INTERPRET(Mod) +BIN_INTERPRET(Shl) +BIN_INTERPRET(Shr) +BIN_INTERPRET(Ushr) +BIN_INTERPRET(And) +BIN_INTERPRET(Or) +BIN_INTERPRET(Xor) + + +typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); + +Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("BinExp::interpretCommon2() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1 && + e1->op != TOKnull && + e1->op != TOKstring && + e1->op != TOKarrayliteral && + e1->op != TOKstructliteral) + goto Lcant; + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + if (e2->isConst() != 1 && + e2->op != TOKnull && + e2->op != TOKstring && + e2->op != TOKarrayliteral && + e2->op != TOKstructliteral) + goto Lcant; + + e = (*fp)(op, type, e1, e2); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define BIN_INTERPRET2(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon2(istate, &op); \ +} + +BIN_INTERPRET2(Equal) +BIN_INTERPRET2(Identity) +BIN_INTERPRET2(Cmp) + +Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) +{ +#if LOG + printf("BinExp::interpretAssignCommon() %s\n", toChars()); +#endif + Expression *e = EXP_CANT_INTERPRET; + Expression *e1 = this->e1; + + if (fp) + { + if (e1->op == TOKcast) + { CastExp *ce = (CastExp *)e1; + e1 = ce->e1; + } + } + if (e1 == EXP_CANT_INTERPRET) + return e1; + Expression *e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + return e2; + + /* Assignment to variable of the form: + * v = e2 + */ + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && !v->isDataseg()) + { + /* Chase down rebinding of out and ref + */ + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; + if (ve2->var->isSymbolDeclaration()) + { + /* This can happen if v is a struct initialized to + * 0 using an __initZ SymbolDeclaration from + * TypeStruct::defaultInit() + */ + } + else + v = ve2->var->isVarDeclaration(); + assert(v); + } + + Expression *ev = v->value; + if (fp && !ev) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + if (fp) + e2 = (*fp)(v->type, ev, e2); + else + { /* Look for special case of struct being initialized with 0. + */ + if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) + { + e2 = v->type->defaultInit(); + } + e2 = Cast(v->type, v->type, e2); + } + if (e2 != EXP_CANT_INTERPRET) + { + if (!v->isParameter()) + { + for (size_t i = 0; 1; i++) + { + if (i == istate->vars.dim) + { istate->vars.push(v); + //printf("\tadding %s to istate\n", v->toChars()); + break; + } + if (v == (VarDeclaration *)istate->vars.data[i]) + break; + } + } + v->value = e2; + e = Cast(type, type, post ? ev : e2); + } + } + } + /* Assignment to struct member of the form: + * v.var = e2 + */ + else if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKvar) + { VarExp *ve = (VarExp *)((DotVarExp *)e1)->e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + + if (v->isDataseg()) + return EXP_CANT_INTERPRET; + if (fp && !v->value) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + Expression *vie = v->value; + if (vie->op == TOKvar) + { + Declaration *d = ((VarExp *)vie)->var; + vie = getVarExp(e1->loc, istate, d); + } + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + StructLiteralExp *se = (StructLiteralExp *)vie; + VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration(); + if (!vf) + return EXP_CANT_INTERPRET; + int fieldi = se->getFieldIndex(type, vf->offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + Expression *ev = se->getField(type, vf->offset); + if (fp) + e2 = (*fp)(type, ev, e2); + else + e2 = Cast(type, type, e2); + if (e2 == EXP_CANT_INTERPRET) + return e2; + + if (!v->isParameter()) + { + for (size_t i = 0; 1; i++) + { + if (i == istate->vars.dim) + { istate->vars.push(v); + break; + } + if (v == (VarDeclaration *)istate->vars.data[i]) + break; + } + } + + /* Create new struct literal reflecting updated fieldi + */ + Expressions *expsx = new Expressions(); + expsx->setDim(se->elements->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j == fieldi) + expsx->data[j] = (void *)e2; + else + expsx->data[j] = se->elements->data[j]; + } + v->value = new StructLiteralExp(se->loc, se->sd, expsx); + v->value->type = se->type; + + e = Cast(type, type, post ? ev : e2); + } + /* Assignment to struct member of the form: + * *(symoffexp) = e2 + */ + else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff) + { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; + VarDeclaration *v = soe->var->isVarDeclaration(); + + if (v->isDataseg()) + return EXP_CANT_INTERPRET; + if (fp && !v->value) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + Expression *vie = v->value; + if (vie->op == TOKvar) + { + Declaration *d = ((VarExp *)vie)->var; + vie = getVarExp(e1->loc, istate, d); + } + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + StructLiteralExp *se = (StructLiteralExp *)vie; + int fieldi = se->getFieldIndex(type, soe->offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + Expression *ev = se->getField(type, soe->offset); + if (fp) + e2 = (*fp)(type, ev, e2); + else + e2 = Cast(type, type, e2); + if (e2 == EXP_CANT_INTERPRET) + return e2; + + if (!v->isParameter()) + { + for (size_t i = 0; 1; i++) + { + if (i == istate->vars.dim) + { istate->vars.push(v); + break; + } + if (v == (VarDeclaration *)istate->vars.data[i]) + break; + } + } + + /* Create new struct literal reflecting updated fieldi + */ + Expressions *expsx = new Expressions(); + expsx->setDim(se->elements->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j == fieldi) + expsx->data[j] = (void *)e2; + else + expsx->data[j] = se->elements->data[j]; + } + v->value = new StructLiteralExp(se->loc, se->sd, expsx); + v->value->type = se->type; + + e = Cast(type, type, post ? ev : e2); + } + /* Assignment to array element of the form: + * a[i] = e2 + */ + else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar) + { IndexExp *ie = (IndexExp *)e1; + VarExp *ve = (VarExp *)ie->e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + + if (!v || v->isDataseg()) + return EXP_CANT_INTERPRET; + if (!v->value) + { + if (fp) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + + Type *t = v->type->toBasetype(); + if (t->ty == Tsarray) + { + /* This array was void initialized. Create a + * default initializer for it. + * What we should do is fill the array literal with + * NULL data, so use-before-initialized can be detected. + * But we're too lazy at the moment to do it, as that + * involves redoing Index() and whoever calls it. + */ + Expression *ev = v->type->defaultInit(); + size_t dim = ((TypeSArray *)t)->dim->toInteger(); + Expressions *elements = new Expressions(); + elements->setDim(dim); + for (size_t i = 0; i < dim; i++) + elements->data[i] = (void *)ev; + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = v->type; + v->value = ae; + } + else + return EXP_CANT_INTERPRET; + } + + ArrayLiteralExp *ae = NULL; + AssocArrayLiteralExp *aae = NULL; + StringExp *se = NULL; + if (v->value->op == TOKarrayliteral) + ae = (ArrayLiteralExp *)v->value; + else if (v->value->op == TOKassocarrayliteral) + aae = (AssocArrayLiteralExp *)v->value; + else if (v->value->op == TOKstring) + se = (StringExp *)v->value; + else + return EXP_CANT_INTERPRET; + + Expression *index = ie->e2->interpret(istate); + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + Expression *ev; + if (fp || ae || se) // not for aae, because key might not be there + { + ev = Index(type, v->value, index); + if (ev == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + + if (fp) + e2 = (*fp)(type, ev, e2); + else + e2 = Cast(type, type, e2); + if (e2 == EXP_CANT_INTERPRET) + return e2; + + if (!v->isParameter()) + { + for (size_t i = 0; 1; i++) + { + if (i == istate->vars.dim) + { istate->vars.push(v); + break; + } + if (v == (VarDeclaration *)istate->vars.data[i]) + break; + } + } + + if (ae) + { + /* Create new array literal reflecting updated elem + */ + int elemi = index->toInteger(); + Expressions *expsx = new Expressions(); + expsx->setDim(ae->elements->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j == elemi) + expsx->data[j] = (void *)e2; + else + expsx->data[j] = ae->elements->data[j]; + } + v->value = new ArrayLiteralExp(ae->loc, expsx); + v->value->type = ae->type; + } + else if (aae) + { + /* Create new associative array literal reflecting updated key/value + */ + Expressions *keysx = aae->keys; + Expressions *valuesx = new Expressions(); + valuesx->setDim(aae->values->dim); + int updated = 0; + for (size_t j = valuesx->dim; j; ) + { j--; + Expression *ekey = (Expression *)aae->keys->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); + if (ex == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (ex->isBool(TRUE)) + { valuesx->data[j] = (void *)e2; + updated = 1; + } + else + valuesx->data[j] = aae->values->data[j]; + } + if (!updated) + { // Append index/e2 to keysx[]/valuesx[] + valuesx->push(e2); + keysx = (Expressions *)keysx->copy(); + keysx->push(index); + } + v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); + v->value->type = aae->type; + } + else if (se) + { + /* Create new string literal reflecting updated elem + */ + int elemi = index->toInteger(); + unsigned char *s; + s = (unsigned char *)mem.calloc(se->len + 1, se->sz); + memcpy(s, se->string, se->len * se->sz); + unsigned value = e2->toInteger(); + switch (se->sz) + { + case 1: s[elemi] = value; break; + case 2: ((unsigned short *)s)[elemi] = value; break; + case 4: ((unsigned *)s)[elemi] = value; break; + default: + assert(0); + break; + } + StringExp *se2 = new StringExp(se->loc, s, se->len); + se2->committed = se->committed; + se2->postfix = se->postfix; + se2->type = se->type; + v->value = se2; + } + else + assert(0); + + e = Cast(type, type, post ? ev : e2); + } + else + { +#ifdef DEBUG + dump(0); +#endif + } + return e; +} + +Expression *AssignExp::interpret(InterState *istate) +{ + return interpretAssignCommon(istate, NULL); +} + +#define BIN_ASSIGN_INTERPRET(op) \ +Expression *op##AssignExp::interpret(InterState *istate) \ +{ \ + return interpretAssignCommon(istate, &op); \ +} + +BIN_ASSIGN_INTERPRET(Add) +BIN_ASSIGN_INTERPRET(Min) +BIN_ASSIGN_INTERPRET(Cat) +BIN_ASSIGN_INTERPRET(Mul) +BIN_ASSIGN_INTERPRET(Div) +BIN_ASSIGN_INTERPRET(Mod) +BIN_ASSIGN_INTERPRET(Shl) +BIN_ASSIGN_INTERPRET(Shr) +BIN_ASSIGN_INTERPRET(Ushr) +BIN_ASSIGN_INTERPRET(And) +BIN_ASSIGN_INTERPRET(Or) +BIN_ASSIGN_INTERPRET(Xor) + +Expression *PostExp::interpret(InterState *istate) +{ +#if LOG + printf("PostExp::interpret() %s\n", toChars()); +#endif + Expression *e; + if (op == TOKplusplus) + e = interpretAssignCommon(istate, &Add, 1); + else + e = interpretAssignCommon(istate, &Min, 1); +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("PostExp::interpret() CANT\n"); +#endif + return e; +} + +Expression *AndAndExp::interpret(InterState *istate) +{ +#if LOG + printf("AndAndExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + { + e = e2->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else + e = EXP_CANT_INTERPRET; + } + } + else + e = EXP_CANT_INTERPRET; + } + return e; +} + +Expression *OrOrExp::interpret(InterState *istate) +{ +#if LOG + printf("OrOrExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else if (e->isBool(FALSE)) + { + e = e2->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else + e = EXP_CANT_INTERPRET; + } + } + else + e = EXP_CANT_INTERPRET; + } + return e; +} + + +Expression *CallExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("CallExp::interpret() %s\n", toChars()); +#endif + if (e1->op == TOKvar) + { + FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); + if (fd) + { +#if DMDV2 + enum BUILTIN b = fd->isBuiltin(); + if (b) + { Expressions args; + args.setDim(arguments->dim); + for (size_t i = 0; i < args.dim; i++) + { + Expression *earg = (Expression *)arguments->data[i]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return earg; + args.data[i] = (void *)earg; + } + e = eval_builtin(b, &args); + if (!e) + e = EXP_CANT_INTERPRET; + } + else +#endif + // Inline .dup + if (fd->ident == Id::adDup && arguments && arguments->dim == 2) + { + e = (Expression *)arguments->data[1]; + e = e->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + e = expType(type, e); + } + } + else + { + Expression *eresult = fd->interpret(istate, arguments); + if (eresult) + e = eresult; + else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } + return e; +} + +Expression *CommaExp::interpret(InterState *istate) +{ +#if LOG + printf("CommaExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + e = e2->interpret(istate); + return e; +} + +Expression *CondExp::interpret(InterState *istate) +{ +#if LOG + printf("CondExp::interpret() %s\n", toChars()); +#endif + Expression *e = econd->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = e1->interpret(istate); + else if (e->isBool(FALSE)) + e = e2->interpret(istate); + else + e = EXP_CANT_INTERPRET; + } + return e; +} + +Expression *ArrayLengthExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("ArrayLengthExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + { + e = ArrayLength(type, e1); + } + else if (e1->op == TOKnull) + { + e = new IntegerExp(loc, 0, type); + } + else + goto Lcant; + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +Expression *IndexExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("IndexExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + + if (e1->op == TOKstring || e1->op == TOKarrayliteral) + { + /* Set the $ variable + */ + e = ArrayLength(Type::tsize_t, e1); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar->value = e; + } + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + return Index(type, e1, e2); + +Lcant: + return EXP_CANT_INTERPRET; +} + + +Expression *SliceExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *lwr; + Expression *upr; + +#if LOG + printf("SliceExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (!this->lwr) + { + e = e1->castTo(NULL, type); + return e->interpret(istate); + } + + /* Set the $ variable + */ + e = ArrayLength(Type::tsize_t, e1); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar->value = e; + + /* Evaluate lower and upper bounds of slice + */ + lwr = this->lwr->interpret(istate); + if (lwr == EXP_CANT_INTERPRET) + goto Lcant; + upr = this->upr->interpret(istate); + if (upr == EXP_CANT_INTERPRET) + goto Lcant; + + return Slice(type, e1, lwr, upr); + +Lcant: + return EXP_CANT_INTERPRET; +} + + +Expression *CatExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("CatExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + { + goto Lcant; + } + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + return Cat(type, e1, e2); + +Lcant: +#if LOG + printf("CatExp::interpret() %s CANT\n", toChars()); +#endif + return EXP_CANT_INTERPRET; +} + + +Expression *CastExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("CastExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + return Cast(type, to, e1); + +Lcant: +#if LOG + printf("CastExp::interpret() %s CANT\n", toChars()); +#endif + return EXP_CANT_INTERPRET; +} + + +Expression *AssertExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("AssertExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isBool(TRUE)) + { + } + else if (e1->isBool(FALSE)) + { + if (msg) + { + e = msg->interpret(istate); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + error("%s", e->toChars()); + } + else + error("%s failed", toChars()); + goto Lcant; + } + else + goto Lcant; + return e1; + +Lcant: + return EXP_CANT_INTERPRET; +} + +Expression *PtrExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("PtrExp::interpret() %s\n", toChars()); +#endif + + // Constant fold *(&structliteral + offset) + if (e1->op == TOKadd) + { AddExp *ae = (AddExp *)e1; + if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) + { AddrExp *ade = (AddrExp *)ae->e1; + Expression *ex = ade->e1; + ex = ex->interpret(istate); + if (ex != EXP_CANT_INTERPRET) + { + if (ex->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ex; + unsigned offset = ae->e2->toInteger(); + e = se->getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + e = Ptr(type, e1); + } + else if (e1->op == TOKsymoff) + { SymOffExp *soe = (SymOffExp *)e1; + VarDeclaration *v = soe->var->isVarDeclaration(); + if (v) + { Expression *ev = getVarExp(loc, istate, v); + if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ev; + e = se->getField(type, soe->offset); + if (!e) + e = EXP_CANT_INTERPRET; + } + } + } +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); +#endif + return e; +} + +Expression *DotVarExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("DotVarExp::interpret() %s\n", toChars()); +#endif + + Expression *ex = e1->interpret(istate); + if (ex != EXP_CANT_INTERPRET) + { + if (ex->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ex; + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { e = se->getField(type, v->offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); +#endif + return e; +} + +/******************************* Special Functions ***************************/ + +Expression *interpret_aaLen(InterState *istate, Expressions *arguments) +{ + if (!arguments || arguments->dim != 1) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); + return e; +} + +Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) +{ + //printf("interpret_aaKeys()\n"); + if (!arguments || arguments->dim != 2) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); + return e; +} + +Expression *interpret_aaValues(InterState *istate, Expressions *arguments) +{ + //printf("interpret_aaValues()\n"); + if (!arguments || arguments->dim != 3) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->values); + //printf("result is %s\n", e->toChars()); + return e; +} +