Diff
Not logged in

Differences From Artifact [a7c677ad83621b47]:

To Artifact [cd1c3d2598ac30ce]:


20 20 public: 21 21 /// Initialize evaluator with empty context 22 22 this() { theContext = new Table; } 23 23 24 24 /// Evaluate the AST 25 25 Value evalAST(AST e) 26 26 { 27 - return eval(e, ValueLayer, theContext, OverwriteCtx); 27 + return macroAndEval(e, ValueLayer, theContext, OverwriteCtx)[0]; 28 28 } 29 29 30 30 /// Evaluate the string 31 31 Value evalString(S,T...)(S str, T fn_ln_cn) 32 32 { 33 33 return evalAST(parseString(str,fn_ln_cn)); 34 34 } ................................................................................ 45 45 return theContext; 46 46 } 47 47 48 48 private: 49 49 Table theContext; 50 50 51 51 enum : bool { CascadeCtx=false, OverwriteCtx=true }; 52 + 52 53 Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 53 54 { 54 55 // dynamic-overload-resolution-pattern: modify here 55 56 enum funName = "eval"; 56 57 alias TypeTuple!(e,lay,ctx,overwriteCtx) params; 57 58 58 59 // dynamic-overload-resolution-pattern: dispatch ................................................................................ 65 66 66 67 // dynamic-overload-resolution-pattern: default behavior 67 68 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 68 69 } 69 70 70 71 Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 71 72 { 72 - if( isMacroishLayer(lay) ) 73 + if( isASTLayer(lay) ) 73 74 return ast2table(e, (AST e){return eval(e,lay,ctx);}); 74 75 if( lay==ValueLayer ) 75 76 return new StrValue(e.data); 76 77 return lift(new StrValue(e.data), lay, ctx, e.pos); 77 78 } 78 79 79 80 Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 80 81 { 81 - if( isMacroishLayer(lay) ) 82 + if( isASTLayer(lay) ) 82 83 return ast2table(e, (AST e){return eval(e,lay,ctx);}); 83 84 if( lay==ValueLayer ) 84 85 return new IntValue(e.data); 85 86 return lift(new IntValue(e.data), lay, ctx, e.pos); 86 87 } 87 88 88 89 Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 89 90 { 90 - if( isMacroishLayer(lay) ) 91 - if( ctx.has(e.name,MacroLayer) ) 91 + if( isASTLayer(lay) ) 92 + if( isMacroLayer(lay) && ctx.has(e.name,MacroLayer) ) 92 93 return ctx.get(e.name, MacroLayer, e.pos); 93 94 else 94 95 return ast2table(e, (AST e){return eval(e,lay,ctx);}); 95 96 if( lay==ValueLayer || ctx.has(e.name, lay) ) 96 97 return ctx.get(e.name, lay, e.pos); 97 98 return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos); 98 99 } 99 100 100 101 Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 101 102 { 102 103 Value f = eval( e.fun, lay, ctx ); 103 - if( isMacroishLayer(lay) ) 104 - if( auto ff = cast(FunValue)f ) 105 - return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos, getNameIfPossible(e.fun)); 104 + if( isASTLayer(lay) ) { 105 + auto ff = cast(FunValue)f; 106 + if( ff !is null && isMacroLayer(lay) ) 107 + return invokeFunction(ff, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun)); 106 108 else 107 109 return ast2table(e, (AST e){return eval(e,lay,ctx);}); 110 + } 108 111 return invokeFunction(f, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun)); 109 112 } 110 113 111 114 Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 112 115 { 113 - if( isMacroishLayer(lay) ) 114 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 116 + if( isASTLayer(lay) ) 117 + { 118 + // need this for correct scoping (outer scope macro variables must be hidden!) 119 + Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet); 120 + foreach(p; e.params) 121 + newCtx.set(p.name, ValueLayer, new UndefinedValue); 122 + return ast2table(e, (AST e){return eval(e,lay,newCtx);}); 123 + } 115 124 else 116 125 return createNewFunction(e, ctx); 117 126 } 118 127 119 128 Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 120 129 { 121 130 if( isNoLayerChangeLayer(lay) ) ................................................................................ 122 131 return ast2table(e, (AST e){return eval(e,lay,ctx);}); 123 132 else 124 133 return eval(e.expr, e.layer, ctx); 125 134 } 126 135 127 136 Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 128 137 { 129 - // todo @macro let 130 - if( isMacroishLayer(lay) ) 131 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 138 + Table newCtx = overwriteCtx ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 139 + if( isASTLayer(lay) ) 140 + return ast2table(e, (AST ee){ 141 + if(ee is e.expr) // need this for correct scoping (outer scope macro variables must be hidden!) 142 + newCtx.set(e.name, ValueLayer, new UndefinedValue); 143 + return eval(ee,lay,newCtx); 144 + }); 132 145 else 133 146 { 147 + Value ri = eval(e.init, lay, newCtx); 148 + newCtx.set(e.name, e.layer.empty ? lay : e.layer, ri); 149 + return eval(e.expr, lay, newCtx, OverwriteCtx); 150 + } 151 + } 152 + 153 +private: 154 + // little little bit incremental macro defining version. 155 + // enables @macro foo(x)=... in ... foo ..., only at the top level of the 156 + // interpreter and functions. better than nothing :P 157 + Tuple!(Value,AST) macroAndEval( AST e_, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 158 + { 159 + assert( !isASTLayer(lay) ); 160 + 161 + AST decodeAST(Value v, LexPosition pos) 162 + { 163 + // [TODO] more informative error message 164 + return polemy2d!(AST)(v, pos); 165 + } 166 + 167 + if(auto e = cast(Let)e_) 168 + { 169 + AST ai = decodeAST(eval(e.init, RawMacroLayer, ctx), e.init.pos); 170 + Value vi = eval(ai, lay, ctx); 171 + 134 172 if( !overwriteCtx ) 135 173 ctx = new Table(ctx, Table.Kind.NotPropagateSet); 136 - Value ri = eval(e.init, lay, ctx); 137 - string theLayer = e.layer.empty ? lay : e.layer; // neutral layer 138 - ctx.set(e.name, theLayer, ri); 139 - return eval(e.expr, lay, ctx, OverwriteCtx); 174 + string theLayer = e.layer.empty ? lay : e.layer; 175 + ctx.set(e.name, theLayer, vi); 176 + 177 + auto ave = macroAndEval( e.expr, lay, ctx, OverwriteCtx ); 178 + AST a = new Let(e.pos, e.name, e.layer, ai, ave[1]); 179 + return tuple(ave[0], a); 180 + } 181 + else 182 + { 183 + AST a = decodeAST(eval(e_, RawMacroLayer, ctx), e_.pos); 184 + Value v = eval(a, lay, ctx); 185 + return tuple(v, a); 140 186 } 141 187 } 142 188 143 189 private: 144 190 string getNameIfPossible(AST e) 145 191 { 146 192 if(auto v = cast(Var)e) ................................................................................ 151 197 Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos, string callstackmsg) 152 198 { 153 199 if(auto f = cast(FunValue)_f) 154 200 { 155 201 Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 156 202 foreach(i,p; f.params()) 157 203 if( p.layers.empty ) 158 - newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx)); 204 + newCtx.set(p.name, isMacroLayer(lay)?MacroLayer:lay, eval(args[i], lay, ctx)); 159 205 else 160 206 foreach(argLay; p.layers) 161 207 newCtx.set(p.name, argLay, eval(args[i], argLay, ctx)); 162 208 scope _ = new PushCallStack(pos, callstackmsg); 163 - return f.invoke(lay==RawMacroLayer ? MacroLayer : lay, newCtx, pos); 209 + return f.invoke(isMacroLayer(lay)?MacroLayer:lay, newCtx, pos); 164 210 } 165 211 throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); 166 212 } 167 213 168 214 Value lift(Value v, Layer lay, Table ctx, LexPosition pos) 169 215 { 170 - assert( !isMacroishLayer(lay), "lift to the @macro layer should never happen" ); 216 + assert( !isASTLayer(lay), "lift to the @macro layer should never happen" ); 171 217 172 218 // functions are automatically lifterd 173 219 if( cast(FunValue) v ) 174 220 return v; 175 221 176 222 if( !ctx.has(lay, SystemLayer) ) 177 223 throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" ); ................................................................................ 229 275 return this.defCtx.opCmp(rhs.defCtx); 230 276 } 231 277 assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 232 278 } 233 279 234 280 override Value invoke(Layer lay, Table ctx, LexPosition pos) 235 281 { 236 - if( lay == MacroLayer ) 282 + if( isASTLayer(lay) ) 237 283 return eval(ast.funbody, lay, ctx); 238 - try { 239 - if( afterMacroAST is null ) 240 - afterMacroAST = polemy2d!(AST)(eval(e.funbody, RawMacroLayer, ctx), pos); 241 - return eval(afterMacroAST, lay, ctx); 242 - } catch( RuntimeException e ) { 243 - throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line, e.next) : e; 284 + if( afterMacroAST is null ) 285 + { 286 + auto va = macroAndEval(e.funbody, lay, ctx); 287 + afterMacroAST = va[1]; 288 + return va[0]; 244 289 } 290 + else 291 + return eval(afterMacroAST, lay, ctx); 245 292 } 246 293 247 294 AST afterMacroAST; 248 295 } 249 296 return new UserDefinedFunValue(e,ctx); 250 297 } 251 298 ................................................................................ 310 357 } 311 358 unittest 312 359 { 313 360 auto e = new Evaluator; 314 361 enrollRuntimeLibrary(e); 315 362 auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) ); 316 363 assert_eq( r, new IntValue(BigInt(21+21*21)) ); 317 - assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) ); 364 + assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(21+21*21) ); 318 365 assert_nothrow( e.globalContext.get("x",ValueLayer) ); 319 366 assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) ); 320 367 } 321 368 unittest 322 369 { 323 370 auto e = new Evaluator; 324 371 enrollRuntimeLibrary(e); 325 - assert_eq( e.evalString(`let x=1; let y=(let x=2); x`), new IntValue(BigInt(1)) ); 326 - assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new IntValue(BigInt(2)) ); 372 + assert_eq( e.evalString(`let x=1; let y=(let x=2); x`), new IntValue(1) ); 373 + assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new IntValue(2) ); 327 374 } 328 375 329 376 unittest 330 377 { 331 378 auto e = new Evaluator; 332 379 enrollRuntimeLibrary(e); 333 380 assert_eq( e.evalString(`@a x=1; @b x=2; @a(x)`), new IntValue(BigInt(1)) );