Check-in [6ac127ddd0]
Not logged in
Overview
SHA1 Hash:6ac127ddd018bd755afda6da3b52bd5f3cac909c
Date: 2010-11-23 16:42:13
User: kinaba
Comment:new evaluator
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified .poseidon from [ce44f33cc750cc08] to [92babe531ac51123].

35 35 <name>polemy\ast.d</name> 36 36 <name>polemy\eval.d</name> 37 37 <name>polemy\failure.d</name> 38 38 <name>polemy\fresh.d</name> 39 39 <name>polemy\layer.d</name> 40 40 <name>polemy\lex.d</name> 41 41 <name>polemy\parse.d</name> 42 + <name>polemy\runtime.d</name> 42 43 <name>polemy\value.d</name> 43 44 <name>tricks\test.d</name> 44 45 <name>tricks\tricks.d</name> 45 46 </source> 46 47 <interface /> 47 48 <resource /> 48 49 <othersDMD />

Modified doc/candydoc/modules.ddoc from [db7191f79aae7372] to [5f7a14107fdf7182].

6 6 $(MODULE polemy.failure) 7 7 $(MODULE polemy.layer) 8 8 $(MODULE polemy.fresh) 9 9 $(MODULE polemy.lex) 10 10 $(MODULE polemy.parse) 11 11 $(MODULE polemy.ast) 12 12 $(MODULE polemy.eval) 13 + $(MODULE polemy.runtime) 13 14 $(MODULE polemy.value)

Modified main.d from [636370f08c051cf2] to [e659b2cb410288fd].

6 6 */ 7 7 module main; 8 8 import std.stdio; 9 9 import std.algorithm; 10 10 import std.array; 11 11 import polemy.value; 12 12 import polemy.failure; 13 +import polemy.layer; 13 14 import polemy.parse; 14 15 import polemy.ast; 15 16 import polemy.eval; 16 -import polemy.layer; 17 17 18 18 enum VersionNoMajor = 0; 19 19 enum VersionNoMinor = 1; 20 20 enum VersionNoRev = 0; 21 21 22 22 /// Read-Eval-Print-Loop 23 23 24 24 class REPL 25 25 { 26 +Evaluator ev; 26 27 /// Load the prelude environment 27 28 this() 28 29 { 29 - ctx = createGlobalContext(); 30 + ev = new Evaluator; 30 31 } 31 32 32 33 /// Print the version number etc. 33 34 void greet() 34 35 { 35 36 writefln("Welcome to Polemy %d.%d.%d", VersionNoMajor, VersionNoMinor, VersionNoRev); 36 37 } 37 38 38 39 /// Run one file on the global scope 39 40 void runFile(string filename) 40 41 { 41 - eval(parseFile(filename), ctx, false, ValueLayer); 42 + ev.evalFile(filename); 42 43 } 43 44 44 45 /// Repeat the singleInteraction 45 46 void replLoop() 46 47 { 47 48 while( singleInteraction() ) {} 48 49 } ................................................................................ 74 75 { 75 76 scope(failure) 76 77 { buf = ""; lineno = nextlineno; } 77 78 78 79 buf ~= s; 79 80 nextlineno ++; 80 81 try 81 - { lastVal = eval(parseString(buf, "<REPL>", lineno), ctx, false, ValueLayer); } 82 + { lastVal = ev.evalString(buf, "<REPL>", lineno); } 82 83 catch( UnexpectedEOF ) 83 84 { return false; } // wait 84 85 buf = ""; 85 86 lineno = nextlineno; 86 87 return true; 87 88 } 88 89 }

Modified polemy/_common.d from [05624ab3274c99f8] to [05c4f6a92646def3].

10 10 public import std.algorithm; 11 11 public import std.array; 12 12 public import std.bigint; 13 13 public import std.conv : text; 14 14 public import std.exception; 15 15 public import std.range; 16 16 public import std.stdio : DBG = writeln; 17 +public import std.typecons; 18 +public import std.typetuple;

Modified polemy/ast.d from [73653a45c2c5d30a] to [cf8f245149fce4dc].

14 14 { 15 15 LexPosition pos; 16 16 mixin SimpleConstructor; 17 17 mixin SimplePatternMatch; 18 18 } 19 19 20 20 /// 21 -class IntLiteral : AST 21 +class Int : AST 22 22 { 23 23 BigInt data; 24 24 mixin SimpleClass; 25 25 this(LexPosition pos, int n) {super(pos); data = n;} 26 26 this(LexPosition pos, long n) {super(pos); data = n;} 27 27 this(LexPosition pos, BigInt n) {super(pos); data = n;} 28 28 this(LexPosition pos, string n) {super(pos); data = BigInt(n);} 29 29 } 30 30 31 31 /// 32 -class StrLiteral : AST 32 +class Str : AST 33 33 { 34 34 string data; 35 35 mixin SimpleClass; 36 36 } 37 37 38 38 /// 39 -class VarExpression : AST 39 +class Var : AST 40 40 { 41 41 string name; 42 42 mixin SimpleClass; 43 43 } 44 44 45 45 /// 46 -class LayExpression : AST 46 +class Lay : AST 47 47 { 48 48 Layer layer; 49 49 AST expr; 50 50 mixin SimpleClass; 51 51 } 52 52 53 53 /// 54 -class LetExpression : AST 54 +class Let : AST 55 55 { 56 56 string name; 57 57 Layer layer; 58 58 AST init; 59 59 AST expr; 60 60 mixin SimpleClass; 61 61 } 62 62 63 63 /// 64 -class FuncallExpression : AST 64 +class App : AST 65 65 { 66 66 AST fun; 67 67 AST[] args; 68 68 this(LexPosition pos, AST fun, AST[] args...) 69 69 { super(pos); this.fun=fun; this.args=args.dup; } 70 70 mixin SimpleClass; 71 71 } ................................................................................ 75 75 { 76 76 string name; 77 77 Layer[] layers; 78 78 mixin SimpleClass; 79 79 } 80 80 81 81 /// 82 -class FunLiteral : AST 82 +class Fun : AST 83 83 { 84 84 Parameter[] params; 85 85 AST funbody; 86 86 mixin SimpleClass; 87 87 } 88 88 89 89 /// Handy Generator for AST nodes. To use this, mixin EasyAst; ................................................................................ 91 91 /*mixin*/ 92 92 template EasyAST() 93 93 { 94 94 /// 95 95 template genEast(T) 96 96 { T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } } 97 97 98 - alias genEast!StrLiteral strl; /// 99 - alias genEast!IntLiteral intl; /// 98 + alias genEast!Str strl; /// 99 + alias genEast!Int intl; /// 100 100 auto fun(string[] xs, AST ps) { 101 - return genEast!FunLiteral(array(map!((string x){return new Parameter(x,[]);})(xs)),ps); } 102 - auto funp(Parameter[] xs, AST ps) { return genEast!FunLiteral(xs,ps); } /// 103 - alias genEast!VarExpression var; /// 104 - alias genEast!LayExpression lay; /// 105 - alias genEast!LetExpression let; /// 106 - alias genEast!FuncallExpression call; /// 101 + return genEast!Fun(array(map!((string x){return new Parameter(x,[]);})(xs)),ps); } 102 + auto funp(Parameter[] xs, AST ps) { return genEast!Fun(xs,ps); } /// 103 + alias genEast!Var var; /// 104 + alias genEast!Lay lay; /// 105 + alias genEast!Let let; /// 106 + alias genEast!App call; /// 107 107 auto param(string name, string[] lay...) { return new Parameter(name, lay); } /// 108 108 }

Modified polemy/eval.d from [9a9618fb0277f966] to [b119954d6ce43301].

7 7 module polemy.eval; 8 8 import polemy._common; 9 9 import polemy.failure; 10 10 import polemy.ast; 11 11 import polemy.parse; 12 12 import polemy.value; 13 13 import polemy.layer; 14 -import std.typecons; 15 -import std.stdio; 16 14 17 -/// 18 -Table createGlobalContext() 15 +class Evaluator 19 16 { 20 - auto ctx = new Table; 21 - ctx.set("+", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} )); 22 - ctx.set("-", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} )); 23 - ctx.set("*", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} )); 24 - ctx.set("/", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} )); 25 - ctx.set("%", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} )); 26 - ctx.set("||", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} )); 27 - ctx.set("&&", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} )); 28 - ctx.set("<", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} )); 29 - ctx.set(">", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} )); 30 - ctx.set("<=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} )); 31 - ctx.set(">=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} )); 32 - ctx.set("==", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} )); 33 - ctx.set("!=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} )); 34 - ctx.set("print", ValueLayer, native( (Value a){ 35 - writeln(a); 36 - return new IntValue(BigInt(0)); 37 - })); 38 - ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe){ 39 - auto toRun = (x.data==0 ? fe : ft); 40 - // [TODO] fill positional information 41 - return toRun.invoke(null, ValueLayer, toRun.definitionContext()); 42 -// return toRun.invoke(pos, lay, toRun.definitionContext()); 43 - })); 44 - ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} )); 45 - ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} )); 46 - ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} )); 47 - ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} )); 48 - ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} )); 49 - ctx.set(".", ValueLayer, native( (Table t, StrValue s){ 50 - return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndValue); 51 - }) ); 52 - ctx.set(".?", ValueLayer, native( (Table t, StrValue s){ 53 - return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0)); 54 - }) ); 55 - ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){ 56 - auto t2 = new Table(t, Table.Kind.NotPropagateSet); 57 - t2.set(s.data, ValueLayer, v); 58 - return t2; 59 - }) ); 60 - ctx.set("{}", ValueLayer, native( (){ 61 - return new Table; 62 - }) ); 63 - return ctx; 64 -} 65 - 66 -/// Entry point of this module 67 - 68 -Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn) 69 -{ 70 - return eval( polemy.parse.parseString(str, fn_ln_cn) ); 71 -} 72 - 73 -/// Entry point of this module 74 - 75 -Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn) 76 -{ 77 - return eval( polemy.parse.parseFile(filename, ln_cn) ); 78 -} 79 - 80 -/// Entry point of this module 81 - 82 -Tuple!(Value,"val",Table,"ctx") eval(AST e) 83 -{ 84 - Table ctx = createGlobalContext(); 85 - return typeof(return)(eval(e, ctx, false, ValueLayer), ctx); 86 -} 87 - 88 -Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false) 89 -{ 90 - if(auto f = cast(FunValue)_f) 17 +public: 18 + this() { theContext = new Table; } 19 + 20 + Value evalAST(AST e) 21 + { 22 + return eval(e, ValueLayer, theContext, OverwriteCtx); 23 + } 24 + 25 + Value evalString(S,T...)(S str, T fn_ln_cn) 26 + { 27 + return evalAST(parseString(str,fn_ln_cn)); 28 + } 29 + 30 + Value evalFile(S,T...)(S filename, T ln_cn) 31 + { 32 + return evalAST(parseFile(filename,ln_cn)); 33 + } 34 + 35 + Table globalContext() 36 + { 37 + return theContext; 38 + } 39 + 40 +private: 41 + Table theContext; 42 + 43 +private: 44 + enum : bool { CascadeCtx=false, OverwriteCtx=true }; 45 + 46 + Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 47 + { 48 + // dynamic-overload-resolution-pattern: modify here 49 + enum funName = "eval"; 50 + alias TypeTuple!(e,lay,ctx,overwriteCtx) params; 51 + 52 + // dynamic-overload-resolution-pattern: dispatch 53 + alias typeof(__traits(getOverloads, this, funName)) ovTypes; 54 + alias staticMap!(firstParam, ovTypes) fstTypes; 55 + alias DerivedToFront!(fstTypes) fstTypes_sorted; 56 + foreach(i, T; fstTypes_sorted) 57 + static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] ) 58 + return __traits(getOverloads, this, funName)[i](_x, params[1..$]); 59 + 60 + // dynamic-overload-resolution-pattern: default behavior 61 + assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 62 + } 63 + 64 +private: 65 + Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 66 + { 67 + Value v = new StrValue(e.data); 68 + if( lay==RawMacroLayer || lay==MacroLayer ) 69 + { 70 + auto ast = new Table; 71 + ast.set("pos", ValueLayer, fromPos(e.pos)); 72 + ast.set("is", ValueLayer, new StrValue("str")); 73 + ast.set("data", ValueLayer, v); 74 + return ast; 75 + } 76 + if( lay==ValueLayer ) 77 + return v; 78 + return lift(v, lay, ctx, e.pos); 79 + } 80 + 81 + Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 82 + { 83 + Value v = new IntValue(e.data); 84 + if( lay==RawMacroLayer || lay==MacroLayer ) 85 + { 86 + auto ast = new Table; 87 + ast.set("pos", ValueLayer, fromPos(e.pos)); 88 + ast.set("is", ValueLayer, new StrValue("int")); 89 + ast.set("data", ValueLayer, v); 90 + return ast; 91 + } 92 + if( lay==ValueLayer ) 93 + return v; 94 + return lift(v, lay, ctx, e.pos); 95 + } 96 + 97 + Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 98 + { 99 + if( lay==RawMacroLayer || lay==MacroLayer ) 100 + { 101 + if( ctx.has(e.name,MacroLayer) ) 102 + return ctx.get(e.name, MacroLayer, e.pos); 103 + auto ast = new Table; 104 + ast.set("pos", ValueLayer, fromPos(e.pos)); 105 + ast.set("is", ValueLayer, new StrValue("var")); 106 + ast.set("name", ValueLayer, new StrValue(e.name)); 107 + return ast; 108 + } 109 + if( lay==ValueLayer || ctx.has(e.name, lay) ) 110 + return ctx.get(e.name, lay, e.pos); 111 + return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos); 112 + } 113 + 114 + Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 115 + { 116 + Value f = eval( e.fun, lay, ctx ); 117 + if( lay==RawMacroLayer || lay==MacroLayer ) 118 + { 119 + if( auto ff = cast(FunValue)f ) 120 + return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos); 121 + Table ast = new Table; 122 + ast.set("pos", ValueLayer, fromPos(e.pos)); 123 + ast.set("is", ValueLayer, new StrValue("app")); 124 + ast.set("fun", ValueLayer, f); 125 + Table args = new Table; 126 + foreach_reverse(a; e.args) 127 + args = makeCons(eval(a, lay, ctx), args); 128 + ast.set("args", ValueLayer, args); 129 + return ast; 130 + } 131 + else 132 + { 133 + return invokeFunction(f, e.args, lay, ctx, e.pos); 134 + } 135 + } 136 + 137 + Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 138 + { 139 + if( lay==RawMacroLayer || lay==MacroLayer ) 140 + { 141 + Table t = new Table; 142 + t.set("pos", ValueLayer, fromPos(e.pos)); 143 + t.set("is", ValueLayer, new StrValue("fun")); 144 + t.set("funbody", ValueLayer, eval(e.funbody,lay,ctx)); 145 + Table params = new Table; 146 + foreach_reverse(p; e.params) 147 + { 148 + Table lays = new Table; 149 + foreach_reverse(l; p.layers) 150 + lays = makeCons(new StrValue(l), lays); 151 + Table kv = new Table; 152 + kv.set("name", ValueLayer, new StrValue(p.name)); 153 + kv.set("layers", ValueLayer, lays); 154 + Table cons = new Table; 155 + params = makeCons(kv, params); 156 + } 157 + t.set("params", ValueLayer, params); 158 + return t; 159 + } 160 + else 161 + { 162 + return createNewFunction(e, ctx); 163 + } 164 + } 165 + 166 + Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 91 167 { 92 - Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 93 - foreach(i,p; f.params()) 94 - if( p.layers.empty ) 95 - if(lay==MacroLayer) 96 - ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro)); 97 - else 98 - ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay)); 99 - else 100 - foreach(argLay; p.layers) 101 - if(argLay==MacroLayer) 102 - ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro)); 103 - else 104 - ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay)); 105 - return f.invoke(pos, lay, ctx); 168 + if( lay == RawMacroLayer ) 169 + { 170 + Value r = eval(e.expr, lay, ctx); 171 + auto ast = new Table; // todo: pos 172 + ast.set("pos", ValueLayer, fromPos(e.pos)); 173 + ast.set("is", ValueLayer, new StrValue("lay")); 174 + ast.set("layer", ValueLayer, new StrValue(e.layer)); 175 + ast.set("expr", ValueLayer, r); 176 + return ast; 177 + } 178 + else 179 + return eval(e.expr, e.layer, ctx); 106 180 } 107 - throw genex!RuntimeException(pos, "tried to call non-function"); 108 -} 109 181 110 -Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx) 111 -{ 112 - // functions are automatically lifterd 113 - if( cast(FunValue) v ) 114 - return v; 115 - 116 - // similar to invoke Function, but with only one argument bound to ValueLayer 117 - Value _f = callerCtx.get(lay, SystemLayer, pos); 118 - if(auto f = cast(FunValue)_f) 182 + Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 119 183 { 120 - Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 121 - auto ps = f.params(); 122 - if( ps.length != 1 ) 123 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 124 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 184 + // todo @macro let 185 + if( lay==RawMacroLayer || lay==MacroLayer ) 125 186 { 126 - ctx.set(ps[0].name, ValueLayer, v); 127 - return f.invoke(pos, ValueLayer, ctx); 187 + auto ast = new Table; // todo: pos 188 + ast.set("pos", ValueLayer, fromPos(e.pos)); 189 + ast.set("is", ValueLayer, new StrValue("let")); 190 + ast.set("name", ValueLayer, new StrValue(e.name)); 191 + ast.set("layer", ValueLayer, new StrValue(e.layer)); 192 + ast.set("init", ValueLayer, eval(e.init, lay, ctx)); 193 + ast.set("expr", ValueLayer, eval(e.expr, lay, ctx)); 194 + return ast; 128 195 } 129 196 else 130 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 131 - } 132 - throw genex!RuntimeException(pos, "tried to call non-function"); 133 -} 134 - 135 -/// Entry point of this module 136 -/// If splitCtx = true, then inner variable declaration do not overwrite ctx. 137 -/// lay is the layer ID for evaluation (standard value semantics uses ValueLayer). 138 - 139 -Value eval(AST e, Table ctx, bool splitCtx, Layer lay) 140 -{ 141 - return e.match( 142 - (StrLiteral e) 143 197 { 144 - Value v = new StrValue(e.data); 145 - if( lay == ValueLayer ) 146 - return v; 147 - else 148 - return lift(e.pos,v,lay,ctx); 149 - }, 150 - (IntLiteral e) 151 - { 152 - Value v = new IntValue(e.data); 153 - if( lay == ValueLayer ) 154 - return v; 155 - else // rise 156 - return lift(e.pos,v,lay,ctx); 157 - }, 158 - (VarExpression e) 159 - { 160 - if( lay == ValueLayer ) 161 - return ctx.get(e.name, lay, e.pos); 162 - if( ctx.has(e.name, lay, e.pos) ) 163 - return ctx.get(e.name, lay, e.pos); 164 - else 165 - return lift(e.pos, ctx.get(e.name, ValueLayer, e.pos), lay, ctx); 166 - }, 167 - (LayExpression e) 168 - { 169 - if( e.layer == MacroLayer ) 170 - return macroEval(e.expr, ctx, false); 171 - else 172 - return eval(e.expr, ctx, true, e.layer); 173 - }, 174 - (LetExpression e) 175 - { 176 - // for letrec, we need this, but should avoid overwriting???? 177 - // ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos); 178 - if(splitCtx) 198 + if( !overwriteCtx ) 179 199 ctx = new Table(ctx, Table.Kind.NotPropagateSet); 180 - Value v = eval(e.init, ctx, true, lay); 181 - ctx.set(e.name, (e.layer.length ? e.layer : lay), v, e.pos); 182 - return eval(e.expr, ctx, false, lay); 183 - }, 184 - (FuncallExpression e) 185 - { 186 - return invokeFunction(e.pos, eval(e.fun, ctx, true, lay), e.args, ctx, lay); 187 - }, 188 - (FunLiteral e) 189 - { 190 - return new UserDefinedFunValue(e, ctx); 191 - }, 192 - delegate Value (AST e) 200 + Value ri = eval(e.init, lay, ctx); 201 + string theLayer = e.layer.empty ? (lay==RawMacroLayer ? MacroLayer : lay) : e.layer; 202 + ctx.set(e.name, theLayer, ri); 203 + return eval(e.expr, lay, ctx, OverwriteCtx); 204 + } 205 + } 206 + 207 +private: 208 + Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null) 209 + { 210 + if(auto f = cast(FunValue)_f) 193 211 { 194 - throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e))); 212 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 213 + foreach(i,p; f.params()) 214 + if( p.layers.empty ) 215 + newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx)); 216 + else 217 + foreach(argLay; p.layers) 218 + newCtx.set(p.name, argLay, eval(args[i], argLay, ctx)); 219 + return f.invoke(pos, lay, newCtx); 195 220 } 196 - ); 197 -} 198 - 199 -// [TODO] Optimization 200 -Value macroEval(AST e, Table ctx, bool AlwaysMacro) 201 -{ 202 - Layer theLayer = ValueLayer; 221 + throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); 222 + } 203 223 204 - Table makeCons(Value a, Value d) 224 + Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null) 205 225 { 206 - Table t = new Table; 207 - t.set("car", theLayer, a); 208 - t.set("cdr", theLayer, d); 209 - return t; 226 + // functions are automatically lifterd 227 + if( cast(FunValue) v ) 228 + return v; 229 + 230 + // similar to invoke Function, but with only one argument bound to ValueLayer 231 + if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos)) 232 + { 233 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 234 + auto ps = f.params(); 235 + if( ps.length != 1 ) 236 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 237 + if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 238 + { 239 + newCtx.set(ps[0].name, ValueLayer, v); 240 + return f.invoke(pos, ValueLayer, newCtx); 241 + } 242 + else 243 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer"); 244 + } 245 + throw genex!RuntimeException(pos, "tried to call non-function"); 210 246 } 211 247 212 - Table pos = new Table; 213 - if( e.pos !is null ) { 214 - pos.set("filename", theLayer, new StrValue(e.pos.filename)); 215 - pos.set("lineno", theLayer, new IntValue(BigInt(e.pos.lineno))); 216 - pos.set("column", theLayer, new IntValue(BigInt(e.pos.column))); 217 - } else { 218 - pos.set("filename", theLayer, new StrValue("nullpos")); 219 - pos.set("lineno", theLayer, new IntValue(BigInt(0))); 220 - pos.set("column", theLayer, new IntValue(BigInt(0))); 221 - } 222 - 223 - return e.match( 224 - (StrLiteral e) 248 + Value createNewFunction(Fun e, Table ctx) 249 + { 250 + class UserDefinedFunValue : FunValue 225 251 { 226 - Table t = new Table; 227 - t.set("pos", theLayer, pos); 228 - t.set("is", theLayer, new StrValue("str")); 229 - t.set("data", theLayer, new StrValue(e.data)); 230 - return t; 231 - }, 232 - (IntLiteral e) 233 - { 234 - Table t = new Table; 235 - t.set("pos", theLayer, pos); 236 - t.set("is", theLayer, new StrValue("int")); 237 - t.set("data", theLayer, new IntValue(e.data)); 238 - return t; 239 - }, 240 - (VarExpression e) 241 - { 242 - if( ctx.has(e.name, MacroLayer, e.pos) ) 243 - return ctx.get(e.name, MacroLayer, e.pos); 244 - else { 245 - Table t = new Table; 246 - t.set("pos", theLayer, pos); 247 - t.set("is", theLayer, new StrValue("var")); 248 - t.set("name", theLayer, new StrValue(e.name)); 249 - return cast(Value)t; 252 + Fun ast; 253 + Table defCtx; 254 + override const(Parameter[]) params() { return ast.params; } 255 + override Table definitionContext() { return defCtx; } 256 + 257 + this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; } 258 + override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } 259 + override bool opEquals(Object rhs_) const /// member-by-member equality 260 + { 261 + if( auto rhs = cast(typeof(this))rhs_ ) 262 + return this.ast==rhs.ast && this.defCtx==rhs.defCtx; 263 + assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 264 + } 265 + override hash_t toHash() const /// member-by-member hash 266 + { 267 + return typeid(this.ast).getHash(&this.ast) + typeid(this.defCtx).getHash(&this.defCtx); 268 + } 269 + override int opCmp(Object rhs_) /// member-by-member compare 270 + { 271 + if( auto rhs = cast(typeof(this))rhs_ ) 272 + { 273 + if(auto i = this.ast.opCmp(rhs.ast)) 274 + return i; 275 + return this.defCtx.opCmp(rhs.defCtx); 276 + } 277 + assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 250 278 } 251 - }, 252 - (LayExpression e) 253 - { 254 - if( AlwaysMacro ) 279 + 280 + override Value invoke(LexPosition pos, Layer lay, Table ctx) 255 281 { 256 - Table t = new Table; 257 - t.set("pos", theLayer, pos); 258 - t.set("is", theLayer, new StrValue("lay")); 259 - t.set("layer", theLayer, new StrValue(e.layer)); 260 - t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro)); 261 - return cast(Value)t; 282 + if( lay == MacroLayer ) 283 + return eval(ast.funbody, lay, ctx); 284 + auto macroed = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx)); 285 + return eval(macroed, lay, ctx); 262 286 } 263 - else 264 - { 265 - if( e.layer == MacroLayer ) 266 - return macroEval(e.expr, ctx, false); 267 - else 268 - return eval(e.expr, ctx, true, e.layer); 269 - } 270 - }, 271 - (LetExpression e) 287 + } 288 + return new UserDefinedFunValue(e,ctx); 289 + } 290 + 291 +public: 292 + /// TODO: move up 293 + /// TDOO: to other layers? 294 + void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg) 295 + { 296 + class NativeFunValue : FunValue 272 297 { 273 - Table t = new Table; 274 - t.set("pos", theLayer, pos); 275 - t.set("is", theLayer, new StrValue("let")); 276 - t.set("name", theLayer, new StrValue(e.name)); 277 - t.set("init", theLayer, macroEval(e.init,ctx,AlwaysMacro)); 278 - t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro)); 279 - return t; 280 - }, 281 - (FuncallExpression e) 282 - { 283 - Value _f = macroEval(e.fun,ctx,AlwaysMacro); 284 - 285 - if( auto f = cast(FunValue)_f ) 286 - return invokeFunction(e.pos, f, e.args, ctx, MacroLayer, AlwaysMacro); 287 - 288 - Table t = new Table; 289 - t.set("pos", theLayer, pos); 290 - t.set("is", theLayer, new StrValue("app")); 291 - t.set("fun", theLayer, _f); 292 - Table args = new Table; 293 - foreach_reverse(a; e.args) { 294 - Table cons = new Table; 295 - cons.set("car",theLayer,macroEval(a,ctx,AlwaysMacro)); 296 - cons.set("cdr",theLayer,args); 297 - args = cons; 298 + Parameter[] params_data; 299 + override string toString() { return sprintf!"(native:%x)"(dg.funcptr); } 300 + override const(Parameter[]) params() { return params_data; } 301 + override Table definitionContext() { return new Table; } // todo: cache 302 + this(){ 303 + foreach(i, Ti; T) 304 + params_data ~= new Parameter(text(i), []); 305 + } 306 + override Value invoke(LexPosition pos, Layer lay, Table ctx) 307 + { 308 + if( lay != ValueLayer ) 309 + throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function"); 310 + T typed_args; 311 + foreach(i, Ti; T) { 312 + typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer); 313 + if( typed_args[i] is null ) 314 + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); 315 + } 316 + try { 317 + return dg(typed_args); 318 + } catch( RuntimeException e ) { 319 + throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; 320 + } 298 321 } 299 - t.set("args", theLayer, args); 300 - return cast(Value)t; 301 - }, 302 - (FunLiteral e) 303 - { 304 - Table t = new Table; 305 - t.set("pos", theLayer, pos); 306 - t.set("is", theLayer, new StrValue("fun")); 307 - t.set("funbody", theLayer, macroEval(e.funbody,ctx,AlwaysMacro)); 308 - Table params = new Table; 309 - foreach_reverse(p; e.params) 310 - { 311 - Table lays = new Table; 312 - foreach_reverse(lay; p.layers) 313 - lays = makeCons(new StrValue(lay), lays); 314 - Table kv = new Table; 315 - kv.set("name", theLayer, new StrValue(p.name)); 316 - kv.set("layers", theLayer, lays); 317 - Table cons = new Table; 318 - params = makeCons(kv, params); 319 - } 320 - t.set("params", theLayer, params); 321 - return t; 322 - }, 323 - delegate Value (AST e) 324 - { 325 - throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e))); 326 322 } 327 - ); 323 + theContext.set(name, lay, new NativeFunValue); 324 + } 325 +} 326 + 327 +version(unittest) import polemy.runtime; 328 +unittest 329 +{ 330 + auto e = new Evaluator; 331 + enrollRuntimeLibrary(e); 332 + auto r = assert_nothrow( e.evalString(`var x = 21; x + x*x;`) ); 333 + assert_eq( r, new IntValue(BigInt(21+21*21)) ); 334 + assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21)) ); 335 + assert_nothrow( e.globalContext.get("x",ValueLayer) ); 336 + assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) ); 337 +} 338 +unittest 339 +{ 340 + auto e = new Evaluator; 341 + enrollRuntimeLibrary(e); 342 + auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) ); 343 + assert_eq( r, new IntValue(BigInt(21+21*21)) ); 344 + assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) ); 345 + assert_nothrow( e.globalContext.get("x",ValueLayer) ); 346 + assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) ); 347 +} 348 +unittest 349 +{ 350 + auto e = new Evaluator; 351 + enrollRuntimeLibrary(e); 352 + assert_eq( e.evalString(`let x=1; let y=(let x=2); x`), new IntValue(BigInt(1)) ); 353 + assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new IntValue(BigInt(2)) ); 354 +} 355 + 356 +unittest 357 +{ 358 + auto e = new Evaluator; 359 + enrollRuntimeLibrary(e); 360 + assert_eq( e.evalString(`@a x=1; @b x=2; @a(x)`), new IntValue(BigInt(1)) ); 361 + assert_eq( e.evalString(`@a x=1; @b x=2; @b(x)`), new IntValue(BigInt(2)) ); 362 + assert_eq( e.evalString(`let x=1; let _ = (@a x=2;2); x`), new IntValue(BigInt(1)) ); 363 + e = new Evaluator; 364 + assert_throw!Throwable( e.evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) ); 365 +} 366 + 367 +unittest 368 +{ 369 + auto e = new Evaluator; 370 + enrollRuntimeLibrary(e); 371 + assert_eq( e.evalString(` 372 + @@s(x){x}; 373 + @s "+" = fun(x, y) {@value( 374 + @s(x) - @s(y) 375 + )}; 376 + @s(1 + 2) 377 + `), new IntValue(BigInt(-1)) ); 378 +} 379 + 380 +unittest 381 +{ 382 + auto e = new Evaluator; 383 + enrollRuntimeLibrary(e); 384 + assert_eq( e.evalString(` 385 +@@3(x){x}; 386 +def incr(x) { x+1 }; 387 +@ 3 incr(x) {@value( if(@ 3(x)+1< 3){@ 3(x)+1}else{0} )}; 388 +def fb(n @value @3) { @3(n) }; 389 +fb(incr(incr(incr(0)))) 390 + `), new IntValue(BigInt(0)) ); 328 391 } 329 392 330 393 unittest 331 394 { 332 - auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) ); 333 - assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 334 - assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) ); 335 - assert_nothrow( r.ctx.get("x",ValueLayer) ); 336 - assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) ); 337 -} 338 -unittest 339 -{ 340 - auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) ); 341 - assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 342 - assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) ); 343 - assert_nothrow( r.ctx.get("x",ValueLayer) ); 344 - assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) ); 345 -} 346 -unittest 347 -{ 348 - assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(BigInt(1)) ); 349 - assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new IntValue(BigInt(2)) ); 350 -} 351 -unittest 352 -{ 353 - assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt(1)) ); 354 - assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt(2)) ); 355 - assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValue(BigInt(1)) ); 356 - assert_throw!Throwable( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) ); 395 + auto e = new Evaluator; 396 + enrollRuntimeLibrary(e); 397 + assert_nothrow( e.evalString(` 398 +@macro twice(x) { x; x }; 399 +def main() { twice(1) }; 400 +main() 401 + `) ); 357 402 } 358 403 /* 359 404 unittest 360 405 { 361 406 assert_eq( evalString(`var fac = fun(x){ 362 407 if(x) 363 408 { x*fac(x-1); } ................................................................................ 369 414 if(x<2) 370 415 { 1; } 371 416 else 372 417 { fib(x-1) + fib(x-2); }; 373 418 }; 374 419 fib(5);`).val, new IntValue(BigInt(8))); 375 420 } 376 - 377 -unittest 378 -{ 379 - assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) ); 380 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) ); 381 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) ); 382 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) ); 383 -} 384 - 385 421 unittest 386 422 { 387 423 assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) ); 388 424 // there was a bug that declaration in the first line of function definition 389 425 // cannot be recursive 390 426 assert_nothrow( evalString(`def foo() { 391 427 def bar(y) { if(y<1) {0} else {bar(0)} }; 392 428 bar(1) 393 429 }; foo()`) ); 394 430 } 395 431 */

Modified polemy/layer.d from [91a3b7f2c4f61824] to [79038e8ac0f7ba6a].

10 10 11 11 /// Type for the layer ID 12 12 13 13 alias string Layer; 14 14 15 15 enum : Layer 16 16 { 17 - SystemLayer = "(system)", /// Predefined layer for internal data 18 - ValueLayer = "@value", /// Predefined layer for normal run 19 - MacroLayer = "@macro", /// Predefined layer for macro run 17 + SystemLayer = "(system)", /// Predefined layer for internal data 18 + ValueLayer = "@value", /// Predefined layer for normal run 19 + MacroLayer = "@macro", /// Predefined layer for macro run 20 + RawMacroLayer = "(rawmacro)", /// Predefined layer for raw-macro run 20 21 }

Modified polemy/parse.d from [789e91a27a62e096] to [9df8a8a07696ff22].

98 98 string kwd = "@" ~ layer; 99 99 string var = layer; 100 100 101 101 auto e = tryEat("(") 102 102 ? parseLambdaAfterOpenParen(pos) // let var ( ... 103 103 : (eat("=", "after "~kwd), E(0)); // let var = ... 104 104 if( moreDeclarationExists() ) 105 - return new LetExpression(pos, var, SystemLayer, e, Body()); 105 + return new Let(pos, var, SystemLayer, e, Body()); 106 106 else 107 - return new LetExpression(pos, var, SystemLayer, e, 108 - new LayExpression(pos, SystemLayer, new VarExpression(pos, var)) 107 + return new Let(pos, var, SystemLayer, e, 108 + new Lay(pos, SystemLayer, new Var(pos, var)) 109 109 ); 110 110 } 111 111 else 112 112 { 113 113 string kwd = layer; 114 114 if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="var") && !tryEat(kwd="def") ) 115 115 return null; // none of {@lay, let, var, def} occurred, it's not a declaration ................................................................................ 117 117 auto varpos = currentPosition(); 118 118 string var = eatId("after "~kwd, AllowQuoted); // name of the declared variable 119 119 120 120 auto e = tryEat("(") 121 121 ? parseLambdaAfterOpenParen(varpos) // let var ( ... 122 122 : (eat("=", "after "~kwd), E(0)); // let var = ... 123 123 if( moreDeclarationExists() ) 124 - return new LetExpression(pos, var, layer, e, Body()); 124 + return new Let(pos, var, layer, e, Body()); 125 125 else 126 - return new LetExpression(pos, var, layer, e, new VarExpression(varpos, var)); 126 + return new Let(pos, var, layer, e, new Var(varpos, var)); 127 127 } 128 128 } 129 129 130 130 AST TopLevelExpression() 131 131 { 132 132 /// TopLevelExpression ::= Expression ([";"|"in"] Body?)? 133 133 134 134 auto pos = currentPosition(); 135 135 auto e = E(0); 136 136 if( moreDeclarationExists() ) 137 - return new LetExpression(pos, "_", "", e, Body()); 137 + return new Let(pos, "_", "", e, Body()); 138 138 else 139 139 return e; 140 140 } 141 141 142 142 private bool moreDeclarationExists() 143 143 { 144 144 return (tryEat(";") || tryEat("in")) && !closingBracket(); ................................................................................ 177 177 return lhs; 178 178 179 179 auto pos = currentPosition(); 180 180 foreach(op; operator_perferences[level]) 181 181 if( tryEat(op) ) 182 182 if( op[0]=='.' ) 183 183 return rec( 184 - new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, parseId())); 184 + new App(lhs.pos, new Var(pos, op), lhs, parseId())); 185 185 else 186 - return rec( 187 - new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, E(level+1))); 186 + return rec( 187 + new App(lhs.pos, new Var(pos, op), lhs, E(level+1))); 188 188 return lhs; 189 189 } 190 190 191 191 if( operator_perferences.length <= level ) 192 192 return Funcall(); 193 193 else 194 194 return rec(E(level+1)); ................................................................................ 209 209 throw genex!UnexpectedEOF(pos, "closing ')' for arguments not found"); 210 210 args ~= E(0); 211 211 if( !tryEat(",") ) { 212 212 eat(")", "after function parameters"); 213 213 break; 214 214 } 215 215 } 216 - e = new FuncallExpression(e.pos, e, args); 216 + e = new App(e.pos, e, args); 217 217 } 218 218 else if( tryEat("{") ) 219 219 { 220 220 e = parseTableSetAfterBrace(e); 221 221 } 222 222 else 223 223 break; ................................................................................ 230 230 return e; 231 231 auto pos = currentPosition(); 232 232 for(;;) 233 233 { 234 234 string key = eatId("for table key", AllowQuoted); 235 235 eat(":", "after table key"); 236 236 AST val = E(0); 237 - e = new FuncallExpression(pos, new VarExpression(pos,".="), 238 - e, new StrLiteral(pos,key), val); 237 + e = new App(pos, new Var(pos,".="), 238 + e, new Str(pos,key), val); 239 239 if( !tryEat(",") ) 240 240 { 241 241 eat("}", "for the end of table literal"); 242 242 break; 243 243 } 244 244 } 245 245 return e; ................................................................................ 250 250 if( lex.empty ) 251 251 throw genex!UnexpectedEOF(currentPosition(), "Reached EOF when tried to parse an expression"); 252 252 253 253 auto pos = lex.front.pos; 254 254 if( lex.front.quoted ) 255 255 { 256 256 scope(exit) lex.popFront; 257 - return new StrLiteral(pos, lex.front.str); 257 + return new Str(pos, lex.front.str); 258 258 } 259 259 if( isNumber(lex.front.str) ) 260 260 { 261 261 scope(exit) lex.popFront; 262 - return new IntLiteral(pos, BigInt(cast(string)lex.front.str)); 262 + return new Int(pos, BigInt(cast(string)lex.front.str)); 263 263 } 264 264 if( tryEat("@") ) 265 265 { 266 266 auto lay = "@"~eatId("for layer ID"); 267 267 eat("(", "for layered execution"); 268 268 auto e = Body(); 269 269 eat(")", "after "~lay~"(..."); 270 - return new LayExpression(pos, lay, e); 270 + return new Lay(pos, lay, e); 271 271 } 272 272 if( tryEat("(") ) 273 273 { 274 274 auto e = Body(); 275 275 eat(")", "after parenthesized expression"); 276 276 return e; 277 277 } 278 278 if( tryEat("{") ) 279 279 { 280 - AST e = new FuncallExpression(pos, new VarExpression(pos,"{}")); 280 + AST e = new App(pos, new Var(pos,"{}")); 281 281 return parseTableSetAfterBrace(e); 282 282 } 283 283 if( tryEat("if") ) 284 284 { 285 285 eat("(", "after if"); 286 286 auto cond = E(0); 287 287 eat(")", "after if condition"); ................................................................................ 292 292 auto el = doNothingExpression(); 293 293 auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos); 294 294 if( tryEat("else") ) { 295 295 eat("{", "after else"); 296 296 el = Body(); 297 297 eat("}", "after else body"); 298 298 } 299 - return new FuncallExpression(pos, 300 - new VarExpression(pos, "if"), 299 + return new App(pos, 300 + new Var(pos, "if"), 301 301 cond, 302 - new FunLiteral(thenPos, [], th), 303 - new FunLiteral(elsePos, [], el) 302 + new Fun(thenPos, [], th), 303 + new Fun(elsePos, [], el) 304 304 ); 305 305 } 306 306 if( tryEat("case") ) 307 307 { 308 308 return parsePatternMatch(pos); 309 309 } 310 310 if( tryEat("fun") || tryEat("\u03BB") ) // lambda!! 311 311 { 312 312 eat("(", "after fun"); 313 313 return parseLambdaAfterOpenParen(pos); 314 314 } 315 315 scope(exit) lex.popFront; 316 - return new VarExpression(pos, lex.front.str); 316 + return new Var(pos, lex.front.str); 317 317 } 318 318 319 319 AST parsePatternMatch(LexPosition pos) 320 320 { 321 321 // case( pmExpr )cases 322 322 //==> 323 323 // let pmVar = pmExpr in (... let pmTryFirst = ... in pmTryFirst()) 324 324 eat("(", "after case"); 325 325 AST pmExpr = E(0); 326 326 eat(")", "after case"); 327 327 string pmVar = freshVarName(); 328 328 string pmTryFirst = freshVarName(); 329 329 AST pmBody = parsePatternMatchCases(pmVar, pmTryFirst, 330 - new FuncallExpression(pos, new VarExpression(pos, pmTryFirst))); 331 - return new LetExpression(pos, pmVar, [], pmExpr, pmBody); 330 + new App(pos, new Var(pos, pmTryFirst))); 331 + return new Let(pos, pmVar, [], pmExpr, pmBody); 332 332 } 333 333 334 334 AST parsePatternMatchCases(string pmVar, string tryThisBranchVar, AST thenDoThis) 335 335 { 336 336 // when( pat ) { cBody } 337 337 //==> 338 338 // ... let failBranchVar = ... in ................................................................................ 343 343 string failBranchVar = freshVarName(); 344 344 345 345 eat("(", "after when"); 346 346 auto pr = parsePattern(); 347 347 eat(")", "after when"); 348 348 eat("{", "after pattern"); 349 349 AST cBody = Body(); 350 - AST judgement = new FuncallExpression(pos, new VarExpression(pos, "if"), 351 - ppTest(pmVar, pr), new FunLiteral(pos,[],ppBind(pmVar, pr, cBody)), 352 - new VarExpression(pos, failBranchVar)); 350 + AST judgement = new App(pos, new Var(pos, "if"), 351 + ppTest(pmVar, pr), new Fun(pos,[],ppBind(pmVar, pr, cBody)), 352 + new Var(pos, failBranchVar)); 353 353 eat("}", "after pattern clause"); 354 354 return parsePatternMatchCases(pmVar, failBranchVar, 355 - new LetExpression(pos, tryThisBranchVar, [], 356 - new FunLiteral(pos,[],judgement), thenDoThis) 355 + new Let(pos, tryThisBranchVar, [], 356 + new Fun(pos,[],judgement), thenDoThis) 357 357 ); 358 358 } 359 359 else 360 360 { 361 361 auto pos = currentPosition(); 362 - AST doNothing = new FunLiteral(pos,[], 363 - new StrLiteral(pos, sprintf!"(pattern match failure:%s)"(pos))); 364 - return new LetExpression(currentPosition(), tryThisBranchVar, [], doNothing, thenDoThis); 362 + AST doNothing = new Fun(pos,[], 363 + new Str(pos, sprintf!"(pattern match failure:%s)"(pos))); 364 + return new Let(currentPosition(), tryThisBranchVar, [], doNothing, thenDoThis); 365 365 } 366 366 } 367 367 368 368 // hageshiku tenuki 369 369 abstract class SinglePattern 370 370 { 371 371 string[] path; 372 372 mixin SimpleClass; 373 373 private AST access(string pmVar, string[] path) { 374 374 auto pos = currentPosition(); 375 - AST e = new VarExpression(pos, pmVar); 375 + AST e = new Var(pos, pmVar); 376 376 foreach(p; path) 377 - e = new FuncallExpression(pos, new VarExpression(pos, "."), e, new StrLiteral(pos, p)); 377 + e = new App(pos, new Var(pos, "."), e, new Str(pos, p)); 378 378 return e; 379 379 } 380 380 private AST has(AST e, string k) { 381 381 auto pos = currentPosition(); 382 382 return opAndAnd( 383 - new FuncallExpression(pos, new VarExpression(pos, "_istable"), e), 384 - new FuncallExpression(pos, new VarExpression(pos, ".?"), e, new StrLiteral(pos, k)) 383 + new App(pos, new Var(pos, "_istable"), e), 384 + new App(pos, new Var(pos, ".?"), e, new Str(pos, k)) 385 385 ); 386 386 } 387 387 private AST opAndAnd(AST a, AST b) { 388 388 if( a is null ) return b; 389 389 if( b is null ) return a; 390 390 auto pos = currentPosition(); 391 - return new FuncallExpression(pos, 392 - new VarExpression(pos, "if"), 391 + return new App(pos, 392 + new Var(pos, "if"), 393 393 a, 394 - new FunLiteral(pos, [], b), 395 - new FunLiteral(pos, [], new IntLiteral(pos, 0)) 394 + new Fun(pos, [], b), 395 + new Fun(pos, [], new Int(pos, 0)) 396 396 ); 397 397 } 398 398 AST ppTest(string pmVar) { 399 399 AST c = null; 400 400 for(int i=0; i<path.length; ++i) 401 401 c = opAndAnd(c, has(access(pmVar,path[0..i]), path[i])); 402 402 return c; ................................................................................ 409 409 } 410 410 class VarPattern : SinglePattern 411 411 { 412 412 string name; 413 413 mixin SimpleClass; 414 414 AST ppBind(string pmVar, AST thenDoThis) { 415 415 auto pos = currentPosition(); 416 - return new LetExpression(pos, name, [], access(pmVar,path), thenDoThis); 416 + return new Let(pos, name, [], access(pmVar,path), thenDoThis); 417 417 } 418 418 } 419 419 class ConstantPattern : SinglePattern 420 420 { 421 421 AST e; 422 422 mixin SimpleClass; 423 423 AST ppTest(string pmVar) { 424 424 auto pos = currentPosition(); 425 425 return opAndAnd( super.ppTest(pmVar), 426 - new FuncallExpression(pos, new VarExpression(pos,"=="), access(pmVar,path), e) 426 + new App(pos, new Var(pos,"=="), access(pmVar,path), e) 427 427 ); 428 428 } 429 429 } 430 430 431 431 SinglePattern[] parsePattern(string[] path = null) 432 432 { 433 433 SinglePattern[] result; ................................................................................ 441 441 } while( tryEat(",") ); 442 442 eat("}", "at the end of table pattern"); 443 443 } 444 444 } 445 445 else 446 446 { 447 447 AST e = E(0); 448 - if(auto ev = cast(VarExpression)e) 448 + if(auto ev = cast(Var)e) 449 449 if(ev.name == "_") 450 450 result ~= new WildPattern(path); 451 451 else 452 452 result ~= new VarPattern(path, ev.name); 453 453 else 454 454 result ~= new ConstantPattern(path, e); 455 455 } ................................................................................ 460 460 { 461 461 auto pos = currentPosition(); 462 462 AST cond = null; 463 463 foreach(p; pats) { 464 464 AST c2 = p.ppTest(pmVar); 465 465 if( c2 !is null ) 466 466 cond = cond is null ? c2 467 - : new FuncallExpression(pos, new VarExpression(pos,"&&"), cond, c2); 467 + : new App(pos, new Var(pos,"&&"), cond, c2); 468 468 } 469 - return cond is null ? new IntLiteral(currentPosition(), 1) : cond; 469 + return cond is null ? new Int(currentPosition(), 1) : cond; 470 470 } 471 471 472 472 AST ppBind(string pmVar, SinglePattern[] pats, AST thenDoThis) 473 473 { 474 474 foreach(p; pats) 475 475 thenDoThis = p.ppBind(pmVar, thenDoThis); 476 476 return thenDoThis; 477 477 } 478 478 479 479 AST parseId() 480 480 { 481 481 scope(exit) lex.popFront; 482 - return new StrLiteral(currentPosition(), lex.front.str); 482 + return new Str(currentPosition(), lex.front.str); 483 483 } 484 484 485 485 AST parseLambdaAfterOpenParen(immutable LexPosition pos) 486 486 { 487 487 Parameter[] params; 488 488 while( !tryEat(")") ) 489 489 { ................................................................................ 492 492 eat(")", "after function parameters"); 493 493 break; 494 494 } 495 495 } 496 496 eat("{", "after function parameters"); 497 497 auto funbody = Body(); 498 498 eat("}", "after function body"); 499 - return new FunLiteral(pos, params, funbody); 499 + return new Fun(pos, params, funbody); 500 500 } 501 501 502 502 Parameter parseParam() 503 503 { 504 504 string var; 505 505 string[] lay; 506 506 while( !closingBracket() && !lex.empty && lex.front.str!="," ) ................................................................................ 554 554 throw genex!ParseException(currentPosition(), "identifier is expected but not found "~msg); 555 555 scope(exit) lex.popFront; 556 556 return lex.front.str; 557 557 } 558 558 559 559 AST doNothingExpression() 560 560 { 561 - return new StrLiteral(currentPosition(), "(empty function body)"); 561 + return new Str(currentPosition(), "(empty function body)"); 562 562 } 563 563 564 564 immutable(LexPosition) currentPosition() 565 565 { 566 566 return lex.empty ? null : lex.front.pos; 567 567 } 568 568 }

Modified polemy/value.d from [0386a7dd31807f87] to [19366410c0eeb209].

43 43 44 44 45 45 /// 46 46 abstract class FunValue : Value 47 47 { 48 48 const(Parameter[]) params(); 49 49 Table definitionContext(); 50 - Value invoke(in LexPosition pos, Layer lay, Table ctx); 51 -} 52 - 53 -import polemy.eval; // circular... 54 -version = MacroCache; 55 -//version = AutoMemoization; 56 -//version = AutoRerun; 57 - 58 -/// 59 -class UserDefinedFunValue : FunValue 60 -{ 61 - FunLiteral ast; 62 - Table defCtx; 63 - 64 - this(FunLiteral ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; } 65 - override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); } 66 - override bool opEquals(Object rhs_) const /// member-by-member equality 67 - { 68 - if( auto rhs = cast(typeof(this))rhs_ ) 69 - return this.ast==rhs.ast && this.defCtx==rhs.defCtx; 70 - assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 71 - } 72 - override hash_t toHash() const /// member-by-member hash 73 - { 74 - return typeid(this.ast).getHash(&this.ast) + typeid(this.defCtx).getHash(&this.defCtx); 75 - } 76 - override int opCmp(Object rhs_) /// member-by-member compare 77 - { 78 - if( auto rhs = cast(typeof(this))rhs_ ) 79 - { 80 - if(auto i = this.ast.opCmp(rhs.ast)) 81 - return i; 82 - return this.defCtx.opCmp(rhs.defCtx); 83 - } 84 - assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 85 - } 86 - 87 - private AST preprocessed_funbody; 88 - private Value[Value[]][Layer] memo; 89 - 90 - override const(Parameter[]) params() { return ast.params; } 91 - override Table definitionContext() { return defCtx; } 92 - override Value invoke(in LexPosition pos, Layer lay, Table ctx) 93 - { 94 - // TODO: only auto raised ones need memo? no? 95 - // how can we integrate re-run ?? 96 - version(AutoMemoization) 97 - { 98 - Value[] memokey; 99 - if( lay != ValueLayer && lay != MacroLayer ) 100 - { 101 - foreach(i,p; ast.params) 102 - memokey ~= ctx.get(p.name, lay); // lay? 103 - if( auto memolay = lay in memo ) 104 - if( auto pv = memokey in *memolay ) 105 - return *pv; 106 - memo[lay][memokey] = lift(ast.pos,new UndValue,lay,ctx); 107 - } 108 - } 109 - 110 - // @macro run!!! 111 - if( lay == MacroLayer ) 112 - return macroEval(ast.funbody, ctx, false); 113 - 114 - version(MacroCache) { 115 - if( preprocessed_funbody is null ) { 116 - // .prototype!, forced macro cannot access parameters 117 - ctx.kill = true; scope(exit)ctx.kill=false; 118 - preprocessed_funbody = tableToAST(ValueLayer,macroEval(ast.funbody, ctx, true)); 119 - } 120 - } else { 121 - if( preprocessed_funbody is null ) { 122 - // .prototype!, forced macro cannot access parameters 123 - ctx.kill = true; scope(exit)ctx.kill=false; 124 - preprocessed_funbody = tableToAST(ValueLayer,macroEval(ast.funbody, ctx, true)); 125 - } 126 - } 127 - 128 - auto v = eval(preprocessed_funbody, ctx, true, lay); 129 - version(AutoMemoization) 130 - { 131 - if( lay != ValueLayer && lay != MacroLayer ) 132 - { 133 - memo[lay][memokey] = v; 134 - version(AutoReRun) 135 - memo[lay][memokey] = eval(preprocessed_funbody, ctx, true, lay); // re-Run!! 136 - } 137 - } 138 - return v; 139 - } 140 -} 141 - 142 -/// 143 -abstract class NativeFunValue : FunValue 144 -{ 145 - Parameter[] params_data; 146 - override const(Parameter[]) params() { return params_data; } 147 - override Table definitionContext() { return new Table; } // todo: cache overrie 148 -} 149 - 150 -/// Named Constructor for FunValue 151 - 152 -FunValue native(R,T...)(R delegate (T) dg) 153 -{ 154 - return new class NativeFunValue { 155 - this() 156 - { 157 - foreach(i, Ti; T) 158 - params_data ~= new Parameter(text(i), []); 159 - } 160 - override Value invoke(in LexPosition pos, Layer lay, Table ctx) 161 - { 162 - if( lay != ValueLayer ) 163 - throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function"); 164 - T typed_args; 165 - foreach(i, Ti; T) { 166 - typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer); 167 - if( typed_args[i] is null ) 168 - throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1)); 169 - } 170 - try { 171 - return dg(typed_args); 172 - } catch( RuntimeException e ) { 173 - throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e; 174 - } 175 - } 176 - }; 50 + Value invoke(LexPosition pos, Layer lay, Table ctx); 177 51 } 178 52 179 53 /// Context (variable environment) 180 54 /// Simlar to prototype chain of ECMAScript etc. 181 55 /// But extended with the notion of "Layer" 182 56 183 57 class Table : Value ................................................................................ 184 58 { 185 59 enum Kind {PropagateSet, NotPropagateSet}; 186 60 bool kill = false; // to refactor 187 61 188 62 this( Table proto=null, Kind k = Kind.PropagateSet ) 189 63 { this.prototype = proto; this.kind = k; } 190 64 191 - void set(string i, Layer lay, Value v, in LexPosition pos=null) 65 + void set(string i, Layer lay, Value v, LexPosition pos=null) 192 66 { 193 67 if( setIfExist(i, lay, v) ) 194 68 return; 195 69 data[i][lay] = v; 196 70 } 197 71 198 - bool has(string i, Layer lay, in LexPosition pos=null) 72 + bool has(string i, Layer lay) const 199 73 { 200 74 if( i in data ) { 201 75 if( lay !in data[i] ) 202 76 return false; 203 77 if(kill) 204 78 return false; 205 79 return true; 206 80 } 207 81 if( prototype is null ) 208 82 return false; 209 - return prototype.has(i, lay, pos); 83 + return prototype.has(i, lay); 210 84 } 211 85 212 - Value get(string i, Layer lay, in LexPosition pos=null) 86 + Value get(string i, Layer lay, LexPosition pos=null) 213 87 { 214 88 if( i in data ) { 215 89 // [TODO] consider forwarding to proto also in this case 216 90 if( lay !in data[i] ) 217 91 throw genex!RuntimeException(pos, sprintf!"'%s' is not set in layer %s"(i,lay)); 218 92 if(kill) 219 93 throw genex!RuntimeException(pos, sprintf!"'%s' is killed in macro"(i)); ................................................................................ 244 118 string result; 245 119 bool first = true; 246 120 foreach(k, l2d; data) 247 121 foreach(l,d; l2d) 248 122 { 249 123 if(first) first=false; else result~=", "; 250 124 result ~= k; 251 - result ~= l; 125 + if( l.empty ) 126 + result ~= "(emptylayer)"; 127 + else if( l != ValueLayer ) 128 + result ~= l; 252 129 result ~= ":"; 253 130 result ~= text(cast(Value)d); 254 131 } 255 132 if( prototype !is null ) 256 133 { 257 134 result ~= " / "; 258 135 result ~= prototype.toStringWithoutParen(); ................................................................................ 371 248 if( nodeType is null ) 372 249 throw genex!RuntimeException(cast(LexPosition)null, "Invalid AST {is:(not string)}"); 373 250 auto pos = extractPos(t); 374 251 switch(nodeType.data) 375 252 { 376 253 case "int": 377 254 if(auto v = t.access!IntValue(theLayer, "data")) 378 - return new IntLiteral(pos, v.data); 255 + return new Int(pos, v.data); 379 256 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"int", data:(not int)}`); 380 257 case "str": 381 258 if(auto v = t.access!StrValue(theLayer, "data")) 382 - return new StrLiteral(pos, v.data); 259 + return new Str(pos, v.data); 383 260 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"str", data:(not string)}`); 384 261 case "var": 385 262 if(auto v = t.access!StrValue(theLayer, "name")) 386 - return new VarExpression(pos, v.data); 263 + return new Var(pos, v.data); 387 264 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"var", name:(not string)}`); 388 265 case "lay": 389 266 if(auto v = t.access!StrValue(theLayer, "layer")) 390 267 if(auto e = t.access!Table(theLayer, "expr")) 391 - return new LayExpression(pos, v.data, tableToAST(theLayer,e)); 268 + return new Lay(pos, v.data, tableToAST(theLayer,e)); 392 269 else 393 270 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"lay", expr:(not table)}`); 394 271 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"lay", layer:(not string)}`); 395 272 case "let": 396 273 if(auto n = t.access!StrValue(theLayer, "name")) 397 274 if(auto e = t.access!Table(theLayer, "init")) 398 275 if(auto b = t.access!Table(theLayer, "expr")) ................................................................................ 399 276 { 400 277 string nn = n.data; 401 278 auto ee = tableToAST(theLayer, e); 402 279 auto bb = tableToAST(theLayer, b); 403 280 Layer lay=""; 404 281 if(auto l = t.access!StrValue(theLayer, "layer")) 405 282 lay = l.data; 406 - return new LetExpression(pos, nn, lay, ee, bb); 283 + return new Let(pos, nn, lay, ee, bb); 407 284 } 408 285 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"let", name:"???", init:"???", expr:"???"}`); 409 286 case "app": 410 287 if(auto f = t.access!Table(theLayer, "fun")) 411 288 if(auto a = t.access!Table(theLayer, "args")) 412 - return new FuncallExpression(pos, tableToAST(theLayer,f), tableToASTList(theLayer,a)); 289 + return new App(pos, tableToAST(theLayer,f), tableToASTList(theLayer,a)); 413 290 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"app", fun:???, args:???}`); 414 291 case "fun": 415 292 if(auto p = t.access!Table(theLayer, "params")) 416 293 if(auto b = t.access!Table(theLayer, "funbody")) 417 294 { 418 295 Parameter[] ps; 419 296 foreach(v; tableAsConsList(theLayer, p)) ................................................................................ 436 313 Layer[] emp; 437 314 ps ~= new Parameter(ss.data, emp); 438 315 continue; 439 316 } 440 317 throw genex!RuntimeException(cast(LexPosition)null, sprintf!`Invalid AST {bad fun params %s}`(v)); 441 318 } 442 319 auto bb = tableToAST(theLayer, b); 443 - return new FunLiteral(pos,ps,bb); 320 + return new Fun(pos,ps,bb); 444 321 } 445 322 throw genex!RuntimeException(cast(LexPosition)null, `Invalid AST {is:"fun", param:???, body:???}`); 446 323 default: 447 324 throw genex!RuntimeException(cast(LexPosition)null, sprintf!`Invalid AST {is: "%s"} unknown`(nodeType.data)); 448 325 } 449 326 } 327 + 328 +Table makeCons(Value a, Value d) 329 +{ 330 + Table t = new Table; 331 + t.set("car", ValueLayer, a); 332 + t.set("cdr", ValueLayer, d); 333 + return t; 334 +} 335 + 336 +Table fromPos(LexPosition pos) 337 +{ 338 + Table t = new Table; 339 + if( pos !is null ) { 340 + t.set("filename", ValueLayer, new StrValue(pos.filename)); 341 + t.set("lineno", ValueLayer, new IntValue(BigInt(pos.lineno))); 342 + t.set("column", ValueLayer, new IntValue(BigInt(pos.column))); 343 + } else { 344 + t.set("filename", ValueLayer, new StrValue("nullpos")); 345 + t.set("lineno", ValueLayer, new IntValue(BigInt(0))); 346 + t.set("column", ValueLayer, new IntValue(BigInt(0))); 347 + } 348 + return t; 349 +}

Modified sample/plusminus.pmy from [2f68238d12815ac3] to [d3a50b6eb8c63c2d].

1 1 @@s(x){x}; 2 -@s "+" = fun(x, y) {@v( 2 +@s "+" = fun(x, y) {@value( 3 3 @s(x) - @s(y) 4 4 )}; 5 5 6 6 print( 1 + 2 ); 7 7 print( @s(1 + 2) );

Modified tricks/tricks.d from [0eae6cc37f045c97] to [004818c087feff6a].

388 388 ), 6); 389 389 assert_eq( d2.match( 390 390 when!(D1, (x, y){return x + cast(int)y;}), 391 391 otherwise!({return 999;}), 392 392 when!(D2, (x){return x.length;}) 393 393 ), 999); 394 394 } 395 + 396 +/// Will be used for dynamic overload resolution pattern 397 + 398 +template firstParam(T) 399 +{ 400 + alias ParameterTypeTuple!(T)[0] firstParam; 401 +}