@@ -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'