# HG changeset patch # User korDen # Date 1282567944 -14400 # Node ID cab4c37afb8994297e44697ca7f5a87f5d196535 # Parent 6557375aff35bc661de490500c74a8fe51638413 A bunch of implementations diff -r 6557375aff35 -r cab4c37afb89 commands.txt --- a/commands.txt Mon Aug 23 03:21:32 2010 +0400 +++ b/commands.txt Mon Aug 23 16:52:24 2010 +0400 @@ -42,6 +42,7 @@ dmd\CatAssignExp.d dmd\Port.d dmd\declaration\MATCH.d +dmd\interpret\Util.d dmd\templates\Util.d dmd\expression\Util.d dmd\expression\Add.d diff -r 6557375aff35 -r cab4c37afb89 dmd/AddAssignExp.d --- a/dmd/AddAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AddAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -138,7 +138,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/AddExp.d --- a/dmd/AddExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AddExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -111,7 +111,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/AndAndExp.d --- a/dmd/AndAndExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AndAndExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -105,7 +105,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/AndAssignExp.d --- a/dmd/AndAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AndAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -27,7 +27,7 @@ return commonSemanticAssignIntegral(sc); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/AndExp.d --- a/dmd/AndExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AndExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -73,7 +73,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ArrayLengthExp.d --- a/dmd/ArrayLengthExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ArrayLengthExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -54,7 +54,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ArrayLiteralExp.d --- a/dmd/ArrayLiteralExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ArrayLiteralExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -240,7 +240,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/AssertExp.d --- a/dmd/AssertExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AssertExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -90,7 +90,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/AssignExp.d --- a/dmd/AssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -369,9 +369,9 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); + return interpretAssignCommon(istate, null); } Identifier opId() diff -r 6557375aff35 -r cab4c37afb89 dmd/AssocArrayLiteralExp.d --- a/dmd/AssocArrayLiteralExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/AssocArrayLiteralExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -166,7 +166,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/BinExp.d --- a/dmd/BinExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/BinExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -1,6 +1,26 @@ module dmd.BinExp; +import dmd.SliceExp; +import dmd.IndexExp; +import dmd.StructDeclaration; +import dmd.expression.ArrayLength; +import dmd.expression.Equal; +import dmd.expression.Index; +import dmd.ArrayLiteralExp; +import dmd.AssocArrayLiteralExp; +import dmd.StringExp; +import dmd.TypeSArray; +import dmd.PtrExp; +import dmd.SymOffExp; +import dmd.Declaration; +import dmd.StructLiteralExp; import dmd.Expression; +import dmd.interpret.Util; +import dmd.GlobalExpressions; +import dmd.Cast; +import dmd.CastExp; +import dmd.VarDeclaration; +import dmd.DotVarExp; import dmd.Loc; import dmd.ClassDeclaration; import dmd.OutBuffer; @@ -57,6 +77,8 @@ import dmd.backend.iasm : binary; +import std.exception : assumeUnique; +import core.stdc.stdlib : calloc; import std.stdio : writef; /************************************** @@ -652,19 +674,654 @@ assert(false); } - Expression interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)) + Expression interpretCommon(InterState istate, Expression *(*fp)(Type *, Expression *, Expression *)) { assert(false); } - Expression interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)) + Expression interpretCommon2(InterState istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)) { assert(false); } - Expression interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0) + Expression interpretAssignCommon(InterState istate, Expression (*fp)(Type, Expression, Expression), int post = 0) { - assert(false); +version (LOG) { + printf("BinExp.interpretAssignCommon() %.*s\n", toChars()); +} + Expression e = EXP_CANT_INTERPRET; + Expression e1 = this.e1; + + if (fp) + { + if (e1.op == TOKcast) + { + CastExp ce = cast(CastExp)e1; + e1 = ce.e1; + } + } + if (e1 is EXP_CANT_INTERPRET) + return e1; + Expression e2 = this.e2.interpret(istate); + if (e2 is EXP_CANT_INTERPRET) + return e2; + + // Chase down rebinding of out and ref. + if (e1.op == TOKvar) + { + VarExp ve = cast(VarExp)e1; + VarDeclaration v = ve.var.isVarDeclaration(); + if (v && v.value && v.value.op == TOKvar) + { + VarExp ve2 = cast(VarExp)v.value; + if (ve2.var.isSymbolDeclaration()) + { + // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct.defaultInit() + } + else + 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 = (cast(DotVarExp)e1).e1; + // Get rid of 'this'. + if (aggregate.op == TOKthis && istate.localThis) + aggregate = istate.localThis; + } + + /* Assignment to variable of the form: + * v = e2 + */ + if (e1.op == TOKvar) + { + VarExp ve = cast(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()) + { + Expression ev = v.value; + if (fp && !ev) + { + error("variable %s is used before initialization", v.toChars()); + return e; + } + if (fp) + e2 = (*fp)(v.type, ev, e2); + else + { + /* Look for special case of struct being initialized with 0. + */ + if (v.type.toBasetype().ty == Tstruct && e2.op == TOKint64) + { + e2 = v.type.defaultInit(Loc(0)); + } + e2 = Cast(v.type, v.type, e2); + } + if (e2 is 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 && aggregate.op == TOKvar) + { + VarDeclaration v = (cast(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 = cast(VarExp)v.value; + if (ve2.var.isSymbolDeclaration()) + { + // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct.defaultInit() + } + else + v = ve2.var.isVarDeclaration(); + assert(v); + } + } + if (fp && !v.value) + { + error("variable %s is used before initialization", v.toChars()); + return e; + } + if (v.value is null && v.init.isVoidInitializer()) + { + /* Since a void initializer initializes to undefined + * values, it is valid here to use the default initializer. + * No attempt is made to determine if someone actually relies + * on the void value - to do that we'd need a VoidExp. + * That's probably a good enhancement idea. + */ + v.value = v.type.defaultInit(Loc(0)); + } + Expression vie = v.value; + if (vie.op == TOKvar) + { + Declaration d = (cast(VarExp)vie).var; + vie = getVarExp(e1.loc, istate, d); + } + if (vie.op != TOKstructliteral) + return EXP_CANT_INTERPRET; + StructLiteralExp se = cast(StructLiteralExp)vie; + VarDeclaration vf = (cast(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 is EXP_CANT_INTERPRET) + return e2; + + addVarToInterstate(istate, v); + + /* Create new struct literal reflecting updated fieldi + */ + Expressions expsx = changeOneElement(se.elements, fieldi, cast(void*)e2); + v.value = new StructLiteralExp(se.loc, se.sd, expsx); + v.value.type = se.type; + + e = Cast(type, type, post ? ev : e2); + } + /* Assignment to struct member of the form: + * *(symoffexp) = e2 + */ + else if (e1.op == TOKstar && (cast(PtrExp)e1).e1.op == TOKsymoff) + { + SymOffExp soe = cast(SymOffExp)(cast(PtrExp)e1).e1; + 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; + } + Expression vie = v.value; + if (vie.op == TOKvar) + { + Declaration d = (cast(VarExp)vie).var; + vie = getVarExp(e1.loc, istate, d); + } + if (vie.op != TOKstructliteral) + return EXP_CANT_INTERPRET; + StructLiteralExp se = cast(StructLiteralExp)vie; + int fieldi = se.getFieldIndex(type, soe.offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + Expression ev = se.getField(type, soe.offset); + if (fp) + e2 = (*fp)(type, ev, e2); + else + e2 = Cast(type, type, e2); + if (e2 is EXP_CANT_INTERPRET) + return e2; + + addVarToInterstate(istate, v); + + /* Create new struct literal reflecting updated fieldi + */ + Expressions expsx = changeOneElement(se.elements, fieldi, cast(void*)e2); + v.value = new StructLiteralExp(se.loc, se.sd, expsx); + v.value.type = se.type; + + e = Cast(type, type, post ? ev : e2); + } + /* Assignment to array element of the form: + * a[i] = e2 + */ + else if (e1.op == TOKindex && (cast(IndexExp)e1).e1.op == TOKvar) + { + IndexExp ie = cast(IndexExp)e1; + VarExp ve = cast(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 = cast(VarExp)v.value; + if (ve2.var.isSymbolDeclaration()) + { + // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct.defaultInit() + } + else + v = ve2.var.isVarDeclaration(); + assert(v); + } + if (!v.value) + { + if (fp) + { + error("variable %s is used before initialization", v.toChars()); + return e; + } + + Type t = v.type.toBasetype(); + if (t.ty == Tsarray) + { + /* This array was void initialized. Create a + * default initializer for it. + * What we should do is fill the array literal with + * null data, so use-before-initialized can be detected. + * But we're too lazy at the moment to do it, as that + * involves redoing Index() and whoever calls it. + */ + + size_t dim = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); + v.value = createBlockDuplicatedArrayLiteral(v.type, + v.type.defaultInit(Loc(0)), dim); + } + else + return EXP_CANT_INTERPRET; + } + + ArrayLiteralExp ae = null; + AssocArrayLiteralExp aae = null; + StringExp se = null; + if (v.value.op == TOKarrayliteral) + ae = cast(ArrayLiteralExp)v.value; + else if (v.value.op == TOKassocarrayliteral) + aae = cast(AssocArrayLiteralExp)v.value; + else if (v.value.op == TOKstring) + se = cast(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 !is EXP_CANT_INTERPRET && ie.lengthVar) + ie.lengthVar.value = ee; + Expression index = ie.e2.interpret(istate); + if (index is EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + Expression ev; + if (fp || ae || se) // not for aae, because key might not be there + { + ev = Index(type, v.value, index); + if (ev is EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + + if (fp) + e2 = (*fp)(type, ev, e2); + else + e2 = Cast(type, type, e2); + if (e2 is EXP_CANT_INTERPRET) + return e2; + + addVarToInterstate(istate, v); + if (ae) + { + /* Create new array literal reflecting updated elem + */ + int elemi = cast(int)index.toInteger(); + Expressions expsx = changeOneElement(ae.elements, elemi, cast(void*)e2); + v.value = new ArrayLiteralExp(ae.loc, expsx); + v.value.type = ae.type; + } + else if (aae) + { + /* Create new associative array literal reflecting updated key/value + */ + Expressions keysx = aae.keys; + Expressions valuesx = new Expressions(); + valuesx.setDim(aae.values.dim); + int updated = 0; + for (size_t j = valuesx.dim; j; ) + { + j--; + Expression ekey = cast(Expression)aae.keys.data[j]; + Expression ex = Equal(TOKequal, Type.tbool, ekey, index); + if (ex is EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (ex.isBool(true)) + { + valuesx.data[j] = cast(void*)e2; + updated = 1; + } + else + valuesx.data[j] = aae.values.data[j]; + } + if (!updated) + { + // Append index/e2 to keysx[]/valuesx[] + valuesx.push(cast(void*)e2); + keysx = cast(Expressions)keysx.copy(); + keysx.push(cast(void*)index); + } + v.value = new AssocArrayLiteralExp(aae.loc, keysx, valuesx); + v.value.type = aae.type; + } + else if (se) + { + /* Create new string literal reflecting updated elem + */ + int elemi = cast(int)index.toInteger(); + char* s; + s = cast(char*)calloc(se.len + 1, se.sz); + memcpy(s, se.string_, se.len * se.sz); + dchar value = cast(dchar)e2.toInteger(); + switch (se.sz) + { + case 1: s[elemi] = cast(char)value; break; + case 2: (cast(wchar*)s)[elemi] = cast(wchar)value; break; + case 4: (cast(dchar*)s)[elemi] = value; break; + default: + assert(0); + break; + } + StringExp se2 = new StringExp(se.loc, assumeUnique(s[0..se.len])); + se2.committed = se.committed; + se2.postfix = se.postfix; + se2.type = se.type; + v.value = se2; + } + else + assert(0); + + e = Cast(type, type, post ? ev : e2); + } + + /* Assignment to struct element in array, of the form: + * a[i].var = e2 + */ + else if (e1.op == TOKdotvar && aggregate.op == TOKindex && + (cast(IndexExp)aggregate).e1.op == TOKvar) + { + IndexExp ie = cast(IndexExp)aggregate; + VarExp ve = cast(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 = cast(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 t2 = v.type.toBasetype(); + if (t2.ty != Tsarray) + { + error("Cannot index an uninitialized variable"); + return EXP_CANT_INTERPRET; + } + + Type telem = (cast(TypeSArray)t2).nextOf().toBasetype(); + if (telem.ty != Tstruct) { return EXP_CANT_INTERPRET; } + + // Create a default struct literal... + StructDeclaration sym = (cast(TypeStruct)telem).sym; + StructLiteralExp structinit = createDefaultInitStructLiteral(v.loc, sym); + + // ... and use to create a blank array literal + size_t dim = cast(size_t)(cast(TypeSArray)t2).dim.toInteger(); + ae = createBlockDuplicatedArrayLiteral(v.type, structinit, dim); + v.value = ae; + } + if (cast(Expression)(ae.elements) is 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 !is 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 is EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + int elemi = cast(int)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 = cast(Expression)(ae.elements.data[elemi]); + if (vie.op != TOKstructliteral) + return EXP_CANT_INTERPRET; + + // Work out which field needs to be changed + StructLiteralExp se = cast(StructLiteralExp)vie; + VarDeclaration vf = (cast(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, cast(void*)e2); + Expression newstruct = new StructLiteralExp(se.loc, se.sd, expsx); + + // Create new array literal reflecting updated struct elem + ae.elements = changeOneElement(ae.elements, elemi, cast(void*)newstruct); + return ae; + } + /* Slice assignment, initialization of static arrays + * a[] = e + */ + else if (e1.op == TOKslice && (cast(SliceExp)e1).e1.op == TOKvar) + { + SliceExp sexp = cast(SliceExp)e1; + VarExp ve = cast(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 = cast(VarExp)v.value; + if (ve2.var.isSymbolDeclaration()) + { + // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct.defaultInit() + } + else + v = ve2.var.isVarDeclaration(); + assert(v); + } + /* Set the $ variable + */ + Expression ee = v.value ? ArrayLength(Type.tsize_t, v.value) + : EXP_CANT_INTERPRET; + if (ee !is 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 is EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + if (sexp.lwr) + { + lower = sexp.lwr.interpret(istate); + if (lower is EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + Type t = v.type.toBasetype(); + size_t dim; + if (t.ty == Tsarray) + dim = cast(size_t)(cast(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 = (cast(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 ? cast(int)upper.toInteger() : dim; + int lowerbound = lower ? cast(int)lower.toInteger() : 0; + + ArrayLiteralExp existing; + if ((cast(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 = cast(ArrayLiteralExp)v.value; + else + { + // this can only happen with static arrays + existing = createBlockDuplicatedArrayLiteral(v.type, v.type.defaultInit(Loc(0)), dim); + } + } + + if (e2.op == TOKarrayliteral) + { + // Static array assignment from literal + ArrayLiteralExp ae = cast(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 = cast(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()); +version (DEBUG) { + dump(0); +} + } + return e; } bool canThrow() diff -r 6557375aff35 -r cab4c37afb89 dmd/BoolExp.d --- a/dmd/BoolExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/BoolExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -35,7 +35,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/BreakStatement.d --- a/dmd/BreakStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/BreakStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -98,7 +98,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/CallExp.d --- a/dmd/CallExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CallExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -1,6 +1,7 @@ module dmd.CallExp; import dmd.Expression; +import dmd.Cast; import dmd.WANT; import dmd.BUILTIN; import dmd.TypeFunction; @@ -70,6 +71,8 @@ import dmd.backend.TYM; import dmd.codegen.Util; +import std.stdio; + class CallExp : UnaExp { Expressions arguments; @@ -807,9 +810,83 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); + Expression e = EXP_CANT_INTERPRET; + +version (LOG) { + printf("CallExp.interpret() %.*s\n", toChars()); +} + if (e1.op == TOKdotvar) + { + Expression pthis = (cast(DotVarExp)e1).e1; + FuncDeclaration fd = (cast(DotVarExp)e1).var.isFuncDeclaration(); + TypeFunction tf = fd ? cast(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 = (cast(VarExp)e1).var.isFuncDeclaration(); + if (fd) + { +///version (DMDV2) { + BUILTIN b = fd.isBuiltin(); + if (b) + { + scope Expressions args = new Expressions(); + args.setDim(arguments.dim); + for (size_t i = 0; i < args.dim; i++) + { + Expression earg = cast(Expression)arguments.data[i]; + earg = earg.interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return earg; + args.data[i] = cast(void*)earg; + } + e = eval_builtin(b, args); + if (!e) + e = EXP_CANT_INTERPRET; + } + else +///} + // Inline .dup + if (fd.ident == Id.adDup && arguments && arguments.dim == 2) + { + e = cast(Expression)arguments.data[1]; + e = e.interpret(istate); + if (e !is EXP_CANT_INTERPRET) + { + e = expType(type, e); + } + } + else + { + Expression eresult = fd.interpret(istate, arguments); + if (eresult) + e = eresult; + else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } + return e; } bool checkSideEffect(int flag) diff -r 6557375aff35 -r cab4c37afb89 dmd/CaseStatement.d --- a/dmd/CaseStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CaseStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -139,7 +139,7 @@ return true; } - Expression interpret(InterState *istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/Cast.d --- a/dmd/Cast.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/Cast.d Mon Aug 23 16:52:24 2010 +0400 @@ -126,7 +126,7 @@ Expression exp = new IntegerExp(0); exp = Cast(v.type, v.type, exp); - if (exp == EXP_CANT_INTERPRET) + if (exp is EXP_CANT_INTERPRET) return exp; elements.push(cast(void*)exp); } diff -r 6557375aff35 -r cab4c37afb89 dmd/CastExp.d --- a/dmd/CastExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CastExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -336,7 +336,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/CatAssignExp.d --- a/dmd/CatAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CatAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -81,7 +81,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/CatExp.d --- a/dmd/CatExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CatExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -153,9 +153,30 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); + Expression e; + Expression e1; + Expression e2; + +version (LOG) { + printf("CatExp.interpret() %.*s\n", toChars()); +} + e1 = this.e1.interpret(istate); + if (e1 is EXP_CANT_INTERPRET) + { + goto Lcant; + } + e2 = this.e2.interpret(istate); + if (e2 is EXP_CANT_INTERPRET) + goto Lcant; + return Cat(type, e1, e2); + + Lcant: +version (LOG) { + printf("CatExp.interpret() %.*s CANT\n", toChars()); +} + return EXP_CANT_INTERPRET; } Identifier opId() diff -r 6557375aff35 -r cab4c37afb89 dmd/Catch.d --- a/dmd/Catch.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/Catch.d Mon Aug 23 16:52:24 2010 +0400 @@ -33,7 +33,8 @@ Catch syntaxCopy() { - assert(false); + Catch c = new Catch(loc, (type ? type.syntaxCopy() : null), ident, (handler ? handler.syntaxCopy() : null)); + return c; } void semantic(Scope sc) diff -r 6557375aff35 -r cab4c37afb89 dmd/CmpExp.d --- a/dmd/CmpExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CmpExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -130,7 +130,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ComExp.d --- a/dmd/ComExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ComExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -61,7 +61,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/CommaExp.d --- a/dmd/CommaExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CommaExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -118,7 +118,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ComplexExp.d --- a/dmd/ComplexExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ComplexExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -46,7 +46,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/CompoundStatement.d --- a/dmd/CompoundStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/CompoundStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -268,9 +268,33 @@ return rs; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); + Expression e = null; + +version (LOG) { + printf("CompoundStatement.interpret()\n"); +} + if (istate.start == this) + istate.start = null; + if (statements) + { + for (size_t i = 0; i < statements.dim; i++) + { + Statement s = cast(Statement)statements.data[i]; + + if (s) + { + e = s.interpret(istate); + if (e) + break; + } + } + } +version (LOG) { + printf("-CompoundStatement.interpret() %p\n", e); +} + return e; } int inlineCost(InlineCostState* ics) diff -r 6557375aff35 -r cab4c37afb89 dmd/ContinueStatement.d --- a/dmd/ContinueStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ContinueStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -106,7 +106,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/DeclarationExp.d --- a/dmd/DeclarationExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/DeclarationExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -19,6 +19,7 @@ import dmd.Global; import dmd.TOK; import dmd.VoidInitializer; +import dmd.GlobalExpressions; import dmd.Type; import dmd.codegen.Util; @@ -119,9 +120,54 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); +version (LOG) { + printf("DeclarationExp.interpret() %s\n", toChars()); +} + Expression e; + VarDeclaration v = declaration.isVarDeclaration(); + if (v) + { + Dsymbol s = v.toAlias(); + if (s == v && !v.isStatic() && v.init) + { + ExpInitializer ie = v.init.isExpInitializer(); + if (ie) + e = ie.exp.interpret(istate); + else if (v.init.isVoidInitializer()) + e = null; + } +///version (DMDV2) { + else if (s == v && (v.isConst() || v.isInvariant()) && v.init) +///} else { +/// else if (s == v && v.isConst() && v.init) +///} + { + e = v.init.toExpression(); + if (!e) + e = EXP_CANT_INTERPRET; + else if (!e.type) + e.type = v.type; + } + } + else if (declaration.isAttribDeclaration() || + declaration.isTemplateMixin() || + declaration.isTupleDeclaration()) + { + // These can be made to work, too lazy now + error("Declaration %s is not yet implemented in CTFE", toChars()); + + e = EXP_CANT_INTERPRET; + } + else + { // Others should not contain executable code, so are trivial to evaluate + e = null; + } +version (LOG) { + printf("-DeclarationExp.interpret(%.*s): %p\n", toChars(), e); +} + return e; } bool checkSideEffect(int flag) diff -r 6557375aff35 -r cab4c37afb89 dmd/DefaultStatement.d --- a/dmd/DefaultStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/DefaultStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -74,7 +74,7 @@ return true; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/DivAssignExp.d --- a/dmd/DivAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/DivAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -91,7 +91,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/DivExp.d --- a/dmd/DivExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/DivExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -105,7 +105,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/DoStatement.d --- a/dmd/DoStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/DoStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -97,7 +97,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/DotVarExp.d --- a/dmd/DotVarExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/DotVarExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -232,7 +232,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/EqualExp.d --- a/dmd/EqualExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/EqualExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -131,7 +131,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ExpStatement.d --- a/dmd/ExpStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ExpStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -14,6 +14,7 @@ import dmd.IRState; import dmd.BE; import dmd.TOK; +import dmd.GlobalExpressions; import dmd.DeclarationStatement; import dmd.Util : printf; @@ -65,9 +66,22 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); +version (LOG) { + printf("ExpStatement.interpret(%s)\n", exp ? exp.toChars() : ""); +} + mixin(START!()); + if (exp) + { + Expression e = exp.interpret(istate); + if (e is EXP_CANT_INTERPRET) + { + //printf("-ExpStatement.interpret(): %p\n", e); + return EXP_CANT_INTERPRET; + } + } + return null; } BE blockExit() diff -r 6557375aff35 -r cab4c37afb89 dmd/ForStatement.d --- a/dmd/ForStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ForStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -152,7 +152,7 @@ return false; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ForeachRangeStatement.d --- a/dmd/ForeachRangeStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ForeachRangeStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -202,7 +202,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ForeachStatement.d --- a/dmd/ForeachStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ForeachStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -805,7 +805,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/FuncDeclaration.d --- a/dmd/FuncDeclaration.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/FuncDeclaration.d Mon Aug 23 16:52:24 2010 +0400 @@ -2,8 +2,10 @@ import dmd.Declaration; import dmd.DotIdExp; +import dmd.AddrExp; import dmd.TryFinallyStatement; import dmd.StaticDtorDeclaration; +import dmd.GlobalExpressions; import dmd.PeelStatement; import dmd.SynchronizedStatement; import dmd.TOK; @@ -112,7 +114,9 @@ import core.stdc.stdio; import core.stdc.string; -version (Bug4054) import core.memory; +version (Bug4054) import core.memory; + +import dmd.interpret.Util; import std.string; @@ -2067,7 +2071,7 @@ bool isOverloadable() { - assert(false); + return 1; // functions can be overloaded } bool isPure() @@ -2146,9 +2150,282 @@ ident !is Id.cpctor); } - Expression interpret(InterState* istate, Expressions arguments, Expression thisexp = null) + /************************************* + * Attempt to interpret a function given the arguments. + * Input: + * 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 interpret(InterState istate, Expressions arguments, Expression thisarg = null) { - assert(false); +version (LOG) { + printf("\n********\nFuncDeclaration.interpret(istate = %p) %s\n", istate, toChars()); + printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); +} + if (global.errors) + return null; + if (ident == Id.aaLen) + return interpret_aaLen(istate, arguments); + else if (ident == Id.aaKeys) + return interpret_aaKeys(istate, arguments); + else if (ident == Id.aaValues) + return interpret_aaValues(istate, arguments); + + if (cantInterpret || semanticRun == 3) + return null; + + if (!fbody) + { + cantInterpret = 1; + return null; + } + + if (semanticRun < 3 && scope_) + { + semantic3(scope_); + if (global.errors) // if errors compiling this function + return null; + } + if (semanticRun < 4) + return null; + + Type tb = type.toBasetype(); + assert(tb.ty == Tfunction); + TypeFunction tf = cast(TypeFunction)tb; + Type tret = tf.next.toBasetype(); + 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++) + { + Argument arg = Argument.getNth(tf.parameters, i); + if (arg.storageClass & STClazy) + { + cantInterpret = 1; + return null; + } + } + } + + scope InterState istatex = new InterState(); + istatex.caller = istate; + istatex.fd = this; + istatex.localThis = thisarg; + + scope Expressions vsave = new Expressions(); // 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 && (parameters.dim == dim))); + vsave.setDim(dim); + + /* Evaluate all the arguments to the function, + * store the results in eargs[] + */ + scope Expressions eargs = new Expressions(); + eargs.setDim(dim); + + for (size_t i = 0; i < dim; i++) + { + Expression earg = cast(Expression)arguments.data[i]; + Argument arg = Argument.getNth(tf.parameters, i); + + if (arg.storageClass & (STCout | STCref)) + { + } + else + { /* Value parameters + */ + Type ta = arg.type.toBasetype(); + if (ta.ty == Tsarray && earg.op == TOKaddress) + { + /* Static arrays are passed by a simple pointer. + * Skip past this to get at the actual arg. + */ + earg = (cast(AddrExp)earg).e1; + } + earg = earg.interpret(istate ? istate : istatex); + if (earg is EXP_CANT_INTERPRET) + { + cantInterpret = 1; + return null; + } + } + eargs.data[i] = cast(void*)earg; + } + + for (size_t i = 0; i < dim; i++) + { + Expression earg = cast(Expression)eargs.data[i]; + Argument arg = Argument.getNth(tf.parameters, i); + VarDeclaration v = cast(VarDeclaration)parameters.data[i]; + vsave.data[i] = cast(void*)v.value; +version (LOG) { + printf("arg[%d] = %s\n", i, earg.toChars()); +} + if (arg.storageClass & (STCout | STCref) && earg.op==TOKvar) + { + /* Bind out or ref parameter to the corresponding + * variable v2 + */ + 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 = cast(VarExp)earg; + v2 = ve.var.isVarDeclaration(); + if (!v2) + { + cantInterpret = 1; + return null; + } + if (!v2.value || v2.value.op != TOKvar) + break; + if ((cast(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 + } + earg = v2.value; + } + + v.value = new VarExp(earg.loc, v2); + + /* Don't restore the value of v2 upon function return + */ + assert(istate); + for (size_t j = 0; j < istate.vars.dim; j++) + { + VarDeclaration vd = cast(VarDeclaration)istate.vars.data[j]; + if (vd == v2) + { + istate.vars.data[j] = null; + break; + } + } + } + else + { + // Value parameters and non-trivial references + v.value = earg; + } +version (LOG) { + printf("interpreted arg[%d] = %s\n", i, earg.toChars()); +} + } + } + // Don't restore the value of 'this' upon function return + if (needThis() && thisarg.op==TOKvar) { + VarDeclaration thisvar = (cast(VarExp)thisarg).var.isVarDeclaration(); + for (size_t i = 0; i < istate.vars.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)istate.vars.data[i]; + if (v == thisvar) + { + istate.vars.data[i] = null; + break; + } + } + } + + /* Save the values of the local variables used + */ + scope Expressions valueSaves = new Expressions(); + if (istate && !isNested()) + { + //printf("saving local variables...\n"); + valueSaves.setDim(istate.vars.dim); + for (size_t i = 0; i < istate.vars.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)istate.vars.data[i]; + if (v) + { + //printf("\tsaving [%d] %s = %s\n", i, v.toChars(), v.value ? v.value.toChars() : ""); + valueSaves.data[i] = cast(void*)v.value; + v.value = null; + } + } + } + + Expression e = null; + while (1) + { + e = fbody.interpret(istatex); + if (e is EXP_CANT_INTERPRET) + { +version (LOG) { + printf("function body failed to interpret\n"); +} + e = null; + } + + /* This is how we deal with a recursive statement AST + * that has arbitrary goto statements in it. + * Bubble up a 'result' which is the target of the goto + * statement, then go recursively down the AST looking + * for that statement, then execute starting there. + */ + if (e is EXP_GOTO_INTERPRET) + { + istatex.start = istatex.gotoTarget; // set starting statement + istatex.gotoTarget = null; + } + else + break; + } + /* Restore the parameter values + */ + for (size_t i = 0; i < dim; i++) + { + VarDeclaration v = cast(VarDeclaration)parameters.data[i]; + v.value = cast(Expression)vsave.data[i]; + } + + if (istate && !isNested()) + { + /* Restore the variable values + */ + //printf("restoring local variables...\n"); + for (size_t i = 0; i < istate.vars.dim; i++) + { + VarDeclaration v = cast(VarDeclaration)istate.vars.data[i]; + if (v) + { + v.value = cast(Expression)valueSaves.data[i]; + //printf("\trestoring [%d] %s = %s\n", i, v.toChars(), v.value ? v.value.toChars() : ""); + } + } + } + return e; } void inlineScan() @@ -2646,10 +2923,11 @@ type *t; n = sym.Sident; - version (Bug4054) - id = cast(char*) GC.malloc(8 + 5 + strlen(n) + 1); - else - id = cast(char*) alloca(8 + 5 + strlen(n) + 1); + version (Bug4054) { + id = cast(char*) GC.malloc(8 + 5 + strlen(n) + 1); + } else { + id = cast(char*) alloca(8 + 5 + strlen(n) + 1); + } sprintf(id, "_thunk%d__%s", offset, n); s = symbol_calloc(id); slist_add(s); diff -r 6557375aff35 -r cab4c37afb89 dmd/GotoCaseStatement.d --- a/dmd/GotoCaseStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/GotoCaseStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -32,7 +32,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/GotoDefaultStatement.d --- a/dmd/GotoDefaultStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/GotoDefaultStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -31,7 +31,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/GotoStatement.d --- a/dmd/GotoStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/GotoStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -75,7 +75,7 @@ return BE.BEgoto; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/IdentityExp.d --- a/dmd/IdentityExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/IdentityExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -66,7 +66,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/IfStatement.d --- a/dmd/IfStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/IfStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -119,7 +119,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/IndexExp.d --- a/dmd/IndexExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/IndexExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -242,7 +242,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/IntegerExp.d --- a/dmd/IntegerExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/IntegerExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -84,9 +84,12 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); +version (LOG) { + printf("IntegerExp.interpret() %s\n", toChars()); +} + return this; } string toChars() diff -r 6557375aff35 -r cab4c37afb89 dmd/InterState.d --- a/dmd/InterState.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/InterState.d Mon Aug 23 16:52:24 2010 +0400 @@ -5,9 +5,14 @@ import dmd.Expression; import dmd.Statement; -struct InterState +class InterState { - InterState* caller; // calling function's InterState + this() + { + vars = new Dsymbols(); + } + + InterState caller; // calling function's InterState FuncDeclaration fd; // function being interpreted Dsymbols vars; // variables used in this function Statement start; // if !=NULL, start execution at this statement diff -r 6557375aff35 -r cab4c37afb89 dmd/LabelStatement.d --- a/dmd/LabelStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/LabelStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -105,7 +105,7 @@ return true; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/MinAssignExp.d --- a/dmd/MinAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/MinAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -66,7 +66,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/MinExp.d --- a/dmd/MinExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/MinExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -137,7 +137,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ModAssignExp.d --- a/dmd/ModAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ModAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -26,7 +26,7 @@ return commonSemanticAssign(sc); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ModExp.d --- a/dmd/ModExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ModExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -72,7 +72,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/MulAssignExp.d --- a/dmd/MulAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/MulAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -83,7 +83,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/MulExp.d --- a/dmd/MulExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/MulExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -110,7 +110,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/NegExp.d --- a/dmd/NegExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/NegExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -10,7 +10,8 @@ import dmd.Scope; import dmd.IRState; import dmd.ArrayTypes; -import dmd.TOK; +import dmd.TOK; +import dmd.Id; import dmd.expression.Neg; @@ -63,7 +64,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } @@ -80,7 +81,7 @@ Identifier opId() { - assert(false); + return Id.neg; } elem* toElem(IRState* irs) diff -r 6557375aff35 -r cab4c37afb89 dmd/NotExp.d --- a/dmd/NotExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/NotExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -44,7 +44,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/NullExp.d --- a/dmd/NullExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/NullExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -44,7 +44,7 @@ int isConst() { - assert(false); + return 0; } void toCBuffer(OutBuffer buf, HdrGenState* hgs) @@ -135,7 +135,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/OrAssignExp.d --- a/dmd/OrAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/OrAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -27,7 +27,7 @@ return commonSemanticAssignIntegral(sc); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/OrExp.d --- a/dmd/OrExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/OrExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -74,7 +74,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/OrOrExp.d --- a/dmd/OrOrExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/OrOrExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -108,7 +108,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/OverExp.d --- a/dmd/OverExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/OverExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -5,6 +5,7 @@ import dmd.Scope; import dmd.Loc; import dmd.TOK; +import dmd.Type; class OverExp : Expression { @@ -12,8 +13,10 @@ this(OverloadSet s) { - assert(false); - super(Loc(0), TOK.init, 0); + super(loc, TOKoverloadset, OverExp.sizeof); + //printf("OverExp(this = %p, '%s')\n", this, var.toChars()); + vars = s; + type = Type.tvoid; } int isLvalue() diff -r 6557375aff35 -r cab4c37afb89 dmd/OverloadSet.d --- a/dmd/OverloadSet.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/OverloadSet.d Mon Aug 23 16:52:24 2010 +0400 @@ -9,18 +9,18 @@ this() { - assert(false); + a = new Dsymbols(); } void push(Dsymbol s) { - assert(false); + a.push(cast(void*)s); } OverloadSet isOverloadSet() { return this; } string kind() { - assert(false); + return "overloadset"; } } \ No newline at end of file diff -r 6557375aff35 -r cab4c37afb89 dmd/PostExp.d --- a/dmd/PostExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/PostExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -52,7 +52,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/PtrExp.d --- a/dmd/PtrExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/PtrExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -180,7 +180,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/RealExp.d --- a/dmd/RealExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/RealExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -47,7 +47,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ReturnStatement.d --- a/dmd/ReturnStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ReturnStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -32,6 +32,7 @@ import dmd.WANT; import dmd.VarExp; import dmd.VarDeclaration; +import dmd.GlobalExpressions; import dmd.BE; import dmd.codegen.Util; @@ -351,9 +352,21 @@ return result; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); +version (LOG) { + printf("ReturnStatement.interpret(%s)\n", exp ? exp.toChars() : ""); +} + mixin(START!()); + if (!exp) + return EXP_VOID_INTERPRET; +version (LOG) { + Expression e = exp.interpret(istate); + printf("e = %p\n", e); + return e; +} else { + return exp.interpret(istate); +} } int inlineCost(InlineCostState* ics) diff -r 6557375aff35 -r cab4c37afb89 dmd/ScopeStatement.d --- a/dmd/ScopeStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ScopeStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -122,7 +122,7 @@ return statement ? statement.isEmpty() : true; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ShlAssignExp.d --- a/dmd/ShlAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ShlAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -44,7 +44,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ShlExp.d --- a/dmd/ShlExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ShlExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -54,7 +54,7 @@ return shift_optimize(result, this, &Shl); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ShrAssignExp.d --- a/dmd/ShrAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ShrAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -46,7 +46,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/ShrExp.d --- a/dmd/ShrExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ShrExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -52,7 +52,7 @@ return shift_optimize(result, this, &Shr); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/SliceExp.d --- a/dmd/SliceExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/SliceExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -1,6 +1,7 @@ module dmd.SliceExp; import dmd.Expression; +import dmd.expression.ArrayLength; import dmd.backend.elem; import dmd.UnaExp; import dmd.Identifier; @@ -328,9 +329,46 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); + Expression e; + Expression e1; + Expression lwr; + Expression upr; + +version (LOG) { + printf("SliceExp.interpret() %s\n", toChars()); +} + e1 = this.e1.interpret(istate); + if (e1 is EXP_CANT_INTERPRET) + goto Lcant; + if (!this.lwr) + { + e = e1.castTo(null, type); + return e.interpret(istate); + } + + /* Set the $ variable + */ + e = ArrayLength(Type.tsize_t, e1); + if (e is EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar.value = e; + + /* Evaluate lower and upper bounds of slice + */ + lwr = this.lwr.interpret(istate); + if (lwr is EXP_CANT_INTERPRET) + goto Lcant; + upr = this.upr.interpret(istate); + if (upr is EXP_CANT_INTERPRET) + goto Lcant; + + return Slice(type, e1, lwr, upr); + + Lcant: + return EXP_CANT_INTERPRET; } void dump(int indent) diff -r 6557375aff35 -r cab4c37afb89 dmd/Statement.d --- a/dmd/Statement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/Statement.d Mon Aug 23 16:52:24 2010 +0400 @@ -23,6 +23,18 @@ import dmd.Global; import dmd.Util; +template START() +{ + enum START = q{ + if (istate.start) + { + if (istate.start != this) + return null; + istate.start = null; + } + }; +} + class Statement { Loc loc; @@ -159,7 +171,7 @@ return null; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/StringExp.d --- a/dmd/StringExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/StringExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -168,9 +168,12 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); +version (LOG) { + printf("StringExp.interpret() %.*s\n", toChars()); +} + return this; } /********************************** diff -r 6557375aff35 -r cab4c37afb89 dmd/StructLiteralExp.d --- a/dmd/StructLiteralExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/StructLiteralExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -1,11 +1,16 @@ module dmd.StructLiteralExp; import dmd.Expression; +import dmd.expression.Util; +import dmd.ErrorExp; +import dmd.Dsymbol; +import dmd.VarDeclaration; import dmd.StructDeclaration; import dmd.backend.elem; import dmd.InterState; import dmd.MATCH; import dmd.WANT; +import dmd.TY; import dmd.Type; import dmd.OutBuffer; import dmd.Loc; @@ -48,7 +53,95 @@ Expression semantic(Scope sc) { - assert(false); + Expression e; + int nfields = sd.fields.dim - sd.isnested; + +version (LOGSEMANTIC) { + printf("StructLiteralExp.semantic('%s')\n", toChars()); +} + if (type) + return this; + + // Run semantic() on each element + for (size_t i = 0; i < elements.dim; i++) + { + e = cast(Expression)elements.data[i]; + if (!e) + continue; + e = e.semantic(sc); + elements.data[i] = cast(void*)e; + } + expandTuples(elements); + size_t offset = 0; + for (size_t i = 0; i < elements.dim; i++) + { + e = cast(Expression)elements.data[i]; + if (!e) + continue; + + if (!e.type) + error("%s has no value", e.toChars()); + e = resolveProperties(sc, e); + if (i >= nfields) + { + error("more initializers than fields of %s", sd.toChars()); + return new ErrorExp(); + } + Dsymbol s = cast(Dsymbol)sd.fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v); + if (v.offset < offset) + error("overlapping initialization for %s", v.toChars()); + offset = v.offset + cast(uint)v.type.size(); + + Type telem = v.type; + while (!e.implicitConvTo(telem) && telem.toBasetype().ty == Tsarray) + { + /* Static array initialization, as in: + * T[3][5] = e; + */ + telem = telem.toBasetype().nextOf(); + } + + e = e.implicitCastTo(sc, telem); + + elements.data[i] = cast(void*)e; + } + + /* Fill out remainder of elements[] with default initializers for fields[] + */ + for (size_t i = elements.dim; i < nfields; i++) + { + Dsymbol s = cast(Dsymbol)sd.fields.data[i]; + VarDeclaration v = s.isVarDeclaration(); + assert(v); + assert(!v.isThisDeclaration()); + + if (v.offset < offset) + { + e = null; + sd.hasUnions = 1; + } + else + { + if (v.init) + { + e = v.init.toExpression(); + if (!e) + error("cannot make expression out of initializer for %s", v.toChars()); + } + else + { + e = v.type.defaultInit(Loc(0)); + e.loc = loc; + } + offset = v.offset + cast(uint)v.type.size(); + } + elements.push(cast(void*)e); + } + + type = sd.type; + return this; } Expression getField(Type type, uint offset) @@ -102,7 +195,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/SwitchStatement.d --- a/dmd/SwitchStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/SwitchStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -243,7 +243,7 @@ return result; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/TemplateDeclaration.d --- a/dmd/TemplateDeclaration.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/TemplateDeclaration.d Mon Aug 23 16:52:24 2010 +0400 @@ -1290,8 +1290,11 @@ return .isVariadic(parameters); } + /*********************************** + * We can overload templates. + */ bool isOverloadable() { - assert(false); + return 1; } } \ No newline at end of file diff -r 6557375aff35 -r cab4c37afb89 dmd/ThisExp.d --- a/dmd/ThisExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/ThisExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -102,7 +102,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/TryCatchStatement.d --- a/dmd/TryCatchStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/TryCatchStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -35,7 +35,18 @@ Statement syntaxCopy() { - assert(false); + Array a = new Array(); + a.setDim(catches.dim); + for (int i = 0; i < a.dim; i++) + { + Catch c; + + c = cast(Catch)catches.data[i]; + c = c.syntaxCopy(); + a.data[i] = cast(void*)c; + } + TryCatchStatement s = new TryCatchStatement(loc, body_.syntaxCopy(), a); + return s; } Statement semantic(Scope sc) diff -r 6557375aff35 -r cab4c37afb89 dmd/TupleExp.d --- a/dmd/TupleExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/TupleExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -218,7 +218,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/TypeInfoTupleDeclaration.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TypeInfoTupleDeclaration.d Mon Aug 23 16:52:24 2010 +0400 @@ -0,0 +1,18 @@ +module dmd.TypeInfoTupleDeclaration; + +import dmd.Type; +import dmd.TypeInfoDeclaration; +import dmd.backend.dt_t; + +class TypeInfoTupleDeclaration : TypeInfoDeclaration +{ + this(Type tinfo) + { + super(tinfo, 0); + } + + void toDt(dt_t **pdt) + { + assert(false); + } +} \ No newline at end of file diff -r 6557375aff35 -r cab4c37afb89 dmd/TypeTypedef.d --- a/dmd/TypeTypedef.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/TypeTypedef.d Mon Aug 23 16:52:24 2010 +0400 @@ -263,7 +263,15 @@ MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes) { - assert(false); + // Extra check + if (tparam && tparam.ty == Ttypedef) + { + TypeTypedef tp = cast(TypeTypedef)tparam; + + if (sym != tp.sym) + return MATCHnomatch; + } + return Type.deduceType(sc, tparam, parameters, dedtypes); } TypeInfoDeclaration getTypeInfoDeclaration() diff -r 6557375aff35 -r cab4c37afb89 dmd/UnaExp.d --- a/dmd/UnaExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/UnaExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -75,7 +75,7 @@ assert(false); } - Expression interpretCommon(InterState* istate, Expression *(*fp)(Type* a0, Expression* a1)) + Expression interpretCommon(InterState istate, Expression *(*fp)(Type* a0, Expression* a1)) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/UnrolledLoopStatement.d --- a/dmd/UnrolledLoopStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/UnrolledLoopStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -88,7 +88,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/UshrAssignExp.d --- a/dmd/UshrAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/UshrAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -42,7 +42,7 @@ return this; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/UshrExp.d --- a/dmd/UshrExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/UshrExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -52,7 +52,7 @@ return shift_optimize(result, this, &Ushr); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/VarExp.d --- a/dmd/VarExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/VarExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -18,6 +18,7 @@ import dmd.STC; import dmd.SymbolExp; import dmd.Type; +import dmd.interpret.Util; import dmd.backend.dt_t; import dmd.expression.Util; @@ -147,9 +148,12 @@ return fromConstInitializer(result, this); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { - assert(false); +version (LOG) { + printf("VarExp.interpret() %.*s\n", toChars()); +} + return getVarExp(loc, istate, var); } void dump(int indent) diff -r 6557375aff35 -r cab4c37afb89 dmd/WhileStatement.d --- a/dmd/WhileStatement.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/WhileStatement.d Mon Aug 23 16:52:24 2010 +0400 @@ -65,7 +65,7 @@ assert(false); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/XorAssignExp.d --- a/dmd/XorAssignExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/XorAssignExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -25,7 +25,7 @@ return commonSemanticAssignIntegral(sc); } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/XorExp.d --- a/dmd/XorExp.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/XorExp.d Mon Aug 23 16:52:24 2010 +0400 @@ -70,7 +70,7 @@ return e; } - Expression interpret(InterState* istate) + Expression interpret(InterState istate) { assert(false); } diff -r 6557375aff35 -r cab4c37afb89 dmd/expression/Equal.d --- a/dmd/expression/Equal.d Mon Aug 23 03:21:32 2010 +0400 +++ b/dmd/expression/Equal.d Mon Aug 23 16:52:24 2010 +0400 @@ -92,7 +92,7 @@ Expression ee2 = cast(Expression)es2.elements.data[i]; Expression v = Equal(TOK.TOKequal, Type.tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) + if (v is EXP_CANT_INTERPRET) return EXP_CANT_INTERPRET; long tmp = v.toInteger(); cmp = (tmp != 0); @@ -161,7 +161,7 @@ break; } Expression v = Equal(TOK.TOKequal, Type.tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) + if (v is EXP_CANT_INTERPRET) return EXP_CANT_INTERPRET; long tmp = v.toInteger(); cmp = (tmp != 0); diff -r 6557375aff35 -r cab4c37afb89 dmd/interpret/Util.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/interpret/Util.d Mon Aug 23 16:52:24 2010 +0400 @@ -0,0 +1,213 @@ +module dmd.interpret.Util; + +import dmd.StructDeclaration; +import dmd.Expression; +import dmd.InterState; +import dmd.ArrayTypes; +import dmd.GlobalExpressions; +import dmd.TOK; +import dmd.AssocArrayLiteralExp; +import dmd.IntegerExp; +import dmd.Type; +import dmd.Declaration; +import dmd.Loc; +import dmd.ArrayLiteralExp; +import dmd.TypeAArray; +import dmd.TypeSArray; +import dmd.STC; +import dmd.SymbolDeclaration; +import dmd.StructLiteralExp; +import dmd.VarDeclaration; +import dmd.Util; + +Expression interpret_aaLen(InterState istate, Expressions arguments) +{ + if (!arguments || arguments.dim != 1) + return null; + Expression earg = cast(Expression)arguments.data[0]; + earg = earg.interpret(istate); + if (earg is EXP_CANT_INTERPRET) + return null; + if (earg.op != TOKassocarrayliteral) + return null; + AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)earg; + Expression e = new IntegerExp(aae.loc, aae.keys.dim, Type.tsize_t); + return e; +} + +Expression interpret_aaKeys(InterState istate, Expressions arguments) +{ +version (LOG) { + printf("interpret_aaKeys()\n"); +} + if (!arguments || arguments.dim != 2) + return null; + Expression earg = cast(Expression)arguments.data[0]; + earg = earg.interpret(istate); + if (earg is EXP_CANT_INTERPRET) + return null; + if (earg.op != TOKassocarrayliteral) + return null; + AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)earg; + Expression e = new ArrayLiteralExp(aae.loc, aae.keys); + Type elemType = (cast(TypeAArray)aae.type).index; + e.type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments.dim : 0)); + return e; +} + +Expression interpret_aaValues(InterState istate, Expressions arguments) +{ + //printf("interpret_aaValues()\n"); + if (!arguments || arguments.dim != 3) + return null; + Expression earg = cast(Expression)arguments.data[0]; + earg = earg.interpret(istate); + if (earg is EXP_CANT_INTERPRET) + return null; + if (earg.op != TOKassocarrayliteral) + return null; + AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)earg; + Expression e = new ArrayLiteralExp(aae.loc, aae.values); + Type elemType = (cast(TypeAArray)aae.type).next; + e.type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments.dim : 0)); + //printf("result is %s\n", e.toChars()); + return e; +} + +Expression getVarExp(Loc loc, InterState istate, Declaration d) +{ + Expression e = EXP_CANT_INTERPRET; + VarDeclaration v = d.isVarDeclaration(); + SymbolDeclaration s = d.isSymbolDeclaration(); + if (v) + { +///version (DMDV2) { + if ((v.isConst() || v.isInvariant() || v.storage_class & STCmanifest) && v.init && !v.value) +///} else { +/// if (v.isConst() && v.init) +///} + { + e = v.init.toExpression(); + if (e && !e.type) + e.type = v.type; + } + else + { + e = v.value; + 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 !is EXP_CANT_INTERPRET) + e = e.interpret(istate); + } + if (!e) + e = EXP_CANT_INTERPRET; + } + else if (s) + { + if (s.dsym.toInitializer() == s.sym) + { + Expressions exps = new Expressions(); + e = new StructLiteralExp(Loc(0), s.dsym, exps); + e = e.semantic(null); + } + } + return e; +} + +/* 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] = cast(void*)elem; + } + + ArrayLiteralExp ae = new ArrayLiteralExp(Loc(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] = cast(void*)(cast(VarDeclaration)(sym.fields.data[j])).type.defaultInit(Loc(0)); + } + 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(cast(void*)v); + //printf("\tadding %s to istate\n", v.toChars()); + break; + } + if (v == cast(VarDeclaration)istate.vars.data[i]) + break; + } + } +} \ No newline at end of file