changeset 63:cab4c37afb89

A bunch of implementations
author korDen
date Mon, 23 Aug 2010 16:52:24 +0400
parents 6557375aff35
children 4290d870944a
files commands.txt dmd/AddAssignExp.d dmd/AddExp.d dmd/AndAndExp.d dmd/AndAssignExp.d dmd/AndExp.d dmd/ArrayLengthExp.d dmd/ArrayLiteralExp.d dmd/AssertExp.d dmd/AssignExp.d dmd/AssocArrayLiteralExp.d dmd/BinExp.d dmd/BoolExp.d dmd/BreakStatement.d dmd/CallExp.d dmd/CaseStatement.d dmd/Cast.d dmd/CastExp.d dmd/CatAssignExp.d dmd/CatExp.d dmd/Catch.d dmd/CmpExp.d dmd/ComExp.d dmd/CommaExp.d dmd/ComplexExp.d dmd/CompoundStatement.d dmd/ContinueStatement.d dmd/DeclarationExp.d dmd/DefaultStatement.d dmd/DivAssignExp.d dmd/DivExp.d dmd/DoStatement.d dmd/DotVarExp.d dmd/EqualExp.d dmd/ExpStatement.d dmd/ForStatement.d dmd/ForeachRangeStatement.d dmd/ForeachStatement.d dmd/FuncDeclaration.d dmd/GotoCaseStatement.d dmd/GotoDefaultStatement.d dmd/GotoStatement.d dmd/IdentityExp.d dmd/IfStatement.d dmd/IndexExp.d dmd/IntegerExp.d dmd/InterState.d dmd/LabelStatement.d dmd/MinAssignExp.d dmd/MinExp.d dmd/ModAssignExp.d dmd/ModExp.d dmd/MulAssignExp.d dmd/MulExp.d dmd/NegExp.d dmd/NotExp.d dmd/NullExp.d dmd/OrAssignExp.d dmd/OrExp.d dmd/OrOrExp.d dmd/OverExp.d dmd/OverloadSet.d dmd/PostExp.d dmd/PtrExp.d dmd/RealExp.d dmd/ReturnStatement.d dmd/ScopeStatement.d dmd/ShlAssignExp.d dmd/ShlExp.d dmd/ShrAssignExp.d dmd/ShrExp.d dmd/SliceExp.d dmd/Statement.d dmd/StringExp.d dmd/StructLiteralExp.d dmd/SwitchStatement.d dmd/TemplateDeclaration.d dmd/ThisExp.d dmd/TryCatchStatement.d dmd/TupleExp.d dmd/TypeInfoTupleDeclaration.d dmd/TypeTypedef.d dmd/UnaExp.d dmd/UnrolledLoopStatement.d dmd/UshrAssignExp.d dmd/UshrExp.d dmd/VarExp.d dmd/WhileStatement.d dmd/XorAssignExp.d dmd/XorExp.d dmd/expression/Equal.d dmd/interpret/Util.d
diffstat 92 files changed, 1666 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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()
--- 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);
 	}
--- 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()
--- 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);
 	}
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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);
 		}
--- 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);
 	}
--- 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);
 	}
--- 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()
--- 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)
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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()
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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()
--- 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
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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()
--- 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
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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;
 	}
 
 	/**********************************
--- 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);
 	}
--- 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);
 	}
--- 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
--- 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);
 	}
--- 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)
--- 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);
 	}
--- /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
--- 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()
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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)
--- 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);
 	}
--- 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);
 	}
--- 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);
 	}
--- 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);
--- /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