@@ -1,370 +1,368 @@ -/** - * Authors: k.inaba - * License: NYSL 0.9982 http://www.kmonos.net/nysl/ - * - * Parser for Polemy programming language - */ -module polemy.parse; -import polemy._common; -import polemy.lex; -import polemy.ast; - -/// Parsing Failure - -class ParserException : Exception -{ -private: - this(string msg) { super(msg); } - static ParserException create(Lexer)(Lexer lex, string msg) - { - return new ParserException(sprintf!"[%s] %s"( - lex.empty ? "EOF" : to!string(lex.front.pos), msg)); - } -} - -/// Named Constructor of Parser - -auto parserFromLexer(Lexer)(Lexer lex) -{ - return new Parser!Lexer(lex); -} - -/// Named Constructor of Parser (just fwd to lexerFromString) - -auto parserFromString(T...)(T params) -{ - return parserFromLexer(polemy.lex.lexerFromString(params)); -} - -/// Named Constructor of Parser (just fwd to lexerFromFile) - -auto parserFromFile(T...)(T params) -{ - return parserFromLexer(polemy.lex.lexerFromFile(params)); -} - -/// Parser - -class Parser(Lexer) -{ - this(Lexer lex) - { - 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 && (lex.front.quoted || lex.front.str!="}") ) - p ~= parseStatement(); - return p; - } - - Statement parseStatement() - { - auto saved = lex.save; - scope(failure) lex = saved; - - if( lex.empty ) - throw new ParserException("EOF during parsing a statement"); - auto pos = lex.front.pos; - - if( !lex.front.quoted && lex.front.str=="var" ) - { - // "var" Var "=" Expression ";" - lex.popFront; - string var = lex.front.str; - lex.popFront; - eat("=", "for variable declaration"); - auto parsed = new DeclStatement(pos, var, parseExpression()); - eat(";", "after variable declaration"); - return parsed; - } - else - { - // Expression ";" - auto parsed = new ExprStatement(pos, parseExpression()); - eat(";", "after statement"); - return parsed; - } - } - - Expression parseExpression() - { - auto saved = lex.save; - scope(failure) lex = saved; - return parseE(0); - } - - // [TODO] multi-char operators are not supported by the lexer... - static immutable string[][] operator_perferences = [ - ["="], - ["or"], - ["and"], - ["!="], - ["=="], - ["<","<=",">",">="], - ["|"], - ["^"], - ["&"], - ["<<", ">>"], - ["+","-"], - ["*","/","%"] - ]; - - Expression parseE(int level = 0) - { - if( operator_perferences.length <= level ) - return parseBaseExpression(); - else - { - auto ops = operator_perferences[level]; - auto e = parseE(level+1); - seq: - while( !lex.empty ) - { - auto pos = lex.front.pos; - foreach(op; ops) - if( tryEat(op) ) - { - if( op == "=" ) // right assoc - return new AssignExpression(e.pos, e, parseE(level)); - else - e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, parseE(level+1)); - continue seq; - } - break; - } - return e; - } - } - - Expression parseBaseExpression() - { - if( lex.empty ) - throw new ParserException("EOF during parsing an expression"); - auto pos = lex.front.pos; - Expression e = parseBaseBaseExpression(); - while( tryEat("(") ) // funcall - { - Expression[] args; - while( !tryEat(")") ) { - if( lex.empty ) { - auto ex = ParserException.create(lex,"Unexpected EOF"); - throw ex; - } - args ~= parseE(); - if( !tryEat(",") ) { - eat(")", "after function parameters"); - break; - } - } - e = new FuncallExpression(pos, e, args); - } - return e; - } - - Expression parseBaseBaseExpression() - { - if( lex.empty ) - throw new ParserException("EOF during parsing an expression"); - auto pos = lex.front.pos; - - if( lex.front.quoted ) - { - scope(exit) lex.popFront; - return new StrLiteralExpression(pos, lex.front.str); - } - if( isNumber(lex.front.str) ) // is_number - { - scope(exit) lex.popFront; - return new IntLiteralExpression(pos, BigInt(cast(string)lex.front.str)); - } - if( tryEat("(") ) - { - 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; - while(!tryEat(")")) - { - if( lex.empty ) { - auto e = ParserException.create(lex,"Unexpected EOF"); - throw e; - } - if( lex.front.quoted ) { - auto e = ParserException.create(lex,"Identifier Expected for parameters"); - throw e; - } - params ~= lex.front.str; - lex.popFront; - if( !tryEat(",") ) { - eat(")", "after function parameters"); - break; - } - } - eat("{", "after function parameters"); - Statement[] funbody; - while(!tryEat("}")) { - if( lex.empty ) { - auto e = ParserException.create(lex,"Unexpected EOF"); - throw e; - } - funbody ~= parseStatement(); - } - return new FunLiteralExpression(pos, params, funbody); - } - scope(exit) lex.popFront; - return new VarExpression(pos, lex.front.str); - } - -private: - Lexer lex; - - void eat(string kwd, lazy string msg) - { - if( !tryEat(kwd) ) - { - auto e = ParserException.create(lex, "'"~kwd~"' is expected "~msg~" but '" - ~(lex.empty ? "EOF" : lex.front.str)~"' occured"); - throw e; - } - } - - bool tryEat(string kwd) - { - if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) - return false; - lex.popFront; - return true; - } - - bool isNumber(string s) - { - return find!(`a<'0'||'9'",">="], + ["|"], + ["^"], + ["&"], + ["<<", ">>"], + ["+","-"], + ["*","/","%"] + ]; + + Expression parseE(int level = 0) + { + if( operator_perferences.length <= level ) + return parseBaseExpression(); + else + { + auto ops = operator_perferences[level]; + auto e = parseE(level+1); + seq: + while( !lex.empty ) + { + auto pos = lex.front.pos; + foreach(op; ops) + if( tryEat(op) ) + { + if( op == "=" ) // right assoc + return new AssignExpression(e.pos, e, parseE(level)); + else + e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, parseE(level+1)); + continue seq; + } + break; + } + return e; + } + } + + Expression parseBaseExpression() + { + if( lex.empty ) + throw new ParserException("EOF during parsing an expression"); + auto pos = lex.front.pos; + Expression e = parseBaseBaseExpression(); + while( tryEat("(") ) // funcall + { + Expression[] args; + while( !tryEat(")") ) { + if( lex.empty ) { + auto ex = ParserException.create(lex,"Unexpected EOF"); + throw ex; + } + args ~= parseE(); + if( !tryEat(",") ) { + eat(")", "after function parameters"); + break; + } + } + e = new FuncallExpression(pos, e, args); + } + return e; + } + + Expression parseBaseBaseExpression() + { + if( lex.empty ) + throw new ParserException("EOF during parsing an expression"); + auto pos = lex.front.pos; + + if( lex.front.quoted ) + { + scope(exit) lex.popFront; + return new StrLiteralExpression(pos, lex.front.str); + } + if( isNumber(lex.front.str) ) // is_number + { + scope(exit) lex.popFront; + return new IntLiteralExpression(pos, BigInt(cast(string)lex.front.str)); + } + if( tryEat("(") ) + { + 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; + while(!tryEat(")")) + { + if( lex.empty ) { + auto e = ParserException.create(lex,"Unexpected EOF"); + throw e; + } + if( lex.front.quoted ) { + auto e = ParserException.create(lex,"Identifier Expected for parameters"); + throw e; + } + params ~= lex.front.str; + lex.popFront; + if( !tryEat(",") ) { + eat(")", "after function parameters"); + break; + } + } + eat("{", "after function parameters"); + Statement[] funbody; + while(!tryEat("}")) { + if( lex.empty ) { + auto e = ParserException.create(lex,"Unexpected EOF"); + throw e; + } + funbody ~= parseStatement(); + } + return new FunLiteralExpression(pos, params, funbody); + } + scope(exit) lex.popFront; + return new VarExpression(pos, lex.front.str); + } + +private: + Lexer lex; + + void eat(string kwd, lazy string msg) + { + if( !tryEat(kwd) ) + { + auto e = ParserException.create(lex, "'"~kwd~"' is expected "~msg~" but '" + ~(lex.empty ? "EOF" : lex.front.str)~"' occured"); + throw e; + } + } + + bool tryEat(string kwd) + { + if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) + return false; + lex.popFront; + return true; + } + + bool isNumber(string s) + { + return find!(`a<'0'||'9'