Differences From Artifact [a7c677ad83621b47]:
- File
polemy/eval.d
- 2010-11-23 13:55:15 - part of checkin [2134cd44cc] on branch trunk - further clean-up for polemy2d (user: kinaba) [annotate]
To Artifact [cd1c3d2598ac30ce]:
- File
polemy/eval.d
- 2010-11-23 18:28:47 - part of checkin [ba11f1d551] on branch trunk - fixed the macro scoping rules concerning non-macro let (user: kinaba) [annotate]
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)) );