Differences From Artifact [27ad20bc14df9938]:
- File
polemy/eval.d
- 2010-11-21 08:18:05 - part of checkin [a5fe6233c1] on branch trunk - layered parameters implemented (user: kinaba) [annotate]
To Artifact [0e6e0e9d77fcbedc]:
- File
polemy/eval.d
- 2010-11-21 09:53:17 - part of checkin [435fa085ec] on branch trunk - refactored predefined layer names, and filled readme.txt. (user: kinaba) [annotate]
6 6 */
7 7 module polemy.eval;
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 +import polemy.layer;
13 14 import std.typecons;
14 15 import std.stdio;
15 16
16 17 ///
17 18 Table createGlobalContext()
18 19 {
19 20 auto ctx = new Table;
20 - ctx.set("+", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} ));
21 - ctx.set("-", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} ));
22 - ctx.set("*", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} ));
23 - ctx.set("/", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} ));
24 - ctx.set("%", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} ));
25 - ctx.set("||", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} ));
26 - ctx.set("&&", "@v", native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} ));
27 - ctx.set("<", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} ));
28 - ctx.set(">", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} ));
29 - ctx.set("<=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} ));
30 - ctx.set(">=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} ));
31 - ctx.set("==", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} ));
32 - ctx.set("!=", "@v", native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} ));
33 - ctx.set("print", "@v", native( (Value a){
21 + ctx.set("+", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} ));
22 + ctx.set("-", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} ));
23 + ctx.set("*", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} ));
24 + ctx.set("/", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} ));
25 + ctx.set("%", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} ));
26 + ctx.set("||", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} ));
27 + ctx.set("&&", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} ));
28 + ctx.set("<", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} ));
29 + ctx.set(">", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} ));
30 + ctx.set("<=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} ));
31 + ctx.set(">=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} ));
32 + ctx.set("==", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} ));
33 + ctx.set("!=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} ));
34 + ctx.set("print", ValueLayer, native( (Value a){
34 35 writeln(a);
35 36 return new IntValue(BigInt(178));
36 37 }));
37 - ctx.set("if", "@v", native( (IntValue x, FunValue ft, FunValue fe){
38 + ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe){
38 39 auto toRun = (x.data==0 ? fe : ft);
39 - return toRun.invoke(null, "@v", toRun.definitionContext());
40 + return toRun.invoke(null, ValueLayer, toRun.definitionContext());
40 41 // return toRun.invoke(pos, lay, toRun.definitionContext());
41 42 }));
42 - ctx.set("_isint", "@v", native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} ));
43 - ctx.set("_isstr", "@v", native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} ));
44 - ctx.set("_isfun", "@v", native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} ));
45 - ctx.set("_isundefined", "@v", native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} ));
46 - ctx.set("_istable", "@v", native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} ));
47 - ctx.set(".", "@v", native( (Table t, StrValue s){
48 - return (t.has(s.data, "@v") ? t.get(s.data, "@v") : new UndValue);
43 + ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} ));
44 + ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} ));
45 + ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} ));
46 + ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} ));
47 + ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} ));
48 + ctx.set(".", ValueLayer, native( (Table t, StrValue s){
49 + return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndValue);
50 + }) );
51 + ctx.set(".?", ValueLayer, native( (Table t, StrValue s){
52 + return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0));
49 53 }) );
50 - ctx.set(".?", "@v", native( (Table t, StrValue s){
51 - return new IntValue(BigInt(t.has(s.data, "@v") ? 1 : 0));
52 - }) );
53 - ctx.set(".=", "@v", native( (Table t, StrValue s, Value v){
54 + ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){
54 55 auto t2 = new Table(t, Table.Kind.NotPropagateSet);
55 - t2.set(s.data, "@v", v);
56 + t2.set(s.data, ValueLayer, v);
56 57 return t2;
57 58 }) );
58 - ctx.set("{}", "@v", native( (){
59 + ctx.set("{}", ValueLayer, native( (){
59 60 return new Table;
60 61 }) );
61 62 return ctx;
62 63 }
63 64
64 65 /// Entry point of this module
65 66
................................................................................
76 77 }
77 78
78 79 /// Entry point of this module
79 80
80 81 Tuple!(Value,"val",Table,"ctx") eval(AST e)
81 82 {
82 83 Table ctx = createGlobalContext();
83 - return typeof(return)(eval(e, ctx, false, "@v"), ctx);
84 + return typeof(return)(eval(e, ctx, false, ValueLayer), ctx);
84 85 }
85 86
86 87 Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false)
87 88 {
88 89 if(auto f = cast(FunValue)_f)
89 90 {
90 91 Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
91 92 foreach(i,p; f.params())
92 93 if( p.layers.empty )
93 - if(lay=="@macro")
94 + if(lay==MacroLayer)
94 95 ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro));
95 96 else
96 97 ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay));
97 98 else
98 99 foreach(argLay; p.layers)
99 - if(argLay=="@macro")
100 + if(argLay==MacroLayer)
100 101 ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro));
101 102 else
102 103 ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay));
103 104 return f.invoke(pos, lay, ctx);
104 105 }
105 106 throw genex!RuntimeException(pos, "tried to call non-function");
106 107 }
107 108
108 109 Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx)
109 110 {
110 - // similar to invoke Function, but with only one argument bound to @v
111 - Value _f = callerCtx.get(lay, "(system)", pos);
111 + // similar to invoke Function, but with only one argument bound to ValueLayer
112 + Value _f = callerCtx.get(lay, SystemLayer, pos);
112 113 if(auto f = cast(FunValue)_f)
113 114 {
114 115 Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
115 116 auto ps = f.params();
116 117 if( ps.length != 1 )
117 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at @v layer");
118 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]=="@v" )
118 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
119 + if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
119 120 {
120 - ctx.set(ps[0].name, "@v", v);
121 - return f.invoke(pos, "@v", ctx);
121 + ctx.set(ps[0].name, ValueLayer, v);
122 + return f.invoke(pos, ValueLayer, ctx);
122 123 }
123 124 else
124 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at @v layer");
125 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
125 126 }
126 127 throw genex!RuntimeException(pos, "tried to call non-function");
127 128 }
128 129
129 130 /// Entry point of this module
130 131 /// If splitCtx = true, then inner variable declaration do not overwrite ctx.
131 -/// lay is the layer ID for evaluation (standard value semantics uses "@v").
132 +/// lay is the layer ID for evaluation (standard value semantics uses ValueLayer).
132 133
133 134 Value eval(AST e, Table ctx, bool splitCtx, Layer lay)
134 135 {
135 136 return e.match(
136 137 (StrLiteral e)
137 138 {
138 139 Value v = new StrValue(e.data);
139 - if( lay == "@v" )
140 + if( lay == ValueLayer )
140 141 return v;
141 142 else
142 143 return lift(e.pos,v,lay,ctx);
143 144 },
144 145 (IntLiteral e)
145 146 {
146 147 Value v = new IntValue(e.data);
147 - if( lay == "@v" )
148 + if( lay == ValueLayer )
148 149 return v;
149 150 else // rise
150 151 return lift(e.pos,v,lay,ctx);
151 152 },
152 153 (VarExpression e)
153 154 {
154 - if( lay == "@v" )
155 + if( lay == ValueLayer )
155 156 return ctx.get(e.var, lay, e.pos);
156 157 try {
157 158 return ctx.get(e.var, lay, e.pos);
158 159 } catch( Throwable ) { // [TODO] more precise...
159 - return lift(e.pos, ctx.get(e.var, "@v", e.pos), lay, ctx);
160 + return lift(e.pos, ctx.get(e.var, ValueLayer, e.pos), lay, ctx);
160 161 }
161 162 },
162 163 (LayeredExpression e)
163 164 {
164 - if( e.lay == "@macro" )
165 + if( e.lay == MacroLayer )
165 166 return macroEval(e.expr, ctx, false);
166 167 else
167 168 return eval(e.expr, ctx, true, e.lay);
168 169 },
169 170 (LetExpression e)
170 171 {
171 172 // for letrec, we need this, but should avoid overwriting????
172 - // ctx.set(e.var, "@v", new UndefinedValue, e.pos);
173 + // ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos);
173 174 if(splitCtx)
174 175 ctx = new Table(ctx, Table.Kind.NotPropagateSet);
175 176 Value v = eval(e.init, ctx, true, lay);
176 177 ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos);
177 178 return eval(e.expr, ctx, false, lay);
178 179 },
179 180 (FuncallExpression e)
................................................................................
195 196 }
196 197 );
197 198 }
198 199
199 200 // [TODO] Optimization
200 201 Value macroEval(AST e, Table ctx, bool AlwaysMacro)
201 202 {
202 - Layer theLayer = "@v";
203 + Layer theLayer = ValueLayer;
203 204
204 205 Table pos = new Table;
205 206 pos.set("filename", theLayer, new StrValue(e.pos.filename));
206 207 pos.set("lineno", theLayer, new IntValue(BigInt(e.pos.lineno)));
207 208 pos.set("column", theLayer, new IntValue(BigInt(e.pos.column)));
208 209 return e.match(
209 210 (StrLiteral e)
................................................................................
221 222 t.set("is", theLayer, new StrValue("int"));
222 223 t.set("data", theLayer, new IntValue(e.data));
223 224 return t;
224 225 },
225 226 (VarExpression e)
226 227 {
227 228 try {
228 - return ctx.get(e.var, "@macro", e.pos);
229 + return ctx.get(e.var, MacroLayer, e.pos);
229 230 } catch( Throwable ) {// [TODO] more precies...
230 231 Table t = new Table;
231 232 t.set("pos", theLayer, pos);
232 233 t.set("is", theLayer, new StrValue("var"));
233 234 t.set("name", theLayer, new StrValue(e.var));
234 235 return cast(Value)t;
235 236 }
................................................................................
243 244 t.set("is", theLayer, new StrValue("lay"));
244 245 t.set("layer", theLayer, new StrValue(e.lay));
245 246 t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro));
246 247 return cast(Value)t;
247 248 }
248 249 else
249 250 {
250 - if( e.lay == "@macro" )
251 + if( e.lay == MacroLayer )
251 252 return macroEval(e.expr, ctx, false);
252 253 else
253 254 return eval(e.expr, ctx, true, e.lay);
254 255 }
255 256 },
256 257 (LetExpression e)
257 258 {
................................................................................
264 265 return t;
265 266 },
266 267 (FuncallExpression e)
267 268 {
268 269 Value _f = macroEval(e.fun,ctx,AlwaysMacro);
269 270
270 271 if( auto f = cast(FunValue)_f )
271 - return invokeFunction(e.pos, f, e.args, ctx, "@macro", AlwaysMacro);
272 + return invokeFunction(e.pos, f, e.args, ctx, MacroLayer, AlwaysMacro);
272 273
273 274 Table t = new Table;
274 275 t.set("pos", theLayer, pos);
275 276 t.set("is", theLayer, new StrValue("app"));
276 277 t.set("fun", theLayer, _f);
277 278 Table args = new Table;
278 279 foreach_reverse(a; e.args) {
................................................................................
317 318 );
318 319 }
319 320
320 321 unittest
321 322 {
322 323 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) );
323 324 assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
324 - assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21)) );
325 - assert_nothrow( r.ctx.get("x","@v") );
326 - assert_throw!RuntimeException( r.ctx.get("y","@v") );
325 + assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) );
326 + assert_nothrow( r.ctx.get("x",ValueLayer) );
327 + assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
327 328 }
328 329 unittest
329 330 {
330 331 auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) );
331 332 assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
332 - assert_eq( r.ctx.get("x","@v"), new IntValue(BigInt(21+21*21)) );
333 - assert_nothrow( r.ctx.get("x","@v") );
334 - assert_throw!RuntimeException( r.ctx.get("y","@v") );
333 + assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) );
334 + assert_nothrow( r.ctx.get("x",ValueLayer) );
335 + assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
335 336 }
336 337 unittest
337 338 {
338 339 assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(BigInt(1)) );
339 340 assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new IntValue(BigInt(2)) );
340 341 }
341 342 unittest
................................................................................
364 365 fib(5);`).val, new IntValue(BigInt(8)));
365 366 }
366 367
367 368 unittest
368 369 {
369 370 assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) );
370 371 assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) );
371 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@v(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) );
372 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@v(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) );
372 + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) );
373 + assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) );
373 374 }
374 375
375 376 unittest
376 377 {
377 378 assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) );
378 379 // there was a bug that declaration in the first line of function definition
379 380 // cannot be recursive
380 381 assert_nothrow( evalString(`def foo() {
381 382 def bar(y) { if(y<1) {0} else {bar(0)} };
382 383 bar(1)
383 384 }; foo()`) );
384 385 }
385 -