5081139836 2010-11-09 kinaba: /** 4198578702 2010-11-07 kinaba: * Authors: k.inaba 4198578702 2010-11-07 kinaba: * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4198578702 2010-11-07 kinaba: * 4198578702 2010-11-07 kinaba: * Parser for Polemy programming language 423f308350 2010-11-07 kinaba: */ 4198578702 2010-11-07 kinaba: module polemy.parse; 4198578702 2010-11-07 kinaba: import polemy._common; 423f308350 2010-11-07 kinaba: import polemy.lex; 423f308350 2010-11-07 kinaba: import polemy.ast; 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: /// Exception from this module 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: class ParseException : Exception 423f308350 2010-11-07 kinaba: { 2459e9a821 2010-11-09 kinaba: mixin ExceptionWithPosition; 423f308350 2010-11-07 kinaba: } b985f3bf91 2010-11-08 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Entry points of this module b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: auto parseString(S, T...)(S str, T fn_ln_cn) b985f3bf91 2010-11-08 kinaba: { return parserFromString(str, fn_ln_cn).parse(); } b985f3bf91 2010-11-08 kinaba: 7de80acfb8 2010-11-09 kinaba: auto parseFile(S, T...)(S filename, T ln_cn) d78d700f7a 2010-11-09 kinaba: { return parserFromFile(filename, ln_cn).parse(); } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Named Constructor of Parser 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: private auto parserFromLexer(Lexer)(Lexer lex) b985f3bf91 2010-11-08 kinaba: { return new Parser!Lexer(lex); } 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: private auto parserFromString(T...)(T params) b985f3bf91 2010-11-08 kinaba: { return parserFromLexer(polemy.lex.lexerFromString(params)); } 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: private auto parserFromFile(T...)(T params) b985f3bf91 2010-11-08 kinaba: { return parserFromLexer(polemy.lex.lexerFromFile(params)); } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Parser 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: private class Parser(Lexer) b985f3bf91 2010-11-08 kinaba: if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) ) 423f308350 2010-11-07 kinaba: { b985f3bf91 2010-11-08 kinaba: AST parse() 423f308350 2010-11-07 kinaba: { b985f3bf91 2010-11-08 kinaba: auto e = Body(); b985f3bf91 2010-11-08 kinaba: if( !lex.empty ) 2459e9a821 2010-11-09 kinaba: throw genex!ParseException(currentPosition(), "parsing ended but some tokens left"); b985f3bf91 2010-11-08 kinaba: return e; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: AST Body() 423f308350 2010-11-07 kinaba: { 2459e9a821 2010-11-09 kinaba: if( lex.empty || !lex.front.quoted && ["}",")","]"].canFind(lex.front.str) ) b985f3bf91 2010-11-08 kinaba: return doNothingExpression(); 633e700889 2010-11-07 kinaba: dc93ad8cf6 2010-11-09 kinaba: auto saved = lex.save; 423f308350 2010-11-07 kinaba: auto pos = lex.front.pos; aa770610d3 2010-11-08 kinaba: string kwd = lex.front.str; aa770610d3 2010-11-08 kinaba: if( tryEat("let") || tryEat("var") || tryEat("def") || tryEat("@") ) 423f308350 2010-11-07 kinaba: { dc93ad8cf6 2010-11-09 kinaba: if( kwd == "@" ) { 2459e9a821 2010-11-09 kinaba: kwd ~= eatId("after @",true); dc93ad8cf6 2010-11-09 kinaba: if( tryEat("(") ) { dc93ad8cf6 2010-11-09 kinaba: lex = saved; dc93ad8cf6 2010-11-09 kinaba: goto asExpression; dc93ad8cf6 2010-11-09 kinaba: } dc93ad8cf6 2010-11-09 kinaba: } b985f3bf91 2010-11-08 kinaba: immutable LexPosition varpos = (lex.empty ? null : lex.front.pos); 2459e9a821 2010-11-09 kinaba: string var = eatId("after "~kwd,true); 68546f3e9f 2010-11-09 kinaba: // [TODO] refactor. only auto e = ... differ 68546f3e9f 2010-11-09 kinaba: if(tryEat("(")) { 68546f3e9f 2010-11-09 kinaba: kwd = (kwd[0]=='@' ? kwd : ""); // "let, var, def ==> neutral layer" 68546f3e9f 2010-11-09 kinaba: auto e = parseLambdaAfterOpenParen(varpos); 68546f3e9f 2010-11-09 kinaba: if( tryEat(";") && !lex.empty && (lex.front.quoted || !["}",")","]"].canFind(lex.front.str)) ) 68546f3e9f 2010-11-09 kinaba: return new LetExpression(pos, var, kwd, e, Body()); 68546f3e9f 2010-11-09 kinaba: else 68546f3e9f 2010-11-09 kinaba: return new LetExpression(pos, var, kwd, e, new VarExpression(varpos, var)); 68546f3e9f 2010-11-09 kinaba: } else { 68546f3e9f 2010-11-09 kinaba: eat("=", "after "~kwd); 68546f3e9f 2010-11-09 kinaba: kwd = (kwd[0]=='@' ? kwd : ""); // "let, var, def ==> neutral layer" 68546f3e9f 2010-11-09 kinaba: auto e = E(0); 68546f3e9f 2010-11-09 kinaba: if( tryEat(";") && !lex.empty && (lex.front.quoted || !["}",")","]"].canFind(lex.front.str)) ) 68546f3e9f 2010-11-09 kinaba: return new LetExpression(pos, var, kwd, e, Body()); 68546f3e9f 2010-11-09 kinaba: else 68546f3e9f 2010-11-09 kinaba: return new LetExpression(pos, var, kwd, e, new VarExpression(varpos, var)); 68546f3e9f 2010-11-09 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else 423f308350 2010-11-07 kinaba: { dc93ad8cf6 2010-11-09 kinaba: asExpression: b985f3bf91 2010-11-08 kinaba: auto e = E(0); b985f3bf91 2010-11-08 kinaba: if( tryEat(";") && !lex.empty && (lex.front.quoted || (lex.front.str!="}" && lex.front.str!=")")) ) 2459e9a821 2010-11-09 kinaba: return new LetExpression(pos, "_", "", e, Body()); b985f3bf91 2010-11-08 kinaba: else b985f3bf91 2010-11-08 kinaba: return e; 5d4cb856d8 2010-11-07 kinaba: } 5d4cb856d8 2010-11-07 kinaba: } 5d4cb856d8 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: // [TODO] make customizable from program 5d4cb856d8 2010-11-07 kinaba: static immutable string[][] operator_perferences = [ b985f3bf91 2010-11-08 kinaba: ["||"], b985f3bf91 2010-11-08 kinaba: ["&&"], 5d4cb856d8 2010-11-07 kinaba: ["!="], 5d4cb856d8 2010-11-07 kinaba: ["=="], 5d4cb856d8 2010-11-07 kinaba: ["<","<=",">",">="], 5d4cb856d8 2010-11-07 kinaba: ["|"], 5d4cb856d8 2010-11-07 kinaba: ["^"], 5d4cb856d8 2010-11-07 kinaba: ["&"], 5d4cb856d8 2010-11-07 kinaba: ["<<", ">>"], 5d4cb856d8 2010-11-07 kinaba: ["+","-"], b985f3bf91 2010-11-08 kinaba: ["~"], b985f3bf91 2010-11-08 kinaba: ["*","/","%"], b985f3bf91 2010-11-08 kinaba: ["^^"] 5d4cb856d8 2010-11-07 kinaba: ]; 5d4cb856d8 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: AST E(int level) 5d4cb856d8 2010-11-07 kinaba: { 5d4cb856d8 2010-11-07 kinaba: if( operator_perferences.length <= level ) b985f3bf91 2010-11-08 kinaba: return Funcall(); 5d4cb856d8 2010-11-07 kinaba: else 5d4cb856d8 2010-11-07 kinaba: { 5d4cb856d8 2010-11-07 kinaba: auto ops = operator_perferences[level]; b985f3bf91 2010-11-08 kinaba: auto e = E(level+1); 5d4cb856d8 2010-11-07 kinaba: seq: 5d4cb856d8 2010-11-07 kinaba: while( !lex.empty ) 5d4cb856d8 2010-11-07 kinaba: { 5d4cb856d8 2010-11-07 kinaba: auto pos = lex.front.pos; 5d4cb856d8 2010-11-07 kinaba: foreach(op; ops) 5d4cb856d8 2010-11-07 kinaba: if( tryEat(op) ) 5d4cb856d8 2010-11-07 kinaba: { b985f3bf91 2010-11-08 kinaba: e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, E(level+1)); 5d4cb856d8 2010-11-07 kinaba: continue seq; 5d4cb856d8 2010-11-07 kinaba: } 5d4cb856d8 2010-11-07 kinaba: break; 5d4cb856d8 2010-11-07 kinaba: } 5d4cb856d8 2010-11-07 kinaba: return e; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: AST Funcall() 3f5dc76a75 2010-11-07 kinaba: { b985f3bf91 2010-11-08 kinaba: auto e = BaseExpression(); b985f3bf91 2010-11-08 kinaba: while( tryEat("(") ) 3f5dc76a75 2010-11-07 kinaba: { 2459e9a821 2010-11-09 kinaba: auto pos = currentPosition(); b985f3bf91 2010-11-08 kinaba: AST[] args; 3f5dc76a75 2010-11-07 kinaba: while( !tryEat(")") ) { b985f3bf91 2010-11-08 kinaba: if( lex.empty ) 2459e9a821 2010-11-09 kinaba: throw genex!UnexpectedEOF(pos,"Closing ')' for arguments not found"); b985f3bf91 2010-11-08 kinaba: args ~= E(0); 3f5dc76a75 2010-11-07 kinaba: if( !tryEat(",") ) { 3f5dc76a75 2010-11-07 kinaba: eat(")", "after function parameters"); 3f5dc76a75 2010-11-07 kinaba: break; 3f5dc76a75 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: } b985f3bf91 2010-11-08 kinaba: e = new FuncallExpression(e.pos, e, args); 3f5dc76a75 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: return e; 3f5dc76a75 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: AST BaseExpression() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( lex.empty ) 2459e9a821 2010-11-09 kinaba: throw genex!UnexpectedEOF(currentPosition(), "Reached EOF when tried to parse an expression"); b985f3bf91 2010-11-08 kinaba: 423f308350 2010-11-07 kinaba: auto pos = lex.front.pos; 8d297342aa 2010-11-08 kinaba: if( lex.front.quoted ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: scope(exit) lex.popFront; b985f3bf91 2010-11-08 kinaba: return new StrLiteral(pos, lex.front.str); 423f308350 2010-11-07 kinaba: } b985f3bf91 2010-11-08 kinaba: if( isNumber(lex.front.str) ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: scope(exit) lex.popFront; b985f3bf91 2010-11-08 kinaba: return new IntLiteral(pos, BigInt(cast(string)lex.front.str)); dc93ad8cf6 2010-11-09 kinaba: } dc93ad8cf6 2010-11-09 kinaba: if( tryEat("@") ) dc93ad8cf6 2010-11-09 kinaba: { dc93ad8cf6 2010-11-09 kinaba: auto lay = "@"~eatId("for layer ID"); dc93ad8cf6 2010-11-09 kinaba: eat("(", "for layered execution"); dc93ad8cf6 2010-11-09 kinaba: auto e = E(0); dc93ad8cf6 2010-11-09 kinaba: eat(")", "after "~lay~"(..."); dc93ad8cf6 2010-11-09 kinaba: return new LayeredExpression(pos, lay, e); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: if( tryEat("(") ) 423f308350 2010-11-07 kinaba: { b985f3bf91 2010-11-08 kinaba: auto e = Body(); 423f308350 2010-11-07 kinaba: eat(")", "after parenthesized expression"); 423f308350 2010-11-07 kinaba: return e; 3f5dc76a75 2010-11-07 kinaba: } 633e700889 2010-11-07 kinaba: if( tryEat("if") ) 3f5dc76a75 2010-11-07 kinaba: { 633e700889 2010-11-07 kinaba: eat("(", "after if"); b985f3bf91 2010-11-08 kinaba: auto cond = E(0); 633e700889 2010-11-07 kinaba: eat(")", "after if condition"); 633e700889 2010-11-07 kinaba: auto thenPos = lex.front.pos; 633e700889 2010-11-07 kinaba: eat("{", "after if condition"); b985f3bf91 2010-11-08 kinaba: auto th = Body(); 633e700889 2010-11-07 kinaba: eat("}", "after if-then body"); b985f3bf91 2010-11-08 kinaba: auto el = doNothingExpression(); b985f3bf91 2010-11-08 kinaba: auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos); 633e700889 2010-11-07 kinaba: if( tryEat("else") ) { 633e700889 2010-11-07 kinaba: eat("{", "after else"); b985f3bf91 2010-11-08 kinaba: el = Body(); 633e700889 2010-11-07 kinaba: eat("}", "after else body"); 3f5dc76a75 2010-11-07 kinaba: } 633e700889 2010-11-07 kinaba: return new FuncallExpression(pos, 633e700889 2010-11-07 kinaba: new VarExpression(pos, "if"), 633e700889 2010-11-07 kinaba: cond, b985f3bf91 2010-11-08 kinaba: new FunLiteral(thenPos, [], th), b985f3bf91 2010-11-08 kinaba: new FunLiteral(elsePos, [], el) 633e700889 2010-11-07 kinaba: ); 633e700889 2010-11-07 kinaba: } 77abaf5f42 2010-11-09 kinaba: if( tryEat("fun") || tryEat("\u03BB") ) 633e700889 2010-11-07 kinaba: { 633e700889 2010-11-07 kinaba: eat("(", "after fun"); 68546f3e9f 2010-11-09 kinaba: return parseLambdaAfterOpenParen(pos); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: scope(exit) lex.popFront; 423f308350 2010-11-07 kinaba: return new VarExpression(pos, lex.front.str); 68546f3e9f 2010-11-09 kinaba: } 68546f3e9f 2010-11-09 kinaba: 68546f3e9f 2010-11-09 kinaba: AST parseLambdaAfterOpenParen(immutable LexPosition pos) 68546f3e9f 2010-11-09 kinaba: { 68546f3e9f 2010-11-09 kinaba: string[] params; 68546f3e9f 2010-11-09 kinaba: while( !tryEat(")") ) 68546f3e9f 2010-11-09 kinaba: { 68546f3e9f 2010-11-09 kinaba: params ~= eatId("for function parameter"); 68546f3e9f 2010-11-09 kinaba: if( !tryEat(",") ) { 68546f3e9f 2010-11-09 kinaba: eat(")", "after function parameters"); 68546f3e9f 2010-11-09 kinaba: break; 68546f3e9f 2010-11-09 kinaba: } 68546f3e9f 2010-11-09 kinaba: } 68546f3e9f 2010-11-09 kinaba: eat("{", "after function parameters"); 68546f3e9f 2010-11-09 kinaba: auto funbody = Body(); 68546f3e9f 2010-11-09 kinaba: eat("}", "after function body"); 68546f3e9f 2010-11-09 kinaba: return new FunLiteral(pos, params, funbody); b985f3bf91 2010-11-08 kinaba: } b985f3bf91 2010-11-08 kinaba: 423f308350 2010-11-07 kinaba: private: 423f308350 2010-11-07 kinaba: Lexer lex; b985f3bf91 2010-11-08 kinaba: this(Lexer lex) { this.lex = lex; } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: void eat(string kwd, lazy string msg) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( !tryEat(kwd) ) 2459e9a821 2010-11-09 kinaba: if( lex.empty ) 2459e9a821 2010-11-09 kinaba: throw genex!UnexpectedEOF( 2459e9a821 2010-11-09 kinaba: currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg)); 2459e9a821 2010-11-09 kinaba: else 2459e9a821 2010-11-09 kinaba: throw genex!ParseException( 2459e9a821 2010-11-09 kinaba: currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg)); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: bool tryEat(string kwd) 423f308350 2010-11-07 kinaba: { 8d297342aa 2010-11-08 kinaba: if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) 423f308350 2010-11-07 kinaba: return false; 423f308350 2010-11-07 kinaba: lex.popFront; 423f308350 2010-11-07 kinaba: return true; 423f308350 2010-11-07 kinaba: } 8d297342aa 2010-11-08 kinaba: 2459e9a821 2010-11-09 kinaba: string eatId(lazy string msg, bool allowQuoted=false) b985f3bf91 2010-11-08 kinaba: { 2459e9a821 2010-11-09 kinaba: if( lex.empty ) 2459e9a821 2010-11-09 kinaba: throw genex!UnexpectedEOF(currentPosition(), "identifier is expected but not found "~msg); 2459e9a821 2010-11-09 kinaba: if( !allowQuoted && lex.front.quoted ) 2459e9a821 2010-11-09 kinaba: throw genex!ParseException(currentPosition(), "identifier is expected but not found "~msg); 2459e9a821 2010-11-09 kinaba: scope(exit) lex.popFront; 2459e9a821 2010-11-09 kinaba: return lex.front.str; b985f3bf91 2010-11-08 kinaba: } b985f3bf91 2010-11-08 kinaba: 8d297342aa 2010-11-08 kinaba: bool isNumber(string s) 8d297342aa 2010-11-08 kinaba: { 8d297342aa 2010-11-08 kinaba: return find!(`a<'0'||'9'<a`)(s).empty; b985f3bf91 2010-11-08 kinaba: } b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: AST doNothingExpression() b985f3bf91 2010-11-08 kinaba: { 2459e9a821 2010-11-09 kinaba: return new IntLiteral(currentPosition(), BigInt(178)); 2459e9a821 2010-11-09 kinaba: } 2459e9a821 2010-11-09 kinaba: 2459e9a821 2010-11-09 kinaba: immutable(LexPosition) currentPosition() 2459e9a821 2010-11-09 kinaba: { 2459e9a821 2010-11-09 kinaba: return lex.empty ? null : lex.front.pos; 8d297342aa 2010-11-08 kinaba: } 3f5dc76a75 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: 3f5dc76a75 2010-11-07 kinaba: unittest 3f5dc76a75 2010-11-07 kinaba: { b985f3bf91 2010-11-08 kinaba: mixin EasyAST; b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`123`), intl(123)); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`"foo"`), strl("foo")); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`fun(){1}`), fun([],intl(1))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`fun(x){1}`), fun(["x"],intl(1))); 77abaf5f42 2010-11-09 kinaba: assert_eq(parseString("\u03BB(){1}"), fun([],intl(1))); 77abaf5f42 2010-11-09 kinaba: assert_eq(parseString("\u03BB(x){1}"), fun(["x"],intl(1))); 2459e9a821 2010-11-09 kinaba: assert_eq(parseString(`1;2`), let("_","",intl(1),intl(2))); 2459e9a821 2010-11-09 kinaba: assert_eq(parseString(`1;2;`), let("_","",intl(1),intl(2))); 0f02103885 2010-11-09 kinaba: assert_eq(parseString(`let x=1;2`), let("x","",intl(1),intl(2))); 0f02103885 2010-11-09 kinaba: assert_eq(parseString(`var x=1;2;`), let("x","",intl(1),intl(2))); 0f02103885 2010-11-09 kinaba: assert_eq(parseString(`def x=1`), let("x","",intl(1),var("x"))); aa770610d3 2010-11-08 kinaba: assert_eq(parseString(`@val x=1;`), let("x","@val",intl(1),var("x"))); aa770610d3 2010-11-08 kinaba: assert_eq(parseString(`@typ x="#int";`), let("x","@typ",strl("#int"),var("x"))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`f(1,2)`), call(var("f"),intl(1),intl(2))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`if(1){2}`), call(var("if"),intl(1),fun([],intl(2)),fun([],intl(178)))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`if(1){2}else{3}`), call(var("if"),intl(1),fun([],intl(2)),fun([],intl(3)))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`if(1){}else{3}()()`), b985f3bf91 2010-11-08 kinaba: call(call(call(var("if"),intl(1),fun([],intl(178)),fun([],intl(3)))))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`1+2*3`), call(var("+"),intl(1),call(var("*"),intl(2),intl(3)))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`(1+2)*3`), call(var("*"),call(var("+"),intl(1),intl(2)),intl(3))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`1*(2+3)`), call(var("*"),intl(1),call(var("+"),intl(2),intl(3)))); b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(`1*2+3`), call(var("+"),call(var("*"),intl(1),intl(2)),intl(3))); dc93ad8cf6 2010-11-09 kinaba: assert_eq(parseString(`@x(1)`), lay("@x", intl(1))); b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(` aa770610d3 2010-11-08 kinaba: let x = 100; #comment aa770610d3 2010-11-08 kinaba: let y = 200; #comment!!!!! b985f3bf91 2010-11-08 kinaba: x+y b985f3bf91 2010-11-08 kinaba: `), 0f02103885 2010-11-09 kinaba: let("x", "", intl(100), let("y", "", intl(200), call(var("+"), var("x"), var("y")))) b985f3bf91 2010-11-08 kinaba: ); b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: assert_eq(parseString(` b985f3bf91 2010-11-08 kinaba: var fac = fun(x){ if(x <= 1) {1} else {x*fac(x-1)} }; b985f3bf91 2010-11-08 kinaba: fac(10) b985f3bf91 2010-11-08 kinaba: `), 0f02103885 2010-11-09 kinaba: let("fac", "", fun(["x"], b985f3bf91 2010-11-08 kinaba: call(var("if"), b985f3bf91 2010-11-08 kinaba: call(var("<="), var("x"), intl(1)), b985f3bf91 2010-11-08 kinaba: fun([], intl(1)), b985f3bf91 2010-11-08 kinaba: fun([], call(var("*"), var("x"), call(var("fac"),call(var("-"),var("x"),intl(1))))) b985f3bf91 2010-11-08 kinaba: )), b985f3bf91 2010-11-08 kinaba: call(var("fac"),intl(10)) b985f3bf91 2010-11-08 kinaba: ) b985f3bf91 2010-11-08 kinaba: ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 2459e9a821 2010-11-09 kinaba: assert_throw!UnexpectedEOF(parseString(`1+`)); b985f3bf91 2010-11-08 kinaba: assert_throw!ParseException(parseString(`1+2}`)); 2459e9a821 2010-11-09 kinaba: assert_throw!UnexpectedEOF(parseString(`let "x"`)); 2459e9a821 2010-11-09 kinaba: assert_throw!UnexpectedEOF(parseString(`var`)); aa770610d3 2010-11-08 kinaba: assert_throw!ParseException(parseString(`@val x ==`)); b985f3bf91 2010-11-08 kinaba: assert_throw!ParseException(parseString(`if(){1}`)); 2459e9a821 2010-11-09 kinaba: assert_throw!UnexpectedEOF(parseString(`f(`)); 68546f3e9f 2010-11-09 kinaba: } 68546f3e9f 2010-11-09 kinaba: 68546f3e9f 2010-11-09 kinaba: unittest 68546f3e9f 2010-11-09 kinaba: { 68546f3e9f 2010-11-09 kinaba: mixin EasyAST; 68546f3e9f 2010-11-09 kinaba: assert_eq(parseString(`def foo(x) { x+1 }; foo`), 68546f3e9f 2010-11-09 kinaba: let("foo", "", 68546f3e9f 2010-11-09 kinaba: fun(["x"], call(var("+"), var("x"), intl(1))), 68546f3e9f 2010-11-09 kinaba: var("foo")) 68546f3e9f 2010-11-09 kinaba: ); 423f308350 2010-11-07 kinaba: }