Differences From Artifact [c5ee9ab6830c78bd]:
- File
polemy/eval.d
- 2010-11-07 12:46:23 - part of checkin [3f5dc76a75] on branch trunk - Added funcall expression parser and function literal parser. (user: kinaba) [annotate]
To Artifact [cea762cacb86424f]:
- File
polemy/eval.d
- 2010-11-07 14:34:29 - part of checkin [0569f7b8c2] on branch trunk - - Added function literal evaluator (i.e., closure). - Workaround for d2stacktrace's infinite-loop bug. (when std.demangle.demangle use exception inside it, it will go into an infinite loop. to avoid this, I choose to unset TraceHandler during stacktrace generation. This is far from the complete solution, but at least it should work as expected under single-thread environment...) (user: kinaba) [annotate]
2 * Authors: k.inaba 2 * Authors: k.inaba
3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/
4 * 4 *
5 * Evaluator for Polemy programming language. 5 * Evaluator for Polemy programming language.
6 */ 6 */
7 module polemy.eval; 7 module polemy.eval;
8 import polemy._common; 8 import polemy._common;
> 9 import polemy.lex : LexPosition;
9 import polemy.ast; 10 import polemy.ast;
10 import polemy.parse; 11 import polemy.parse;
11 import polemy.runtime; 12 import polemy.runtime;
> 13 import std.typecons;
12 14
13 Context createGlobalContext() 15 Context createGlobalContext()
14 { 16 {
15 auto ctx = new Context; 17 auto ctx = new Context;
16 ctx.add("+", new PrimitiveFunction(delegate Value(Value[] args){ | 18 ctx.add("+", new FunValue(delegate Value(immutable LexPosition pos, Valu
17 if( args.length != 2 ) 19 if( args.length != 2 )
18 throw new PolemyRuntimeException("+ takes two arguments! | 20 throw new PolemyRuntimeException("+ takes two arguments!
19 if( auto x = cast(IntValue)args[0] ) 21 if( auto x = cast(IntValue)args[0] )
20 if( auto y = cast(IntValue)args[1] ) 22 if( auto y = cast(IntValue)args[1] )
21 return new IntValue(x.data+y.data); 23 return new IntValue(x.data+y.data);
22 throw new PolemyRuntimeException("cannot add non-integers"); // | 24 throw new PolemyRuntimeException("cannot add non-integers ["~to!
23 })); 25 }));
24 ctx.add("-", new PrimitiveFunction(delegate Value(Value[] args){ | 26 ctx.add("-", new FunValue(delegate Value(immutable LexPosition pos, Valu
25 if( args.length != 2 ) 27 if( args.length != 2 )
26 throw new PolemyRuntimeException("- takes two arguments! | 28 throw new PolemyRuntimeException("- takes two arguments!
27 if( auto x = cast(IntValue)args[0] ) 29 if( auto x = cast(IntValue)args[0] )
28 if( auto y = cast(IntValue)args[1] ) 30 if( auto y = cast(IntValue)args[1] )
29 return new IntValue(x.data-y.data); 31 return new IntValue(x.data-y.data);
30 throw new PolemyRuntimeException("cannot add non-integers"); // | 32 throw new PolemyRuntimeException("cannot add non-integers ["~to!
31 })); 33 }));
32 ctx.add("*", new PrimitiveFunction(delegate Value(Value[] args){ | 34 ctx.add("*", new FunValue(delegate Value(immutable LexPosition pos, Valu
33 if( args.length != 2 ) 35 if( args.length != 2 )
34 throw new PolemyRuntimeException("* takes two arguments! | 36 throw new PolemyRuntimeException("* takes two arguments!
35 if( auto x = cast(IntValue)args[0] ) 37 if( auto x = cast(IntValue)args[0] )
36 if( auto y = cast(IntValue)args[1] ) 38 if( auto y = cast(IntValue)args[1] )
37 return new IntValue(x.data*y.data); 39 return new IntValue(x.data*y.data);
38 throw new PolemyRuntimeException("cannot add non-integers"); // | 40 throw new PolemyRuntimeException("cannot add non-integers ["~to!
39 })); 41 }));
40 ctx.add("/", new PrimitiveFunction(delegate Value(Value[] args){ | 42 ctx.add("/", new FunValue(delegate Value(immutable LexPosition pos, Valu
41 if( args.length != 2 ) 43 if( args.length != 2 )
42 throw new PolemyRuntimeException("/ takes two arguments! | 44 throw new PolemyRuntimeException("/ takes two arguments!
43 if( auto x = cast(IntValue)args[0] ) 45 if( auto x = cast(IntValue)args[0] )
44 if( auto y = cast(IntValue)args[1] ) 46 if( auto y = cast(IntValue)args[1] )
45 return new IntValue(x.data/y.data); 47 return new IntValue(x.data/y.data);
46 throw new PolemyRuntimeException("cannot add non-integers"); // | 48 throw new PolemyRuntimeException("cannot add non-integers ["~to!
47 })); 49 }));
48 return ctx; 50 return ctx;
49 } 51 }
50 52
51 Context evalString(T...)(T params) | 53 Tuple!(Value,"val",Context,"ctx") evalString(T...)(T params)
52 { 54 {
53 return eval( parserFromString(params).parseProgram() ); 55 return eval( parserFromString(params).parseProgram() );
54 } 56 }
55 57
56 Context evalFile(T...)(T params) | 58 Tuple!(Value,"val",Context,"ctx") evalFile(T...)(T params)
57 { 59 {
58 return eval( parserFromFile(params).parseProgram() ); 60 return eval( parserFromFile(params).parseProgram() );
59 } 61 }
60 62
61 Context eval(Program prog) | 63 Tuple!(Value,"val",Context,"ctx") eval(Program prog)
62 { 64 {
63 return eval(prog, createGlobalContext()); | 65 Context ctx = createGlobalContext();
> 66 return typeof(return)(eval(prog, ctx), ctx);
64 } 67 }
65 68
66 Context eval(Program prog, Context ctx) | 69 Value eval(Program prog, Context ctx)
67 { 70 {
> 71 Value v = new UndefinedValue;
68 foreach(s; prog) 72 foreach(s; prog)
69 ctx = eval(s, ctx); | 73 v = eval(s, ctx);
70 return ctx; | 74 return v;
71 } 75 }
72 76
73 Context eval(Statement _s, Context ctx) | 77 Value eval(Statement _s, Context ctx)
74 { 78 {
75 if( auto s = cast(DeclStatement)_s ) 79 if( auto s = cast(DeclStatement)_s )
76 { 80 {
77 auto v = eval(s.expr, ctx); 81 auto v = eval(s.expr, ctx);
78 ctx.add(s.var, v); 82 ctx.add(s.var, v);
79 return ctx; | 83 return v;
80 } 84 }
81 else 85 else
82 if( auto s = cast(ExprStatement)_s ) 86 if( auto s = cast(ExprStatement)_s )
83 { 87 {
84 eval(s.expr, ctx); | 88 return eval(s.expr, ctx);
85 return ctx; <
86 } 89 }
87 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Statement %s a 90 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Statement %s a
88 } 91 }
89 92
90 Value eval(Expression _e, Context ctx) 93 Value eval(Expression _e, Context ctx)
91 { 94 {
92 if( auto e = cast(StrLiteralExpression)_e ) 95 if( auto e = cast(StrLiteralExpression)_e )
................................................................................................................................................................................
118 if( auto e = cast(FuncallExpression)_e ) 121 if( auto e = cast(FuncallExpression)_e )
119 { 122 {
120 Value _f = eval(e.fun, ctx); 123 Value _f = eval(e.fun, ctx);
121 if( auto f = cast(FunValue)_f ) { 124 if( auto f = cast(FunValue)_f ) {
122 Value[] args; 125 Value[] args;
123 foreach(a; e.args) 126 foreach(a; e.args)
124 args ~= eval(a, ctx); 127 args ~= eval(a, ctx);
125 return f.call(args); | 128 return f.call(e.pos, args);
126 } else 129 } else
127 throw new PolemyRuntimeException(sprintf!"Non-funcion is 130 throw new PolemyRuntimeException(sprintf!"Non-funcion is
> 131 }
> 132 else
> 133 if( auto e = cast(FunLiteralExpression)_e )
> 134 {
> 135 return new FunValue(delegate Value(immutable LexPosition pos, Va
> 136 if( e.params.length != args.length )
> 137 throw new PolemyRuntimeException(sprintf!"Argume
> 138 (e.params.length, args.length, e.pos));
> 139 Context ctxNeo = new Context(ctx);
> 140 foreach(i,p; e.params)
> 141 ctxNeo.add(p, args[i]);
> 142 return eval(e.funbody, ctxNeo);
> 143 });
128 } 144 }
129 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s 145 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s
130 } 146 }
131 147
132 <
133 version(unittest) import polemy.parse; <
134 version(unittest) import std.stdio; | 148 import std.stdio;
135 version(unittest) import std.exception; <
136 unittest 149 unittest
137 { 150 {
138 auto ctx = evalString(`var x = 21; x = x + x*x;`); | 151 auto r = evalString(`var x = 21; x = x + x*x;`);
> 152 assert( r.val == new IntValue(BigInt(21+21*21)) );
139 assert( ctx["x"] == new IntValue(BigInt(21+21*21)) ); | 153 assert( r.ctx["x"] == new IntValue(BigInt(21+21*21)) );
140 assert( !collectException(ctx["x"]) ); | 154 assert( !collectException(r.ctx["x"]) );
141 assert( collectException(ctx["y"]) ); | 155 assert( collectException(r.ctx["y"]) );
142 } 156 }
143 unittest 157 unittest
144 { 158 {
145 assert( collectException(evalString(`var x = 21; x = x + x*y;`)) ); 159 assert( collectException(evalString(`var x = 21; x = x + x*y;`)) );
> 160 assert( collectException(evalString(`x=1;`)) );
> 161 }
> 162 unittest
> 163 {
> 164 auto r = evalString(`var x = fun(a){1+a;}(2);`);
> 165 assert( r.ctx["x"] == new IntValue(BigInt(3)) );
> 166 assert( r.val == new IntValue(BigInt(3)) );
146 } 167 }
147 unittest 168 unittest
148 { 169 {
149 assert( collectException(evalString(`var x = 21; y = x + x*x;`)) ); | 170 auto r = evalString(`var x = 1; var f = fun(){x=x+1;}; f(); f(); f();`);
> 171 assert( r.ctx["x"] == new IntValue(BigInt(4)) );
> 172 assert( r.val == new IntValue(BigInt(4)) );
150 } 173 }