Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -28,24 +28,18 @@ ctx.set(">", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} )); ctx.set("<=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} )); ctx.set(">=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} )); ctx.set("==", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} )); ctx.set("!=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} )); - ctx.set("print", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - foreach(a; args) - write(a); - writeln(""); + ctx.set("print", "@v", native( (Value a){ + writeln(a); return new IntValue(BigInt(178)); })); - ctx.set("if", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){ - if( args.length != 3 ) - throw genex!RuntimeException(pos, "if takes three arguments!!"); - if( auto x = cast(IntValue)args[0] ) - if( auto ft = cast(FunValue)args[1] ) - if( auto fe = cast(FunValue)args[2] ) - return (x.data == 0 ? fe : ft).call(pos,lay,[]); - throw genex!RuntimeException(pos, "type mismatch in if"); + ctx.set("if", "@v", native( (IntValue x, FunValue ft, FunValue fe){ + auto toRun = (x.data==0 ? fe : ft); + return toRun.invoke(null, "@v", toRun.definitionContext()); +// return toRun.invoke(pos, lay, toRun.definitionContext()); })); ctx.set("_isint", "@v", native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} )); ctx.set("_isstr", "@v", native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} )); ctx.set("_isfun", "@v", native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} )); ctx.set("_isundefined", "@v", native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} )); @@ -86,11 +80,54 @@ Tuple!(Value,"val",Table,"ctx") eval(AST e) { Table ctx = createGlobalContext(); return typeof(return)(eval(e, ctx, false, "@v"), ctx); } - + +Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false) +{ + if(auto f = cast(FunValue)_f) + { + Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); + foreach(i,p; f.params()) + if( p.layers.empty ) + if(lay=="@macro") + ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro)); + else + ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay)); + else + foreach(argLay; p.layers) + if(argLay=="@macro") + ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro)); + else + ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay)); + return f.invoke(pos, lay, ctx); + } + throw genex!RuntimeException(pos, "tried to call non-function"); +} + +Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx) +{ + // similar to invoke Function, but with only one argument bound to @v + Value _f = callerCtx.get(lay, "(system)", pos); + if(auto f = cast(FunValue)_f) + { + Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); + auto ps = f.params(); + if( ps.length != 1 ) + throw genex!RuntimeException(pos, "lift function must take exactly one argument at @v layer"); + if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]=="@v" ) + { + ctx.set(ps[0].name, "@v", v); + return f.invoke(pos, "@v", ctx); + } + else + throw genex!RuntimeException(pos, "lift function must take exactly one argument at @v layer"); + } + throw genex!RuntimeException(pos, "tried to call non-function"); +} + /// Entry point of this module /// If splitCtx = true, then inner variable declaration do not overwrite ctx. /// lay is the layer ID for evaluation (standard value semantics uses "@v"). Value eval(AST e, Table ctx, bool splitCtx, Layer lay) @@ -99,32 +136,29 @@ (StrLiteral e) { Value v = new StrValue(e.data); if( lay == "@v" ) return v; - else // rise - return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [v]); + else + return lift(e.pos,v,lay,ctx); }, (IntLiteral e) { Value v = new IntValue(e.data); if( lay == "@v" ) return v; else // rise - return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [v]); + return lift(e.pos,v,lay,ctx); }, (VarExpression e) { if( lay == "@v" ) return ctx.get(e.var, lay, e.pos); try { return ctx.get(e.var, lay, e.pos); } catch( Throwable ) { // [TODO] more precise... - // rise from @v - return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", - [ctx.get(e.var, "@v", e.pos)] - ); + return lift(e.pos, ctx.get(e.var, "@v", e.pos), lay, ctx); } }, (LayeredExpression e) { if( e.lay == "@macro" ) @@ -142,59 +176,20 @@ ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos); return eval(e.expr, ctx, false, lay); }, (FuncallExpression e) { - Value _f = eval(e.fun, ctx, true, lay); - if( auto f = cast(FunValue)_f ) { - Value[] args; - foreach(a; e.args) - args ~= eval(a, ctx, true, lay); - return f.call(e.pos, lay, args); - } - throw genex!RuntimeException(e.pos, "Non-funcion is applied"); + return invokeFunction(e.pos, eval(e.fun, ctx, true, lay), e.args, ctx, lay); }, (FunLiteral e) { Value[Value[]][Layer] memo; AST macroMemo = null; // cache // funvalue need not be rised - // no, need to be rised !! suppose @t(fib)("int") - return new FunValue(delegate Value(immutable LexPosition pos, string lay, Value[] args){ - // TODO: only auto raised ones need memo? no? - // auto memoization - if( lay != "@v" && lay != "@macro" ) - { - if( auto memolay = lay in memo ) - if( auto pv = args in *memolay ) - return *pv; - memo[lay][args] = (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", - [new UndValue] - ); - } - - if( e.params.length != args.length ) - throw genex!RuntimeException(e.pos, sprintf!"Argument Number Mismatch (%d required but %d given)" - (e.params.length, args.length)); - Table ctxNeo = new Table(ctx, Table.Kind.NotPropagateSet); - foreach(i,p; e.params) - ctxNeo.set(p.name, lay, args[i]); - - // @macro run!!! - if( lay == "@macro" ) - return macroEval(e.funbody, ctxNeo, false); - if( macroMemo is null ) - macroMemo = tableToAST("@v",macroEval(e.funbody, ctxNeo, true)); - auto v = eval(macroMemo, ctxNeo, true, lay); - - //auto v = eval(e.funbody, ctxNeo, true, lay); - // auto memoization - if( lay != "@v" && lay != "@macro" ) - memo[lay][args] = v; - return v; - }); + // no, need to be rised !! suppose @t(fib)("int") + return new UserDefinedFunValue(e, ctx); }, delegate Value (AST e) { throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e))); } @@ -250,11 +245,14 @@ t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro)); return cast(Value)t; } else { - return eval(e.expr, ctx, true, e.lay); + if( e.lay == "@macro" ) + return macroEval(e.expr, ctx, false); + else + return eval(e.expr, ctx, true, e.lay); } }, (LetExpression e) { Table t = new Table; @@ -267,19 +265,13 @@ }, (FuncallExpression e) { Value _f = macroEval(e.fun,ctx,AlwaysMacro); - // copy & pase from normal eval - // [TODO] sync with @layerd parameters. - if( auto f = cast(FunValue)_f ) { - Value[] args; - foreach(a; e.args) - args ~= macroEval(a, ctx, AlwaysMacro); - return f.call(e.pos, "@macro", args); // explicit @macro is the best??? - } - + if( auto f = cast(FunValue)_f ) + return invokeFunction(e.pos, f, e.args, ctx, "@macro", AlwaysMacro); + Table t = new Table; t.set("pos", theLayer, pos); t.set("is", theLayer, new StrValue("app")); t.set("fun", theLayer, _f); Table args = new Table; @@ -388,5 +380,6 @@ assert_nothrow( evalString(`def foo() { def bar(y) { if(y<1) {0} else {bar(0)} }; bar(1) }; foo()`) ); } + Index: polemy/value.d ================================================================== --- polemy/value.d +++ polemy/value.d @@ -31,56 +31,106 @@ mixin SimpleClass; override string toString() const { return data; } } -/// -class FunValue : Value -{ - Value delegate(immutable LexPosition pos, string lay, Value[]) data; - - mixin SimpleConstructor; - alias data call; - override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); } -} - /// class UndValue : Value { mixin SimpleClass; override string toString() const { return ""; } } -/// Named Constructor for FunValue -FunValue nativef(Value delegate(immutable LexPosition pos, Layer lay, Value[] args) dg) +/// +abstract class FunValue : Value +{ + const(Parameter[]) params(); + Table definitionContext(); + Value invoke(in LexPosition pos, Layer lay, Table ctx); +} + +import polemy.eval; // circular... + +/// +class UserDefinedFunValue : FunValue +{ + FunLiteral ast; + Table defCtx; + override const(Parameter[]) params() { return ast.params; } + override Table definitionContext() { return defCtx; } + override Value invoke(in LexPosition pos, Layer lay, Table ctx) + { + // TODO: only auto raised ones need memo? no? + // auto memoization +/* + if( lay != "@v" && lay != "@macro" ) + { + if( auto memolay = lay in memo ) + if( auto pv = args in *memolay ) + return *pv; + memo[lay][args] = lift(e.pos,new UndValue,lay,ctx); + } + +*/ + // @macro run!!! + if( lay == "@macro" ) + return macroEval(ast.funbody, ctx, false); +/*TODO memo*/ AST macroMemo; + if( macroMemo is null ) { + // .prototype!, forced macro cannot access parameters + ctx.kill = true; scope(exit)ctx.kill=false; + macroMemo = tableToAST("@v",macroEval(ast.funbody, ctx, true)); + } + auto v = eval(macroMemo, ctx, true, lay); + + //auto v = eval(e.funbody, ctxNeo, true, lay); + // auto memoization +// if( lay != "@v" && lay != "@macro" ) +// memo[lay][args] = v; + return v; + } + + mixin SimpleClass; + override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } +} + +/// +abstract class NativeFunValue : FunValue { - return new FunValue(dg); + Parameter[] params_data; + override const(Parameter[]) params() { return params_data; } + override Table definitionContext() { return new Table; } // todo: cache overrie } /// Named Constructor for FunValue FunValue native(R,T...)(R delegate (T) dg) { - return nativef( delegate Value(immutable LexPosition pos, Layer lay, Value[] args) { - if( lay != "@v" ) - throw genex!RuntimeException(pos, "only @v layer can call native function"); - if( T.length != args.length ) - throw genex!RuntimeException(pos, "argument number mismatch!"); - T typed_args; - foreach(i, Ti; T) + return new class NativeFunValue { + this() + { + foreach(i, Ti; T) + params_data ~= new Parameter(text(i), []); + } + override Value invoke(in LexPosition pos, Layer lay, Table ctx) { - typed_args[i] = cast(Ti) args[i]; - if( typed_args[i] is null ) - throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); - } - try { - return dg(typed_args); - } catch( RuntimeException e ) { - throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; + if( lay != "@v" ) + throw genex!RuntimeException(pos, "only @v layer can call native function"); + T typed_args; + foreach(i, Ti; T) { + typed_args[i] = cast(Ti) ctx.get(text(i), "@v"); + if( typed_args[i] is null ) + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); + } + try { + return dg(typed_args); + } catch( RuntimeException e ) { + throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; + } } - }); + }; } /// Layer ID alias string Layer; @@ -90,10 +140,11 @@ /// But extended with the notion of "Layer" class Table : Value { enum Kind {PropagateSet, NotPropagateSet}; + bool kill = false; // to refactor this( Table proto=null, Kind k = Kind.PropagateSet ) { this.prototype = proto; this.kind = k; } void set(string i, Layer lay, Value v, in LexPosition pos=null) @@ -105,10 +156,12 @@ bool has(string i, Layer lay, in LexPosition pos=null) { if( i in data ) { if( lay !in data[i] ) + return false; + if(kill) return false; return true; } if( prototype is null ) return false; @@ -119,10 +172,12 @@ { if( i in data ) { // [TODO] consider forwarding to proto also in this case if( lay !in data[i] ) throw genex!RuntimeException(pos, sprintf!"variable %s is not set in layer %s"(i,lay)); + if(kill) + throw genex!RuntimeException(pos, sprintf!"variable %s is killed in macro"(i)); return data[i][lay]; } if( prototype is null ) throw new RuntimeException(pos, sprintf!"variable %s not found"(i)); return prototype.get(i, lay, pos); Index: sample/macro.pmy ================================================================== --- sample/macro.pmy +++ sample/macro.pmy @@ -49,9 +49,8 @@ print(maxBad(printAndReturn(100),printAndReturn(200))); print("--------------"); print( LetItBe( 1+2+3, it*it ) ); print("--------------"); print(pow10(2)); - }; main()