Diff
Not logged in

Differences From Artifact [9a9618fb0277f966]:

To Artifact [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 */