Differences From Artifact [9a9618fb0277f966]:
- File
polemy/eval.d
- 2010-11-21 15:48:16 - part of checkin [f86026acb8] on branch trunk - macro cache and automemoization reloaded. auto re-run implemented. but automemo and autorerun is currently disabled. we need Table.opCmp... we also need to think more about the memoization (user: kinaba) [annotate]
To Artifact [b119954d6ce43301]:
- File
polemy/eval.d
- 2010-11-23 07:42:13 - part of checkin [6ac127ddd0] on branch trunk - new evaluator (user: kinaba) [annotate]
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 13 import polemy.layer;
14 -import std.typecons;
15 -import std.stdio;
16 14
17 -///
18 -Table createGlobalContext()
15 +class Evaluator
19 16 {
20 - auto ctx = new Table;
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){
35 - writeln(a);
36 - return new IntValue(BigInt(0));
37 - }));
38 - ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe){
39 - auto toRun = (x.data==0 ? fe : ft);
40 - // [TODO] fill positional information
41 - return toRun.invoke(null, ValueLayer, toRun.definitionContext());
42 -// return toRun.invoke(pos, lay, toRun.definitionContext());
43 - }));
44 - ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} ));
45 - ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} ));
46 - ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} ));
47 - ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} ));
48 - ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} ));
49 - ctx.set(".", ValueLayer, native( (Table t, StrValue s){
50 - return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndValue);
51 - }) );
52 - ctx.set(".?", ValueLayer, native( (Table t, StrValue s){
53 - return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0));
54 - }) );
55 - ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){
56 - auto t2 = new Table(t, Table.Kind.NotPropagateSet);
57 - t2.set(s.data, ValueLayer, v);
58 - return t2;
59 - }) );
60 - ctx.set("{}", ValueLayer, native( (){
61 - return new Table;
62 - }) );
63 - return ctx;
64 -}
65 -
66 -/// Entry point of this module
67 -
68 -Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn)
69 -{
70 - return eval( polemy.parse.parseString(str, fn_ln_cn) );
71 -}
72 -
73 -/// Entry point of this module
74 -
75 -Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn)
76 -{
77 - return eval( polemy.parse.parseFile(filename, ln_cn) );
78 -}
79 -
80 -/// Entry point of this module
81 -
82 -Tuple!(Value,"val",Table,"ctx") eval(AST e)
83 -{
84 - Table ctx = createGlobalContext();
85 - return typeof(return)(eval(e, ctx, false, ValueLayer), ctx);
86 -}
87 -
88 -Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false)
89 -{
90 - if(auto f = cast(FunValue)_f)
17 +public:
18 + this() { theContext = new Table; }
19 +
20 + Value evalAST(AST e)
21 + {
22 + return eval(e, ValueLayer, theContext, OverwriteCtx);
23 + }
24 +
25 + Value evalString(S,T...)(S str, T fn_ln_cn)
26 + {
27 + return evalAST(parseString(str,fn_ln_cn));
28 + }
29 +
30 + Value evalFile(S,T...)(S filename, T ln_cn)
31 + {
32 + return evalAST(parseFile(filename,ln_cn));
33 + }
34 +
35 + Table globalContext()
36 + {
37 + return theContext;
38 + }
39 +
40 +private:
41 + Table theContext;
42 +
43 +private:
44 + enum : bool { CascadeCtx=false, OverwriteCtx=true };
45 +
46 + Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
47 + {
48 + // dynamic-overload-resolution-pattern: modify here
49 + enum funName = "eval";
50 + alias TypeTuple!(e,lay,ctx,overwriteCtx) params;
51 +
52 + // dynamic-overload-resolution-pattern: dispatch
53 + alias typeof(__traits(getOverloads, this, funName)) ovTypes;
54 + alias staticMap!(firstParam, ovTypes) fstTypes;
55 + alias DerivedToFront!(fstTypes) fstTypes_sorted;
56 + foreach(i, T; fstTypes_sorted)
57 + static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] )
58 + return __traits(getOverloads, this, funName)[i](_x, params[1..$]);
59 +
60 + // dynamic-overload-resolution-pattern: default behavior
61 + assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined"));
62 + }
63 +
64 +private:
65 + Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
66 + {
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 + }
76 + if( lay==ValueLayer )
77 + return v;
78 + return lift(v, lay, ctx, e.pos);
79 + }
80 +
81 + Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
82 + {
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 + }
92 + if( lay==ValueLayer )
93 + return v;
94 + return lift(v, lay, ctx, e.pos);
95 + }
96 +
97 + Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
98 + {
99 + if( lay==RawMacroLayer || lay==MacroLayer )
100 + {
101 + if( ctx.has(e.name,MacroLayer) )
102 + 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 + }
109 + if( lay==ValueLayer || ctx.has(e.name, lay) )
110 + return ctx.get(e.name, lay, e.pos);
111 + return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos);
112 + }
113 +
114 + Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
115 + {
116 + Value f = eval( e.fun, lay, ctx );
117 + if( lay==RawMacroLayer || lay==MacroLayer )
118 + {
119 + if( auto ff = cast(FunValue)f )
120 + 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 + }
135 + }
136 +
137 + Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
138 + {
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 + }
160 + else
161 + {
162 + return createNewFunction(e, ctx);
163 + }
164 + }
165 +
166 + Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
91 167 {
92 - Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
93 - foreach(i,p; f.params())
94 - if( p.layers.empty )
95 - if(lay==MacroLayer)
96 - ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro));
97 - else
98 - ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay));
99 - else
100 - foreach(argLay; p.layers)
101 - if(argLay==MacroLayer)
102 - ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro));
103 - else
104 - ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay));
105 - return f.invoke(pos, lay, ctx);
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 + }
178 + else
179 + return eval(e.expr, e.layer, ctx);
106 180 }
107 - throw genex!RuntimeException(pos, "tried to call non-function");
108 -}
109 181
110 -Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx)
111 -{
112 - // functions are automatically lifterd
113 - if( cast(FunValue) v )
114 - return v;
115 -
116 - // similar to invoke Function, but with only one argument bound to ValueLayer
117 - Value _f = callerCtx.get(lay, SystemLayer, pos);
118 - if(auto f = cast(FunValue)_f)
182 + Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
119 183 {
120 - Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
121 - auto ps = f.params();
122 - if( ps.length != 1 )
123 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
124 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
184 + // todo @macro let
185 + if( lay==RawMacroLayer || lay==MacroLayer )
125 186 {
126 - ctx.set(ps[0].name, ValueLayer, v);
127 - return f.invoke(pos, ValueLayer, 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;
128 195 }
129 196 else
130 - throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
131 - }
132 - throw genex!RuntimeException(pos, "tried to call non-function");
133 -}
134 -
135 -/// Entry point of this module
136 -/// If splitCtx = true, then inner variable declaration do not overwrite ctx.
137 -/// lay is the layer ID for evaluation (standard value semantics uses ValueLayer).
138 -
139 -Value eval(AST e, Table ctx, bool splitCtx, Layer lay)
140 -{
141 - return e.match(
142 - (StrLiteral e)
143 197 {
144 - Value v = new StrValue(e.data);
145 - if( lay == ValueLayer )
146 - return v;
147 - else
148 - return lift(e.pos,v,lay,ctx);
149 - },
150 - (IntLiteral e)
151 - {
152 - Value v = new IntValue(e.data);
153 - if( lay == ValueLayer )
154 - return v;
155 - else // rise
156 - return lift(e.pos,v,lay,ctx);
157 - },
158 - (VarExpression e)
159 - {
160 - if( lay == ValueLayer )
161 - return ctx.get(e.name, lay, e.pos);
162 - if( ctx.has(e.name, lay, e.pos) )
163 - return ctx.get(e.name, lay, e.pos);
164 - else
165 - return lift(e.pos, ctx.get(e.name, ValueLayer, e.pos), lay, ctx);
166 - },
167 - (LayExpression e)
168 - {
169 - if( e.layer == MacroLayer )
170 - return macroEval(e.expr, ctx, false);
171 - else
172 - return eval(e.expr, ctx, true, e.layer);
173 - },
174 - (LetExpression e)
175 - {
176 - // for letrec, we need this, but should avoid overwriting????
177 - // ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos);
178 - if(splitCtx)
198 + if( !overwriteCtx )
179 199 ctx = new Table(ctx, Table.Kind.NotPropagateSet);
180 - Value v = eval(e.init, ctx, true, lay);
181 - ctx.set(e.name, (e.layer.length ? e.layer : lay), v, e.pos);
182 - return eval(e.expr, ctx, false, lay);
183 - },
184 - (FuncallExpression e)
185 - {
186 - return invokeFunction(e.pos, eval(e.fun, ctx, true, lay), e.args, ctx, lay);
187 - },
188 - (FunLiteral e)
189 - {
190 - return new UserDefinedFunValue(e, ctx);
191 - },
192 - delegate Value (AST e)
200 + Value ri = eval(e.init, lay, ctx);
201 + string theLayer = e.layer.empty ? (lay==RawMacroLayer ? MacroLayer : lay) : e.layer;
202 + ctx.set(e.name, theLayer, ri);
203 + return eval(e.expr, lay, ctx, OverwriteCtx);
204 + }
205 + }
206 +
207 +private:
208 + Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null)
209 + {
210 + if(auto f = cast(FunValue)_f)
193 211 {
194 - throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e)));
212 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
213 + foreach(i,p; f.params())
214 + if( p.layers.empty )
215 + newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx));
216 + else
217 + foreach(argLay; p.layers)
218 + newCtx.set(p.name, argLay, eval(args[i], argLay, ctx));
219 + return f.invoke(pos, lay, newCtx);
195 220 }
196 - );
197 -}
198 -
199 -// [TODO] Optimization
200 -Value macroEval(AST e, Table ctx, bool AlwaysMacro)
201 -{
202 - Layer theLayer = ValueLayer;
221 + throw genex!RuntimeException(pos, text("tried to call non-function: ",_f));
222 + }
203 223
204 - Table makeCons(Value a, Value d)
224 + Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null)
205 225 {
206 - Table t = new Table;
207 - t.set("car", theLayer, a);
208 - t.set("cdr", theLayer, d);
209 - return t;
226 + // functions are automatically lifterd
227 + if( cast(FunValue) v )
228 + return v;
229 +
230 + // similar to invoke Function, but with only one argument bound to ValueLayer
231 + if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos))
232 + {
233 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
234 + auto ps = f.params();
235 + if( ps.length != 1 )
236 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
237 + if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
238 + {
239 + newCtx.set(ps[0].name, ValueLayer, v);
240 + return f.invoke(pos, ValueLayer, newCtx);
241 + }
242 + else
243 + throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
244 + }
245 + throw genex!RuntimeException(pos, "tried to call non-function");
210 246 }
211 247
212 - Table pos = new Table;
213 - if( e.pos !is null ) {
214 - pos.set("filename", theLayer, new StrValue(e.pos.filename));
215 - pos.set("lineno", theLayer, new IntValue(BigInt(e.pos.lineno)));
216 - pos.set("column", theLayer, new IntValue(BigInt(e.pos.column)));
217 - } else {
218 - pos.set("filename", theLayer, new StrValue("nullpos"));
219 - pos.set("lineno", theLayer, new IntValue(BigInt(0)));
220 - pos.set("column", theLayer, new IntValue(BigInt(0)));
221 - }
222 -
223 - return e.match(
224 - (StrLiteral e)
248 + Value createNewFunction(Fun e, Table ctx)
249 + {
250 + class UserDefinedFunValue : FunValue
225 251 {
226 - Table t = new Table;
227 - t.set("pos", theLayer, pos);
228 - t.set("is", theLayer, new StrValue("str"));
229 - t.set("data", theLayer, new StrValue(e.data));
230 - return t;
231 - },
232 - (IntLiteral e)
233 - {
234 - Table t = new Table;
235 - t.set("pos", theLayer, pos);
236 - t.set("is", theLayer, new StrValue("int"));
237 - t.set("data", theLayer, new IntValue(e.data));
238 - return t;
239 - },
240 - (VarExpression e)
241 - {
242 - if( ctx.has(e.name, MacroLayer, e.pos) )
243 - return ctx.get(e.name, MacroLayer, e.pos);
244 - else {
245 - Table t = new Table;
246 - t.set("pos", theLayer, pos);
247 - t.set("is", theLayer, new StrValue("var"));
248 - t.set("name", theLayer, new StrValue(e.name));
249 - return cast(Value)t;
252 + Fun ast;
253 + Table defCtx;
254 + override const(Parameter[]) params() { return ast.params; }
255 + override Table definitionContext() { return defCtx; }
256 +
257 + this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; }
258 + override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); }
259 + override bool opEquals(Object rhs_) const /// member-by-member equality
260 + {
261 + if( auto rhs = cast(typeof(this))rhs_ )
262 + return this.ast==rhs.ast && this.defCtx==rhs.defCtx;
263 + assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
264 + }
265 + override hash_t toHash() const /// member-by-member hash
266 + {
267 + return typeid(this.ast).getHash(&this.ast) + typeid(this.defCtx).getHash(&this.defCtx);
268 + }
269 + override int opCmp(Object rhs_) /// member-by-member compare
270 + {
271 + if( auto rhs = cast(typeof(this))rhs_ )
272 + {
273 + if(auto i = this.ast.opCmp(rhs.ast))
274 + return i;
275 + return this.defCtx.opCmp(rhs.defCtx);
276 + }
277 + assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
250 278 }
251 - },
252 - (LayExpression e)
253 - {
254 - if( AlwaysMacro )
279 +
280 + override Value invoke(LexPosition pos, Layer lay, Table ctx)
255 281 {
256 - Table t = new Table;
257 - t.set("pos", theLayer, pos);
258 - t.set("is", theLayer, new StrValue("lay"));
259 - t.set("layer", theLayer, new StrValue(e.layer));
260 - t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro));
261 - return cast(Value)t;
282 + if( lay == MacroLayer )
283 + return eval(ast.funbody, lay, ctx);
284 + auto macroed = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx));
285 + return eval(macroed, lay, ctx);
262 286 }
263 - else
264 - {
265 - if( e.layer == MacroLayer )
266 - return macroEval(e.expr, ctx, false);
267 - else
268 - return eval(e.expr, ctx, true, e.layer);
269 - }
270 - },
271 - (LetExpression e)
287 + }
288 + return new UserDefinedFunValue(e,ctx);
289 + }
290 +
291 +public:
292 + /// TODO: move up
293 + /// TDOO: to other layers?
294 + void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg)
295 + {
296 + class NativeFunValue : FunValue
272 297 {
273 - Table t = new Table;
274 - t.set("pos", theLayer, pos);
275 - t.set("is", theLayer, new StrValue("let"));
276 - t.set("name", theLayer, new StrValue(e.name));
277 - t.set("init", theLayer, macroEval(e.init,ctx,AlwaysMacro));
278 - t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro));
279 - return t;
280 - },
281 - (FuncallExpression e)
282 - {
283 - Value _f = macroEval(e.fun,ctx,AlwaysMacro);
284 -
285 - if( auto f = cast(FunValue)_f )
286 - return invokeFunction(e.pos, f, e.args, ctx, MacroLayer, AlwaysMacro);
287 -
288 - Table t = new Table;
289 - t.set("pos", theLayer, pos);
290 - t.set("is", theLayer, new StrValue("app"));
291 - t.set("fun", theLayer, _f);
292 - Table args = new Table;
293 - foreach_reverse(a; e.args) {
294 - Table cons = new Table;
295 - cons.set("car",theLayer,macroEval(a,ctx,AlwaysMacro));
296 - cons.set("cdr",theLayer,args);
297 - args = cons;
298 + Parameter[] params_data;
299 + override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
300 + override const(Parameter[]) params() { return params_data; }
301 + override Table definitionContext() { return new Table; } // todo: cache
302 + this(){
303 + foreach(i, Ti; T)
304 + params_data ~= new Parameter(text(i), []);
305 + }
306 + override Value invoke(LexPosition pos, Layer lay, Table ctx)
307 + {
308 + if( lay != ValueLayer )
309 + throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function");
310 + T typed_args;
311 + foreach(i, Ti; T) {
312 + typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer);
313 + if( typed_args[i] is null )
314 + throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1));
315 + }
316 + try {
317 + return dg(typed_args);
318 + } catch( RuntimeException e ) {
319 + throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e;
320 + }
298 321 }
299 - t.set("args", theLayer, args);
300 - return cast(Value)t;
301 - },
302 - (FunLiteral e)
303 - {
304 - Table t = new Table;
305 - t.set("pos", theLayer, pos);
306 - t.set("is", theLayer, new StrValue("fun"));
307 - t.set("funbody", theLayer, macroEval(e.funbody,ctx,AlwaysMacro));
308 - Table params = new Table;
309 - foreach_reverse(p; e.params)
310 - {
311 - Table lays = new Table;
312 - foreach_reverse(lay; p.layers)
313 - lays = makeCons(new StrValue(lay), lays);
314 - Table kv = new Table;
315 - kv.set("name", theLayer, new StrValue(p.name));
316 - kv.set("layers", theLayer, lays);
317 - Table cons = new Table;
318 - params = makeCons(kv, params);
319 - }
320 - t.set("params", theLayer, params);
321 - return t;
322 - },
323 - delegate Value (AST e)
324 - {
325 - throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e)));
326 322 }
327 - );
323 + theContext.set(name, lay, new NativeFunValue);
324 + }
325 +}
326 +
327 +version(unittest) import polemy.runtime;
328 +unittest
329 +{
330 + auto e = new Evaluator;
331 + enrollRuntimeLibrary(e);
332 + auto r = assert_nothrow( e.evalString(`var x = 21; x + x*x;`) );
333 + assert_eq( r, new IntValue(BigInt(21+21*21)) );
334 + assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21)) );
335 + assert_nothrow( e.globalContext.get("x",ValueLayer) );
336 + assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) );
337 +}
338 +unittest
339 +{
340 + auto e = new Evaluator;
341 + enrollRuntimeLibrary(e);
342 + auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) );
343 + assert_eq( r, new IntValue(BigInt(21+21*21)) );
344 + assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) );
345 + assert_nothrow( e.globalContext.get("x",ValueLayer) );
346 + assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) );
347 +}
348 +unittest
349 +{
350 + auto e = new Evaluator;
351 + enrollRuntimeLibrary(e);
352 + assert_eq( e.evalString(`let x=1; let y=(let x=2); x`), new IntValue(BigInt(1)) );
353 + assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new IntValue(BigInt(2)) );
354 +}
355 +
356 +unittest
357 +{
358 + auto e = new Evaluator;
359 + enrollRuntimeLibrary(e);
360 + assert_eq( e.evalString(`@a x=1; @b x=2; @a(x)`), new IntValue(BigInt(1)) );
361 + assert_eq( e.evalString(`@a x=1; @b x=2; @b(x)`), new IntValue(BigInt(2)) );
362 + assert_eq( e.evalString(`let x=1; let _ = (@a x=2;2); x`), new IntValue(BigInt(1)) );
363 + e = new Evaluator;
364 + assert_throw!Throwable( e.evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) );
365 +}
366 +
367 +unittest
368 +{
369 + auto e = new Evaluator;
370 + enrollRuntimeLibrary(e);
371 + assert_eq( e.evalString(`
372 + @@s(x){x};
373 + @s "+" = fun(x, y) {@value(
374 + @s(x) - @s(y)
375 + )};
376 + @s(1 + 2)
377 + `), new IntValue(BigInt(-1)) );
378 +}
379 +
380 +unittest
381 +{
382 + auto e = new Evaluator;
383 + enrollRuntimeLibrary(e);
384 + assert_eq( e.evalString(`
385 +@@3(x){x};
386 +def incr(x) { x+1 };
387 +@ 3 incr(x) {@value( if(@ 3(x)+1< 3){@ 3(x)+1}else{0} )};
388 +def fb(n @value @3) { @3(n) };
389 +fb(incr(incr(incr(0))))
390 + `), new IntValue(BigInt(0)) );
328 391 }
329 392
330 393 unittest
331 394 {
332 - auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) );
333 - assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
334 - assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) );
335 - assert_nothrow( r.ctx.get("x",ValueLayer) );
336 - assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
337 -}
338 -unittest
339 -{
340 - auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) );
341 - assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
342 - assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) );
343 - assert_nothrow( r.ctx.get("x",ValueLayer) );
344 - assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
345 -}
346 -unittest
347 -{
348 - assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(BigInt(1)) );
349 - assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new IntValue(BigInt(2)) );
350 -}
351 -unittest
352 -{
353 - assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt(1)) );
354 - assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt(2)) );
355 - assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValue(BigInt(1)) );
356 - assert_throw!Throwable( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) );
395 + auto e = new Evaluator;
396 + enrollRuntimeLibrary(e);
397 + assert_nothrow( e.evalString(`
398 +@macro twice(x) { x; x };
399 +def main() { twice(1) };
400 +main()
401 + `) );
357 402 }
358 403 /*
359 404 unittest
360 405 {
361 406 assert_eq( evalString(`var fac = fun(x){
362 407 if(x)
363 408 { x*fac(x-1); }
................................................................................
369 414 if(x<2)
370 415 { 1; }
371 416 else
372 417 { fib(x-1) + fib(x-2); };
373 418 };
374 419 fib(5);`).val, new IntValue(BigInt(8)));
375 420 }
376 -
377 -unittest
378 -{
379 - assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) );
380 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) );
381 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) );
382 - assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) );
383 -}
384 -
385 421 unittest
386 422 {
387 423 assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) );
388 424 // there was a bug that declaration in the first line of function definition
389 425 // cannot be recursive
390 426 assert_nothrow( evalString(`def foo() {
391 427 def bar(y) { if(y<1) {0} else {bar(0)} };
392 428 bar(1)
393 429 }; foo()`) );
394 430 }
395 431 */