Differences From Artifact [003971cb94b55966]:
- File
polemy/eval.d
- 2010-11-08 11:42:14 - part of checkin [5e407d7cf8] on branch trunk - Lexer Refactored so that it can accpet multi-symbol token (user: kinaba) [annotate]
To Artifact [1a40d715cf0caee4]:
- File
polemy/eval.d
- 2010-11-09 05:19:20 - part of checkin [8de5b49cdf] on branch trunk - split tricks module into a separate package. (user: kinaba) [annotate]
1 /** | 1 /**
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.lex : LexPosition;
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 std.typecons; 13 import std.typecons;
14 import std.stdio; 14 import std.stdio;
15 15
16 Context createGlobalContext() | 16 Table createGlobalContext()
17 { 17 {
18 auto ctx = new Context; | 18 auto ctx = new Table;
> 19 // [TODO] autogenerate these typechecks
19 ctx.add("+", new FunValue(delegate Value(immutable LexPosition pos, Valu | 20 ctx.set("+", "@val", new FunValue(delegate Value(immutable LexPosition p
20 if( args.length != 2 ) 21 if( args.length != 2 )
21 throw new PolemyRuntimeException("+ takes two arguments! | 22 throw new RuntimeException(pos, "+ takes two arguments!!
22 if( auto x = cast(IntValue)args[0] ) 23 if( auto x = cast(IntValue)args[0] )
23 if( auto y = cast(IntValue)args[1] ) 24 if( auto y = cast(IntValue)args[1] )
24 return new IntValue(x.data+y.data); 25 return new IntValue(x.data+y.data);
25 throw new PolemyRuntimeException("cannot add non-integers ["~to! | 26 throw new RuntimeException(pos, "cannot add non-integers");
26 })); 27 }));
27 ctx.add("-", new FunValue(delegate Value(immutable LexPosition pos, Valu | 28 ctx.set("-", "@val", new FunValue(delegate Value(immutable LexPosition p
28 if( args.length != 2 ) 29 if( args.length != 2 )
29 throw new PolemyRuntimeException("- takes two arguments! | 30 throw new RuntimeException(pos, "- takes two arguments!!
30 if( auto x = cast(IntValue)args[0] ) 31 if( auto x = cast(IntValue)args[0] )
31 if( auto y = cast(IntValue)args[1] ) 32 if( auto y = cast(IntValue)args[1] )
32 return new IntValue(x.data-y.data); 33 return new IntValue(x.data-y.data);
33 throw new PolemyRuntimeException("cannot add non-integers ["~to! | 34 throw new RuntimeException(pos, "cannot subtract non-integers");
34 })); 35 }));
35 ctx.add("*", new FunValue(delegate Value(immutable LexPosition pos, Valu | 36 ctx.set("*", "@val", new FunValue(delegate Value(immutable LexPosition p
36 if( args.length != 2 ) 37 if( args.length != 2 )
37 throw new PolemyRuntimeException("* takes two arguments! | 38 throw new RuntimeException(pos, "* takes two arguments!!
38 if( auto x = cast(IntValue)args[0] ) 39 if( auto x = cast(IntValue)args[0] )
39 if( auto y = cast(IntValue)args[1] ) 40 if( auto y = cast(IntValue)args[1] )
40 return new IntValue(x.data*y.data); 41 return new IntValue(x.data*y.data);
41 throw new PolemyRuntimeException("cannot add non-integers ["~to! | 42 throw new RuntimeException(pos, "cannot multiply non-integers");
42 })); 43 }));
43 ctx.add("/", new FunValue(delegate Value(immutable LexPosition pos, Valu | 44 ctx.set("/", "@val", new FunValue(delegate Value(immutable LexPosition p
44 if( args.length != 2 ) 45 if( args.length != 2 )
45 throw new PolemyRuntimeException("/ takes two arguments! | 46 throw new RuntimeException(pos, "/ takes two arguments!!
46 if( auto x = cast(IntValue)args[0] ) 47 if( auto x = cast(IntValue)args[0] )
47 if( auto y = cast(IntValue)args[1] ) 48 if( auto y = cast(IntValue)args[1] )
48 return new IntValue(x.data/y.data); 49 return new IntValue(x.data/y.data);
49 throw new PolemyRuntimeException("cannot add non-integers ["~to! | 50 throw new RuntimeException(pos, "cannot divide non-integers");
50 })); 51 }));
51 ctx.add("<", new FunValue(delegate Value(immutable LexPosition pos, Valu | 52 ctx.set("<", "@val", new FunValue(delegate Value(immutable LexPosition p
52 if( args.length != 2 ) 53 if( args.length != 2 )
53 throw new PolemyRuntimeException("< takes two arguments! | 54 throw new RuntimeException(pos, "< takes two arguments!!
54 if( auto x = cast(IntValue)args[0] ) 55 if( auto x = cast(IntValue)args[0] )
55 if( auto y = cast(IntValue)args[1] ) 56 if( auto y = cast(IntValue)args[1] )
56 return new IntValue(BigInt(to!int(x.data < y.dat 57 return new IntValue(BigInt(to!int(x.data < y.dat
57 throw new PolemyRuntimeException("cannot add non-integers ["~to! | 58 throw new RuntimeException(pos, "cannot compare non-integers");
58 })); 59 }));
59 ctx.add(">", new FunValue(delegate Value(immutable LexPosition pos, Valu | 60 ctx.set(">", "@val", new FunValue(delegate Value(immutable LexPosition p
60 if( args.length != 2 ) 61 if( args.length != 2 )
61 throw new PolemyRuntimeException("> takes two arguments! | 62 throw new RuntimeException(pos, "> takes two arguments!!
62 if( auto x = cast(IntValue)args[0] ) 63 if( auto x = cast(IntValue)args[0] )
63 if( auto y = cast(IntValue)args[1] ) 64 if( auto y = cast(IntValue)args[1] )
64 return new IntValue(BigInt(to!int(x.data>y.data) 65 return new IntValue(BigInt(to!int(x.data>y.data)
65 throw new PolemyRuntimeException("cannot add non-integers ["~to! | 66 throw new RuntimeException(pos, "cannot compare non-integers");
66 })); 67 }));
67 ctx.add("print", new FunValue(delegate Value(immutable LexPosition pos, | 68 ctx.set("print", "@val", new FunValue(delegate Value(immutable LexPositi
68 foreach(a; args) 69 foreach(a; args)
69 write(a); 70 write(a);
70 writeln(""); 71 writeln("");
71 return new UndefinedValue; | 72 return new IntValue(BigInt(178));
72 })); 73 }));
73 ctx.add("if", new FunValue(delegate Value(immutable LexPosition pos, Val | 74 ctx.set("if", "@val", new FunValue(delegate Value(immutable LexPosition
74 if( args.length != 3 ) 75 if( args.length != 3 )
75 throw new PolemyRuntimeException("if takes three argumen | 76 throw new RuntimeException(pos, "if takes three argument
76 if( auto x = cast(IntValue)args[0] ) 77 if( auto x = cast(IntValue)args[0] )
77 if( auto ft = cast(FunValue)args[1] ) 78 if( auto ft = cast(FunValue)args[1] )
78 if( auto fe = cast(FunValue)args[2] ) 79 if( auto fe = cast(FunValue)args[2] )
79 return (x.data == 0 ? fe : ft).call(pos,[]); 80 return (x.data == 0 ? fe : ft).call(pos,[]);
80 throw new PolemyRuntimeException("type mismatch in if ["~to!stri | 81 throw new RuntimeException(pos, "type mismatch in if");
81 })); 82 }));
82 return ctx; 83 return ctx;
83 } 84 }
84 85
85 Tuple!(Value,"val",Context,"ctx") evalString(T...)(T params) | 86 /// Entry point of this module
> 87
> 88 Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn)
86 { 89 {
87 return eval( parserFromString(params).parseProgram() ); | 90 return eval( polemy.parse.parseString(str, fn_ln_cn) );
88 } 91 }
89 92
90 Tuple!(Value,"val",Context,"ctx") evalFile(T...)(T params) | 93 Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filenae, T ln_cn)
91 { 94 {
92 return eval( parserFromFile(params).parseProgram() ); | 95 return eval( polemy.parse.parseFile(filename, ln_cn) );
93 } 96 }
94 97
95 Tuple!(Value,"val",Context,"ctx") eval(Program prog) | 98 Tuple!(Value,"val",Table,"ctx") eval(AST e)
96 { 99 {
97 Context ctx = createGlobalContext(); | 100 Table ctx = createGlobalContext();
98 return typeof(return)(eval(prog, ctx), ctx); | 101 return typeof(return)(eval(e, ctx), ctx);
99 } 102 }
100 103
101 Value eval(Program prog, Context ctx) | 104 Value eval(AST _e, Table ctx, bool splitCtx = true)
102 { <
103 Value v = new UndefinedValue; <
104 foreach(s; prog) <
105 v = eval(s, ctx); <
106 return v; <
107 } <
108 <
109 Value eval(Statement _s, Context ctx) <
110 { 105 {
111 if( auto s = cast(DeclStatement)_s ) <
112 { <
113 auto v = eval(s.expr, ctx); <
114 ctx.add(s.var, v); <
115 return v; <
116 } <
117 else <
118 if( auto s = cast(ExprStatement)_s ) <
119 { <
120 return eval(s.expr, ctx); <
121 } <
122 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Statement %s a <
123 } <
124 <
125 Value eval(Expression _e, Context ctx) <
126 { <
127 if( auto e = cast(StrLiteralExpression)_e ) | 106 if( auto e = cast(StrLiteral)_e )
128 { 107 {
129 return new StrValue(e.data); 108 return new StrValue(e.data);
130 } 109 }
131 else 110 else
132 if( auto e = cast(IntLiteralExpression)_e ) | 111 if( auto e = cast(IntLiteral)_e )
133 { 112 {
134 return new IntValue(e.data); 113 return new IntValue(e.data);
135 } 114 }
136 else 115 else
137 if( auto e = cast(VarExpression)_e ) 116 if( auto e = cast(VarExpression)_e )
138 { 117 {
139 return ctx[e.var]; | 118 return ctx.get(e.var, "@val", e.pos);
140 } 119 }
141 else 120 else
142 if( auto e = cast(AssignExpression)_e ) | 121 if( auto e = cast(LetExpression)_e )
143 { 122 {
144 if( auto ev = cast(VarExpression)e.lhs ) | 123 // for letrec, we need this, but should avoid overwriting????
145 { <
> 124 // ctx.set(e.var, "@val", new UndefinedValue, e.pos);
146 Value r = eval(e.rhs, ctx); | 125 Value v = eval(e.init, ctx, true);
147 ctx[ev.var] = r; | 126 ctx.set(e.var, "@val", v, e.pos);
148 return r; | 127 return eval(e.expr, ctx);
149 } <
150 throw new PolemyRuntimeException(sprintf!"Lhs of assignment must <
151 } 128 }
152 else 129 else
153 if( auto e = cast(FuncallExpression)_e ) 130 if( auto e = cast(FuncallExpression)_e )
154 { 131 {
155 Value _f = eval(e.fun, ctx); 132 Value _f = eval(e.fun, ctx);
156 if( auto f = cast(FunValue)_f ) { 133 if( auto f = cast(FunValue)_f ) {
157 Value[] args; 134 Value[] args;
158 foreach(a; e.args) 135 foreach(a; e.args)
159 args ~= eval(a, ctx); 136 args ~= eval(a, ctx);
160 return f.call(e.pos, args); 137 return f.call(e.pos, args);
161 } else 138 } else
162 throw new PolemyRuntimeException(sprintf!"Non-funcion is | 139 throw new RuntimeException(e.pos, "Non-funcion is applie
163 } 140 }
164 else 141 else
165 if( auto e = cast(FunLiteralExpression)_e ) | 142 if( auto e = cast(FunLiteral)_e )
166 { 143 {
167 return new FunValue(delegate Value(immutable LexPosition pos, Va 144 return new FunValue(delegate Value(immutable LexPosition pos, Va
168 if( e.params.length != args.length ) 145 if( e.params.length != args.length )
169 throw new PolemyRuntimeException(sprintf!"Argume | 146 throw new RuntimeException(e.pos, sprintf!"Argum
170 (e.params.length, args.length, e.pos)); | 147 (e.params.length, args.length));
171 Context ctxNeo = new Context(ctx); | 148 Table ctxNeo = new Table(ctx, Table.Kind.NotPropagateSet
172 foreach(i,p; e.params) 149 foreach(i,p; e.params)
173 ctxNeo.add(p, args[i]); | 150 ctxNeo.set(p, "@val", args[i]);
174 return eval(e.funbody, ctxNeo); 151 return eval(e.funbody, ctxNeo);
175 }); 152 });
176 } 153 }
177 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s | 154 throw new RuntimeException(_e.pos, sprintf!"Unknown Kind of Expression %
178 } 155 }
179 156
180 unittest 157 unittest
181 { 158 {
182 auto r = evalString(`var x = 21; x = x + x*x;`); | 159 auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) );
183 assert( r.val == new IntValue(BigInt(21+21*21)) ); | 160 assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
184 assert( r.ctx["x"] == new IntValue(BigInt(21+21*21)) ); | 161 assert_eq( r.ctx.get("x","@val"), new IntValue(BigInt(21)) );
185 assert( !collectException(r.ctx["x"]) ); | 162 assert_nothrow( r.ctx.get("x","@val") );
186 assert( collectException(r.ctx["y"]) ); | 163 assert_throw!RuntimeException( r.ctx.get("y","@val") );
187 } 164 }
188 unittest 165 unittest
189 { 166 {
190 assert( collectException(evalString(`var x = 21; x = x + x*y;`)) ); | 167 auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) );
191 assert( collectException(evalString(`x=1;`)) ); | 168 assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
> 169 assert_eq( r.ctx.get("x","@val"), new IntValue(BigInt(21+21*21)) );
> 170 assert_nothrow( r.ctx.get("x","@val") );
> 171 assert_throw!RuntimeException( r.ctx.get("y","@val") );
192 } 172 }
193 unittest 173 unittest
194 { 174 {
195 auto r = evalString(`var x = fun(a){1+a;}(2);`); | 175 assert_nothrow( evalString(`print("Hello, world!");`) );
196 assert( r.ctx["x"] == new IntValue(BigInt(3)) ); | 176 assert_nothrow( evalString(`print(fun(){});`) );
197 assert( r.val == new IntValue(BigInt(3)) ); <
198 } 177 }
199 unittest 178 unittest
200 { 179 {
201 auto r = evalString(`var x = 1; var f = fun(){x=x+1;}; f(); f(); f();`); <
202 assert( r.ctx["x"] == new IntValue(BigInt(4)) ); <
203 assert( r.val == new IntValue(BigInt(4)) ); <
204 } <
205 unittest <
206 { <
207 evalString(`print("Hello, world!");`); <
208 evalString(`print(fun(){});`); <
209 } <
210 unittest <
211 { <
212 evalString(`var fac = fun(x){ | 180 assert_nothrow( evalString(`var fac = fun(x){
213 1; 181 1;
214 }; 182 };
215 print(fac(3));`); | 183 print(fac(3));`));
216 evalString(`var fac = fun(x){ | 184 assert_nothrow( evalString(`var fac = fun(x){
217 if(x) 185 if(x)
218 { x*fac(x-1); } 186 { x*fac(x-1); }
219 else 187 else
220 { 1; }; 188 { 1; };
221 }; 189 };
222 print(fac(10));`); | 190 print(fac(10));`));
223 evalString(`var fib = fun(x){ | 191 assert_nothrow( evalString(`var fib = fun(x){
224 if(x<2) 192 if(x<2)
225 { 1; } 193 { 1; }
226 else 194 else
227 { fib(x-1) + fib(x-2); }; 195 { fib(x-1) + fib(x-2); };
228 }; 196 };
229 print(fib(10));`); | 197 print(fib(10));`));
230 } 198 }