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 55 class VarExpression : Expression 56 56 { 57 57 string var; 58 58 mixin SimpleConstructor; 59 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 64 Expression lhs; 66 65 Expression rhs; 67 66 mixin SimpleConstructor; 68 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 5 * Evaluator for Polemy programming language. 6 6 */ 7 7 module polemy.eval; 8 8 import polemy._common; 9 9 import polemy.ast; 10 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!!"); // TODO improve this message 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"); // TODO improve this message 22 + })); 23 + ctx.add("-", new PrimitiveFunction(delegate Value(Value[] args){ 24 + if( args.length != 2 ) 25 + throw new PolemyRuntimeException("- takes two arguments!!"); // TODO improve this message 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"); // TODO improve this message 30 + })); 31 + ctx.add("*", new PrimitiveFunction(delegate Value(Value[] args){ 32 + if( args.length != 2 ) 33 + throw new PolemyRuntimeException("* takes two arguments!!"); // TODO improve this message 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"); // TODO improve this message 38 + })); 39 + ctx.add("/", new PrimitiveFunction(delegate Value(Value[] args){ 40 + if( args.length != 2 ) 41 + throw new PolemyRuntimeException("/ takes two arguments!!"); // TODO improve this message 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"); // TODO improve this message 46 + })); 47 + return ctx; 48 +} 11 49 12 50 Context eval(Program prog) 13 51 { 14 - return eval(prog, new Context); 52 + return eval(prog, createGlobalContext()); 15 53 } 16 54 17 55 Context eval(Program prog, Context ctx) 18 56 { 19 57 foreach(s; prog) 20 58 ctx = eval(s, ctx); 21 59 return ctx; ................................................................................ 51 89 } 52 90 else 53 91 if( auto e = cast(VarExpression)_e ) 54 92 { 55 93 return ctx[e.var]; 56 94 } 57 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); 65 - ctx[ev.var] = r; 66 - return r; 67 - } 68 - throw new PolemyRuntimeException(sprintf!"Lhs of assignment must be a variable: %s"(e.pos)); 100 + Value r = eval(e.rhs, ctx); 101 + ctx[ev.var] = r; 102 + return r; 69 103 } 70 - 71 - Value l = eval(e.lhs, ctx); 72 - Value r = eval(e.rhs, ctx); 73 - if( auto lv = cast(IntValue)l ) 74 - if( auto rv = cast(IntValue)r ) 75 - final switch(e.op) 76 - { 77 - case "+": return new IntValue(lv.data+rv.data); 78 - case "-": return new IntValue(lv.data-rv.data); 79 - case "*": return new IntValue(lv.data*rv.data); 80 - case "/": return new IntValue(lv.data/rv.data); 81 - } 82 - else 83 - throw new PolemyRuntimeException(sprintf!"rhs of %s must be an integer but was %s at [%s]"(e.op, typeid(r), e.rhs.pos)); 84 - else 85 - throw new PolemyRuntimeException(sprintf!"lhs of %s must be an integer but was %s at [%s]"(e.op, typeid(l), e.lhs.pos)); 104 + throw new PolemyRuntimeException(sprintf!"Lhs of assignment must be a variable: %s"(e.pos)); 105 + } 106 + else 107 + if( auto e = cast(FuncallExpression)_e ) 108 + { 109 + Value _f = eval(e.fun, ctx); 110 + if( auto f = cast(FunValue)_f ) { 111 + Value[] args; 112 + foreach(a; e.args) 113 + args ~= eval(a, ctx); 114 + return f.call(args); 115 + } else 116 + throw new PolemyRuntimeException(sprintf!"Non-funcion is applied at [%s]"(e.pos)); 86 117 } 87 118 throw new PolemyRuntimeException(sprintf!"Unknown Kind of Expression %s at [%s]"(typeid(_e), _e.pos)); 88 119 } 89 120 90 121 91 122 version(unittest) import polemy.parse; 92 123 version(unittest) import std.stdio;

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

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

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

25 25 26 26 class StrValue : Value 27 27 { 28 28 string data; 29 29 mixin SimpleConstructor; 30 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 45 class Context 34 46 { 35 47 Context parent; 36 48 Value[string] table; 37 49 this(Context parent = null) { this.parent = parent; } 38 50