Mercurial > projects > ddmd
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);