diff dmd/FuncDeclaration.d @ 63:cab4c37afb89

A bunch of implementations
author korDen
date Mon, 23 Aug 2010 16:52:24 +0400
parents fd4acc376c45
children ee3a9f34dc48
line wrap: on
line diff
--- 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);