Diff
Not logged in

Differences From Artifact [c5ee9ab6830c78bd]:

To Artifact [cea762cacb86424f]:


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 }