Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -11,10 +11,11 @@ import polemy.parse; import polemy.value; import polemy.layer; import polemy.value; import polemy.valueconv; +import std.signals; /// Objects for maitaining global environment and evaluation of expression on it class Evaluator { public: @@ -22,11 +23,12 @@ this() { theContext = new Table; } /// Evaluate the AST Value evalAST(AST e) { - return macroAndEval(e, ValueLayer, theContext, OverwriteCtx)[0]; + AST[void*] mandeCache; + return macroAndEval(e, ValueLayer, theContext, OverwriteCtx, mandeCache)[0]; } /// Evaluate the string Value evalString(S,T...)(S str, T fn_ln_cn) { @@ -154,11 +156,12 @@ private: // little little bit incremental macro defining version. // enables @macro foo(x)=... in ... foo ..., only at the top level of the // interpreter and functions. better than nothing :P - Tuple!(Value,AST) macroAndEval( AST e_, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) + Tuple!(Value,AST) macroAndEval( AST e_, Layer lay, Table ctx, bool overwriteCtx + , ref AST[void*] mandeCache) // [TODO] avoid assuming non-moving GC { assert( !isASTLayer(lay) ); AST decodeAST(Value v, LexPosition pos) { @@ -166,26 +169,40 @@ return polemy2d!(AST)(v, pos); } if(auto e = cast(Let)e_) { - AST ai = decodeAST(eval(e.init, RawMacroLayer, ctx), e.init.pos); + void* key = cast(void*)e.init; + AST ai; + if(auto p = key in mandeCache) + ai = *p; + else { + ai = decodeAST(eval(e.init, RawMacroLayer, ctx), e.init.pos); + mandeCache[key] = ai; + } Value vi = eval(ai, lay, ctx); if( !overwriteCtx ) ctx = new Table(ctx, Table.Kind.NotPropagateSet); string theLayer = e.layer.empty ? lay : e.layer; ctx.set(e.name, theLayer, vi); - auto ave = macroAndEval( e.expr, lay, ctx, OverwriteCtx ); + auto ave = macroAndEval( e.expr, lay, ctx, OverwriteCtx, mandeCache ); AST a = new Let(e.pos, e.name, e.layer, ai, ave[1]); return tuple(ave[0], a); } else { - AST a = decodeAST(eval(e_, RawMacroLayer, ctx), e_.pos); - Value v = eval(a, lay, ctx); + void* key = cast(void*)e_; + AST a; + if(auto p = key in mandeCache) + a = *p; + else { + a = decodeAST(eval(e_, RawMacroLayer, ctx), e_.pos); + mandeCache[key] = a; + } + Value v = eval(a, lay, ctx, overwriteCtx); return tuple(v, a); } } private: @@ -273,10 +290,11 @@ override hash_t toHash() { return (cast(hash_t)cast(void*)ast) + (cast(hash_t)cast(void*)defCtx); } AST macroCache; + AST[void*] mandeCache; static class MemokeyType { void* a; Layer b; Tuple!(string,Layer,Value)[] c; hash_t toHash() { hash_t h = structuralHash(a) + structuralHash(b); @@ -296,11 +314,11 @@ return eval(ast.funbody, lay, ctx); auto nonMemoizedRun = (){ if( macroCache is null ) { - auto va = macroAndEval(e.funbody, lay, ctx); + auto va = macroAndEval(e.funbody, lay, ctx, CascadeCtx, mandeCache); macroCache = va[1]; return va[0]; } else return eval(macroCache, lay, ctx); @@ -468,35 +486,5 @@ // this is a shorthand for // @macro x = fun(){} in @macro(x) // so it is ok to fail, but it is really incovenient on REPL assert_nothrow( e.evalString(`@macro x=fun(){}`) ); } - -/* -unittest -{ - assert_eq( evalString(`var fac = fun(x){ - if(x) - { x*fac(x-1); } - else - { 1; }; - }; - fac(10);`).val, new IntValue(BigInt(10*9*8*5040))); - assert_eq( evalString(`var fib = fun(x){ - if(x<2) - { 1; } - else - { fib(x-1) + fib(x-2); }; - }; - fib(5);`).val, new IntValue(BigInt(8))); -} -unittest -{ - assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) ); - // there was a bug that declaration in the first line of function definition - // cannot be recursive - assert_nothrow( evalString(`def foo() { - def bar(y) { if(y<1) {0} else {bar(0)} }; - bar(1) -}; foo()`) ); -} -*/