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