Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -112,20 +112,35 @@ import std.typetuple; Value eval(AST e, Table ctx, bool splitCtx, Layer lay) { return e.match( (StrLiteral e) - { - return new StrValue(e.data); + { + Value v = new StrValue(e.data); + if( lay == "@v" ) + return v; + else + return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [v]); }, (IntLiteral e) { - return new IntValue(e.data); + Value v = new IntValue(e.data); + if( lay == "@v" ) + return v; + else // are these "@v"s appropriate??? + return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", [v]); }, (VarExpression e) { - return ctx.get(e.var, lay, e.pos); + try { + return ctx.get(e.var, lay, e.pos); + } catch( RuntimeException ) { + // rise + return (cast(FunValue)ctx.get(lay, "(system)", e.pos)).call(e.pos, "@v", + [ctx.get(e.var, "@v", e.pos)] + ); + } }, (LayeredExpression e) { return eval(e.expr, ctx, false, e.lay); }, @@ -216,10 +231,15 @@ fib(10);`).val, new IntValue(BigInt(89))); } unittest { - assert_throw!Throwable( evalString(`@s "+"=fun(x,y){x-y};@s(1+2)`) ); - assert_eq( evalString(`@s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) ); - assert_eq( evalString(`@s "+"=fun(x,y){@v(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) ); - assert_eq( evalString(`@s "+"=fun(x,y){@v(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) ); + assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) ); + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) ); + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@v(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) ); + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@v(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) ); +} + +unittest +{ + assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) ); } Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -74,36 +74,63 @@ AST Declaration() // returns null if it is not a declaration { /// Declaration ::= /// ["@" Layer|"let"|"var"|"def"] Var "=" Expression ([";"|"in"] Body?)? /// | ["@" Layer|"let"|"var"|"def"] Var "(" Param%"," ")" "{" Body "}" ([";"|"in"] Body?)? + /// | ["@" "@" Layer "=" Expression ([";"|"in"] Body?)? + /// | ["@" "@" Layer "(" Param%"," ")" "{" Body "}" ([";"|"in"] Body?)? auto pos = currentPosition(); string layer = ""; + bool layerRiseDecl = false; if( tryEat("@") ) { layer = "@" ~ eatId("after @", AllowQuoted); - if( tryEat("(") ) - return null; // @lay(...) expression, not a declaration - } - - string kwd = layer; - if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="var") && !tryEat(kwd="def") ) - return null; // none of {@lay, let, var, def} occurred, it's not a declaration - - auto varpos = currentPosition(); - string var = eatId("after "~kwd, AllowQuoted); // name of the declared variable - - auto e = tryEat("(") - ? parseLambdaAfterOpenParen(varpos) // let var ( ... - : (eat("=", "after "~kwd), E(0)); // let var = ... - - if( moreDeclarationExists() ) - return new LetExpression(pos, var, layer, e, Body()); + if( layer == "@@" ) + { + layer = "@" ~ eatId("after @@", AllowQuoted); + layerRiseDecl = true; + } + else + { + if( tryEat("(") ) + return null; // @lay(...) expression, not a declaration + } + } + + // [TODO] Refactor + if( layerRiseDecl ) + { + string kwd = "@" ~ layer; + string var = layer; + + auto e = tryEat("(") + ? parseLambdaAfterOpenParen(pos) // let var ( ... + : (eat("=", "after "~kwd), E(0)); // let var = ... + if( moreDeclarationExists() ) + return new LetExpression(pos, var, "(system)", e, Body()); + else + return new LetExpression(pos, var, "(system)", e, new VarExpression(pos, var)); + } else - return new LetExpression(pos, var, layer, e, new VarExpression(varpos, var)); + { + string kwd = layer; + if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="var") && !tryEat(kwd="def") ) + return null; // none of {@lay, let, var, def} occurred, it's not a declaration + + auto varpos = currentPosition(); + string var = eatId("after "~kwd, AllowQuoted); // name of the declared variable + + auto e = tryEat("(") + ? parseLambdaAfterOpenParen(varpos) // let var ( ... + : (eat("=", "after "~kwd), E(0)); // let var = ... + if( moreDeclarationExists() ) + return new LetExpression(pos, var, layer, e, Body()); + else + return new LetExpression(pos, var, layer, e, new VarExpression(varpos, var)); + } } AST TopLevelExpression() { /// TopLevelExpression ::= Expression ([";"|"in"] Body?)? @@ -406,6 +433,9 @@ assert_eq(parseString(`def foo(x) { x+1 }; foo`), let("foo", "", fun(["x"], call(var("+"), var("x"), intl(1))), var("foo")) ); + + assert_eq(parseString(`@@type ( x ) { x }`), + let("@type", "(system)", fun(["x"], var("x")), var("@type")) ); }