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; 3464a035ec 2010-11-20 kinaba: import polemy.failure; 423f308350 2010-11-07 kinaba: import polemy.lex; 423f308350 2010-11-07 kinaba: import polemy.ast; 435fa085ec 2010-11-21 kinaba: import polemy.layer; 3995a5eb6a 2010-11-21 kinaba: import polemy.fresh; 423f308350 2010-11-07 kinaba: a7b5d1d95a 2010-11-12 kinaba: /// Parse a string and return its AST a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: AST parseString(S, T...)(S str, T fn_ln_cn) 38fcc662be 2010-11-10 kinaba: { a7b5d1d95a 2010-11-12 kinaba: return parserFromString(str, fn_ln_cn).parse(); 38fcc662be 2010-11-10 kinaba: } 38fcc662be 2010-11-10 kinaba: a7b5d1d95a 2010-11-12 kinaba: /// Parse the content of a file and return its AST 38fcc662be 2010-11-10 kinaba: 38fcc662be 2010-11-10 kinaba: AST parseFile(S, T...)(S filename, T ln_cn) a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: return parserFromFile(filename, ln_cn).parse(); a7b5d1d95a 2010-11-12 kinaba: } 423f308350 2010-11-07 kinaba: 38fcc662be 2010-11-10 kinaba: // Named Constructors 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) a7b5d1d95a 2010-11-12 kinaba: { return parserFromLexer(lexerFromString(params)); } 423f308350 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: private auto parserFromFile(T...)(T params) a7b5d1d95a 2010-11-12 kinaba: { return parserFromLexer(lexerFromFile(params)); } 423f308350 2010-11-07 kinaba: 38fcc662be 2010-11-10 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() b985f3bf91 2010-11-08 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; b985f3bf91 2010-11-08 kinaba: } b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: AST Body() b985f3bf91 2010-11-08 kinaba: { a7b5d1d95a 2010-11-12 kinaba: /// Body ::= Declaration a7b5d1d95a 2010-11-12 kinaba: /// | TopLevelExpression a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: if( closingBracket() ) b985f3bf91 2010-11-08 kinaba: return doNothingExpression(); b985f3bf91 2010-11-08 kinaba: dc93ad8cf6 2010-11-09 kinaba: auto saved = lex.save; a7b5d1d95a 2010-11-12 kinaba: if( auto e = Declaration() ) a7b5d1d95a 2010-11-12 kinaba: return e; a7b5d1d95a 2010-11-12 kinaba: lex = saved; a7b5d1d95a 2010-11-12 kinaba: return TopLevelExpression(); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: AST Declaration() // returns null if it is not a declaration a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: /// Declaration ::= a7b5d1d95a 2010-11-12 kinaba: /// ["@" Layer|"let"|"var"|"def"] Var "=" Expression ([";"|"in"] Body?)? a7b5d1d95a 2010-11-12 kinaba: /// | ["@" Layer|"let"|"var"|"def"] Var "(" Param%"," ")" "{" Body "}" ([";"|"in"] Body?)? c368edbcb1 2010-11-13 kinaba: /// | ["@" "@" Layer "=" Expression ([";"|"in"] Body?)? c368edbcb1 2010-11-13 kinaba: /// | ["@" "@" Layer "(" Param%"," ")" "{" Body "}" ([";"|"in"] Body?)? a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: auto pos = currentPosition(); 2bdfb8a182 2010-11-21 kinaba: Layer layer = ""; 2bdfb8a182 2010-11-21 kinaba: bool layerLiftDecl = false; a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: if( tryEat("@") ) dc93ad8cf6 2010-11-09 kinaba: { a7b5d1d95a 2010-11-12 kinaba: layer = "@" ~ eatId("after @", AllowQuoted); c368edbcb1 2010-11-13 kinaba: if( layer == "@@" ) c368edbcb1 2010-11-13 kinaba: { c368edbcb1 2010-11-13 kinaba: layer = "@" ~ eatId("after @@", AllowQuoted); 2bdfb8a182 2010-11-21 kinaba: layerLiftDecl = true; c368edbcb1 2010-11-13 kinaba: } c368edbcb1 2010-11-13 kinaba: else c368edbcb1 2010-11-13 kinaba: { c368edbcb1 2010-11-13 kinaba: if( tryEat("(") ) c368edbcb1 2010-11-13 kinaba: return null; // @lay(...) expression, not a declaration c368edbcb1 2010-11-13 kinaba: } c368edbcb1 2010-11-13 kinaba: } c368edbcb1 2010-11-13 kinaba: c368edbcb1 2010-11-13 kinaba: // [TODO] Refactor 2bdfb8a182 2010-11-21 kinaba: if( layerLiftDecl ) c368edbcb1 2010-11-13 kinaba: { c368edbcb1 2010-11-13 kinaba: string kwd = "@" ~ layer; c368edbcb1 2010-11-13 kinaba: string var = layer; c368edbcb1 2010-11-13 kinaba: c368edbcb1 2010-11-13 kinaba: auto e = tryEat("(") c368edbcb1 2010-11-13 kinaba: ? parseLambdaAfterOpenParen(pos) // let var ( ... c368edbcb1 2010-11-13 kinaba: : (eat("=", "after "~kwd), E(0)); // let var = ... c368edbcb1 2010-11-13 kinaba: if( moreDeclarationExists() ) 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, var, SystemLayer, e, Body()); c368edbcb1 2010-11-13 kinaba: else 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, var, SystemLayer, e, 6ac127ddd0 2010-11-23 kinaba: new Lay(pos, SystemLayer, new Var(pos, var)) 2bdfb8a182 2010-11-21 kinaba: ); c368edbcb1 2010-11-13 kinaba: } b985f3bf91 2010-11-08 kinaba: else c368edbcb1 2010-11-13 kinaba: { c368edbcb1 2010-11-13 kinaba: string kwd = layer; c368edbcb1 2010-11-13 kinaba: if( layer.empty && !tryEat(kwd="let") && !tryEat(kwd="var") && !tryEat(kwd="def") ) c368edbcb1 2010-11-13 kinaba: return null; // none of {@lay, let, var, def} occurred, it's not a declaration c368edbcb1 2010-11-13 kinaba: c368edbcb1 2010-11-13 kinaba: auto varpos = currentPosition(); c368edbcb1 2010-11-13 kinaba: string var = eatId("after "~kwd, AllowQuoted); // name of the declared variable c368edbcb1 2010-11-13 kinaba: c368edbcb1 2010-11-13 kinaba: auto e = tryEat("(") c368edbcb1 2010-11-13 kinaba: ? parseLambdaAfterOpenParen(varpos) // let var ( ... c368edbcb1 2010-11-13 kinaba: : (eat("=", "after "~kwd), E(0)); // let var = ... c368edbcb1 2010-11-13 kinaba: if( moreDeclarationExists() ) 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, var, layer, e, Body()); c368edbcb1 2010-11-13 kinaba: else 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, var, layer, e, new Var(varpos, var)); c368edbcb1 2010-11-13 kinaba: } b985f3bf91 2010-11-08 kinaba: } b985f3bf91 2010-11-08 kinaba: a7b5d1d95a 2010-11-12 kinaba: AST TopLevelExpression() a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: /// TopLevelExpression ::= Expression ([";"|"in"] Body?)? a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: auto pos = currentPosition(); a7b5d1d95a 2010-11-12 kinaba: auto e = E(0); a7b5d1d95a 2010-11-12 kinaba: if( moreDeclarationExists() ) 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, "_", "", e, Body()); a7b5d1d95a 2010-11-12 kinaba: else a7b5d1d95a 2010-11-12 kinaba: return e; a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: private bool moreDeclarationExists() a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: return (tryEat(";") || tryEat("in")) && !closingBracket(); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: private bool closingBracket() a7b5d1d95a 2010-11-12 kinaba: { 3995a5eb6a 2010-11-21 kinaba: return lex.empty || !lex.front.quoted && ["}",")","]",","].canFind(lex.front.str); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: // [TODO] make this customizable from program a7b5d1d95a 2010-11-12 kinaba: private static 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: ["*","/","%"], 515502e8d1 2010-11-20 kinaba: ["^^","**"], 515502e8d1 2010-11-20 kinaba: [".",".?"] 5d4cb856d8 2010-11-07 kinaba: ]; 5d4cb856d8 2010-11-07 kinaba: a7b5d1d95a 2010-11-12 kinaba: AST E(size_t level) 5d4cb856d8 2010-11-07 kinaba: { a7b5d1d95a 2010-11-12 kinaba: /// Expression ::= (Binary left-associative operators over) Funcall a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: AST rec(AST lhs) a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: if( closingBracket() ) a7b5d1d95a 2010-11-12 kinaba: return lhs; a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: auto pos = currentPosition(); a7b5d1d95a 2010-11-12 kinaba: foreach(op; operator_perferences[level]) a7b5d1d95a 2010-11-12 kinaba: if( tryEat(op) ) 515502e8d1 2010-11-20 kinaba: if( op[0]=='.' ) 515502e8d1 2010-11-20 kinaba: return rec( 6ac127ddd0 2010-11-23 kinaba: new App(lhs.pos, new Var(pos, op), lhs, parseId())); 515502e8d1 2010-11-20 kinaba: else 6ac127ddd0 2010-11-23 kinaba: return rec( 6ac127ddd0 2010-11-23 kinaba: new App(lhs.pos, new Var(pos, op), lhs, E(level+1))); a7b5d1d95a 2010-11-12 kinaba: return lhs; a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: 5d4cb856d8 2010-11-07 kinaba: if( operator_perferences.length <= level ) b985f3bf91 2010-11-08 kinaba: return Funcall(); 5d4cb856d8 2010-11-07 kinaba: else a7b5d1d95a 2010-11-12 kinaba: return rec(E(level+1)); b985f3bf91 2010-11-08 kinaba: } b985f3bf91 2010-11-08 kinaba: b985f3bf91 2010-11-08 kinaba: AST Funcall() b985f3bf91 2010-11-08 kinaba: { a7b5d1d95a 2010-11-12 kinaba: /// Funcall ::= BaseExpression ["(" Expression%"," ")"]* a7b5d1d95a 2010-11-12 kinaba: b985f3bf91 2010-11-08 kinaba: auto e = BaseExpression(); 6ecc7046fc 2010-11-21 kinaba: for(;;) 6ecc7046fc 2010-11-21 kinaba: if( tryEat("(") ) 6ecc7046fc 2010-11-21 kinaba: { 6ecc7046fc 2010-11-21 kinaba: auto pos = currentPosition(); 6ecc7046fc 2010-11-21 kinaba: AST[] args; 6ecc7046fc 2010-11-21 kinaba: while( !tryEat(")") ) { 6ecc7046fc 2010-11-21 kinaba: if( lex.empty ) 6ecc7046fc 2010-11-21 kinaba: throw genex!UnexpectedEOF(pos, "closing ')' for arguments not found"); 6ecc7046fc 2010-11-21 kinaba: args ~= E(0); 6ecc7046fc 2010-11-21 kinaba: if( !tryEat(",") ) { 6ecc7046fc 2010-11-21 kinaba: eat(")", "after function parameters"); 6ecc7046fc 2010-11-21 kinaba: break; 6ecc7046fc 2010-11-21 kinaba: } 3f5dc76a75 2010-11-07 kinaba: } 6ac127ddd0 2010-11-23 kinaba: e = new App(e.pos, e, args); 6ecc7046fc 2010-11-21 kinaba: } 6ecc7046fc 2010-11-21 kinaba: else if( tryEat("{") ) 6ecc7046fc 2010-11-21 kinaba: { 6ecc7046fc 2010-11-21 kinaba: e = parseTableSetAfterBrace(e); 3f5dc76a75 2010-11-07 kinaba: } 6ecc7046fc 2010-11-21 kinaba: else 6ecc7046fc 2010-11-21 kinaba: break; 6ecc7046fc 2010-11-21 kinaba: return e; 6ecc7046fc 2010-11-21 kinaba: } 6ecc7046fc 2010-11-21 kinaba: 6ecc7046fc 2010-11-21 kinaba: AST parseTableSetAfterBrace(AST e) 6ecc7046fc 2010-11-21 kinaba: { 6ecc7046fc 2010-11-21 kinaba: if( tryEat("}") ) 6ecc7046fc 2010-11-21 kinaba: return e; 6ecc7046fc 2010-11-21 kinaba: auto pos = currentPosition(); 6ecc7046fc 2010-11-21 kinaba: for(;;) 6ecc7046fc 2010-11-21 kinaba: { 6ecc7046fc 2010-11-21 kinaba: string key = eatId("for table key", AllowQuoted); 6ecc7046fc 2010-11-21 kinaba: eat(":", "after table key"); 6ecc7046fc 2010-11-21 kinaba: AST val = E(0); 6ac127ddd0 2010-11-23 kinaba: e = new App(pos, new Var(pos,".="), 6ac127ddd0 2010-11-23 kinaba: e, new Str(pos,key), val); 6ecc7046fc 2010-11-21 kinaba: if( !tryEat(",") ) 6ecc7046fc 2010-11-21 kinaba: { 6ecc7046fc 2010-11-21 kinaba: eat("}", "for the end of table literal"); 6ecc7046fc 2010-11-21 kinaba: break; 6ecc7046fc 2010-11-21 kinaba: } 5d4cb856d8 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: return e; 5d4cb856d8 2010-11-07 kinaba: } 5d4cb856d8 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; 6ac127ddd0 2010-11-23 kinaba: return new Str(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; 6ac127ddd0 2010-11-23 kinaba: return new Int(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"); a5d10ace51 2010-11-09 kinaba: auto e = Body(); dc93ad8cf6 2010-11-09 kinaba: eat(")", "after "~lay~"(..."); 6ac127ddd0 2010-11-23 kinaba: return new Lay(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; 515502e8d1 2010-11-20 kinaba: } 515502e8d1 2010-11-20 kinaba: if( tryEat("{") ) 515502e8d1 2010-11-20 kinaba: { 6ac127ddd0 2010-11-23 kinaba: AST e = new App(pos, new Var(pos,"{}")); 6ecc7046fc 2010-11-21 kinaba: return parseTableSetAfterBrace(e); 633e700889 2010-11-07 kinaba: } 633e700889 2010-11-07 kinaba: if( tryEat("if") ) 633e700889 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"); 633e700889 2010-11-07 kinaba: } 6ac127ddd0 2010-11-23 kinaba: return new App(pos, 6ac127ddd0 2010-11-23 kinaba: new Var(pos, "if"), 633e700889 2010-11-07 kinaba: cond, 6ac127ddd0 2010-11-23 kinaba: new Fun(thenPos, [], th), 6ac127ddd0 2010-11-23 kinaba: new Fun(elsePos, [], el) 633e700889 2010-11-07 kinaba: ); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: if( tryEat("case") ) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: return parsePatternMatch(pos); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: if( tryEat("fun") || tryEat("\u03BB") ) // lambda!! 3f5dc76a75 2010-11-07 kinaba: { 3f5dc76a75 2010-11-07 kinaba: eat("(", "after fun"); 68546f3e9f 2010-11-09 kinaba: return parseLambdaAfterOpenParen(pos); 68546f3e9f 2010-11-09 kinaba: } 68546f3e9f 2010-11-09 kinaba: scope(exit) lex.popFront; 6ac127ddd0 2010-11-23 kinaba: return new Var(pos, lex.front.str); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: AST parsePatternMatch(LexPosition pos) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: // case( pmExpr )cases 3995a5eb6a 2010-11-21 kinaba: //==> 3995a5eb6a 2010-11-21 kinaba: // let pmVar = pmExpr in (... let pmTryFirst = ... in pmTryFirst()) 3995a5eb6a 2010-11-21 kinaba: eat("(", "after case"); 3995a5eb6a 2010-11-21 kinaba: AST pmExpr = E(0); 3995a5eb6a 2010-11-21 kinaba: eat(")", "after case"); 3995a5eb6a 2010-11-21 kinaba: string pmVar = freshVarName(); 3995a5eb6a 2010-11-21 kinaba: string pmTryFirst = freshVarName(); 3995a5eb6a 2010-11-21 kinaba: AST pmBody = parsePatternMatchCases(pmVar, pmTryFirst, 6ac127ddd0 2010-11-23 kinaba: new App(pos, new Var(pos, pmTryFirst))); 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, pmVar, [], pmExpr, pmBody); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: AST parsePatternMatchCases(string pmVar, string tryThisBranchVar, AST thenDoThis) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: // when( pat ) { cBody } 3995a5eb6a 2010-11-21 kinaba: //==> 3995a5eb6a 2010-11-21 kinaba: // ... let failBranchVar = ... in 3995a5eb6a 2010-11-21 kinaba: // let tryThisBranchVar = fun(){ if(test){cBody}else{failBranchVar()} } in thenDoThis 3995a5eb6a 2010-11-21 kinaba: if( tryEat("when") ) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 3995a5eb6a 2010-11-21 kinaba: string failBranchVar = freshVarName(); 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: eat("(", "after when"); 3995a5eb6a 2010-11-21 kinaba: auto pr = parsePattern(); 3995a5eb6a 2010-11-21 kinaba: eat(")", "after when"); 3995a5eb6a 2010-11-21 kinaba: eat("{", "after pattern"); 3995a5eb6a 2010-11-21 kinaba: AST cBody = Body(); 6ac127ddd0 2010-11-23 kinaba: AST judgement = new App(pos, new Var(pos, "if"), 6ac127ddd0 2010-11-23 kinaba: ppTest(pmVar, pr), new Fun(pos,[],ppBind(pmVar, pr, cBody)), 6ac127ddd0 2010-11-23 kinaba: new Var(pos, failBranchVar)); 3995a5eb6a 2010-11-21 kinaba: eat("}", "after pattern clause"); 3995a5eb6a 2010-11-21 kinaba: return parsePatternMatchCases(pmVar, failBranchVar, 6ac127ddd0 2010-11-23 kinaba: new Let(pos, tryThisBranchVar, [], 6ac127ddd0 2010-11-23 kinaba: new Fun(pos,[],judgement), thenDoThis) 3995a5eb6a 2010-11-21 kinaba: ); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: else 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 6ac127ddd0 2010-11-23 kinaba: AST doNothing = new Fun(pos,[], 6ac127ddd0 2010-11-23 kinaba: new Str(pos, sprintf!"(pattern match failure:%s)"(pos))); 6ac127ddd0 2010-11-23 kinaba: return new Let(currentPosition(), tryThisBranchVar, [], doNothing, thenDoThis); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: // hageshiku tenuki 3995a5eb6a 2010-11-21 kinaba: abstract class SinglePattern 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: string[] path; 3995a5eb6a 2010-11-21 kinaba: mixin SimpleClass; 3995a5eb6a 2010-11-21 kinaba: private AST access(string pmVar, string[] path) { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 6ac127ddd0 2010-11-23 kinaba: AST e = new Var(pos, pmVar); 3995a5eb6a 2010-11-21 kinaba: foreach(p; path) 6ac127ddd0 2010-11-23 kinaba: e = new App(pos, new Var(pos, "."), e, new Str(pos, p)); 3995a5eb6a 2010-11-21 kinaba: return e; 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: private AST has(AST e, string k) { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 3995a5eb6a 2010-11-21 kinaba: return opAndAnd( 6ac127ddd0 2010-11-23 kinaba: new App(pos, new Var(pos, "_istable"), e), 6ac127ddd0 2010-11-23 kinaba: new App(pos, new Var(pos, ".?"), e, new Str(pos, k)) 3995a5eb6a 2010-11-21 kinaba: ); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: private AST opAndAnd(AST a, AST b) { 3995a5eb6a 2010-11-21 kinaba: if( a is null ) return b; 3995a5eb6a 2010-11-21 kinaba: if( b is null ) return a; 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 6ac127ddd0 2010-11-23 kinaba: return new App(pos, 6ac127ddd0 2010-11-23 kinaba: new Var(pos, "if"), 3995a5eb6a 2010-11-21 kinaba: a, 6ac127ddd0 2010-11-23 kinaba: new Fun(pos, [], b), 6ac127ddd0 2010-11-23 kinaba: new Fun(pos, [], new Int(pos, 0)) 3995a5eb6a 2010-11-21 kinaba: ); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: AST ppTest(string pmVar) { 3995a5eb6a 2010-11-21 kinaba: AST c = null; 3995a5eb6a 2010-11-21 kinaba: for(int i=0; i<path.length; ++i) 3995a5eb6a 2010-11-21 kinaba: c = opAndAnd(c, has(access(pmVar,path[0..i]), path[i])); 3995a5eb6a 2010-11-21 kinaba: return c; 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: AST ppBind(string pmVar, AST thenDoThis) { return thenDoThis; } 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: class WildPattern : SinglePattern 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: mixin SimpleClass; 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: class VarPattern : SinglePattern 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: string name; 3995a5eb6a 2010-11-21 kinaba: mixin SimpleClass; 3995a5eb6a 2010-11-21 kinaba: AST ppBind(string pmVar, AST thenDoThis) { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 6ac127ddd0 2010-11-23 kinaba: return new Let(pos, name, [], access(pmVar,path), thenDoThis); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: class ConstantPattern : SinglePattern 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: AST e; 3995a5eb6a 2010-11-21 kinaba: mixin SimpleClass; 3995a5eb6a 2010-11-21 kinaba: AST ppTest(string pmVar) { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 3995a5eb6a 2010-11-21 kinaba: return opAndAnd( super.ppTest(pmVar), 6ac127ddd0 2010-11-23 kinaba: new App(pos, new Var(pos,"=="), access(pmVar,path), e) 3995a5eb6a 2010-11-21 kinaba: ); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: SinglePattern[] parsePattern(string[] path = null) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: SinglePattern[] result; 3995a5eb6a 2010-11-21 kinaba: if( tryEat("{") ) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: if( !tryEat("}") ) { 3995a5eb6a 2010-11-21 kinaba: do { 3995a5eb6a 2010-11-21 kinaba: string key = eatId("in table pattern"); 3995a5eb6a 2010-11-21 kinaba: eat(":", "after field-id in table pattern"); 3995a5eb6a 2010-11-21 kinaba: result ~= parsePattern(path ~ key); 3995a5eb6a 2010-11-21 kinaba: } while( tryEat(",") ); 3995a5eb6a 2010-11-21 kinaba: eat("}", "at the end of table pattern"); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: else 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: AST e = E(0); 6ac127ddd0 2010-11-23 kinaba: if(auto ev = cast(Var)e) 3995a5eb6a 2010-11-21 kinaba: if(ev.name == "_") 3995a5eb6a 2010-11-21 kinaba: result ~= new WildPattern(path); 3995a5eb6a 2010-11-21 kinaba: else 3995a5eb6a 2010-11-21 kinaba: result ~= new VarPattern(path, ev.name); 3995a5eb6a 2010-11-21 kinaba: else 3995a5eb6a 2010-11-21 kinaba: result ~= new ConstantPattern(path, e); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: return result; 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: AST ppTest(string pmVar, SinglePattern[] pats) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: auto pos = currentPosition(); 3995a5eb6a 2010-11-21 kinaba: AST cond = null; 3995a5eb6a 2010-11-21 kinaba: foreach(p; pats) { 3995a5eb6a 2010-11-21 kinaba: AST c2 = p.ppTest(pmVar); 3995a5eb6a 2010-11-21 kinaba: if( c2 !is null ) 3995a5eb6a 2010-11-21 kinaba: cond = cond is null ? c2 6ac127ddd0 2010-11-23 kinaba: : new App(pos, new Var(pos,"&&"), cond, c2); 3995a5eb6a 2010-11-21 kinaba: } 6ac127ddd0 2010-11-23 kinaba: return cond is null ? new Int(currentPosition(), 1) : cond; 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: AST ppBind(string pmVar, SinglePattern[] pats, AST thenDoThis) 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: foreach(p; pats) 3995a5eb6a 2010-11-21 kinaba: thenDoThis = p.ppBind(pmVar, thenDoThis); 3995a5eb6a 2010-11-21 kinaba: return thenDoThis; 515502e8d1 2010-11-20 kinaba: } 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: AST parseId() 515502e8d1 2010-11-20 kinaba: { 515502e8d1 2010-11-20 kinaba: scope(exit) lex.popFront; 6ac127ddd0 2010-11-23 kinaba: return new Str(currentPosition(), 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: { 8e6fa743ee 2010-11-11 kinaba: Parameter[] params; 68546f3e9f 2010-11-09 kinaba: while( !tryEat(")") ) 68546f3e9f 2010-11-09 kinaba: { a7b5d1d95a 2010-11-12 kinaba: params ~= parseParam(); 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"); 6ac127ddd0 2010-11-23 kinaba: return new Fun(pos, params, funbody); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: Parameter parseParam() a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: string var; a7b5d1d95a 2010-11-12 kinaba: string[] lay; a7b5d1d95a 2010-11-12 kinaba: while( !closingBracket() && !lex.empty && lex.front.str!="," ) a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: auto pos = currentPosition(); a7b5d1d95a 2010-11-12 kinaba: string p = eatId("for function parameter", AllowQuoted); a7b5d1d95a 2010-11-12 kinaba: if( p == "@" ) a7b5d1d95a 2010-11-12 kinaba: lay ~= "@" ~ eatId("after @", AllowQuoted); a7b5d1d95a 2010-11-12 kinaba: else if( var.empty ) a7b5d1d95a 2010-11-12 kinaba: var = p; a7b5d1d95a 2010-11-12 kinaba: else a7b5d1d95a 2010-11-12 kinaba: throw genex!ParseException(pos, "one parameter has two names"); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: return new Parameter(var, lay); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 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; } a7b5d1d95a 2010-11-12 kinaba: a7b5d1d95a 2010-11-12 kinaba: bool isNumber(string s) a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: return find!(`a<'0' || '9'<a`)(s).empty; a7b5d1d95a 2010-11-12 kinaba: } 6f0ec5b7c9 2010-11-11 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( 6f0ec5b7c9 2010-11-11 kinaba: currentPosition(), sprintf!"%s is expected %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; 8d297342aa 2010-11-08 kinaba: } 8d297342aa 2010-11-08 kinaba: a7b5d1d95a 2010-11-12 kinaba: enum {AllowQuoted=true, DisallowQuoted=false}; a7b5d1d95a 2010-11-12 kinaba: string eatId(lazy string msg, bool aq=DisallowQuoted) 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); a7b5d1d95a 2010-11-12 kinaba: if( !aq && 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: b985f3bf91 2010-11-08 kinaba: AST doNothingExpression() b985f3bf91 2010-11-08 kinaba: { 6ac127ddd0 2010-11-23 kinaba: return new Str(currentPosition(), "(empty function body)"); 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; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 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))); a7b5d1d95a 2010-11-12 kinaba: assert_eq(parseString(`let x=1 in 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))); 2bdfb8a182 2010-11-21 kinaba: assert_eq(parseString(`if(1){2}`), call(var("if"),intl(1),fun([],intl(2)),fun([],strl("(empty function body)")))); 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}()()`), 2bdfb8a182 2010-11-21 kinaba: call(call(call(var("if"),intl(1),fun([],strl("(empty function body)")),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))); a7b5d1d95a 2010-11-12 kinaba: assert_eq(parseString(`fun(x @v @t, y, z @t){}`), 2bdfb8a182 2010-11-21 kinaba: funp([param("x",["@v","@t"]), param("y",[]), param("z",["@t"])], strl("(empty function body)"))); 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: ); 80ff567c75 2010-11-08 kinaba: } 80ff567c75 2010-11-08 kinaba: 80ff567c75 2010-11-08 kinaba: unittest 80ff567c75 2010-11-08 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: ); c368edbcb1 2010-11-13 kinaba: c368edbcb1 2010-11-13 kinaba: assert_eq(parseString(`@@type ( x ) { x }`), 2bdfb8a182 2010-11-21 kinaba: let("@type", SystemLayer, fun(["x"], var("x")), lay(SystemLayer, var("@type"))) ); 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: assert_eq(parseString(`{}`), call(var("{}"))); 515502e8d1 2010-11-20 kinaba: assert_eq(parseString(`{foo:1,"bar":2}`), 515502e8d1 2010-11-20 kinaba: call(var(".="), call(var(".="), call(var("{}")), strl("foo"), intl(1)), strl("bar"), intl(2))); 515502e8d1 2010-11-20 kinaba: assert_eq(parseString(`{}.foo`), call(var("."),call(var("{}")),strl("foo"))); 515502e8d1 2010-11-20 kinaba: assert_eq(parseString(`{}.?foo`), call(var(".?"),call(var("{}")),strl("foo"))); 6ecc7046fc 2010-11-21 kinaba: assert_eq(parseString(`x{y:1}`), call(var(".="),var("x"),strl("y"),intl(1))); 3995a5eb6a 2010-11-21 kinaba: } 3995a5eb6a 2010-11-21 kinaba: 3995a5eb6a 2010-11-21 kinaba: unittest 3995a5eb6a 2010-11-21 kinaba: { 3995a5eb6a 2010-11-21 kinaba: assert_nothrow(parseString(` 3995a5eb6a 2010-11-21 kinaba: case( 1 ) 3995a5eb6a 2010-11-21 kinaba: when(x){1} 3995a5eb6a 2010-11-21 kinaba: `)); 3995a5eb6a 2010-11-21 kinaba: assert_nothrow(parseString(` 3995a5eb6a 2010-11-21 kinaba: case( 1 ) 3995a5eb6a 2010-11-21 kinaba: when({aaaa:_}){1} 3995a5eb6a 2010-11-21 kinaba: `)); 423f308350 2010-11-07 kinaba: }