File Annotation
Not logged in
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: 		["*","/","%"],
a7b5d1d95a 2010-11-12        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) )
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));
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~"(...");
dc93ad8cf6 2010-11-09        kinaba: 			return new LayeredExpression(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;
3f5dc76a75 2010-11-07        kinaba: 		}
633e700889 2010-11-07        kinaba: 		if( tryEat("if") )
3f5dc76a75 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);
423f308350 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);
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");
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: 	}
68546f3e9f 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")) );
423f308350 2010-11-07        kinaba: }