Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -258,34 +258,74 @@ this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; } override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } override int opCmp(Object rhs) { if(auto r = cast(UserDefinedFunValue)rhs) { - auto a = cast(void*)this.ast; - auto b = cast(void*)r.ast; - if(ab) return +1; // [TODO] avoid using pointer value... - return this.defCtx.opCmp(r.defCtx); + if(auto c = typeid(void*).compare(cast(void*)ast, cast(void*)r.ast)) + return c; + if(auto c = typeid(void*).compare(cast(void*)defCtx, cast(void*)r.defCtx)) + return c; + return 0;// [TODO] avoid using pointer value... } if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); throw genex!RuntimeException("comparison with value and something other"); } - mixin SimpleToHash; + override hash_t toHash() { + return (cast(hash_t)cast(void*)ast) + (cast(hash_t)cast(void*)defCtx); + } - AST afterMacroAST; + AST macroCache; + static class MemokeyType + { + void* a; Layer b; Tuple!(string,Layer,Value)[] c; + hash_t toHash() { + hash_t h = structuralHash(a) + structuralHash(b); + foreach(e; c) + h += structuralHash(e[0])+structuralHash(e[1])+structuralHash(e[2]); + return h; + } + mixin SimpleToString; + mixin SimpleConstructor; + mixin SimpleCompareWithoutToHash; + } + static Tuple!(Value,int)[MemokeyType] memo; + override Value invoke(Layer lay, Table ctx, LexPosition pos) { if( isASTLayer(lay) ) return eval(ast.funbody, lay, ctx); - if( afterMacroAST is null ) + + auto nonMemoizedRun = (){ + if( macroCache is null ) + { + auto va = macroAndEval(e.funbody, lay, ctx); + macroCache = va[1]; + return va[0]; + } + else + return eval(macroCache, lay, ctx); + }; + + if( !isUserDefinedLayer(lay) ) + return nonMemoizedRun(); + + MemokeyType memokey = new MemokeyType(cast(void*)ast, lay, ctx.direct_entries()); + + if(auto p = memokey in memo) { - auto va = macroAndEval(e.funbody, lay, ctx); - afterMacroAST = va[1]; - return va[0]; + (*p)[1] ++; + return (*p)[0]; } else - return eval(afterMacroAST, lay, ctx); + memo[memokey] = tuple(lift(new UndefinedValue, lay, ctx, pos), 0); + + Value r = nonMemoizedRun(); + + int touched = memo[memokey][1]; + memo[memokey] = tuple(r, 12345678); + //if(touched) {DBG("rerun :: ",r);r = nonMemoizedRun();} // twice!! + return r; } } return new UserDefinedFunValue(e,ctx); } @@ -302,11 +342,13 @@ override int opCmp(Object rhs) { if(auto r = cast(NativeFunValue)rhs) return typeid(typeof(dg)).compare(&dg,&r.dg); if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); throw genex!RuntimeException("comparison with value and something other"); } - mixin SimpleToHash; + override hash_t toHash() const { + return typeid(dg).getHash(&dg); + } R delegate(T) dg; Parameter[] params_data; this(R delegate(T) dg) Index: polemy/failure.d ================================================================== --- polemy/failure.d +++ polemy/failure.d @@ -51,14 +51,14 @@ LexPosition pos; this( LexPosition pos, string msg, string file=null, size_t line=0, Throwable next=null ) { string fullmsg = pos is null ? sprintf!("\n[??] %s")(msg) : sprintf!("\n[%s] %s")(pos, msg); - for(int i=0; i