Check-in [5d4cb856d8]
Not logged in
Overview
SHA1 Hash:5d4cb856d86f685066e29976e4b93d80ea568e46
Date: 2010-11-07 21:20:47
User: kinaba
Comment:Added FuncallExpression
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified polemy/ast.d from [b98c3d30e8619e71] to [e79569cb2ae94b8c].

55 class VarExpression : Expression 55 class VarExpression : Expression 56 { 56 { 57 string var; 57 string var; 58 mixin SimpleConstructor; 58 mixin SimpleConstructor; 59 mixin SimpleCompare; // do not take "pos" into account 59 mixin SimpleCompare; // do not take "pos" into account 60 } 60 } 61 61 62 class BinOpExpression : Expression | 62 class AssignExpression : Expression 63 { 63 { 64 string op; < 65 Expression lhs; 64 Expression lhs; 66 Expression rhs; 65 Expression rhs; 67 mixin SimpleConstructor; 66 mixin SimpleConstructor; 68 mixin SimpleCompare; // do not take "pos" into account 67 mixin SimpleCompare; // do not take "pos" into account 69 } 68 } > 69 class FuncallExpression : Expression > 70 { > 71 Expression fun; > 72 Expression[] args; > 73 this(immutable LexPosition pos, Expression fun, Expression[] args...) > 74 { super(pos); this.fun=fun; this.args=args.dup; } > 75 mixin SimpleCompare; // do not take "pos" into account > 76 }

Modified polemy/eval.d from [c82fe33ef6c72ef2] to [0a7ac481ec249b42].

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.ast; 9 import polemy.ast; 10 import polemy.runtime; 10 import polemy.runtime; > 11 > 12 Context createGlobalContext() > 13 { > 14 auto ctx = new Context; > 15 ctx.add("+", new PrimitiveFunction(delegate Value(Value[] args){ > 16 if( args.length != 2 ) > 17 throw new PolemyRuntimeException("+ takes two arguments! > 18 if( auto x = cast(IntValue)args[0] ) > 19 if( auto y = cast(IntValue)args[1] ) > 20 return new IntValue(x.data+y.data); > 21 throw new PolemyRuntimeException("cannot add non-integers"); // > 22 })); > 23 ctx.add("-", new PrimitiveFunction(delegate Value(Value[] args){ > 24 if( args.length != 2 ) > 25 throw new PolemyRuntimeException("- takes two arguments! > 26 if( auto x = cast(IntValue)args[0] ) > 27 if( auto y = cast(IntValue)args[1] ) > 28 return new IntValue(x.data-y.data); > 29 throw new PolemyRuntimeException("cannot add non-integers"); // > 30 })); > 31 ctx.add("*", new PrimitiveFunction(delegate Value(Value[] args){ > 32 if( args.length != 2 ) > 33 throw new PolemyRuntimeException("* takes two arguments! > 34 if( auto x = cast(IntValue)args[0] ) > 35 if( auto y = cast(IntValue)args[1] ) > 36 return new IntValue(x.data*y.data); > 37 throw new PolemyRuntimeException("cannot add non-integers"); // > 38 })); > 39 ctx.add("/", new PrimitiveFunction(delegate Value(Value[] args){ > 40 if( args.length != 2 ) > 41 throw new PolemyRuntimeException("/ takes two arguments! > 42 if( auto x = cast(IntValue)args[0] ) > 43 if( auto y = cast(IntValue)args[1] ) > 44 return new IntValue(x.data/y.data); > 45 throw new PolemyRuntimeException("cannot add non-integers"); // > 46 })); > 47 return ctx; > 48 } 11 49 12 Context eval(Program prog) 50 Context eval(Program prog) 13 { 51 { 14 return eval(prog, new Context); | 52 return eval(prog, createGlobalContext()); 15 } 53 } 16 54 17 Context eval(Program prog, Context ctx) 55 Context eval(Program prog, Context ctx) 18 { 56 { 19 foreach(s; prog) 57 foreach(s; prog) 20 ctx = eval(s, ctx); 58 ctx = eval(s, ctx); 21 return ctx; 59 return ctx; ................................................................................................................................................................................ 51 } 89 } 52 else 90 else 53 if( auto e = cast(VarExpression)_e ) 91 if( auto e = cast(VarExpression)_e ) 54 { 92 { 55 return ctx[e.var]; 93 return ctx[e.var]; 56 } 94 } 57 else 95 else 58 if( auto e = cast(BinOpExpression)_e ) | 96 if( auto e = cast(AssignExpression)_e ) 59 { 97 { 60 if( e.op == "=" ) | 98 if( auto ev = cast(VarExpression)e.lhs ) 61 { 99 { 62 if( auto ev = cast(VarExpression)e.lhs ) < 63 { < 64 Value r = eval(e.rhs, ctx); | 100 Value r = eval(e.rhs, ctx); 65 ctx[ev.var] = r; | 101 ctx[ev.var] = r; 66 return r; | 102 return r; 67 } < 68 throw new PolemyRuntimeException(sprintf!"Lhs of assignm < 69 } 103 } > 104 throw new PolemyRuntimeException(sprintf!"Lhs of assignment must 70 | 105 } 71 Value l = eval(e.lhs, ctx); < 72 Value r = eval(e.rhs, ctx); | 106 else 73 if( auto lv = cast(IntValue)l ) | 107 if( auto e = cast(FuncallExpression)_e ) 74 if( auto rv = cast(IntValue)r ) < 75 final switch(e.op) < 76 { | 108 { > 109 Value _f = eval(e.fun, ctx); > 110 if( auto f = cast(FunValue)_f ) { 77 case "+": return new IntValue(lv.data+rv.data); | 111 Value[] args; 78 case "-": return new IntValue(lv.data-rv.data); | 112 foreach(a; e.args) 79 case "*": return new IntValue(lv.data*rv.data); | 113 args ~= eval(a, ctx); 80 case "/": return new IntValue(lv.data/rv.data); | 114 return f.call(args); 81 } < 82 else | 115 } else 83 throw new PolemyRuntimeException(sprintf!"rhs of | 116 throw new PolemyRuntimeException(sprintf!"Non-funcion is 84 else < 85 throw new PolemyRuntimeException(sprintf!"lhs of %s must < 86 } 117 } 87 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s 118 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s 88 } 119 } 89 120 90 121 91 version(unittest) import polemy.parse; 122 version(unittest) import polemy.parse; 92 version(unittest) import std.stdio; 123 version(unittest) import std.stdio;

Modified polemy/parse.d from [fe545db0fb7a2428] to [a819ba1b27fdc13d].

90 } 90 } 91 } 91 } 92 92 93 Expression parseExpression() 93 Expression parseExpression() 94 { 94 { 95 auto saved = lex.save; 95 auto saved = lex.save; 96 scope(failure) lex = saved; 96 scope(failure) lex = saved; 97 < 98 // Expr ::= E0 < 99 // E0 ::= (E1 "=")* E1 < 100 // E1 ::= (E2 "+"|"-")* E2 < 101 // E2 ::= (E3 "*"|"/")* E3 < 102 // E3 ::= int | str | id | "(" Expr ")" < 103 < 104 return parseE0(); | 97 return parseE(0); 105 } 98 } 106 99 107 Expression parseE0() | 100 // [TODO] multi-char operators are not supported by the lexer... 108 { < 109 auto lhs = parseE1(); < > 101 static immutable string[][] operator_perferences = [ > 102 [","], 110 if( tryEat("=") ) | 103 ["="], // caution! left associative 111 lhs = new BinOpExpression(lhs.pos, "=", lhs, parseE0()); | 104 ["or"], 112 return lhs; | 105 ["and"], 113 } < > 106 ["!="], > 107 ["=="], > 108 ["<","<=",">",">="], > 109 ["|"], > 110 ["^"], > 111 ["&"], > 112 ["<<", ">>"], > 113 ["+","-"], > 114 ["*","/","%"] > 115 ]; 114 116 115 Expression parseE1() | 117 Expression parseE(int level = 0) 116 { 118 { 117 for(auto lhs = parseE2();;) | 119 if( operator_perferences.length <= level ) > 120 return parseBaseExpression(); > 121 else 118 { 122 { 119 if( tryEat("+") ) | 123 auto ops = operator_perferences[level]; 120 lhs = new BinOpExpression(lhs.pos, "+", lhs, par | 124 auto e = parseE(level+1); > 125 seq: > 126 while( !lex.empty ) > 127 { > 128 auto pos = lex.front.pos; > 129 foreach(op; ops) 121 else if( tryEat("-") ) | 130 if( tryEat(op) ) 122 lhs = new BinOpExpression(lhs.pos, "-", lhs, par < > 131 { > 132 if( op == "=" ) // right assoc > 133 return new AssignExpress 123 else | 134 else > 135 e = new FuncallExpressio > 136 continue seq; > 137 } > 138 break; > 139 } 124 return lhs; | 140 return e; 125 } 141 } 126 } 142 } 127 143 128 Expression parseE2() | 144 Expression parseBaseExpression() 129 { < 130 for(auto lhs = parseE3();;) < 131 { < 132 if( tryEat("*") ) < 133 lhs = new BinOpExpression(lhs.pos, "*", lhs, par < 134 else if( tryEat("/") ) < 135 lhs = new BinOpExpression(lhs.pos, "/", lhs, par < 136 else < 137 return lhs; < 138 } < 139 } < 140 < 141 Expression parseE3() < 142 { 145 { 143 if( lex.empty ) 146 if( lex.empty ) 144 throw new ParserException("EOF during parsing an express 147 throw new ParserException("EOF during parsing an express 145 auto pos = lex.front.pos; 148 auto pos = lex.front.pos; 146 149 147 if( lex.front.kind == Token.Kind.number ) 150 if( lex.front.kind == Token.Kind.number ) 148 { 151 { ................................................................................................................................................................................ 152 if( lex.front.kind == Token.Kind.stringLiteral ) 155 if( lex.front.kind == Token.Kind.stringLiteral ) 153 { 156 { 154 scope(exit) lex.popFront; 157 scope(exit) lex.popFront; 155 return new StrLiteralExpression(pos, lex.front.str); 158 return new StrLiteralExpression(pos, lex.front.str); 156 } 159 } 157 if( tryEat("(") ) 160 if( tryEat("(") ) 158 { 161 { 159 auto e = parseE0(); | 162 auto e = parseE(); 160 eat(")", "after parenthesized expression"); 163 eat(")", "after parenthesized expression"); 161 return e; 164 return e; 162 } 165 } 163 scope(exit) lex.popFront; 166 scope(exit) lex.popFront; 164 return new VarExpression(pos, lex.front.str); 167 return new VarExpression(pos, lex.front.str); 165 } 168 } 166 169 ................................................................................................................................................................................ 207 auto p = parserFromString(` 210 auto p = parserFromString(` 208 var zzz = 100; # comment 211 var zzz = 100; # comment 209 zzz = zzz + zzz * "fo\no"; # comment 212 zzz = zzz + zzz * "fo\no"; # comment 210 42; 213 42; 211 `); 214 `); 212 215 213 auto s0 = new DeclStatement(null, "zzz", new IntLiteralExpression(null, 216 auto s0 = new DeclStatement(null, "zzz", new IntLiteralExpression(null, 214 auto s1 = new ExprStatement(null, new BinOpExpression(null, "=", | 217 auto s1 = new ExprStatement(null, new AssignExpression(null, 215 new VarExpression(null, "zzz"), 218 new VarExpression(null, "zzz"), 216 new BinOpExpression(null, "+", | 219 new FuncallExpression(null, new VarExpression(null,"+"), 217 new VarExpression(null, "zzz"), 220 new VarExpression(null, "zzz"), 218 new BinOpExpression(null, "*", | 221 new FuncallExpression(null, new VarExpression(null,"*"), 219 new VarExpression(null, "zzz"), 222 new VarExpression(null, "zzz"), 220 new StrLiteralExpression(null, "fo\\no") 223 new StrLiteralExpression(null, "fo\\no") 221 )))); 224 )))); 222 auto s2 = new ExprStatement(null, new IntLiteralExpression(null, BigInt( 225 auto s2 = new ExprStatement(null, new IntLiteralExpression(null, BigInt( 223 226 224 Program prog = p.parseProgram(); 227 Program prog = p.parseProgram(); 225 assert( prog.length == 3 ); 228 assert( prog.length == 3 ); 226 assert( prog[0] == s0 ); 229 assert( prog[0] == s0 ); 227 assert( prog[1] == s1 ); 230 assert( prog[1] == s1 ); 228 assert( prog[2] == s2 ); 231 assert( prog[2] == s2 ); 229 } 232 }

Modified polemy/runtime.d from [3711e4a90323c649] to [c94ffd3733368117].

25 25 26 class StrValue : Value 26 class StrValue : Value 27 { 27 { 28 string data; 28 string data; 29 mixin SimpleConstructor; 29 mixin SimpleConstructor; 30 mixin SimpleCompare; 30 mixin SimpleCompare; 31 } 31 } > 32 > 33 abstract class FunValue : Value > 34 { > 35 Value call(Value[] args); > 36 } > 37 > 38 class PrimitiveFunction : FunValue > 39 { > 40 Value delegate(Value[]) data; > 41 mixin SimpleConstructor; > 42 override Value call(Value[] args) { return data(args); } > 43 } 32 44 33 class Context 45 class Context 34 { 46 { 35 Context parent; 47 Context parent; 36 Value[string] table; 48 Value[string] table; 37 this(Context parent = null) { this.parent = parent; } 49 this(Context parent = null) { this.parent = parent; } 38 50