Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -52,10 +52,19 @@ foreach(a; args) write(a); writeln(""); return new UndefinedValue; })); + ctx.add("if", new FunValue(delegate Value(immutable LexPosition pos, Value[] args){ + if( args.length != 3 ) + throw new PolemyRuntimeException("if takes three arguments!! ["~to!string(pos)~"]"); + if( auto x = cast(IntValue)args[0] ) + if( auto ft = cast(FunValue)args[1] ) + if( auto fe = cast(FunValue)args[2] ) + return (x.data == 0 ? fe : ft).call(pos,[]); + throw new PolemyRuntimeException("type mismatch in if ["~to!string(pos)~"]"); + })); return ctx; } Tuple!(Value,"val",Context,"ctx") evalString(T...)(T params) { @@ -181,5 +190,19 @@ unittest { evalString(`print("Hello, world!");`); evalString(`print(fun(){});`); } +unittest +{ + evalString(`var fac = fun(x){ + 1; + }; + print(fac(3));`); + evalString(`var fac = fun(x){ + if(x) + { x*fac(x-1); } + else + { 1; }; + }; + print(fac(10));`); +} Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -53,12 +53,22 @@ this.lex = lex; } Program parseProgram() { + Program p = parseStatements(); + if( !lex.empty ) { + auto e = ParserException.create(lex, "cannot reach eof"); + throw e; + } + return p; + } + + Program parseStatements() + { Program p; - while( !lex.empty ) + while( !lex.empty && (lex.front.kind!=Token.Kind.identifier || lex.front.str!="}") ) p ~= parseStatement(); return p; } Statement parseStatement() @@ -185,10 +195,33 @@ { auto e = parseE(); eat(")", "after parenthesized expression"); return e; } + if( tryEat("if") ) + { + eat("(", "after if"); + auto cond = parseE(); + eat(")", "after if condition"); + auto thenPos = lex.front.pos; + eat("{", "after if condition"); + Statement[] th = parseStatements(); + eat("}", "after if-then body"); + Statement[] el; + auto elsePos = lex.front.pos; + if( tryEat("else") ) { + eat("{", "after else"); + el = parseStatements(); + eat("}", "after else body"); + } + return new FuncallExpression(pos, + new VarExpression(pos, "if"), + cond, + new FunLiteralExpression(thenPos, [], th), + new FunLiteralExpression(elsePos, [], el) + ); + } if( tryEat("fun") ) { eat("(", "after fun"); string[] params; @@ -312,6 +345,19 @@ } unittest { auto p = parserFromString(`var x = 1; var f = fun(){x=x+1;}; f(); f(); x;`); Program prog = p.parseProgram(); +} + +unittest +{ + auto p = parserFromString(`if(x<2){1;}else{x;};`); + Program prog = p.parseProgram(); + assert( prog[0] == new ExprStatement(null, new FuncallExpression(null, + new VarExpression(null, "if"), + new FuncallExpression(null, new VarExpression(null,"<"), new VarExpression(null,"x"), + new IntLiteralExpression(null, BigInt(2))), + new FunLiteralExpression(null, [], [new ExprStatement(null, new IntLiteralExpression(null, BigInt(1)))]), + new FunLiteralExpression(null, [], [new ExprStatement(null, new VarExpression(null, "x"))]) + ))); } Index: polemy/runtime.d ================================================================== --- polemy/runtime.d +++ polemy/runtime.d @@ -29,12 +29,11 @@ { BigInt data; mixin SimpleConstructor; mixin SimpleCompare; override string toString() const { - const(char)[] cs; data.toString((const(char)[] s){cs=s;}, null); - return to!string(cs); + return std.bigint.toDecimalString(cast(BigInt)data); } } class StrValue : Value {