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: a7b5d1d95a 2010-11-12 kinaba: /// Thrown when encountered a syntax error a7b5d1d95a 2010-11-12 kinaba: b985f3bf91 2010-11-08 kinaba: class ParseException : Exception b985f3bf91 2010-11-08 kinaba: { 2459e9a821 2010-11-09 kinaba: mixin ExceptionWithPosition; 2459e9a821 2010-11-09 kinaba: } b985f3bf91 2010-11-08 kinaba: a7b5d1d95a 2010-11-12 kinaba: /// Parse a string and return its AST a7b5d1d95a 2010-11-12 kinaba: /// Throws: ParseException, LexException, UnexpectedEOF 2459e9a821 2010-11-09 kinaba: 38fcc662be 2010-11-10 kinaba: AST parseString(S, T...)(S str, T fn_ln_cn) a7b5d1d95a 2010-11-12 kinaba: { a7b5d1d95a 2010-11-12 kinaba: return parserFromString(str, fn_ln_cn).parse(); a7b5d1d95a 2010-11-12 kinaba: } 2459e9a821 2010-11-09 kinaba: a7b5d1d95a 2010-11-12 kinaba: /// Parse the content of a file and return its AST a7b5d1d95a 2010-11-12 kinaba: /// Throws: ParseException, LexException, UnexpectedEOF 2459e9a821 2010-11-09 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: } 38fcc662be 2010-11-10 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)); } b985f3bf91 2010-11-08 kinaba: 38fcc662be 2010-11-10 kinaba: // Parser b985f3bf91 2010-11-08 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(); a7b5d1d95a 2010-11-12 kinaba: string layer = ""; c368edbcb1 2010-11-13 kinaba: bool layerRiseDecl = 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); c368edbcb1 2010-11-13 kinaba: layerRiseDecl = 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 c368edbcb1 2010-11-13 kinaba: if( layerRiseDecl ) 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() ) c368edbcb1 2010-11-13 kinaba: return new LetExpression(pos, var, "(system)", e, Body()); c368edbcb1 2010-11-13 kinaba: else c368edbcb1 2010-11-13 kinaba: return new LetExpression(pos, var, "(system)", e, new VarExpression(pos, var)); c368edbcb1 2010-11-13 kinaba: } 5d4cb856d8 2010-11-07 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() ) c368edbcb1 2010-11-13 kinaba: return new LetExpression(pos, var, layer, e, Body()); c368edbcb1 2010-11-13 kinaba: else c368edbcb1 2010-11-13 kinaba: return new LetExpression(pos, var, layer, e, new VarExpression(varpos, var)); c368edbcb1 2010-11-13 kinaba: } 5d4cb856d8 2010-11-07 kinaba: } 5d4cb856d8 2010-11-07 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() ) a7b5d1d95a 2010-11-12 kinaba: return new LetExpression(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: { a7b5d1d95a 2010-11-12 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( 515502e8d1 2010-11-20 kinaba: new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, parseId())); 515502e8d1 2010-11-20 kinaba: else a7b5d1d95a 2010-11-12 kinaba: return rec( a7b5d1d95a 2010-11-12 kinaba: new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, E(level+1))); a7b5d1d95a 2010-11-12 kinaba: return lhs; a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 kinaba: b985f3bf91 2010-11-08 kinaba: if( operator_perferences.length <= level ) b985f3bf91 2010-11-08 kinaba: return Funcall(); b985f3bf91 2010-11-08 kinaba: else a7b5d1d95a 2010-11-12 kinaba: return rec(E(level+1)); 3f5dc76a75 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: b985f3bf91 2010-11-08 kinaba: AST Funcall() 3f5dc76a75 2010-11-07 kinaba: { a7b5d1d95a 2010-11-12 kinaba: /// Funcall ::= BaseExpression ["(" Expression%"," ")"]* a7b5d1d95a 2010-11-12 kinaba: b985f3bf91 2010-11-08 kinaba: auto e = BaseExpression(); b985f3bf91 2010-11-08 kinaba: while( tryEat("(") ) 5d4cb856d8 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 ) a7b5d1d95a 2010-11-12 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: } 5d4cb856d8 2010-11-07 kinaba: } b985f3bf91 2010-11-08 kinaba: e = new FuncallExpression(e.pos, e, args); 423f308350 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: return e; 423f308350 2010-11-07 kinaba: } 423f308350 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)); b985f3bf91 2010-11-08 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~"(..."); dc93ad8cf6 2010-11-09 kinaba: return new LayeredExpression(pos, lay, e); dc93ad8cf6 2010-11-09 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"); a5d10ace51 2010-11-09 kinaba: return e; a5d10ace51 2010-11-09 kinaba: } 515502e8d1 2010-11-20 kinaba: if( tryEat("{") ) 515502e8d1 2010-11-20 kinaba: { 515502e8d1 2010-11-20 kinaba: AST e = new FuncallExpression(pos, new VarExpression(pos,"{}")); 515502e8d1 2010-11-20 kinaba: if( tryEat("}") ) 515502e8d1 2010-11-20 kinaba: return e; 515502e8d1 2010-11-20 kinaba: for(;;) 515502e8d1 2010-11-20 kinaba: { 515502e8d1 2010-11-20 kinaba: string key = eatId("for table key", AllowQuoted); 515502e8d1 2010-11-20 kinaba: eat(":", "after table key"); 515502e8d1 2010-11-20 kinaba: AST val = E(0); 515502e8d1 2010-11-20 kinaba: e = new FuncallExpression(pos, new VarExpression(pos,".="), 515502e8d1 2010-11-20 kinaba: e, new StrLiteral(pos,key), val); 515502e8d1 2010-11-20 kinaba: if( !tryEat(",") ) 515502e8d1 2010-11-20 kinaba: { 515502e8d1 2010-11-20 kinaba: eat("}", "for the end of table literal"); 515502e8d1 2010-11-20 kinaba: break; 515502e8d1 2010-11-20 kinaba: } 515502e8d1 2010-11-20 kinaba: } 515502e8d1 2010-11-20 kinaba: return e; 515502e8d1 2010-11-20 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"); 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: } a7b5d1d95a 2010-11-12 kinaba: if( tryEat("fun") || tryEat("\u03BB") ) // lambda!! 633e700889 2010-11-07 kinaba: { 633e700889 2010-11-07 kinaba: eat("(", "after fun"); 68546f3e9f 2010-11-09 kinaba: return parseLambdaAfterOpenParen(pos); 3f5dc76a75 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); 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; 515502e8d1 2010-11-20 kinaba: return new StrLiteral(currentPosition(), lex.front.str); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 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"); 68546f3e9f 2010-11-09 kinaba: return new FunLiteral(pos, params, funbody); 68546f3e9f 2010-11-09 kinaba: } 68546f3e9f 2010-11-09 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); a7b5d1d95a 2010-11-12 kinaba: } a7b5d1d95a 2010-11-12 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: } 2459e9a821 2010-11-09 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: { 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; 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))); 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))); a7b5d1d95a 2010-11-12 kinaba: assert_eq(parseString(`fun(x @v @t, y, z @t){}`), a7b5d1d95a 2010-11-12 kinaba: funp([param("x",["@v","@t"]), param("y",[]), param("z",["@t"])], intl(178))); 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: ); 3f5dc76a75 2010-11-07 kinaba: } 3f5dc76a75 2010-11-07 kinaba: 3f5dc76a75 2010-11-07 kinaba: unittest 3f5dc76a75 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: ); c368edbcb1 2010-11-13 kinaba: c368edbcb1 2010-11-13 kinaba: assert_eq(parseString(`@@type ( x ) { x }`), c368edbcb1 2010-11-13 kinaba: let("@type", "(system)", fun(["x"], var("x")), 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"))); 423f308350 2010-11-07 kinaba: }