@@ -12,8 +12,9 @@ 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 { @@ -23,9 +24,10 @@ /// 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) @@ -155,9 +157,10 @@ 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) @@ -167,24 +170,38 @@ } 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); } } @@ -274,8 +291,9 @@ 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() { @@ -297,9 +315,9 @@ 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 @@ -469,34 +487,4 @@ // @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()`) ); -} -*/