Differences From Artifact [b119954d6ce43301]:
- File
polemy/eval.d
- 2010-11-23 07:42:13 - part of checkin [6ac127ddd0] on branch trunk - new evaluator (user: kinaba) [annotate]
To Artifact [5a9949a1eb8839b1]:
- File
polemy/eval.d
- 2010-11-23 09:36:27 - part of checkin [b97bd4f713] on branch trunk - automatic AST to table encoder (user: kinaba) [annotate]
8 8 import polemy._common;
9 9 import polemy.failure;
10 10 import polemy.ast;
11 11 import polemy.parse;
12 12 import polemy.value;
13 13 import polemy.layer;
14 14
15 +/// Objects for maitaining global environment and evaluation of expression on it
15 16 class Evaluator
16 17 {
17 18 public:
19 + /// Initialize evaluator with empty context
18 20 this() { theContext = new Table; }
19 21
22 + /// Evaluate the AST
20 23 Value evalAST(AST e)
21 24 {
22 25 return eval(e, ValueLayer, theContext, OverwriteCtx);
23 26 }
24 27
28 + /// Evaluate the string
25 29 Value evalString(S,T...)(S str, T fn_ln_cn)
26 30 {
27 31 return evalAST(parseString(str,fn_ln_cn));
28 32 }
29 33
34 + /// Evaluate the file
30 35 Value evalFile(S,T...)(S filename, T ln_cn)
31 36 {
32 37 return evalAST(parseFile(filename,ln_cn));
33 38 }
34 39
40 + /// Get the global context
35 41 Table globalContext()
36 42 {
37 43 return theContext;
38 44 }
39 45
40 46 private:
41 47 Table theContext;
42 48
43 -private:
44 49 enum : bool { CascadeCtx=false, OverwriteCtx=true };
45 -
46 50 Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
47 51 {
48 52 // dynamic-overload-resolution-pattern: modify here
49 53 enum funName = "eval";
50 54 alias TypeTuple!(e,lay,ctx,overwriteCtx) params;
51 55
52 56 // dynamic-overload-resolution-pattern: dispatch
................................................................................
57 61 static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] )
58 62 return __traits(getOverloads, this, funName)[i](_x, params[1..$]);
59 63
60 64 // dynamic-overload-resolution-pattern: default behavior
61 65 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined"));
62 66 }
63 67
64 -private:
65 68 Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
66 69 {
67 - Value v = new StrValue(e.data);
68 - if( lay==RawMacroLayer || lay==MacroLayer )
69 - {
70 - auto ast = new Table;
71 - ast.set("pos", ValueLayer, fromPos(e.pos));
72 - ast.set("is", ValueLayer, new StrValue("str"));
73 - ast.set("data", ValueLayer, v);
74 - return ast;
75 - }
70 + if( isMacroishLayer(lay) )
71 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
76 72 if( lay==ValueLayer )
77 - return v;
78 - return lift(v, lay, ctx, e.pos);
73 + return new StrValue(e.data);
74 + return lift(new StrValue(e.data), lay, ctx, e.pos);
79 75 }
80 76
81 77 Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
82 78 {
83 - Value v = new IntValue(e.data);
84 - if( lay==RawMacroLayer || lay==MacroLayer )
85 - {
86 - auto ast = new Table;
87 - ast.set("pos", ValueLayer, fromPos(e.pos));
88 - ast.set("is", ValueLayer, new StrValue("int"));
89 - ast.set("data", ValueLayer, v);
90 - return ast;
91 - }
79 + if( isMacroishLayer(lay) )
80 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
92 81 if( lay==ValueLayer )
93 - return v;
94 - return lift(v, lay, ctx, e.pos);
82 + return new IntValue(e.data);
83 + return lift(new IntValue(e.data), lay, ctx, e.pos);
95 84 }
96 85
97 86 Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
98 87 {
99 - if( lay==RawMacroLayer || lay==MacroLayer )
100 - {
88 + if( isMacroishLayer(lay) )
101 89 if( ctx.has(e.name,MacroLayer) )
102 90 return ctx.get(e.name, MacroLayer, e.pos);
103 - auto ast = new Table;
104 - ast.set("pos", ValueLayer, fromPos(e.pos));
105 - ast.set("is", ValueLayer, new StrValue("var"));
106 - ast.set("name", ValueLayer, new StrValue(e.name));
107 - return ast;
108 - }
91 + else
92 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
109 93 if( lay==ValueLayer || ctx.has(e.name, lay) )
110 94 return ctx.get(e.name, lay, e.pos);
111 95 return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos);
112 96 }
113 97
114 98 Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
115 99 {
116 100 Value f = eval( e.fun, lay, ctx );
117 - if( lay==RawMacroLayer || lay==MacroLayer )
118 - {
101 + if( isMacroishLayer(lay) )
119 102 if( auto ff = cast(FunValue)f )
120 103 return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos);
121 - Table ast = new Table;
122 - ast.set("pos", ValueLayer, fromPos(e.pos));
123 - ast.set("is", ValueLayer, new StrValue("app"));
124 - ast.set("fun", ValueLayer, f);
125 - Table args = new Table;
126 - foreach_reverse(a; e.args)
127 - args = makeCons(eval(a, lay, ctx), args);
128 - ast.set("args", ValueLayer, args);
129 - return ast;
130 - }
131 - else
132 - {
133 - return invokeFunction(f, e.args, lay, ctx, e.pos);
134 - }
104 + else
105 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
106 + return invokeFunction(f, e.args, lay, ctx, e.pos);
135 107 }
136 108
137 109 Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
138 110 {
139 - if( lay==RawMacroLayer || lay==MacroLayer )
140 - {
141 - Table t = new Table;
142 - t.set("pos", ValueLayer, fromPos(e.pos));
143 - t.set("is", ValueLayer, new StrValue("fun"));
144 - t.set("funbody", ValueLayer, eval(e.funbody,lay,ctx));
145 - Table params = new Table;
146 - foreach_reverse(p; e.params)
147 - {
148 - Table lays = new Table;
149 - foreach_reverse(l; p.layers)
150 - lays = makeCons(new StrValue(l), lays);
151 - Table kv = new Table;
152 - kv.set("name", ValueLayer, new StrValue(p.name));
153 - kv.set("layers", ValueLayer, lays);
154 - Table cons = new Table;
155 - params = makeCons(kv, params);
156 - }
157 - t.set("params", ValueLayer, params);
158 - return t;
159 - }
111 + if( isMacroishLayer(lay) )
112 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
160 113 else
161 - {
162 114 return createNewFunction(e, ctx);
163 - }
164 115 }
165 116
166 117 Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
167 118 {
168 - if( lay == RawMacroLayer )
169 - {
170 - Value r = eval(e.expr, lay, ctx);
171 - auto ast = new Table; // todo: pos
172 - ast.set("pos", ValueLayer, fromPos(e.pos));
173 - ast.set("is", ValueLayer, new StrValue("lay"));
174 - ast.set("layer", ValueLayer, new StrValue(e.layer));
175 - ast.set("expr", ValueLayer, r);
176 - return ast;
177 - }
119 + if( isNoLayerChangeLayer(lay) )
120 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
178 121 else
179 122 return eval(e.expr, e.layer, ctx);
180 123 }
181 124
182 125 Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
183 126 {
184 127 // todo @macro let
185 - if( lay==RawMacroLayer || lay==MacroLayer )
186 - {
187 - auto ast = new Table; // todo: pos
188 - ast.set("pos", ValueLayer, fromPos(e.pos));
189 - ast.set("is", ValueLayer, new StrValue("let"));
190 - ast.set("name", ValueLayer, new StrValue(e.name));
191 - ast.set("layer", ValueLayer, new StrValue(e.layer));
192 - ast.set("init", ValueLayer, eval(e.init, lay, ctx));
193 - ast.set("expr", ValueLayer, eval(e.expr, lay, ctx));
194 - return ast;
195 - }
128 + if( isMacroishLayer(lay) )
129 + return ast2table(e, (AST e){return eval(e,lay,ctx);});
196 130 else
197 131 {
198 132 if( !overwriteCtx )
199 133 ctx = new Table(ctx, Table.Kind.NotPropagateSet);
200 134 Value ri = eval(e.init, lay, ctx);
201 - string theLayer = e.layer.empty ? (lay==RawMacroLayer ? MacroLayer : lay) : e.layer;
135 + string theLayer = e.layer.empty ? lay : e.layer; // neutral layer
202 136 ctx.set(e.name, theLayer, ri);
203 137 return eval(e.expr, lay, ctx, OverwriteCtx);
204 138 }
205 139 }
206 140
207 141 private:
208 142 Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null)
................................................................................
212 146 Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
213 147 foreach(i,p; f.params())
214 148 if( p.layers.empty )
215 149 newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx));
216 150 else
217 151 foreach(argLay; p.layers)
218 152 newCtx.set(p.name, argLay, eval(args[i], argLay, ctx));
219 - return f.invoke(pos, lay, newCtx);
153 + return f.invoke(lay==RawMacroLayer ? MacroLayer : lay, newCtx, pos);
220 154 }
221 155 throw genex!RuntimeException(pos, text("tried to call non-function: ",_f));
222 156 }
223 157
224 158 Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null)
225 159 {
160 + assert( !isMacroishLayer(lay), "lift to the @macro layer should not happen" );
161 +
226 162 // functions are automatically lifterd
227 163 if( cast(FunValue) v )
228 164 return v;
229 165
230 166 // similar to invoke Function, but with only one argument bound to ValueLayer
231 167 if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos))
232 168 {
................................................................................
233 169 Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
234 170 auto ps = f.params();
235 171 if( ps.length != 1 )
236 172 throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
237 173 if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
238 174 {
239 175 newCtx.set(ps[0].name, ValueLayer, v);
240 - return f.invoke(pos, ValueLayer, newCtx);
176 + return f.invoke(ValueLayer, newCtx, pos);
241 177 }
242 178 else
243 179 throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
244 180 }
245 181 throw genex!RuntimeException(pos, "tried to call non-function");
246 182 }
247 183
................................................................................
273 209 if(auto i = this.ast.opCmp(rhs.ast))
274 210 return i;
275 211 return this.defCtx.opCmp(rhs.defCtx);
276 212 }
277 213 assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
278 214 }
279 215
280 - override Value invoke(LexPosition pos, Layer lay, Table ctx)
216 + override Value invoke(Layer lay, Table ctx, LexPosition pos)
281 217 {
282 218 if( lay == MacroLayer )
283 219 return eval(ast.funbody, lay, ctx);
284 - auto macroed = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx));
285 - return eval(macroed, lay, ctx);
220 + if( afterMacroAST is null )
221 + afterMacroAST = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx));
222 + return eval(afterMacroAST, lay, ctx);
286 223 }
224 +
225 + AST afterMacroAST;
287 226 }
288 227 return new UserDefinedFunValue(e,ctx);
289 228 }
290 229
291 230 public:
292 - /// TODO: move up
293 - /// TDOO: to other layers?
294 - void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg)
231 + /// Add primitive function to the global context
232 + void addPrimitive(R,T...)(string name, Layer defLay, R delegate (T) dg)
295 233 {
296 234 class NativeFunValue : FunValue
297 235 {
298 - Parameter[] params_data;
299 - override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
300 236 override const(Parameter[]) params() { return params_data; }
301 - override Table definitionContext() { return new Table; } // todo: cache
302 - this(){
237 + override Table definitionContext() { return theContext; }
238 +
239 + override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
240 + override int opCmp(Object rhs) {
241 + if(auto r = cast(NativeFunValue)rhs) return typeid(typeof(dg)).compare(&dg,&r.dg);
242 + if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r));
243 + throw genex!RuntimeException(LexPosition.dummy, "comparison with value and somithing other");
244 + }
245 + mixin SimpleToHash;
246 +
247 + R delegate(T) dg;
248 + Parameter[] params_data;
249 +
250 + this(R delegate(T) dg)
251 + {
252 + this.dg = dg;
303 253 foreach(i, Ti; T)
304 254 params_data ~= new Parameter(text(i), []);
305 255 }
306 - override Value invoke(LexPosition pos, Layer lay, Table ctx)
256 +
257 + override Value invoke(Layer lay, Table ctx, LexPosition pos)
307 258 {
308 - if( lay != ValueLayer )
309 - throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function");
259 + if( lay != defLay )
260 + throw genex!RuntimeException(pos, text("only ", defLay, " layer can call native function: ", name));
310 261 T typed_args;
311 262 foreach(i, Ti; T) {
312 - typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer);
263 + typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer, pos);
313 264 if( typed_args[i] is null )
314 - throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1));
265 + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d of native function: %s"(i+1,name));
315 266 }
316 267 try {
317 268 return dg(typed_args);
318 269 } catch( RuntimeException e ) {
319 270 throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e;
320 271 }
321 272 }
322 273 }
323 - theContext.set(name, lay, new NativeFunValue);
274 + theContext.set(name, defLay, new NativeFunValue(dg));
324 275 }
325 276 }
326 277
327 278 version(unittest) import polemy.runtime;
328 279 unittest
329 280 {
330 281 auto e = new Evaluator;