Check-in [ba11f1d551]
Not logged in
Overview
SHA1 Hash:ba11f1d551d70b17cbae9814e1e0057e558e972c
Date: 2010-11-24 03:28:47
User: kinaba
Comment:fixed the macro scoping rules concerning non-macro let
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified polemy/eval.d from [a7c677ad83621b47] to [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)) );

Modified polemy/layer.d from [59dc790b72d21ee0] to [bd983db748e0ad6a].

13 13 14 14 enum : Layer 15 15 { 16 16 SystemLayer = "(system)", /// Predefined layer for internal data 17 17 ValueLayer = "@value", /// Predefined layer for normal run 18 18 MacroLayer = "@macro", /// Predefined layer for macro run (@lay() changes layer) 19 19 RawMacroLayer = "(rawmacro)", /// Predefined layer for macro run (@lay() becomes AST) 20 + AstLayer = "(ast)", /// Predefined layer for macro run (never invoke macro) 20 21 } 21 22 22 23 /// True if it is macro-like layer that basically generates syntax tree 23 24 24 -bool isMacroishLayer( Layer lay ) 25 +bool isASTLayer( Layer lay ) 25 26 { 26 - return lay==MacroLayer || lay==RawMacroLayer; 27 + return lay==MacroLayer || lay==RawMacroLayer || lay==AstLayer; 27 28 } 28 29 29 30 unittest 30 31 { 31 - assert( !isMacroishLayer(SystemLayer) ); 32 - assert( !isMacroishLayer(ValueLayer) ); 33 - assert( isMacroishLayer(MacroLayer) ); 34 - assert( isMacroishLayer(RawMacroLayer) ); 32 + assert( !isASTLayer(SystemLayer) ); 33 + assert( !isASTLayer(ValueLayer) ); 34 + assert( isASTLayer(MacroLayer) ); 35 + assert( isASTLayer(RawMacroLayer) ); 36 + assert( isASTLayer(AstLayer) ); 35 37 } 36 38 37 39 /// True if in the specified layer @lay(...) has no effect and merely produces a syntax tree 38 40 39 41 bool isNoLayerChangeLayer( Layer lay ) 40 42 { 41 - return lay==RawMacroLayer; 43 + return lay==RawMacroLayer || lay==AstLayer; 42 44 } 43 45 44 46 unittest 45 47 { 46 48 assert( !isNoLayerChangeLayer(SystemLayer) ); 47 49 assert( !isNoLayerChangeLayer(ValueLayer) ); 48 50 assert( !isNoLayerChangeLayer(MacroLayer) ); 49 51 assert( isNoLayerChangeLayer(RawMacroLayer) ); 52 + assert( isNoLayerChangeLayer(AstLayer) ); 53 +} 54 + 55 +/// True if do macro expanstion 56 + 57 +bool isMacroLayer( Layer lay ) 58 +{ 59 + return lay==MacroLayer || lay==RawMacroLayer; 60 +} 61 + 62 +unittest 63 +{ 64 + assert( !isMacroLayer(SystemLayer) ); 65 + assert( !isMacroLayer(ValueLayer) ); 66 + assert( isMacroLayer(MacroLayer) ); 67 + assert( isMacroLayer(RawMacroLayer) ); 68 + assert( !isMacroLayer(AstLayer) ); 50 69 }

Modified polemy/parse.d from [50e0836a1ece20de] to [bacc00f3f91907a9].

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 116 116 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 - ? parseLambdaAfterOpenParen(varpos) // let var ( ... 122 - : (eat("=", "after "~kwd), E(0)); // let var = ... 121 + ? parseLambdaAfterOpenParen(pos) // let var ( ... 122 + : (eat("=", "after "~kwd), E(0)); // let var = ... 123 123 if( moreDeclarationExists() ) 124 124 return new Let(pos, var, layer, e, Body()); 125 125 else 126 126 return new Let(pos, var, layer, e, new Var(varpos, var)); 127 127 } 128 128 } 129 129 ................................................................................ 480 480 481 481 AST parseId() 482 482 { 483 483 scope(exit) lex.popFront; 484 484 return new Str(currentPosition(), lex.front.str); 485 485 } 486 486 487 - AST parseLambdaAfterOpenParen(immutable LexPosition pos) 487 + AST parseLambdaAfterOpenParen(LexPosition pos) 488 488 { 489 489 Parameter[] params; 490 490 while( !tryEat(")") ) 491 491 { 492 492 params ~= parseParam(); 493 493 if( !tryEat(",") ) { 494 494 eat(")", "after function parameters"); ................................................................................ 559 559 } 560 560 561 561 AST doNothingExpression() 562 562 { 563 563 return new Str(currentPosition(), "(empty function body)"); 564 564 } 565 565 566 - immutable(LexPosition) currentPosition() 566 + LexPosition currentPosition() 567 567 { 568 568 return lex.empty ? null : lex.front.pos; 569 569 } 570 570 } 571 571 572 572 unittest 573 573 {

Modified polemy/valueconv.d from [2816a291e16d0986] to [94ac916389440918].

62 62 { 63 63 if(auto t = cast(Table)_v) 64 64 { 65 65 LexPosition pos = extractPos(t); 66 66 67 67 StrValue typ = cast(StrValue) t.access!StrValue(ValueLayer, "is"); 68 68 if( typ is null ) 69 - throw genex!RuntimeException(text(`Invalid AST (no "is" field): `, _v)); 69 + throw genex!RuntimeException(callpos, text(`Invalid AST (no "is" field): `, _v)); 70 70 71 71 foreach(AT; ListOfASTTypes) 72 72 if(typ.data == typeid(AT).name.split(".")[$-1].tolower()) 73 73 { 74 74 typeof(AT.tupleof) mems; 75 75 foreach(i,m; mems) 76 76 {

Modified sample/macro.pmy from [274d10aca22ce25f] to [977cd2f997805f91].

1 -@macro twice(x) { x; x }; 1 +@macro twice = fun(x) { x; x }; 2 2 @macro max(x,y) { 3 3 var _x = x; # no hygenic macro btw.... 4 4 var _y = y; # no hygenic macro btw.... 5 5 if(_x<_y){_y}else{_x} 6 6 }; 7 7 def maxNormal(x,y) { 8 8 if(x<y){y}else{x} ................................................................................ 11 11 if(x<y){y}else{x} 12 12 }; 13 13 14 14 @macro LetItBe(x, y) { let it = x in y }; 15 15 16 16 @macro pow10(x) { 17 17 @value( 18 + def pow(y, n) { 19 + if( n == 1 ) { y } 20 + else { 21 + @macro( @value(y) * @value(pow(y,n-1)) ) 22 + } 23 + } 24 + in 25 + pow(@macro(x+1),10) 26 + ) 27 +}; 28 + 29 +@macro pow10Hard(x) { 30 + @value( 18 31 def pow(x, n) { 19 32 if( n == 1 ) { x } 20 33 else { 21 34 @macro( @value(x) * @value(pow(x,n-1)) ) 22 35 } 23 36 } 24 37 in 25 - pow(@macro(x),10) 38 + pow(@macro(x+1),10) 26 39 ) 27 40 }; 28 41 29 42 def printAndReturn(x) 30 43 { 31 44 print(x); 32 45 x 33 46 }; 34 - 35 - 36 - 37 - 38 47 39 48 def main() 40 49 { 41 50 twice( print("foo") ); 42 51 print("--------------"); 43 52 print(max(printAndReturn(100),printAndReturn(200))); 44 53 print("--------------"); 45 54 print(maxNormal(printAndReturn(100),printAndReturn(200))); 46 55 print("--------------"); 47 56 print(maxBad(printAndReturn(100),printAndReturn(200))); 48 57 print("--------------"); 49 58 print( LetItBe( 1+2+3, it*it ) ); 50 59 print("--------------"); 60 + print(pow10(1)); 51 61 print(pow10(2)); 62 + print("--------------"); 63 + print(pow10Hard(1)); 64 + print(pow10Hard(2)); 65 +}; 66 + 67 +main(); 68 + 69 +@macro foo(y) 70 +{ 71 + fun(y){y}(300) 72 +# let y = 300 in y 52 73 }; 53 74 54 -main() 75 +print("--------------"); 76 +print(foo(200));