Mercurial > projects > ldc
diff dmd/interpret.c @ 1587:def7a1d494fd
Merge DMD 1.051
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Fri, 06 Nov 2009 23:58:01 +0100 |
parents | 8026319762be |
children | 8aa756a00228 |
line wrap: on
line diff
--- a/dmd/interpret.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/interpret.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -34,6 +34,7 @@ Dsymbols vars; // variables used in this function Statement *start; // if !=NULL, start execution at this statement Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result + Expression *localThis; // value of 'this', or NULL if none InterState(); }; @@ -50,11 +51,14 @@ /************************************* * Attempt to interpret a function given the arguments. * Input: - * istate state for calling function (NULL if none) + * istate state for calling function (NULL if none) + * arguments function arguments + * thisarg 'this', if a needThis() function, NULL if not. + * * Return result expression if successful, NULL if not. */ -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments) +Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) { #if LOG printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); @@ -72,7 +76,7 @@ if (cantInterpret || semanticRun == 3) return NULL; - if (needThis() || isNested() || !fbody) + if (!fbody) { cantInterpret = 1; return NULL; } @@ -90,11 +94,13 @@ assert(tb->ty == Tfunction); TypeFunction *tf = (TypeFunction *)tb; Type *tret = tf->next->toBasetype(); - if (tf->varargs /*|| tret->ty == Tvoid*/) + if (tf->varargs) { cantInterpret = 1; + error("Variadic functions are not yet implemented in CTFE"); return NULL; } - + + // Ensure there are no lazy parameters if (tf->parameters) { size_t dim = Argument::dim(tf->parameters); for (size_t i = 0; i < dim; i++) @@ -109,13 +115,20 @@ InterState istatex; istatex.caller = istate; istatex.fd = this; + istatex.localThis = thisarg; Expressions vsave; // place to save previous parameter values size_t dim = 0; + if (needThis() && !thisarg) + { cantInterpret = 1; + // error, no this. Prevent segfault. + error("need 'this' to access member %s", toChars()); + return NULL; + } if (arguments) { dim = arguments->dim; - assert(!dim || parameters->dim == dim); + assert(!dim || (parameters && (parameters->dim == dim))); vsave.setDim(dim); /* Evaluate all the arguments to the function, @@ -144,7 +157,9 @@ } earg = earg->interpret(istate ? istate : &istatex); if (earg == EXP_CANT_INTERPRET) + { cantInterpret = 1; return NULL; + } } eargs.data[i] = earg; } @@ -157,23 +172,39 @@ #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif - if (arg->storageClass & (STCout | STCref)) + if (arg->storageClass & (STCout | STCref) && earg->op==TOKvar) { /* Bind out or ref parameter to the corresponding * variable v2 */ - if (!istate || earg->op != TOKvar) + if (!istate) + { cantInterpret = 1; + error("%s cannot be by passed by reference at compile time", earg->toChars()); return NULL; // can't bind to non-interpreted vars - + } + // We need to chase down all of the the passed parameters until + // we find something that isn't a TOKvar, then create a variable + // containg that expression. VarDeclaration *v2; while (1) { VarExp *ve = (VarExp *)earg; v2 = ve->var->isVarDeclaration(); if (!v2) + { cantInterpret = 1; return NULL; + } if (!v2->value || v2->value->op != TOKvar) break; +//TODO +#ifdef IN_DMD + if (((VarExp *)v2->value)->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + break; // eg default-initialized variable + } +#endif earg = v2->value; } @@ -191,8 +222,7 @@ } } else - { /* Value parameters - */ + { // Value parameters and non-trivial references v->value = earg; } #if LOG @@ -200,11 +230,22 @@ #endif } } + // Don't restore the value of 'this' upon function return + if (needThis() && thisarg->op==TOKvar) { + VarDeclaration *thisvar = ((VarExp *)(thisarg))->var->isVarDeclaration(); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v == thisvar) + { istate->vars.data[i] = NULL; + break; + } + } + } /* Save the values of the local variables used */ Expressions valueSaves; - if (istate) + if (istate && !isNested()) { //printf("saving local variables...\n"); valueSaves.setDim(istate->vars.dim); @@ -220,7 +261,6 @@ } Expression *e = NULL; - while (1) { e = fbody->interpret(&istatex); @@ -246,7 +286,6 @@ else break; } - /* Restore the parameter values */ for (size_t i = 0; i < dim; i++) @@ -255,7 +294,7 @@ v->value = (Expression *)vsave.data[i]; } - if (istate) + if (istate && !isNested()) { /* Restore the variable values */ @@ -268,7 +307,6 @@ } } } - return e; } @@ -478,7 +516,7 @@ return e; if (e == EXP_BREAK_INTERPRET) return NULL; - if (e != EXP_CONTINUE_INTERPRET) + if (e && e != EXP_CONTINUE_INTERPRET) return e; } @@ -758,7 +796,7 @@ while (1) { - e = Cmp(TOKlt, key->value->type, key->value, upr); + e = Cmp(TOKlt, key->value->type, key->value, eupr); if (e == EXP_CANT_INTERPRET) break; if (e->isBool(TRUE) == FALSE) @@ -773,19 +811,23 @@ { e = NULL; break; } - e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) + if (e == NULL || e == EXP_CONTINUE_INTERPRET) + { e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + } + else break; - key->value = e; } } else // TOKforeach_reverse { key->value = eupr; - while (1) + do { - e = Cmp(TOKgt, key->value->type, key->value, lwr); + e = Cmp(TOKgt, key->value->type, key->value, elwr); if (e == EXP_CANT_INTERPRET) break; if (e->isBool(TRUE) == FALSE) @@ -805,7 +847,7 @@ { e = NULL; break; } - } + } while (e == NULL || e == EXP_CONTINUE_INTERPRET); } key->value = keysave; return e; @@ -946,6 +988,14 @@ printf("type = %s\n", type->toChars()); dump(0); #endif + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *ThisExp::interpret(InterState *istate) +{ + if (istate->localThis) + return istate->localThis->interpret(istate); return EXP_CANT_INTERPRET; } @@ -991,7 +1041,7 @@ if (v) { #if DMDV2 - if ((v->isConst() || v->isInvariant()) && v->init && !v->value) + if ((v->isConst() || v->isInvariant() || v->storage_class & STCmanifest) && v->init && !v->value) #else if (v->isConst() && v->init) #endif @@ -1001,7 +1051,11 @@ } else { e = v->value; - if (!e) + if (v->isDataseg()) + { error(loc, "static variable %s cannot be read at compile time", v->toChars()); + e = EXP_CANT_INTERPRET; + } + else if (!e) error(loc, "variable %s is used before initialization", v->toChars()); else if (e != EXP_CANT_INTERPRET) e = e->interpret(istate); @@ -1060,6 +1114,8 @@ declaration->isTemplateMixin() || declaration->isTupleDeclaration()) { // These can be made to work, too lazy now + error("Declaration %s is not yet implemented in CTFE", toChars()); + e = EXP_CANT_INTERPRET; } else @@ -1067,7 +1123,7 @@ e = NULL; } #if LOG - printf("-DeclarationExp::interpret(): %p\n", e); + printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e); #endif return e; } @@ -1257,7 +1313,9 @@ /* We don't know how to deal with overlapping fields */ if (sd->hasUnions) - return EXP_CANT_INTERPRET; + { error("Unions with overlapping fields are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } if (elements) { @@ -1429,6 +1487,98 @@ BIN_INTERPRET2(Identity) BIN_INTERPRET2(Cmp) +/* Helper functions for BinExp::interpretAssignCommon + */ + +/*************************************** + * Duplicate the elements array, then set field 'indexToChange' = newelem. + */ +Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem) +{ + Expressions *expsx = new Expressions(); + expsx->setDim(oldelems->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j == indexToChange) + expsx->data[j] = newelem; + else + expsx->data[j] = oldelems->data[j]; + } + return expsx; +} + +/*************************************** + * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint..$] + */ +Expressions *spliceElements(Expressions *oldelems, + Expressions *newelems, size_t insertpoint) +{ + Expressions *expsx = new Expressions(); + expsx->setDim(oldelems->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j >= insertpoint && j < insertpoint + newelems->dim) + expsx->data[j] = newelems->data[j - insertpoint]; + else + expsx->data[j] = oldelems->data[j]; + } + return expsx; +} + +/****************************** + * Create an array literal consisting of 'elem' duplicated 'dim' times. + */ +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, + Expression *elem, size_t dim) +{ + Expressions *elements = new Expressions(); + elements->setDim(dim); + for (size_t i = 0; i < dim; i++) + elements->data[i] = elem; + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = type; + return ae; +} + + +/******************************** + * Necessary because defaultInit() for a struct is a VarExp, not a StructLiteralExp. + */ +StructLiteralExp *createDefaultInitStructLiteral(Loc loc, StructDeclaration *sym) +{ + Expressions *structelems = new Expressions(); + structelems->setDim(sym->fields.dim); + for (size_t j = 0; j < structelems->dim; j++) + { + structelems->data[j] = ((VarDeclaration *)(sym->fields.data[j]))->type->defaultInit(); + } + StructLiteralExp *structinit = new StructLiteralExp(loc, sym, structelems); + // Why doesn't the StructLiteralExp constructor do this, when + // sym->type != NULL ? + structinit->type = sym->type; + return structinit; +} + +/******************************** + * Add v to the istate list, unless it already exists there. + */ +void addVarToInterstate(InterState *istate, VarDeclaration *v) +{ + 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; + } + } +} + Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) { #if LOG @@ -1449,7 +1599,43 @@ Expression *e2 = this->e2->interpret(istate); if (e2 == EXP_CANT_INTERPRET) return e2; + + // Chase down rebinding of out and ref. + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +//TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + e1 = v->value; + } + else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar)) + { + // It is no longer be a TOKvar, eg when a[4] is passed by ref. + e1 = v->value; + } + } + // To reduce code complexity of handling dotvar expressions, + // extract the aggregate now. + Expression *aggregate; + if (e1->op == TOKdotvar) { + aggregate = ((DotVarExp *)e1)->e1; + // Get rid of 'this'. + if (aggregate->op == TOKthis && istate->localThis) + aggregate = istate->localThis; + } + /* Assignment to variable of the form: * v = e2 */ @@ -1457,25 +1643,14 @@ { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); + assert(v); + if (v && v->isDataseg()) + { // Can't modify global or static data + error("%s cannot be modified at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } 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->isStaticStructInitDeclaration()) - { - /* This can happen if v is a struct initialized to - * 0 using an StaticStructInitDeclaration 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()); @@ -1492,35 +1667,46 @@ } 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); - } + if (e2 == EXP_CANT_INTERPRET) + return e2; + + addVarToInterstate(istate, v); + v->value = e2; + e = Cast(type, type, post ? ev : e2); } } + else if (e1->op == TOKdotvar && aggregate->op == TOKdotvar) + { // eg v.u.var = e2, v[3].u.var = e2, etc. + error("Nested struct assignment %s is not yet supported in CTFE", toChars()); + } /* 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(); + else if (e1->op == TOKdotvar && aggregate->op == TOKvar) + { VarDeclaration *v = ((VarExp *)aggregate)->var->isVarDeclaration(); if (v->isDataseg()) + { // Can't modify global or static data + error("%s cannot be modified at compile time", v->toChars()); return EXP_CANT_INTERPRET; + } else { + // Chase down rebinding of out and ref + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +//TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + v = ve2->var->isVarDeclaration(); + assert(v); + } + } if (fp && !v->value) { error("variable %s is used before initialization", v->toChars()); return e; @@ -1557,30 +1743,11 @@ 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; - } - } + addVarToInterstate(istate, v); /* 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]; - } + Expressions *expsx = changeOneElement(se->elements, fieldi, e2); v->value = new StructLiteralExp(se->loc, se->sd, expsx); v->value->type = se->type; @@ -1594,7 +1761,10 @@ VarDeclaration *v = soe->var->isVarDeclaration(); if (v->isDataseg()) + { + error("%s cannot be modified at compile time", v->toChars()); return EXP_CANT_INTERPRET; + } if (fp && !v->value) { error("variable %s is used before initialization", v->toChars()); return e; @@ -1619,30 +1789,11 @@ 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; - } - } + addVarToInterstate(istate, v); /* 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]; - } + Expressions *expsx = changeOneElement(se->elements, fieldi, e2); v->value = new StructLiteralExp(se->loc, se->sd, expsx); v->value->type = se->type; @@ -1655,9 +1806,26 @@ { IndexExp *ie = (IndexExp *)e1; VarExp *ve = (VarExp *)ie->e1; VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v || v->isDataseg()) + { + error("%s cannot be modified at compile time", v ? v->toChars(): "void"); return EXP_CANT_INTERPRET; + } + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +// TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + v = ve2->var->isVarDeclaration(); + assert(v); + } if (!v->value) { if (fp) @@ -1675,15 +1843,10 @@ * 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; + v->value = createBlockDuplicatedArrayLiteral(v->type, + v->type->defaultInit(), dim); } else return EXP_CANT_INTERPRET; @@ -1698,9 +1861,20 @@ aae = (AssocArrayLiteralExp *)v->value; else if (v->value->op == TOKstring) se = (StringExp *)v->value; + else if (v->value->op == TOKnull) + { + // This would be a runtime segfault + error("Cannot index null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } else return EXP_CANT_INTERPRET; + /* Set the $ variable + */ + Expression *ee = ArrayLength(Type::tsize_t, v->value); + if (ee != EXP_CANT_INTERPRET && ie->lengthVar) + ie->lengthVar->value = ee; Expression *index = ie->e2->interpret(istate); if (index == EXP_CANT_INTERPRET) return EXP_CANT_INTERPRET; @@ -1718,34 +1892,14 @@ 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; - } - } - + + addVarToInterstate(istate, v); 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]; - } + Expressions *expsx = changeOneElement(ae->elements, elemi, e2); v->value = new ArrayLiteralExp(ae->loc, expsx); v->value->type = ae->type; } @@ -1808,8 +1962,248 @@ e = Cast(type, type, post ? ev : e2); } + + /* Assignment to struct element in array, of the form: + * a[i].var = e2 + */ + else if (e1->op == TOKdotvar && aggregate->op == TOKindex && + ((IndexExp *)aggregate)->e1->op == TOKvar) + { + IndexExp * ie = (IndexExp *)aggregate; + VarExp *ve = (VarExp *)(ie->e1); + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!v || v->isDataseg()) + { + error("%s cannot be modified at compile time", v ? v->toChars(): "void"); + return EXP_CANT_INTERPRET; + } + Type *t = ve->type->toBasetype(); + ArrayLiteralExp *ae = (ArrayLiteralExp *)v->value; + if (!ae) + { + // assignment to one element in an uninitialized (static) array. + // This is quite difficult, because defaultInit() for a struct is a VarExp, + // not a StructLiteralExp. + Type *t = v->type->toBasetype(); + if (t->ty != Tsarray) + { + error("Cannot index an uninitialized variable"); + return EXP_CANT_INTERPRET; + } + + Type *telem = ((TypeSArray *)t)->nextOf()->toBasetype(); + if (telem->ty != Tstruct) { return EXP_CANT_INTERPRET; } + + // Create a default struct literal... + StructDeclaration *sym = ((TypeStruct *)telem)->sym; + StructLiteralExp *structinit = createDefaultInitStructLiteral(v->loc, sym); + + // ... and use to create a blank array literal + size_t dim = ((TypeSArray *)t)->dim->toInteger(); + ae = createBlockDuplicatedArrayLiteral(v->type, structinit, dim); + v->value = ae; + } + if ((Expression *)(ae->elements) == EXP_CANT_INTERPRET) + { + // Note that this would be a runtime segfault + error("Cannot index null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + // Set the $ variable + Expression *ee = ArrayLength(Type::tsize_t, v->value); + if (ee != EXP_CANT_INTERPRET && ie->lengthVar) + ie->lengthVar->value = ee; + // Determine the index, and check that it's OK. + Expression *index = ie->e2->interpret(istate); + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + int elemi = index->toInteger(); + if (elemi >= ae->elements->dim) + { + error("array index %d is out of bounds %s[0..%d]", elemi, + v->toChars(), ae->elements->dim); + return EXP_CANT_INTERPRET; + } + // Get old element + Expression *vie = (Expression *)(ae->elements->data[elemi]); + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + + // Work out which field needs to be changed + 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; + + // Create new struct literal reflecting updated field + Expressions *expsx = changeOneElement(se->elements, fieldi, e2); + Expression * newstruct = new StructLiteralExp(se->loc, se->sd, expsx); + + // Create new array literal reflecting updated struct elem + ae->elements = changeOneElement(ae->elements, elemi, newstruct); + return ae; + } + /* Slice assignment, initialization of static arrays + * a[] = e + */ + else if (e1->op == TOKslice && ((SliceExp *)e1)->e1->op==TOKvar) + { + SliceExp * sexp = (SliceExp *)e1; + VarExp *ve = (VarExp *)(sexp->e1); + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!v || v->isDataseg()) + { + error("%s cannot be modified at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } + // Chase down rebinding of out and ref + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +// TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + v = ve2->var->isVarDeclaration(); + assert(v); + } + /* Set the $ variable + */ + Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value) + : EXP_CANT_INTERPRET; + if (ee != EXP_CANT_INTERPRET && sexp->lengthVar) + sexp->lengthVar->value = ee; + Expression *upper = NULL; + Expression *lower = NULL; + if (sexp->upr) + { + upper = sexp->upr->interpret(istate); + if (upper == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + if (sexp->lwr) + { + lower = sexp->lwr->interpret(istate); + if (lower == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + Type *t = v->type->toBasetype(); + size_t dim; + if (t->ty == Tsarray) + dim = ((TypeSArray *)t)->dim->toInteger(); + else if (t->ty == Tarray) + { + if (!v->value || v->value->op == TOKnull) + { + error("cannot assign to null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + if (v->value->op == TOKarrayliteral) + dim = ((ArrayLiteralExp *)v->value)->elements->dim; + else if (v->value->op ==TOKstring) + { + error("String slice assignment is not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } + } + else + { + error("%s cannot be evaluated at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + int upperbound = upper ? upper->toInteger() : dim; + int lowerbound = lower ? lower->toInteger() : 0; + + ArrayLiteralExp *existing; + if (((int)lowerbound < 0) || (upperbound > dim)) + { + error("Array bounds [0..%d] exceeded in slice [%d..%d]", dim, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + if (upperbound-lowerbound != dim) + { + // Only modifying part of the array. Must create a new array literal. + // If the existing array is uninitialized (this can only happen + // with static arrays), create it. + if (v->value && v->value->op == TOKarrayliteral) + existing = (ArrayLiteralExp *)v->value; + else + { + // this can only happen with static arrays + existing = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim); + } + } + + if (e2->op == TOKarrayliteral) + { + // Static array assignment from literal + ArrayLiteralExp *ae = (ArrayLiteralExp *)e2; + if (ae->elements->dim != (upperbound - lowerbound)) + { + error("Array length mismatch assigning [0..%d] to [%d..%d]", ae->elements->dim, lowerbound, upperbound); + return e; + } + if (upperbound - lowerbound == dim) + v->value = ae; + else + { + // value[] = value[0..lower] ~ ae ~ value[upper..$] + existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); + v->value = existing; + } + return e2; + } + else if (t->nextOf()->ty == e2->type->ty) + { + // Static array block assignment + if (upperbound-lowerbound ==dim) + v->value = createBlockDuplicatedArrayLiteral(v->type, e2, dim); + else + { + // value[] = value[0..lower] ~ ae ~ value[upper..$] + existing->elements = spliceElements(existing->elements, createBlockDuplicatedArrayLiteral(v->type, e2, upperbound-lowerbound)->elements, lowerbound); + v->value = existing; + } + return e2; + } + else if (e2->op == TOKstring) + { + StringExp *se = (StringExp *)e2; + // This is problematic. char[8] should be storing + // values as a string literal, not + // as an array literal. Then, for static arrays, we + // could do modifications + // in-place, with a dramatic memory and speed improvement. + error("String slice assignment is not yet supported in CTFE"); + return e2; + } + else + { + error("Slice operation %s cannot be evaluated at compile time", toChars()); + return e; + } + } else { + error("%s cannot be evaluated at compile time", toChars()); #ifdef DEBUG dump(0); #endif @@ -1923,6 +2317,27 @@ #if LOG printf("CallExp::interpret() %s\n", toChars()); #endif + if (e1->op == TOKdotvar) + { + Expression * pthis = ((DotVarExp*)e1)->e1; + FuncDeclaration *fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); + TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; + if (tf) + { // Member function call + if(pthis->op == TOKthis) + pthis = istate->localThis; + Expression *eresult = fd->interpret(istate, arguments, pthis); + 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; + } + error("cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } if (e1->op == TOKvar) { FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); @@ -2155,6 +2570,17 @@ #if LOG printf("AssertExp::interpret() %s\n", toChars()); #endif + if( this->e1->op == TOKaddress) + { // Special case: deal with compiler-inserted assert(&this, "null this") + AddrExp *ade = (AddrExp *)this->e1; + if(ade->e1->op == TOKthis && istate->localThis) + return istate->localThis->interpret(istate); + } +if (this->e1->op == TOKthis) +{ + if(istate->localThis) + return istate->localThis->interpret(istate); +} e1 = this->e1->interpret(istate); if (e1 == EXP_CANT_INTERPRET) goto Lcant; @@ -2223,6 +2649,14 @@ } } } +#if DMDV2 +#else // this is required for D1, where structs return *this instead of 'this'. + else if (e1->op == TOKthis) + { + if(istate->localThis) + return istate->localThis->interpret(istate); + } +#endif #if LOG if (e == EXP_CANT_INTERPRET) printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); @@ -2249,7 +2683,7 @@ e = EXP_CANT_INTERPRET; return e; } - } + } else error("%s.%s is not yet implemented at compile time", ex->toChars(), var->toChars()); } #if LOG @@ -2278,7 +2712,9 @@ Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) { - //printf("interpret_aaKeys()\n"); +#if LOG + printf("interpret_aaKeys()\n"); +#endif if (!arguments || arguments->dim != 2) return NULL; Expression *earg = (Expression *)arguments->data[0]; @@ -2289,6 +2725,8 @@ return NULL; AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); + Type *elemType = ((TypeAArray *)aae->type)->index; + e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); return e; } @@ -2305,6 +2743,8 @@ return NULL; AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->values); + Type *elemType = ((TypeAArray *)aae->type)->next; + e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); //printf("result is %s\n", e->toChars()); return e; }