Diff
Not logged in

Differences From Artifact [10da2d7378e56ec4]:

To Artifact [9460508c714f0a1b]:


15 15 import polemy.valueconv; 16 16 import std.signals; 17 17 18 18 /// Objects for maitaining global environment and evaluation of expression on it 19 19 class Evaluator 20 20 { 21 21 public: 22 - /// Initialize evaluator with empty context 23 - this() { theContext = new Table; } 24 - 25 22 /// Evaluate the AST 26 23 Value evalAST(AST e) 27 - { 28 - return macroAndEval(e, ValueLayer, theContext, OverwriteCtx); 29 - } 24 + { return getLayerEval(ValueLayer).macroAndEval(e, theContext, LayerEval.OverwriteCtx); } 30 25 31 26 /// Evaluate the string 32 27 Value evalString(S,T...)(S str, T fn_ln_cn) 33 - { 34 - return evalAST(parseString(str,fn_ln_cn)); 35 - } 28 + { return evalAST(parseString(str,fn_ln_cn)); } 36 29 37 30 /// Evaluate the file 38 31 Value evalFile(S,T...)(S filename, T ln_cn) 39 - { 40 - return evalAST(parseFile(filename,ln_cn)); 41 - } 32 + { return evalAST(parseFile(filename,ln_cn)); } 42 33 43 34 /// Get the global context 44 35 Table globalContext() 36 + { return theContext; } 37 + 38 + /// Initialize evaluator with empty context 39 + this() 45 40 { 46 - return theContext; 41 + theContext = new Table; 42 + theLayers[ValueLayer] = new ValueLayerEval; 43 + theLayers[MacroLayer] = new MacroLayerEval; 44 + theLayers[RawMacroLayer] = new RawMacroLayerEval; 47 45 } 48 46 49 47 private: 50 - Table theContext; 48 + Table theContext; 49 + LayerEval[Layer] theLayers; 51 50 52 - enum : bool { CascadeCtx=false, OverwriteCtx=true }; 53 - 54 - LayerEval getLayerEvaluator(Layer lay) 51 + /// Get the layer evaluator from layer ID 52 + LayerEval getLayerEval(Layer lay) 55 53 { 56 - if( lay == ValueLayer ) 57 - return new ValueLayerEval; 58 - if( lay == RawMacroLayer ) 59 - return new RawMacroLayerEval; 60 - if( lay == MacroLayer ) 61 - return new MacroLayerEval; 62 - return new UserDefinedLayerEval(lay); 54 + if(auto p = lay in theLayers) 55 + return *p; 56 + return theLayers[lay] = new UserDefinedLayerEval(lay); 63 57 } 64 58 59 + /// Interface of layers 65 60 abstract class LayerEval 66 61 { 62 + enum : bool { CascadeCtx=false, OverwriteCtx=true }; 63 + 67 64 /// Concrete layers should implement these 68 - Layer currentLayer(); 69 - Value eval_( Die e, Table ctx, bool ctxMod );/// 70 - Value eval_( Str e, Table ctx, bool ctxMod );/// 71 - Value eval_( Int e, Table ctx, bool ctxMod );/// 72 - Value eval_( Var e, Table ctx, bool ctxMod );/// 73 - Value eval_( Lay e, Table ctx, bool ctxMod );/// 74 - Value eval_( Let e, Table ctx, bool ctxMod );/// 75 - Value eval_( App e, Table ctx, bool ctxMod );/// 76 - Value eval_( Fun e, Table ctx, bool ctxMod );/// 65 + protected Layer layerID(); 66 + protected Value eval_( Die e, Table ctx, bool ctxMod );/// 67 + protected Value eval_( Str e, Table ctx, bool ctxMod );/// 68 + protected Value eval_( Int e, Table ctx, bool ctxMod );/// 69 + protected Value eval_( Var e, Table ctx, bool ctxMod );/// 70 + protected Value eval_( Lay e, Table ctx, bool ctxMod );/// 71 + protected Value eval_( Let e, Table ctx, bool ctxMod );/// 72 + protected Value eval_( App e, Table ctx, bool ctxMod );/// 73 + protected Value eval_( Fun e, Table ctx, bool ctxMod );/// 74 + 75 + /// Should override this also, if the layer may return null for optimization 76 + Value evalToNonNull( AST e, Table ctx, bool ctxMod = CascadeCtx ) 77 + { return eval(e,ctx,ctxMod); } 78 + 79 + /// Do macro expansion first, and then eval. Should override this also if it is NOT macro layer. 80 + Value macroAndEval( AST e, Table ctx, bool ctxMod = CascadeCtx ) 81 + { return evalToNonNull(e,ctx,ctxMod); } 77 82 78 83 /// dynamic-overload-resolution 79 - Value eval( AST e, Table ctx, bool ctxMod ) 84 + Value eval( AST e, Table ctx, bool ctxMod = CascadeCtx ) 80 85 { 81 - enum funName = "eval_"; // modify here to customize 82 - alias TypeTuple!(e,ctx,ctxMod) params; // modify here to customize 86 + enum funName = "eval_"; // modify here for customization 87 + alias TypeTuple!(e,ctx,ctxMod) params; // modify here for customization 83 88 84 89 alias typeof(__traits(getOverloads, this, funName)) ovTypes; 85 90 alias staticMap!(firstParam, ovTypes) fstTypes; 86 91 alias DerivedToFront!(fstTypes) fstTypes_sorted; 87 92 foreach(i, T; fstTypes_sorted) 88 93 static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] ) 89 94 return __traits(getOverloads, this, funName)[i](_x, params[1..$]); 90 95 91 96 // modify here to customize the default behavior 92 97 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 93 98 } 94 99 95 - /// 96 - Value invokeFunction(Value _f, AST[] args, Table ctx, LexPosition pos, string callstackmsg) 100 + /// Function calling convention. 101 + /// Run all arugment AST in the appropriate layer and invoke the function. 102 + Value invokeFunction(Value f_, AST[] args, Table ctx, LexPosition pos, string callstackmsg) 97 103 { 98 - if(auto f = cast(FunValue)_f) 99 - { 100 - Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 101 - foreach(i,p; f.params()) 102 - if( p.layers.empty ) { 103 - Value v = this.eval(args[i], ctx, CascadeCtx); 104 - if(v is null) v = ast2table(args[i]); 105 - newCtx.set(p.name, currentLayer(), v); 104 + FunValue f = cast(FunValue)f_; 105 + if( f is null ) 106 + throw genex!RuntimeException(pos, text("tried to call non-function: ",f)); 107 + if( f.params().length != args.length ) 108 + throw genex!RuntimeException(pos, 109 + sprintf!("%d arguments required but %d passed")(f.params().length, args.length)); 110 + 111 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 112 + foreach(i,p; f.params()) 113 + if( p.layers.empty ) 114 + newCtx.set(p.name, layerID(), this.evalToNonNull(args[i], ctx)); 115 + else 116 + foreach(argLay; p.layers) 117 + { 118 + Layer ll = argLay; 119 + if( isMacroLayer(argLay) && typeid(this)!=typeid(MacroLayerEval) ) 120 + ll = RawMacroLayer; // explicit @macro invokes (rawmacro) 121 + newCtx.set(p.name, argLay, getLayerEval(ll).evalToNonNull(args[i], ctx)); 106 122 } 107 - else 108 - foreach(argLay; p.layers) { 109 - Layer ll = argLay; 110 - if( isMacroLayer(argLay) && typeid(this)!=typeid(MacroLayerEval) ) 111 - ll = RawMacroLayer; // explicit @macro invokes (rawmacro) 112 - Value v = getLayerEvaluator(ll).eval(args[i], ctx, CascadeCtx); 113 - if(v is null) v = ast2table(args[i]); 114 - newCtx.set(p.name, argLay, v); 115 - } 116 - scope _ = new PushCallStack(pos, callstackmsg); 117 - return f.invoke(currentLayer(), newCtx, pos); 118 - } 119 - throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); 123 + scope _ = new PushCallStack(pos, callstackmsg); 124 + return f.invoke(layerID(), newCtx, pos); 120 125 } 121 126 122 - /// 127 + /// Lift the value v to the current layer 123 128 Value lift(Value v, Table ctx, LexPosition pos) 124 129 { 125 - Layer lay = currentLayer(); 126 - 127 - // functions are automatically lifterd 130 + // functions are automatically lifted by itself 128 131 if( cast(FunValue) v ) 129 132 return v; 130 133 134 + Layer lay = layerID(); 135 + 136 + // load the lift function 131 137 if( !ctx.has(lay, LiftLayer) ) 132 138 throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" ); 133 139 134 - // similar to invokeFunction, but with only one argument bound to ValueLayer 135 - auto _f = ctx.get(lay, LiftLayer, pos); 136 - if(auto f = cast(FunValue)_f) 137 - { 138 - Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 139 - auto ps = f.params(); 140 - if( ps.length != 1 ) 141 - throw genex!RuntimeException(pos, 142 - text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); 143 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 144 - { 145 - newCtx.set(ps[0].name, ValueLayer, v); 146 - scope _ = new PushCallStack(pos, lay); 147 - return f.invoke(ValueLayer, newCtx, pos); 148 - } 149 - else 150 - throw genex!RuntimeException(pos, 151 - text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); 152 - } 153 - throw genex!RuntimeException(pos, 154 - text("non-function ", _f, " is registered as the lift function for ", lay)); 140 + Value f_ = ctx.get(lay, LiftLayer, pos); 141 + FunValue f = cast(FunValue) f_; 142 + if( f is null ) 143 + throw genex!RuntimeException(pos, 144 + text("non-function ", f_, " is registered as the lift function for ", lay)); 145 + if( f.params().length != 1 || f.params()[0].layers.length>=1 ) 146 + throw genex!RuntimeException(pos, 147 + text("lift function must take exactly 1 neutral parameter:",lay)); 148 + 149 + // invokeFunction 150 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 151 + newCtx.set(f.params()[0].name, ValueLayer, v); 152 + scope _ = new PushCallStack(pos, "lift to "~lay); 153 + return f.invoke(ValueLayer, newCtx, pos); 155 154 } 156 155 } 157 156 158 157 /// Evaluator for standard @value semantics 159 158 class ValueLayerEval : LayerEval 160 159 { 161 - override Layer currentLayer() 160 + override Layer layerID() 162 161 { 163 162 return ValueLayer; 164 163 } 165 164 override Value eval_( Die e, Table ctx, bool ctxMod ) 166 165 { 167 166 throw genex!RuntimeException(e.pos, "undefined case"); 168 167 } ................................................................................ 172 171 } 173 172 override Value eval_( Int e, Table ctx, bool ctxMod ) 174 173 { 175 174 return new IntValue(e.data); 176 175 } 177 176 override Value eval_( Var e, Table ctx, bool ctxMod ) 178 177 { 179 - return ctx.get(e.name, currentLayer(), e.pos); 178 + return ctx.get(e.name, layerID(), e.pos); 180 179 } 181 180 override Value eval_( Lay e, Table ctx, bool ctxMod ) 182 181 { 183 - auto le = getLayerEvaluator(e.layer); 184 - auto v = le.eval(e.expr,ctx,CascadeCtx); 185 - if( (v is null) && (cast(MacroLayerEval)le !is null) ) 186 - return ast2table(e.expr); 187 - else 188 - return v; 182 + return getLayerEval(e.layer).evalToNonNull(e.expr, ctx); 189 183 } 190 184 override Value eval_( Let e, Table ctx, bool ctxMod ) 191 185 { 192 - Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 193 - Value ri = this.eval(e.init, newCtx, CascadeCtx); 194 - if(e.name!="_") 195 - newCtx.set(e.name, e.layer.empty ? currentLayer() : e.layer, ri); 196 - return this.eval(e.expr, newCtx, OverwriteCtx); 186 + if( !ctxMod ) 187 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 188 + Value ri = this.eval(e.init, ctx); 189 + ctx.set(e.name, e.layer.empty ? layerID(): e.layer, ri); 190 + return this.eval(e.expr, ctx, OverwriteCtx); 197 191 } 198 192 override Value eval_( App e, Table ctx, bool ctxMod ) 199 193 { 200 194 Value f = this.eval( e.fun, ctx, CascadeCtx ); 201 195 return this.invokeFunction(f, e.args, ctx, e.pos, getNameIfPossible(e.fun)); 202 196 } 203 197 override Value eval_( Fun e, Table ctx, bool ctxMod ) 204 198 { 205 199 return createNewFunction(e, ctx); 206 200 } 201 + override Value macroAndEval( AST e, Table ctx, bool ctxMod ) 202 + { 203 + // incremental execution of let-expressions 204 + if(auto le = cast(Let)e) 205 + { 206 + AST ai = runMacro(le.init, ctx); 207 + 208 + if( !ctxMod ) 209 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 210 + 211 + Value vi = this.eval(ai, ctx); 212 + ctx.set(le.name, le.layer.empty ? layerID() : le.layer, vi); 213 + return this.macroAndEval(le.expr, ctx, OverwriteCtx); 214 + } 215 + else 216 + return this.eval(runMacro(e,ctx,ctxMod), ctx, ctxMod); 217 + } 207 218 } 208 219 209 220 /// Evaluator for user-defined layer 210 221 class UserDefinedLayerEval : ValueLayerEval 211 222 { 212 - Layer layerID; 223 + Layer theID; 213 224 mixin SimpleConstructor; 214 225 215 - override Layer currentLayer() 226 + override Layer layerID() 216 227 { 217 - return layerID; 228 + return theID; 218 229 } 219 230 override Value eval_( Die e, Table ctx, bool ctxMod ) 220 231 { 221 - return new UndefinedValue; 232 + return new BottomValue; 222 233 } 223 234 override Value eval_( Str e, Table ctx, bool ctxMod ) 224 235 { 225 - return this.lift(new StrValue(e.data), ctx, e.pos); 236 + return this.lift(super.eval_(e,ctx,ctxMod), ctx, e.pos); 226 237 } 227 238 override Value eval_( Int e, Table ctx, bool ctxMod ) 228 239 { 229 - return this.lift(new IntValue(e.data), ctx, e.pos); 240 + return this.lift(super.eval_(e,ctx,ctxMod), ctx, e.pos); 230 241 } 231 242 override Value eval_( Var e, Table ctx, bool ctxMod ) 232 243 { 233 - if( ctx.has(e.name, currentLayer()) ) 234 - return ctx.get(e.name, currentLayer()); 244 + if( ctx.has(e.name, layerID()) ) 245 + return ctx.get(e.name, layerID()); 235 246 return this.lift(ctx.get(e.name, ValueLayer, e.pos), ctx, e.pos); 236 247 } 237 248 } 238 249 239 - // Convention!! 240 - // returns null if never used macro-like feature 250 + // Macro layer. For optimization, if AST didn't change it returns null 241 251 class MacroLayerEval : LayerEval 242 252 { 243 - override Layer currentLayer() 253 + override Layer layerID() 244 254 { 245 255 return MacroLayer; 256 + } 257 + override Value evalToNonNull( AST e, Table ctx, bool ctxMod = CascadeCtx ) 258 + { 259 + Value v = this.eval(e, ctx, ctxMod); 260 + return v is null ? ast2table(e) : v; 246 261 } 247 262 override Value eval_( Die e, Table ctx, bool ctxMod ) 248 263 { 249 264 return null; 250 265 } 251 266 override Value eval_( Str e, Table ctx, bool ctxMod ) 252 267 { ................................................................................ 254 269 } 255 270 override Value eval_( Int e, Table ctx, bool ctxMod ) 256 271 { 257 272 return null; 258 273 } 259 274 override Value eval_( Var e, Table ctx, bool ctxMod ) 260 275 { 261 - if( ctx.has(e.name, currentLayer()) ) 262 - return ctx.get(e.name, currentLayer(), e.pos); 263 - else 264 - return null; 276 + if( ctx.has(e.name, layerID()) ) 277 + return ctx.get(e.name, layerID(), e.pos); 278 + return null; 265 279 } 266 280 override Value eval_( Lay e, Table ctx, bool ctxMod ) 267 281 { 268 - auto le = getLayerEvaluator(e.layer); 269 - return le.eval(e.expr,ctx,CascadeCtx); 282 + return getLayerEval(e.layer).eval(e.expr,ctx); 270 283 } 271 284 override Value eval_( Let e, Table ctx, bool ctxMod ) 272 285 { 273 - Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 274 - Value ai = this.eval(e.init, newCtx, CascadeCtx); 275 - newCtx.set(e.name, NoopLayer, null); 276 - Value ae = this.eval(e.expr, newCtx, OverwriteCtx); 277 - if( ai is null && ae is null ) 278 - return null; 286 + if( !ctxMod ) 287 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 288 + 289 + Value ai = this.eval(e.init, ctx); 290 + ctx.set(e.name, NoopLayer, null); 291 + Value ae = this.eval(e.expr, ctx, OverwriteCtx); 292 + 293 + if( ai is null && ae is null ) return null; 279 294 if( ai is null ) ai = ast2table(e.init); 280 295 if( ae is null ) ae = ast2table(e.expr); 296 + 281 297 return ast2table(e, delegate Value (AST _){ 282 298 if(_ is e.init) { return ai; } 283 299 if(_ is e.expr) { return ae; } 284 300 assert(false); 285 301 }); 286 302 } 287 303 override Value eval_( App e, Table ctx, bool ctxMod ) 288 304 { 289 - Value f = this.eval( e.fun, ctx, CascadeCtx ); 305 + Value f = this.eval( e.fun, ctx ); 290 306 if(auto ff = cast(FunValue)f) 291 307 return this.invokeFunction(ff, e.args, ctx, e.pos, getNameIfPossible(e.fun)); 292 - else { 308 + else 309 + { 293 310 bool allNull = (f is null); 294 311 Value[] vas; 295 - foreach(a; e.args) { 312 + foreach(a; e.args) 313 + { 296 314 Value va = this.eval(a, ctx, CascadeCtx); 297 315 if(va !is null) allNull = false; 298 316 vas ~= va; 299 317 } 300 318 if( allNull ) 301 319 return null; 302 320 return ast2table(e, delegate Value (AST _){ ................................................................................ 304 322 foreach(i,a; e.args) if(_ is a) return (vas[i] is null ? ast2table(a) : vas[i]); 305 323 assert(false); 306 324 }); 307 325 } 308 326 } 309 327 override Value eval_( Fun e, Table ctx, bool ctxMod ) 310 328 { 311 - Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet); 329 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 312 330 foreach(p; e.params) 313 - newCtx.set(p.name, NoopLayer, null); 314 - Value af = this.eval(e.funbody, newCtx, CascadeCtx); 331 + ctx.set(p.name, NoopLayer, null); 332 + Value af = this.eval(e.funbody, ctx); 315 333 if( af is null ) 316 334 return null; 317 335 return ast2table(e, (AST _){if(_ is e.funbody)return af; assert(false);}); 318 336 } 319 337 } 320 338 339 + /// (rawmacro) layer. almost same as @macro, but the Layer expression becomes AST, too. 321 340 class RawMacroLayerEval : MacroLayerEval 322 341 { 323 342 override Value eval_( Lay e, Table ctx, bool ctxMod ) 324 343 { 325 - Value ae = this.eval(e.expr, ctx, CascadeCtx); 344 + Value ae = this.eval(e.expr, ctx); 326 345 return ae is null ? null 327 346 : ast2table(e, delegate Value (AST _){if(_ is e.expr)return ae; assert(false);}); 328 347 } 329 348 } 330 349 331 -private: 332 - Value macroAndEval( AST e_, Layer lay, Table ctx, bool ctxMod ) 333 - { 334 - assert( !isASTLayer(lay) ); 335 - if(auto e = cast(Let)e_) 336 - { 337 - Value vai = getLayerEvaluator(RawMacroLayer).eval(e.init, ctx, CascadeCtx); 338 - AST ai = (vai is null ? e.init : polemy2d!(AST)(vai, e.pos)); 350 +private: // short utils 339 351 340 - if( !ctxMod ) 341 - ctx = new Table(ctx, Table.Kind.NotPropagateSet); 342 - 343 - Value vi = getLayerEvaluator(lay).eval(ai, ctx, CascadeCtx); 344 - string theLayer = e.layer.empty ? lay : e.layer; 345 - ctx.set(e.name, theLayer, vi); 346 - 347 - return macroAndEval( e.expr, lay, ctx, OverwriteCtx ); 348 - } 349 - else 350 - { 351 - Value va = getLayerEvaluator(RawMacroLayer).eval(e_, ctx, ctxMod); 352 - AST a = (va is null ? e_ : polemy2d!(AST)(va, e_.pos)); 353 - return getLayerEvaluator(lay).eval(a, ctx, ctxMod); 354 - } 355 - } 356 - 357 -private: 358 352 string getNameIfPossible(AST e) 359 353 { 360 354 if(auto v = cast(Var)e) 361 355 return v.name; 362 356 return ""; 363 357 } 364 358 359 + AST runMacro(AST e, Table ctx, bool ctxMod=LayerEval.CascadeCtx) 360 + { 361 + Value v = getLayerEval(RawMacroLayer).eval(e, ctx, ctxMod); 362 + return (v is null ? e : polemy2d!(AST)(v, e.pos)); 363 + } 364 + 365 +private: 365 366 Value createNewFunction(Fun e, Table ctx) 366 367 { 367 368 class UserDefinedFunValue : FunValue 368 369 { 369 370 Fun ast; 370 371 Table defCtx; 371 372 override const(Parameter[]) params() { return ast.params; } ................................................................................ 385 386 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 386 387 throw genex!RuntimeException("comparison with value and something other"); 387 388 } 388 389 override hash_t toHash() { 389 390 return (cast(hash_t)cast(void*)ast) + (cast(hash_t)cast(void*)defCtx); 390 391 } 391 392 392 - AST macroCache; 393 393 AST[void*] mandeCache; 394 394 static class MemokeyType 395 395 { 396 - void* a; Layer b; Tuple!(string,Layer,Value)[] c; 397 - hash_t toHash() { 398 - hash_t h = structuralHash(a) + structuralHash(b); 399 - foreach(e; c) 400 - h += structuralHash(e[0])+structuralHash(e[1])+structuralHash(e[2]); 401 - return h; 402 - } 403 - mixin SimpleToString; 404 - mixin SimpleConstructor; 405 - mixin SimpleCompareWithoutToHash; 396 + void* a; Layer b; Table c; 397 + mixin SimpleClass; 406 398 } 407 399 static Tuple!(Value,int)[MemokeyType] memo; 408 400 409 401 override Value invoke(Layer lay, Table ctx, LexPosition pos) 410 402 { 411 - if( isASTLayer(lay) ) { 412 - Value v = getLayerEvaluator(lay).eval(ast.funbody, ctx, CascadeCtx); 413 - if( v is null ) v = ast2table(ast.funbody); 414 - return v; 415 - } 416 - return macroAndEval(ast.funbody, lay, ctx, CascadeCtx); 417 -/* 418 - auto nonMemoizedRun = (){ 419 - if( macroCache is null ) 420 - { 421 - auto va = macroAndEval(e.funbody, lay, ctx, CascadeCtx, mandeCache); 422 - macroCache = va[1]; 423 - return va[0]; 424 - } 425 - else 426 - return eval(macroCache, lay, ctx); 427 - }; 403 + auto evlay = getLayerEval(lay); 404 + auto nonMemoizedRun = (){ return evlay.macroAndEval(ast.funbody, ctx); }; 428 405 429 406 if( !isUserDefinedLayer(lay) ) 430 407 return nonMemoizedRun(); 431 408 432 - MemokeyType memokey = new MemokeyType(cast(void*)ast, lay, ctx.direct_entries()); 433 - 409 + // automatic memoized co-recursive execution 410 + MemokeyType memokey = new MemokeyType(cast(void*)ast, lay, ctx); 434 411 if(auto p = memokey in memo) 435 412 { 436 413 (*p)[1] ++; 437 414 return (*p)[0]; 438 415 } 439 416 else 440 - memo[memokey] = tuple(lift(new UndefinedValue, lay, ctx, pos), 0); 417 + memo[memokey] = tuple(evlay.lift(new BottomValue, ctx, pos), 0); 441 418 442 419 Value r = nonMemoizedRun(); 443 420 444 421 int touched = memo[memokey][1]; 445 422 memo[memokey] = tuple(r, 12345678); 446 - //if(touched) {DBG("rerun :: ",r);r = nonMemoizedRun();} // twice!! 447 423 return r; 448 -*/ 449 424 } 450 425 } 451 426 return new UserDefinedFunValue(e,ctx); 452 427 } 453 428 454 429 public: 455 430 /// Add primitive function to the global context ................................................................................ 499 474 } 500 475 } 501 476 } 502 477 theContext.set(name, defLay, new NativeFunValue(dg)); 503 478 } 504 479 } 505 480 506 -version(unittest) import polemy.runtime; 481 +version(unittest) 482 + import polemy.runtime; 483 + 507 484 unittest 508 485 { 509 486 auto e = new Evaluator; 510 487 enrollRuntimeLibrary(e); 511 488 auto r = assert_nothrow( e.evalString(`var x = 21; x + x*x;`) ); 512 489 assert_eq( r, new IntValue(BigInt(21+21*21)) ); 513 490 assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21)) ); 514 491 assert_nothrow( e.globalContext.get("x",ValueLayer) ); 515 492 assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) ); 516 493 } 494 + 517 495 unittest 518 496 { 519 497 auto e = new Evaluator; 520 498 enrollRuntimeLibrary(e); 521 499 auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) ); 522 500 assert_eq( r, new IntValue(BigInt(21+21*21)) ); 523 501 assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(21+21*21) ); ................................................................................ 593 571 } 594 572 595 573 unittest 596 574 { 597 575 auto e = new Evaluator; 598 576 enrollRuntimeLibrary(e); 599 577 assert_throw!RuntimeException( e.evalString(`...`) ); 600 - assert_eq( e.evalString(`@@foo(x){x}; @foo(...)`), new UndefinedValue ); 578 + assert_eq( e.evalString(`@@foo(x){x}; @foo(...)`), new BottomValue ); 601 579 }