Check-in [6760e0dd02]
Not logged in
Overview
SHA1 Hash:6760e0dd02038c8bbb6bce53897a05c0e747a122
Date: 2010-11-27 00:13:58
User: kinaba
Comment:evaluator refactoring done. x6 speed up.
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified .poseidon from [561f5c90ad534f85] to [76daaad38468db8e].

7 7 <filter>*.d</filter> 8 8 <showemptyfolder>0</showemptyfolder> 9 9 <buildSpec> 10 10 <buildType>0</buildType> 11 11 <mainFile>main.d</mainFile> 12 12 <Args /> 13 13 <options> 14 - <dmd> -g -profile -unittest </dmd> 14 + <dmd> -g -unittest </dmd> 15 15 <tool /> 16 16 <lib /> 17 17 <implib /> 18 18 <extra /> 19 19 <toolextra /> 20 20 <merge>0</merge> 21 21 <nonfiles>0</nonfiles>

Modified polemy/eval.d from [8d6e708eceba536a] to [10da2d7378e56ec4].

21 21 public: 22 22 /// Initialize evaluator with empty context 23 23 this() { theContext = new Table; } 24 24 25 25 /// Evaluate the AST 26 26 Value evalAST(AST e) 27 27 { 28 - AST[void*] mandeCache; 29 - return macroAndEval(e, ValueLayer, theContext, OverwriteCtx, mandeCache)[0]; 28 + return macroAndEval(e, ValueLayer, theContext, OverwriteCtx); 30 29 } 31 30 32 31 /// Evaluate the string 33 32 Value evalString(S,T...)(S str, T fn_ln_cn) 34 33 { 35 34 return evalAST(parseString(str,fn_ln_cn)); 36 35 } ................................................................................ 48 47 } 49 48 50 49 private: 51 50 Table theContext; 52 51 53 52 enum : bool { CascadeCtx=false, OverwriteCtx=true }; 54 53 55 - Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 54 + LayerEval getLayerEvaluator(Layer lay) 56 55 { 57 - // dynamic-overload-resolution-pattern: modify here 58 - enum funName = "eval"; 59 - alias TypeTuple!(e,lay,ctx,overwriteCtx) params; 60 - 61 - // dynamic-overload-resolution-pattern: dispatch 62 - alias typeof(__traits(getOverloads, this, funName)) ovTypes; 63 - alias staticMap!(firstParam, ovTypes) fstTypes; 64 - alias DerivedToFront!(fstTypes) fstTypes_sorted; 65 - foreach(i, T; fstTypes_sorted) 66 - static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] ) 67 - return __traits(getOverloads, this, funName)[i](_x, params[1..$]); 68 - 69 - // dynamic-overload-resolution-pattern: default behavior 70 - assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 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); 71 63 } 72 64 73 - Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 74 - { 75 - if( isASTLayer(lay) ) 76 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 77 - if( isUserDefinedLayer(lay) ) 78 - return lift(new StrValue(e.data), lay, ctx, e.pos); 79 - return new StrValue(e.data); 80 - } 81 - 82 - Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 65 + abstract class LayerEval 83 66 { 84 - if( isASTLayer(lay) ) 85 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 86 - if( isUserDefinedLayer(lay) ) 87 - return lift(new IntValue(e.data), lay, ctx, e.pos); 88 - return new IntValue(e.data); 89 - } 90 - 91 - Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 92 - { 93 - if( isASTLayer(lay) ) 94 - if( isMacroLayer(lay) && ctx.has(e.name,MacroLayer) ) 95 - return ctx.get(e.name, MacroLayer, e.pos); 96 - else 97 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 98 - if( isUserDefinedLayer(lay) && !ctx.has(e.name, lay) ) 99 - return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos); 100 - return ctx.get(e.name, lay, e.pos); 101 - } 102 - 103 - Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 104 - { 105 - Value f = eval( e.fun, lay, ctx ); 106 - if( isASTLayer(lay) ) { 107 - auto ff = cast(FunValue)f; 108 - if( ff !is null && isMacroLayer(lay) ) 109 - return invokeFunction(ff, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun)); 110 - else 111 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 112 - } 113 - return invokeFunction(f, e.args, lay, ctx, e.pos, getNameIfPossible(e.fun)); 67 + /// 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 );/// 77 + 78 + /// dynamic-overload-resolution 79 + Value eval( AST e, Table ctx, bool ctxMod ) 80 + { 81 + enum funName = "eval_"; // modify here to customize 82 + alias TypeTuple!(e,ctx,ctxMod) params; // modify here to customize 83 + 84 + alias typeof(__traits(getOverloads, this, funName)) ovTypes; 85 + alias staticMap!(firstParam, ovTypes) fstTypes; 86 + alias DerivedToFront!(fstTypes) fstTypes_sorted; 87 + foreach(i, T; fstTypes_sorted) 88 + static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] ) 89 + return __traits(getOverloads, this, funName)[i](_x, params[1..$]); 90 + 91 + // modify here to customize the default behavior 92 + assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 93 + } 94 + 95 + /// 96 + Value invokeFunction(Value _f, AST[] args, Table ctx, LexPosition pos, string callstackmsg) 97 + { 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); 106 + } 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)); 120 + } 121 + 122 + /// 123 + Value lift(Value v, Table ctx, LexPosition pos) 124 + { 125 + Layer lay = currentLayer(); 126 + 127 + // functions are automatically lifterd 128 + if( cast(FunValue) v ) 129 + return v; 130 + 131 + if( !ctx.has(lay, LiftLayer) ) 132 + throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" ); 133 + 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)); 155 + } 114 156 } 115 157 116 - Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 117 - { 118 - if( isASTLayer(lay) ) 119 - { 120 - // need this for correct scoping (outer scope macro variables must be hidden!) 121 - Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet); 122 - foreach(p; e.params) 123 - newCtx.set(p.name, NoopLayer, null); 124 - return ast2table(e, (AST e){return eval(e,lay,newCtx);}); 125 - } 126 - else 127 - return createNewFunction(e, ctx); 128 - } 129 - 130 - Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 158 + /// Evaluator for standard @value semantics 159 + class ValueLayerEval : LayerEval 131 160 { 132 - if( isNoLayerChangeLayer(lay) ) 133 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 134 - else 135 - return eval(e.expr, e.layer, ctx); 136 - } 137 - 138 - Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 139 - { 140 - Table newCtx = overwriteCtx ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 141 - if( isASTLayer(lay) ) 142 - return ast2table(e, (AST ee){ 143 - // need this for correct scoping (outer scope macro variables must be hidden!) 144 - if(e.name!="_" && ee is e.expr) 145 - newCtx.set(e.name, NoopLayer, null); 146 - return eval(ee,lay,newCtx); 147 - }); 148 - else 149 - { 150 - Value ri = eval(e.init, lay, newCtx); 161 + override Layer currentLayer() 162 + { 163 + return ValueLayer; 164 + } 165 + override Value eval_( Die e, Table ctx, bool ctxMod ) 166 + { 167 + throw genex!RuntimeException(e.pos, "undefined case"); 168 + } 169 + override Value eval_( Str e, Table ctx, bool ctxMod ) 170 + { 171 + return new StrValue(e.data); 172 + } 173 + override Value eval_( Int e, Table ctx, bool ctxMod ) 174 + { 175 + return new IntValue(e.data); 176 + } 177 + override Value eval_( Var e, Table ctx, bool ctxMod ) 178 + { 179 + return ctx.get(e.name, currentLayer(), e.pos); 180 + } 181 + override Value eval_( Lay e, Table ctx, bool ctxMod ) 182 + { 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; 189 + } 190 + override Value eval_( Let e, Table ctx, bool ctxMod ) 191 + { 192 + Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 193 + Value ri = this.eval(e.init, newCtx, CascadeCtx); 151 194 if(e.name!="_") 152 - newCtx.set(e.name, e.layer.empty ? lay : e.layer, ri); 153 - return eval(e.expr, lay, newCtx, OverwriteCtx); 195 + newCtx.set(e.name, e.layer.empty ? currentLayer() : e.layer, ri); 196 + return this.eval(e.expr, newCtx, OverwriteCtx); 197 + } 198 + override Value eval_( App e, Table ctx, bool ctxMod ) 199 + { 200 + Value f = this.eval( e.fun, ctx, CascadeCtx ); 201 + return this.invokeFunction(f, e.args, ctx, e.pos, getNameIfPossible(e.fun)); 202 + } 203 + override Value eval_( Fun e, Table ctx, bool ctxMod ) 204 + { 205 + return createNewFunction(e, ctx); 154 206 } 155 207 } 156 208 157 - Value eval( Die e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx ) 209 + /// Evaluator for user-defined layer 210 + class UserDefinedLayerEval : ValueLayerEval 158 211 { 159 - if( isMacroLayer(lay) ) 160 - return ast2table(e, (AST e){return eval(e,lay,ctx);}); 161 - if( isUserDefinedLayer(lay) ) 212 + Layer layerID; 213 + mixin SimpleConstructor; 214 + 215 + override Layer currentLayer() 216 + { 217 + return layerID; 218 + } 219 + override Value eval_( Die e, Table ctx, bool ctxMod ) 220 + { 162 221 return new UndefinedValue; 163 - throw genex!RuntimeException(e.pos, "undefined case"); 222 + } 223 + override Value eval_( Str e, Table ctx, bool ctxMod ) 224 + { 225 + return this.lift(new StrValue(e.data), ctx, e.pos); 226 + } 227 + override Value eval_( Int e, Table ctx, bool ctxMod ) 228 + { 229 + return this.lift(new IntValue(e.data), ctx, e.pos); 230 + } 231 + override Value eval_( Var e, Table ctx, bool ctxMod ) 232 + { 233 + if( ctx.has(e.name, currentLayer()) ) 234 + return ctx.get(e.name, currentLayer()); 235 + return this.lift(ctx.get(e.name, ValueLayer, e.pos), ctx, e.pos); 236 + } 164 237 } 165 238 166 -private: 167 - // little little bit incremental macro defining version. 168 - // enables @macro foo(x)=... in ... foo ..., only at the top level of the 169 - // interpreter and functions. better than nothing :P 170 - Tuple!(Value,AST) macroAndEval( AST e_, Layer lay, Table ctx, bool overwriteCtx 171 - , ref AST[void*] mandeCache) // [TODO] avoid assuming non-moving GC 239 + // Convention!! 240 + // returns null if never used macro-like feature 241 + class MacroLayerEval : LayerEval 172 242 { 173 - assert( !isASTLayer(lay) ); 174 - 175 - AST decodeAST(Value v, LexPosition pos) 243 + override Layer currentLayer() 244 + { 245 + return MacroLayer; 246 + } 247 + override Value eval_( Die e, Table ctx, bool ctxMod ) 248 + { 249 + return null; 250 + } 251 + override Value eval_( Str e, Table ctx, bool ctxMod ) 252 + { 253 + return null; 254 + } 255 + override Value eval_( Int e, Table ctx, bool ctxMod ) 256 + { 257 + return null; 258 + } 259 + override Value eval_( Var e, Table ctx, bool ctxMod ) 260 + { 261 + if( ctx.has(e.name, currentLayer()) ) 262 + return ctx.get(e.name, currentLayer(), e.pos); 263 + else 264 + return null; 265 + } 266 + override Value eval_( Lay e, Table ctx, bool ctxMod ) 176 267 { 177 - // [TODO] more informative error message 178 - return polemy2d!(AST)(v, pos); 268 + auto le = getLayerEvaluator(e.layer); 269 + return le.eval(e.expr,ctx,CascadeCtx); 179 270 } 180 - 181 - if(auto e = cast(Let)e_) 271 + override Value eval_( Let e, Table ctx, bool ctxMod ) 182 272 { 183 - void* key = cast(void*)e.init; 184 - AST ai; 185 - if(auto p = key in mandeCache) 186 - ai = *p; 187 - else { 188 - ai = decodeAST(eval(e.init, RawMacroLayer, ctx), e.init.pos); 189 - mandeCache[key] = ai; 190 - } 191 - Value vi = eval(ai, lay, ctx); 192 - 193 - if( !overwriteCtx ) 194 - ctx = new Table(ctx, Table.Kind.NotPropagateSet); 195 - string theLayer = e.layer.empty ? lay : e.layer; 196 - ctx.set(e.name, theLayer, vi); 197 - 198 - auto ave = macroAndEval( e.expr, lay, ctx, OverwriteCtx, mandeCache ); 199 - AST a = new Let(e.pos, e.name, e.layer, ai, ave[1]); 200 - return tuple(ave[0], a); 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; 279 + if( ai is null ) ai = ast2table(e.init); 280 + if( ae is null ) ae = ast2table(e.expr); 281 + return ast2table(e, delegate Value (AST _){ 282 + if(_ is e.init) { return ai; } 283 + if(_ is e.expr) { return ae; } 284 + assert(false); 285 + }); 201 286 } 202 - else 287 + override Value eval_( App e, Table ctx, bool ctxMod ) 203 288 { 204 - void* key = cast(void*)e_; 205 - AST a; 206 - if(auto p = key in mandeCache) 207 - a = *p; 289 + Value f = this.eval( e.fun, ctx, CascadeCtx ); 290 + if(auto ff = cast(FunValue)f) 291 + return this.invokeFunction(ff, e.args, ctx, e.pos, getNameIfPossible(e.fun)); 208 292 else { 209 - a = decodeAST(eval(e_, RawMacroLayer, ctx), e_.pos); 210 - mandeCache[key] = a; 293 + bool allNull = (f is null); 294 + Value[] vas; 295 + foreach(a; e.args) { 296 + Value va = this.eval(a, ctx, CascadeCtx); 297 + if(va !is null) allNull = false; 298 + vas ~= va; 299 + } 300 + if( allNull ) 301 + return null; 302 + return ast2table(e, delegate Value (AST _){ 303 + if(_ is e.fun) return (f is null ? ast2table(e.fun) : f); 304 + foreach(i,a; e.args) if(_ is a) return (vas[i] is null ? ast2table(a) : vas[i]); 305 + assert(false); 306 + }); 211 307 } 212 - Value v = eval(a, lay, ctx, overwriteCtx); 213 - return tuple(v, a); 308 + } 309 + override Value eval_( Fun e, Table ctx, bool ctxMod ) 310 + { 311 + Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet); 312 + foreach(p; e.params) 313 + newCtx.set(p.name, NoopLayer, null); 314 + Value af = this.eval(e.funbody, newCtx, CascadeCtx); 315 + if( af is null ) 316 + return null; 317 + return ast2table(e, (AST _){if(_ is e.funbody)return af; assert(false);}); 318 + } 319 + } 320 + 321 + class RawMacroLayerEval : MacroLayerEval 322 + { 323 + override Value eval_( Lay e, Table ctx, bool ctxMod ) 324 + { 325 + Value ae = this.eval(e.expr, ctx, CascadeCtx); 326 + return ae is null ? null 327 + : ast2table(e, delegate Value (AST _){if(_ is e.expr)return ae; assert(false);}); 328 + } 329 + } 330 + 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)); 339 + 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); 214 354 } 215 355 } 216 356 217 357 private: 218 358 string getNameIfPossible(AST e) 219 359 { 220 360 if(auto v = cast(Var)e) 221 361 return v.name; 222 362 return ""; 223 363 } 224 364 225 - Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos, string callstackmsg) 226 - { 227 - if(auto f = cast(FunValue)_f) 228 - { 229 - Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 230 - foreach(i,p; f.params()) 231 - if( p.layers.empty ) 232 - newCtx.set(p.name, isMacroLayer(lay)?MacroLayer:lay, eval(args[i], lay, ctx)); 233 - else 234 - foreach(argLay; p.layers) 235 - if( lay!=MacroLayer && isMacroLayer(argLay) ) // explicit @macro invokes (rawmacro) 236 - newCtx.set(p.name, argLay, eval(args[i], RawMacroLayer, ctx)); 237 - else 238 - newCtx.set(p.name, argLay, eval(args[i], argLay, ctx)); 239 - scope _ = new PushCallStack(pos, callstackmsg); 240 - return f.invoke(isMacroLayer(lay)?MacroLayer:lay, newCtx, pos); 241 - } 242 - throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); 243 - } 244 - 245 - Value lift(Value v, Layer lay, Table ctx, LexPosition pos) 246 - { 247 - assert( !isASTLayer(lay), "lift to the @macro layer should never happen" ); 248 - 249 - // functions are automatically lifterd 250 - if( cast(FunValue) v ) 251 - return v; 252 - 253 - if( !ctx.has(lay, LiftLayer) ) 254 - throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" ); 255 - 256 - // similar to invokeFunction, but with only one argument bound to ValueLayer 257 - auto _f = ctx.get(lay, LiftLayer, pos); 258 - if(auto f = cast(FunValue)_f) 259 - { 260 - Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 261 - auto ps = f.params(); 262 - if( ps.length != 1 ) 263 - throw genex!RuntimeException(pos, 264 - text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); 265 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 266 - { 267 - newCtx.set(ps[0].name, ValueLayer, v); 268 - scope _ = new PushCallStack(pos, lay); 269 - return f.invoke(ValueLayer, newCtx, pos); 270 - } 271 - else 272 - throw genex!RuntimeException(pos, 273 - text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); 274 - } 275 - throw genex!RuntimeException(pos, 276 - text("non-function ", _f, " is registered as the lift function for ", lay)); 277 - } 278 - 279 365 Value createNewFunction(Fun e, Table ctx) 280 366 { 281 367 class UserDefinedFunValue : FunValue 282 368 { 283 369 Fun ast; 284 370 Table defCtx; 285 371 override const(Parameter[]) params() { return ast.params; } ................................................................................ 318 404 mixin SimpleConstructor; 319 405 mixin SimpleCompareWithoutToHash; 320 406 } 321 407 static Tuple!(Value,int)[MemokeyType] memo; 322 408 323 409 override Value invoke(Layer lay, Table ctx, LexPosition pos) 324 410 { 325 - if( isASTLayer(lay) ) 326 - return eval(ast.funbody, lay, ctx); 327 - 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 +/* 328 418 auto nonMemoizedRun = (){ 329 419 if( macroCache is null ) 330 420 { 331 421 auto va = macroAndEval(e.funbody, lay, ctx, CascadeCtx, mandeCache); 332 422 macroCache = va[1]; 333 423 return va[0]; 334 424 } ................................................................................ 351 441 352 442 Value r = nonMemoizedRun(); 353 443 354 444 int touched = memo[memokey][1]; 355 445 memo[memokey] = tuple(r, 12345678); 356 446 //if(touched) {DBG("rerun :: ",r);r = nonMemoizedRun();} // twice!! 357 447 return r; 448 +*/ 358 449 } 359 450 } 360 451 return new UserDefinedFunValue(e,ctx); 361 452 } 362 453 363 454 public: 364 455 /// Add primitive function to the global context

Modified polemy/valueconv.d from [cd634c9bb4b6ba14] to [56ac5c69da3fe94e].

173 173 else 174 174 t.set(e.tupleof[i].stringof[2..$], ValueLayer, ast2table(m,rec)); 175 175 return t; 176 176 } 177 177 else 178 178 static assert(false, "unknown type <"~T.stringof~"> during AST encoding"); 179 179 } 180 + 181 +/// No hook version 182 +Value ast2table(T)(T e) 183 +{ 184 + //[TODO] I really need to automate this!!!!!!!!!!!!1 185 + Value rec(AST _) { 186 + if(auto e = cast(Str)_) return ast2table(e, &rec); 187 + if(auto e = cast(Int)_) return ast2table(e, &rec); 188 + if(auto e = cast(Var)_) return ast2table(e, &rec); 189 + if(auto e = cast(Die)_) return ast2table(e, &rec); 190 + if(auto e = cast(Let)_) return ast2table(e, &rec); 191 + if(auto e = cast(Lay)_) return ast2table(e, &rec); 192 + if(auto e = cast(App)_) return ast2table(e, &rec); 193 + if(auto e = cast(Fun)_) return ast2table(e, &rec); 194 + assert(false); 195 + } 196 + return rec(e); 197 +}

Modified sample/macro.pmy from [b441073a5b98679b] to [99466484fdc29835].

94 94 # Both prints "original". Macro respects the neutral layer's "let y=" 95 95 # and "fun(y)". It does not alter the inner scope y 96 96 @macro test1(y) { fun(y){y}("original") }; 97 97 @macro test2(y) { let y = "original" in y }; 98 98 print( test1("replaced?") ); 99 99 print( test2("replaced?") ); 100 100 101 -######################################## 102 -print("----------"); 103 - 104 -# Macro expansion is done only at the first call. 105 -# So by using @macro parameter, it can remember the argument 106 -# of the first call. 107 -def remember1( x @macro, y ) { if x == y then "yes" else "no" }; 108 -print( remember1(1, 1) ); # yes 1 == 1 109 -print( remember1(2,1) ); # yes "1" == 1 110 -print( remember1(2,2) ); # no "1" != 2 111 - 112 -# exactly the same function, but called in different order 113 -def remember2( x @macro, y ) { if x == y then "yes" else "no" }; 114 -print( remember2(2, 2) ); # yes "2" == 2 115 -print( remember2(2, 1) ); # no "2" != 1 116 -print( remember2(1, 1) ); # no "2" != 1 117 - 118 -# Is this a good thing or a bad thing?? 119 - 120 101 ######################################## 121 102 print("----------"); 122 103 123 104 # Trick to extract the AST of a function 124 105 def foo(x) { x + x }; 125 106 print( @macro(@value(foo)(arg1)) ); # prints AST for "arg1 + arg1" 126 107 127 108 # If we wrote @macro(foo(arg1)), it is the AST of "foo(arg1)" 128 109 # Here, by @value(foo) we obtain the "usual" behavior of foo, 129 110 # not the macro-like bahavior to construct AST "foo(??)". 130 111 # But still, by @macro( ... ) layer, the "usual" function is run in 131 112 # macro mode.