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 module polemy.eval; 7 module polemy.eval;
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 import std.typecons; <
15 import std.stdio; <
16 14
17 /// <
18 Table createGlobalContext() <
> 15 class Evaluator
19 { 16 {
> 17 public:
20 auto ctx = new Table; | 18 this() { theContext = new Table; }
21 ctx.set("+", ValueLayer, native( (IntValue lhs, IntValue rhs){return new <
22 ctx.set("-", ValueLayer, native( (IntValue lhs, IntValue rhs){return new <
> 19
23 ctx.set("*", ValueLayer, native( (IntValue lhs, IntValue rhs){return new | 20 Value evalAST(AST e)
24 ctx.set("/", ValueLayer, native( (IntValue lhs, IntValue rhs){return new <
> 21 {
25 ctx.set("%", ValueLayer, native( (IntValue lhs, IntValue rhs){return new | 22 return eval(e, ValueLayer, theContext, OverwriteCtx);
26 ctx.set("||", ValueLayer, native( (IntValue lhs, IntValue rhs){return ne <
27 ctx.set("&&", ValueLayer, native( (IntValue lhs, IntValue rhs){return ne <
> 23 }
> 24
28 ctx.set("<", ValueLayer, native( (Value lhs, Value rhs){return new IntVa | 25 Value evalString(S,T...)(S str, T fn_ln_cn)
29 ctx.set(">", ValueLayer, native( (Value lhs, Value rhs){return new IntVa <
> 26 {
30 ctx.set("<=", ValueLayer, native( (Value lhs, Value rhs){return new IntV | 27 return evalAST(parseString(str,fn_ln_cn));
31 ctx.set(">=", ValueLayer, native( (Value lhs, Value rhs){return new IntV <
32 ctx.set("==", ValueLayer, native( (Value lhs, Value rhs){return new IntV <
> 28 }
> 29
33 ctx.set("!=", ValueLayer, native( (Value lhs, Value rhs){return new IntV | 30 Value evalFile(S,T...)(S filename, T ln_cn)
34 ctx.set("print", ValueLayer, native( (Value a){ <
> 31 {
35 writeln(a); | 32 return evalAST(parseFile(filename,ln_cn));
36 return new IntValue(BigInt(0)); <
37 })); <
> 33 }
> 34
38 ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe) | 35 Table globalContext()
39 auto toRun = (x.data==0 ? fe : ft); <
> 36 {
40 // [TODO] fill positional information | 37 return theContext;
41 return toRun.invoke(null, ValueLayer, toRun.definitionContext()) <
42 // return toRun.invoke(pos, lay, toRun.definitionContext()); <
43 })); <
> 38 }
> 39
> 40 private:
44 ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigI | 41 Table theContext;
45 ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigI <
> 42
46 ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigI | 43 private:
47 ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValu | 44 enum : bool { CascadeCtx=false, OverwriteCtx=true };
48 ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(Bi <
> 45
49 ctx.set(".", ValueLayer, native( (Table t, StrValue s){ | 46 Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
50 return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : <
> 47 {
51 }) ); | 48 // dynamic-overload-resolution-pattern: modify here
52 ctx.set(".?", ValueLayer, native( (Table t, StrValue s){ | 49 enum funName = "eval";
53 return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0)); | 50 alias TypeTuple!(e,lay,ctx,overwriteCtx) params;
54 }) ); <
> 51
55 ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){ | 52 // dynamic-overload-resolution-pattern: dispatch
56 auto t2 = new Table(t, Table.Kind.NotPropagateSet); | 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
> 58 return __traits(getOverloads, this, funName)[i](
> 59
> 60 // dynamic-overload-resolution-pattern: default behavior
> 61 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not
> 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"));
57 t2.set(s.data, ValueLayer, v); | 73 ast.set("data", ValueLayer, v);
> 74 return ast;
> 75 }
> 76 if( lay==ValueLayer )
58 return t2; | 77 return v;
59 }) ); <
> 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"));
60 ctx.set("{}", ValueLayer, native( (){ | 89 ast.set("data", ValueLayer, v);
61 return new Table; | 90 return ast;
62 }) ); <
> 91 }
> 92 if( lay==ValueLayer )
63 return ctx; | 93 return v;
> 94 return lift(v, lay, ctx, e.pos);
64 } | 95 }
65 | 96
66 /// Entry point of this module <
> 97 Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
67 | 98 {
68 Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn) <
> 99 if( lay==RawMacroLayer || lay==MacroLayer )
69 { | 100 {
70 return eval( polemy.parse.parseString(str, fn_ln_cn) ); <
> 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;
71 } | 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)
72 | 112 }
73 /// Entry point of this module <
74 | 113
75 Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn) <
> 114 Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
76 { | 115 {
77 return eval( polemy.parse.parseFile(filename, ln_cn) ); <
> 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, 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;
78 } | 130 }
> 131 else
79 | 132 {
80 /// Entry point of this module <
> 133 return invokeFunction(f, e.args, lay, ctx, e.pos);
81 | 134 }
82 Tuple!(Value,"val",Table,"ctx") eval(AST e) <
> 135 }
83 { | 136
84 Table ctx = createGlobalContext(); <
85 return typeof(return)(eval(e, ctx, false, ValueLayer), ctx); <
> 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);
86 } | 156 }
> 157 t.set("params", ValueLayer, params);
> 158 return t;
87 | 159 }
88 Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, <
> 160 else
89 { | 161 {
90 if(auto f = cast(FunValue)_f) <
> 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.NotPropa <
93 foreach(i,p; f.params()) <
94 if( p.layers.empty ) <
95 if(lay==MacroLayer) | 168 if( lay == RawMacroLayer )
> 169 {
> 170 Value r = eval(e.expr, lay, ctx);
> 171 auto ast = new Table; // todo: pos
96 ctx.set(p.name, lay, macroEval(args[i], | 172 ast.set("pos", ValueLayer, fromPos(e.pos));
97 else | 173 ast.set("is", ValueLayer, new StrValue("lay"));
98 ctx.set(p.name, lay, eval(args[i], calle | 174 ast.set("layer", ValueLayer, new StrValue(e.layer));
99 else | 175 ast.set("expr", ValueLayer, r);
100 foreach(argLay; p.layers) | 176 return ast;
101 if(argLay==MacroLayer) <
102 ctx.set(p.name, argLay, macroEva <
> 177 }
103 else | 178 else
104 ctx.set(p.name, argLay, eval(arg <
105 return f.invoke(pos, lay, ctx); <
> 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) | 182 Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
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 Value <
117 Value _f = callerCtx.get(lay, SystemLayer, pos); <
118 if(auto f = cast(FunValue)_f) <
119 { 183 {
120 Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropa | 184 // todo @macro let
121 auto ps = f.params(); | 185 if( lay==RawMacroLayer || lay==MacroLayer )
122 if( ps.length != 1 ) <
123 throw genex!RuntimeException(pos, "lift function must ta <
124 if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].la <
125 { 186 {
126 ctx.set(ps[0].name, ValueLayer, v); | 187 auto ast = new Table; // todo: pos
127 return f.invoke(pos, ValueLayer, ctx); | 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 else 196 else
130 throw genex!RuntimeException(pos, "lift function must ta <
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); | 198 if( !overwriteCtx )
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 <
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 overwritin <
177 // ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos) <
178 if(splitCtx) <
179 ctx = new Table(ctx, Table.Kind.NotPropagateSet) 199 ctx = new Table(ctx, Table.Kind.NotPropagateSet)
180 Value v = eval(e.init, ctx, true, lay); | 200 Value ri = eval(e.init, lay, ctx);
> 201 string theLayer = e.layer.empty ? (lay==RawMacroLayer ?
181 ctx.set(e.name, (e.layer.length ? e.layer : lay), v, e.p | 202 ctx.set(e.name, theLayer, ri);
182 return eval(e.expr, ctx, false, lay); | 203 return eval(e.expr, lay, ctx, OverwriteCtx);
183 }, <
184 (FuncallExpression e) <
> 204 }
> 205 }
185 { | 206
186 return invokeFunction(e.pos, eval(e.fun, ctx, true, lay) <
187 }, <
> 207 private:
188 (FunLiteral e) | 208 Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosi
189 { | 209 {
190 return new UserDefinedFunValue(e, ctx); | 210 if(auto f = cast(FunValue)_f)
191 }, <
192 delegate Value (AST e) <
193 { 211 {
194 throw genex!RuntimeException(e.pos, sprintf!"Unknown Kin | 212 Table newCtx = new Table(f.definitionContext(), Table.Ki
> 213 foreach(i,p; f.params())
> 214 if( p.layers.empty )
> 215 newCtx.set(p.name, (lay==RawMacroLayer ?
> 216 else
> 217 foreach(argLay; p.layers)
> 218 newCtx.set(p.name, argLay, eval(
> 219 return f.invoke(pos, lay, newCtx);
195 } 220 }
196 ); | 221 throw genex!RuntimeException(pos, text("tried to call non-functi
197 } | 222 }
198 <
199 // [TODO] Optimization <
200 Value macroEval(AST e, Table ctx, bool AlwaysMacro) <
201 { <
202 Layer theLayer = ValueLayer; <
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; | 226 // functions are automatically lifterd
207 t.set("car", theLayer, a); | 227 if( cast(FunValue) v )
208 t.set("cdr", theLayer, d); <
209 return t; | 228 return v;
> 229
> 230 // similar to invoke Function, but with only one argument bound
> 231 if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos))
> 232 {
> 233 Table newCtx = new Table(f.definitionContext(), Table.Ki
> 234 auto ps = f.params();
> 235 if( ps.length != 1 )
> 236 throw genex!RuntimeException(pos, "lift function
> 237 if( ps[0].layers.length==0 || ps[0].layers.length==1 &&
> 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
> 244 }
> 245 throw genex!RuntimeException(pos, "tried to call non-function");
210 } 246 }
211 247
212 Table pos = new Table; | 248 Value createNewFunction(Fun e, Table ctx)
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 | 249 {
223 return e.match( <
224 (StrLiteral e) <
> 250 class UserDefinedFunValue : FunValue
225 { 251 {
226 Table t = new Table; | 252 Fun ast;
227 t.set("pos", theLayer, pos); | 253 Table defCtx;
228 t.set("is", theLayer, new StrValue("str")); | 254 override const(Parameter[]) params() { return ast.params
229 t.set("data", theLayer, new StrValue(e.data)); | 255 override Table definitionContext() { return defCtx; }
230 return t; <
> 256
231 }, | 257 this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=
232 (IntLiteral e) | 258 override string toString() const { return sprintf!"(func
> 259 override bool opEquals(Object rhs_) const /// member-by-
233 { | 260 {
234 Table t = new Table; <
235 t.set("pos", theLayer, pos); | 261 if( auto rhs = cast(typeof(this))rhs_ )
236 t.set("is", theLayer, new StrValue("int")); | 262 return this.ast==rhs.ast && this.defCtx=
237 t.set("data", theLayer, new IntValue(e.data)); | 263 assert(false, sprintf!"Cannot compare %s with %s
238 return t; <
239 }, <
240 (VarExpression e) <
> 264 }
> 265 override hash_t toHash() const /// member-by-member hash
241 { | 266 {
242 if( ctx.has(e.name, MacroLayer, e.pos) ) <
> 267 return typeid(this.ast).getHash(&this.ast) + typ
> 268 }
243 return ctx.get(e.name, MacroLayer, e.pos); | 269 override int opCmp(Object rhs_) /// member-by-member com
244 else { <
> 270 {
245 Table t = new Table; | 271 if( auto rhs = cast(typeof(this))rhs_ )
246 t.set("pos", theLayer, pos); <
> 272 {
247 t.set("is", theLayer, new StrValue("var")); | 273 if(auto i = this.ast.opCmp(rhs.ast))
248 t.set("name", theLayer, new StrValue(e.name)); <
249 return cast(Value)t; | 274 return i;
> 275 return this.defCtx.opCmp(rhs.defCtx);
> 276 }
> 277 assert(false, sprintf!"Cannot compare %s with %s
250 } 278 }
251 }, <
252 (LayExpression e) <
253 { | 279
254 if( AlwaysMacro ) <
> 280 override Value invoke(LexPosition pos, Layer lay, Table
255 { 281 {
256 Table t = new Table; | 282 if( lay == MacroLayer )
257 t.set("pos", theLayer, pos); | 283 return eval(ast.funbody, lay, ctx);
258 t.set("is", theLayer, new StrValue("lay")); | 284 auto macroed = tableToAST(ValueLayer, eval(e.fun
259 t.set("layer", theLayer, new StrValue(e.layer)); | 285 return eval(macroed, lay, ctx);
260 t.set("expr", theLayer, macroEval(e.expr,ctx,Al <
261 return cast(Value)t; <
262 } 286 }
263 else <
> 287 }
> 288 return new UserDefinedFunValue(e,ctx);
> 289 }
264 { | 290
265 if( e.layer == MacroLayer ) <
266 return macroEval(e.expr, ctx, false); <
267 else | 291 public:
268 return eval(e.expr, ctx, true, e.layer); | 292 /// TODO: move up
269 } <
> 293 /// TDOO: to other layers?
270 }, | 294 void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg)
271 (LetExpression e) <
> 295 {
> 296 class NativeFunValue : FunValue
272 { 297 {
273 Table t = new Table; | 298 Parameter[] params_data;
274 t.set("pos", theLayer, pos); | 299 override string toString() { return sprintf!"(native:%x)
275 t.set("is", theLayer, new StrValue("let")); | 300 override const(Parameter[]) params() { return params_dat
276 t.set("name", theLayer, new StrValue(e.name)); | 301 override Table definitionContext() { return new Table; }
277 t.set("init", theLayer, macroEval(e.init,ctx,AlwaysMacro | 302 this(){
278 t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro | 303 foreach(i, Ti; T)
279 return t; | 304 params_data ~= new Parameter(text(i), []
280 }, <
> 305 }
281 (FuncallExpression e) | 306 override Value invoke(LexPosition pos, Layer lay, Table
282 { | 307 {
283 Value _f = macroEval(e.fun,ctx,AlwaysMacro); | 308 if( lay != ValueLayer )
> 309 throw genex!RuntimeException(pos, "only
> 310 T typed_args;
> 311 foreach(i, Ti; T) {
> 312 typed_args[i] = cast(Ti) ctx.get(text(i)
> 313 if( typed_args[i] is null )
> 314 throw genex!RuntimeException(pos
284 | 315 }
285 if( auto f = cast(FunValue)_f ) <
286 return invokeFunction(e.pos, f, e.args, ctx, Mac <
> 316 try {
> 317 return dg(typed_args);
> 318 } catch( RuntimeException e ) {
> 319 throw e.pos is null ? new RuntimeExcepti
287 | 320 }
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,AlwaysMa <
296 cons.set("cdr",theLayer,args); <
297 args = cons; <
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,Alwa <
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 Kin <
326 } 322 }
> 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+2
> 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(Big
> 353 assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new I
> 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(
> 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)
327 ); | 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 unittest 393 unittest
331 { 394 {
332 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) ); | 395 auto e = new Evaluator;
333 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); | 396 enrollRuntimeLibrary(e);
334 assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) ); <
335 assert_nothrow( r.ctx.get("x",ValueLayer) ); | 397 assert_nothrow( e.evalString(`
> 398 @macro twice(x) { x; x };
336 assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) ); | 399 def main() { twice(1) };
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(B <
349 assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new <
350 } <
351 unittest <
352 { <
353 assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt( <
354 assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt( <
355 assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValu <
356 assert_throw!Throwable( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) <
> 400 main()
> 401 `) );
357 } 402 }
358 /* 403 /*
359 unittest 404 unittest
360 { 405 {
361 assert_eq( evalString(`var fac = fun(x){ 406 assert_eq( evalString(`var fac = fun(x){
362 if(x) 407 if(x)
363 { x*fac(x-1); } 408 { x*fac(x-1); }
................................................................................................................................................................................
369 if(x<2) 414 if(x<2)
370 { 1; } 415 { 1; }
371 else 416 else
372 { fib(x-1) + fib(x-2); }; 417 { fib(x-1) + fib(x-2); };
373 }; 418 };
374 fib(5);`).val, new IntValue(BigInt(8))); 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 <
380 assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new In <
381 assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1 <
382 assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@ <
383 } <
384 <
385 unittest 421 unittest
386 { 422 {
387 assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(Bi 423 assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(Bi
388 // there was a bug that declaration in the first line of function defini 424 // there was a bug that declaration in the first line of function defini
389 // cannot be recursive 425 // cannot be recursive
390 assert_nothrow( evalString(`def foo() { 426 assert_nothrow( evalString(`def foo() {
391 def bar(y) { if(y<1) {0} else {bar(0)} }; 427 def bar(y) { if(y<1) {0} else {bar(0)} };
392 bar(1) 428 bar(1)
393 }; foo()`) ); 429 }; foo()`) );
394 } 430 }
395 */ 431 */