@@ -1,47 +1,48 @@ -/** - * 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; +/** + * 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; -/// Exception from this module - -class ParseException : Exception -{ +/// +class ParseException : Exception +{ mixin ExceptionWithPosition; -} +} + +/// Entry points of this module + +AST parseString(S, T...)(S str, T fn_ln_cn) + { return parserFromString(str, fn_ln_cn).parse(); } /// Entry points of this module -auto parseString(S, T...)(S str, T fn_ln_cn) - { return parserFromString(str, fn_ln_cn).parse(); } - -auto parseFile(S, T...)(S filename, T ln_cn) +AST parseFile(S, T...)(S filename, T ln_cn) { return parserFromFile(filename, ln_cn).parse(); } -/// Named Constructor of Parser +// Named Constructors of Parser -private auto parserFromLexer(Lexer)(Lexer lex) - { return new Parser!Lexer(lex); } - -private auto parserFromString(T...)(T params) - { return parserFromLexer(polemy.lex.lexerFromString(params)); } - -private auto parserFromFile(T...)(T params) +private auto parserFromLexer(Lexer)(Lexer lex) + { return new Parser!Lexer(lex); } + +private auto parserFromString(T...)(T params) + { return parserFromLexer(polemy.lex.lexerFromString(params)); } + +private auto parserFromFile(T...)(T params) { return parserFromLexer(polemy.lex.lexerFromFile(params)); } -/// Parser - +// Parser + private class Parser(Lexer) - if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) ) + if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) ) { - AST parse() + AST parse() { auto e = Body(); if( !lex.empty ) throw genex!ParseException(currentPosition(), "parsing ended but some tokens left"); @@ -93,88 +94,88 @@ return new LetExpression(pos, "_", "", e, Body()); else return e; } - } - - // [TODO] make customizable from program - static immutable string[][] operator_perferences = [ - ["||"], - ["&&"], - ["!="], - ["=="], - ["<","<=",">",">="], - ["|"], - ["^"], - ["&"], - ["<<", ">>"], + } + + // [TODO] make customizable from program + static immutable string[][] operator_perferences = [ + ["||"], + ["&&"], + ["!="], + ["=="], + ["<","<=",">",">="], + ["|"], + ["^"], + ["&"], + ["<<", ">>"], ["+","-"], ["~"], ["*","/","%"], ["^^"] - ]; - - AST E(int level) - { - if( operator_perferences.length <= level ) - return Funcall(); - else - { - auto ops = operator_perferences[level]; - auto e = E(level+1); - seq: - while( !lex.empty ) - { - auto pos = lex.front.pos; - foreach(op; ops) - if( tryEat(op) ) - { - e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, E(level+1)); - continue seq; - } - break; - } - return e; - } - } - - AST Funcall() - { + ]; + + AST E(int level) + { + if( operator_perferences.length <= level ) + return Funcall(); + else + { + auto ops = operator_perferences[level]; + auto e = E(level+1); + seq: + while( !lex.empty ) + { + auto pos = lex.front.pos; + foreach(op; ops) + if( tryEat(op) ) + { + e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, E(level+1)); + continue seq; + } + break; + } + return e; + } + } + + AST Funcall() + { auto e = BaseExpression(); - while( tryEat("(") ) + while( tryEat("(") ) { auto pos = currentPosition(); - AST[] args; - while( !tryEat(")") ) { + AST[] args; + while( !tryEat(")") ) { if( lex.empty ) - throw genex!UnexpectedEOF(pos,"Closing ')' for arguments not found"); + throw genex!UnexpectedEOF(pos,"Closing ')' for arguments not found"); args ~= E(0); - if( !tryEat(",") ) { - eat(")", "after function parameters"); - break; - } - } - e = new FuncallExpression(e.pos, e, args); - } - return e; - } - - AST BaseExpression() - { + if( !tryEat(",") ) { + eat(")", "after function parameters"); + break; + } + } + e = new FuncallExpression(e.pos, e, args); + } + return e; + } + + AST BaseExpression() + { if( lex.empty ) throw genex!UnexpectedEOF(currentPosition(), "Reached EOF when tried to parse an expression"); - auto pos = lex.front.pos; - if( lex.front.quoted ) - { - scope(exit) lex.popFront; - return new StrLiteral(pos, lex.front.str); - } - if( isNumber(lex.front.str) ) - { - scope(exit) lex.popFront; - return new IntLiteral(pos, BigInt(cast(string)lex.front.str)); - } + auto pos = lex.front.pos; + if( lex.front.quoted ) + { + scope(exit) lex.popFront; + return new StrLiteral(pos, lex.front.str); + } + if( isNumber(lex.front.str) ) + { + scope(exit) lex.popFront; + return new IntLiteral(pos, BigInt(cast(string)lex.front.str)); + } if( tryEat("@") ) { auto lay = "@"~eatId("for layer ID"); eat("(", "for layered execution"); @@ -181,44 +182,44 @@ auto e = Body(); eat(")", "after "~lay~"(..."); return new LayeredExpression(pos, lay, e); } - if( tryEat("(") ) - { - auto e = Body(); - eat(")", "after parenthesized expression"); - return e; - } - if( tryEat("if") ) - { - eat("(", "after if"); - auto cond = E(0); - eat(")", "after if condition"); - auto thenPos = lex.front.pos; - eat("{", "after if condition"); - auto th = Body(); - eat("}", "after if-then body"); - auto el = doNothingExpression(); - auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos); - if( tryEat("else") ) { - eat("{", "after else"); - el = Body(); - eat("}", "after else body"); - } - return new FuncallExpression(pos, - new VarExpression(pos, "if"), - cond, - new FunLiteral(thenPos, [], th), - new FunLiteral(elsePos, [], el) - ); - } - if( tryEat("fun") || tryEat("\u03BB") ) - { - eat("(", "after fun"); + if( tryEat("(") ) + { + auto e = Body(); + eat(")", "after parenthesized expression"); + return e; + } + if( tryEat("if") ) + { + eat("(", "after if"); + auto cond = E(0); + eat(")", "after if condition"); + auto thenPos = lex.front.pos; + eat("{", "after if condition"); + auto th = Body(); + eat("}", "after if-then body"); + auto el = doNothingExpression(); + auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos); + if( tryEat("else") ) { + eat("{", "after else"); + el = Body(); + eat("}", "after else body"); + } + return new FuncallExpression(pos, + new VarExpression(pos, "if"), + cond, + new FunLiteral(thenPos, [], th), + new FunLiteral(elsePos, [], el) + ); + } + if( tryEat("fun") || tryEat("\u03BB") ) + { + eat("(", "after fun"); return parseLambdaAfterOpenParen(pos); - } - scope(exit) lex.popFront; - return new VarExpression(pos, lex.front.str); + } + scope(exit) lex.popFront; + return new VarExpression(pos, lex.front.str); } AST parseLambdaAfterOpenParen(immutable LexPosition pos) { @@ -234,32 +235,32 @@ eat("{", "after function parameters"); auto funbody = Body(); eat("}", "after function body"); return new FunLiteral(pos, params, funbody); - } - -private: + } + +private: Lexer lex; this(Lexer lex) { this.lex = lex; } - - void eat(string kwd, lazy string msg) - { + + void eat(string kwd, lazy string msg) + { if( !tryEat(kwd) ) if( lex.empty ) throw genex!UnexpectedEOF( currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg)); else throw genex!ParseException( currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg)); - } - - bool tryEat(string kwd) - { - if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) - return false; - lex.popFront; - return true; - } + } + + bool tryEat(string kwd) + { + if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) + return false; + lex.popFront; + return true; + } string eatId(lazy string msg, bool allowQuoted=false) { if( lex.empty ) @@ -268,12 +269,12 @@ throw genex!ParseException(currentPosition(), "identifier is expected but not found "~msg); scope(exit) lex.popFront; return lex.front.str; } - - bool isNumber(string s) - { - return find!(`a<'0'||'9'