Diff
Not logged in

Differences From Artifact [003971cb94b55966]:

To Artifact [1a40d715cf0caee4]:


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 }