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