Website Summary Files Commits Branches @commit @diff @stats
path: root / JSImpl / src / Parser.cpp
diff options
context:
space:
mode:
1 files changed, 1198 insertions, 0 deletions
-rw-r--r--JSImpl/src/Parser.cpp1198
diff --git a/JSImpl/src/Parser.cpp b/JSImpl/src/Parser.cpp
new file mode 100644
index 0000000..8f415fb
--- /dev/null
+++ b/JSImpl/src/Parser.cpp
@@ -0,0 +1,1198 @@
+#include "Parser.h"
+
+class Parser
+{
+public:
+ Parser(const IPLVector<Token>& tokens, const std::function<void()>& onError = {});
+ ExpressionPtr Parse();
+private:
+ enum NormalType {
+ Initial,
+ Normal,
+ };
+
+ enum AllowType {
+ AllowIn,
+ NoIn,
+ };
+
+ enum CompletenessType {
+ NoShortIf,
+ Full
+ };
+
+ bool MatchOneOf(IPLVector<TokenType> types);
+ bool Match(TokenType type);
+ bool Peek(TokenType type);
+ ExpressionPtr RegularExpression();
+ ExpressionPtr ParenthesizedExpression();
+ ExpressionPtr PrimaryExpression(NormalType a);
+ ExpressionPtr FunctionExpression();
+ ExpressionPtr ObjectLiteral();
+ ExpressionPtr ArrayLiteral();
+ ExpressionPtr Unary(NormalType a);
+ ExpressionPtr LeftSideExpression(NormalType a);
+ ExpressionPtr CallExpression(NormalType a);
+ ExpressionPtr CallExpressionHelper(NormalType a);
+ ExpressionPtr ShortNewExpression();
+ ExpressionPtr ShortNewSubexpression();
+ ExpressionPtr FullNewExpression();
+ ExpressionPtr FullNewSubexpression();
+ ExpressionPtr SimpleExpression();
+ ExpressionPtr MultiplicativeExpression(NormalType a);
+ ExpressionPtr AdditiveExpression(NormalType a);
+ ExpressionPtr ShiftExpression(NormalType a);
+ ExpressionPtr RelationalExpression(NormalType a, AllowType b);
+ ExpressionPtr EqualityExpression(NormalType a, AllowType b);
+ ExpressionPtr BitwiseExpression(NormalType a, AllowType b);
+ ExpressionPtr LogicalExpression(NormalType a, AllowType b);
+ ExpressionPtr ConditionalExpression(NormalType a, AllowType b);
+ ExpressionPtr AssignmentExpression(NormalType a, AllowType b);
+ ExpressionPtr Expression(NormalType a, AllowType b);
+ ExpressionPtr OptionalExpression();
+ ExpressionPtr Arguments();
+
+ //Statements
+ ExpressionPtr Statement();
+ ExpressionPtr EmptyStatement();
+ ExpressionPtr VariableDefinition(AllowType b);
+ ExpressionPtr Block();
+ ExpressionPtr LabeledStatement();
+ ExpressionPtr IfStatementfull();
+ ExpressionPtr SwitchStatement();
+ ExpressionPtr DoStatement();
+ ExpressionPtr WhileStatement();
+ ExpressionPtr ForStatement();
+ ExpressionPtr WithStatement();
+ ExpressionPtr ContinueStatement();
+ ExpressionPtr BreakStatement();
+ ExpressionPtr OptionalLabel();
+ ExpressionPtr ReturnStatement();
+ ExpressionPtr TryStatement();
+
+ ExpressionPtr FunctionDefinition();
+ ExpressionPtr Program();
+ ExpressionPtr TopStatements();
+ ExpressionPtr TopStatement();
+
+ struct InternalState
+ {
+ unsigned Current;
+ };
+
+ struct Location
+ {
+ unsigned Line;
+ unsigned Column;
+ };
+ Location GetLocation() const { return { m_Tokens[m_Current].Line , m_Tokens[m_Current].Column }; }
+
+ InternalState Snapshot();
+ void Restore(const InternalState& state);
+
+ Token& Prev() { return m_Tokens[m_Current - 1]; }
+ IPLVector<Token> m_Tokens;
+ unsigned m_Current;
+ std::function<void()> OnError;
+};
+
+Parser::Parser(const IPLVector<Token>& tokens, const std::function<void()>& onError)
+ : m_Tokens(tokens)
+ , m_Current(0)
+ , OnError(onError)
+{
+}
+
+bool Parser::MatchOneOf(IPLVector<TokenType> types)
+{
+ for (auto t : types)
+ {
+ if (t == m_Tokens[m_Current].Type)
+ {
+ ++m_Current;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Parser::Match(TokenType type)
+{
+ if (type == m_Tokens[m_Current].Type)
+ {
+ ++m_Current;
+ return true;
+ }
+ return false;
+}
+
+bool Parser::Peek(TokenType type)
+{
+ return type == m_Tokens[m_Current].Type;
+}
+
+ExpressionPtr Parser::RegularExpression()
+{
+ return nullptr;
+}
+
+ExpressionPtr Parser::PrimaryExpression(NormalType a)
+{
+ if (a == NormalType::Initial)
+ {
+ auto simple = SimpleExpression();
+ return simple;
+ }
+
+ if (auto simple = SimpleExpression())
+ {
+ return simple;
+ }
+ else if(auto function = FunctionExpression())
+ {
+ return function;
+ }
+ else if (auto object = ObjectLiteral())
+ {
+ return object;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::ParenthesizedExpression()
+{
+ if (Match(TokenType::LeftParen))
+ {
+ auto ex = Parser::Expression(NormalType::Normal, AllowType::AllowIn);
+ if (Match(TokenType::RightParen))
+ {
+ return ex;
+ }
+ // TODO log error
+ assert(false);
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::FunctionExpression()
+{
+ auto FormalParameters = [&](IPLVector<IPLString>& identifiers) -> bool {
+ if (Match(TokenType::LeftParen))
+ {
+ while (Match(TokenType::Identifier))
+ {
+ identifiers.push_back(Prev().Lexeme);
+ if (!Match(TokenType::Comma))
+ {
+ break;
+ }
+ }
+
+ if (Match(TokenType::RightParen))
+ {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ auto Body = [&]() -> ExpressionPtr {
+
+ if (Match(TokenType::LeftBrace))
+ {
+ auto ts = TopStatements();
+ if (Match(TokenType::RightBrace))
+ {
+ return ts;
+ }
+ }
+ return nullptr;
+ };
+
+ if (Match(TokenType::Function))
+ {
+ IPLString name;
+ if (Match(TokenType::Identifier))
+ {
+ name = Prev().Lexeme;
+ }
+ IPLVector<IPLString> identifiers;
+ if (FormalParameters(identifiers))
+ {
+ if (auto body = Body())
+ {
+ return IPLMakeSharePtr<FunctionDeclaration>(name, identifiers, body);
+ }
+ else
+ {
+ // TODO log error
+ return nullptr;
+ }
+ }
+ // TODO log error
+ return nullptr;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::ObjectLiteral()
+{
+ if (Match(TokenType::LeftBrace))
+ {
+ using FieldList = IPLVector<ExpressionPtr>;
+ auto MatchLiteralField = [&]() ->ExpressionPtr {
+ if (!Match(TokenType::Identifier))
+ {
+ return nullptr;
+ }
+ auto id = IPLMakeSharePtr<IdentifierExpression>(Prev().Lexeme);
+ if (!Match(TokenType::Colon))
+ {
+ return nullptr;
+ }
+ auto ae = AssignmentExpression(NormalType::Normal, AllowType::AllowIn);
+ return IPLMakeSharePtr<LiteralField>(id, ae);
+ };
+
+ auto MatchFieldList = [&](FieldList& result) -> bool {
+ auto lf = MatchLiteralField();
+ while (lf)
+ {
+ result.push_back(lf);
+ if (!Match(TokenType::Comma))
+ {
+ break;
+ }
+ lf = MatchLiteralField();
+ if (!lf)
+ {
+ // TODO log error
+ return false;
+ }
+ }
+ return true;
+ };
+ FieldList fl;
+ if (!MatchFieldList(fl))
+ {
+ return nullptr;
+ }
+ auto ol = IPLMakeSharePtr<LiteralObject>(fl);
+ if (Match(TokenType::RightBrace))
+ {
+ return ol;
+ }
+ // TODO Add error loging
+ assert(false);
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::ArrayLiteral()
+{
+ if (Match(TokenType::LeftSquareBracket))
+ {
+ auto LiteralElement = [&]() -> ExpressionPtr {
+ return AssignmentExpression(NormalType::Normal, AllowType::AllowIn);
+ };
+
+ auto ElementList = [&]() -> ExpressionPtr {
+ auto result = IPLMakeSharePtr<ListExpression>();
+ while (auto lf = LiteralElement())
+ {
+ result->GetValuesByRef().push_back(lf);
+ if (!Match(TokenType::Comma))
+ {
+ break;
+ }
+ }
+ return result;
+ };
+
+ auto el = ElementList();
+ if (Match(TokenType::RightSquareBracket)) {
+ return el;
+ }
+ // TODO Add error loging
+ assert(false);
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::SimpleExpression()
+{
+ if (Match(TokenType::Number))
+ {
+ return IPLMakeSharePtr<LiteralNumber>(Prev().Number);
+ }
+ else if (Match(TokenType::String))
+ {
+ const auto& lexeme = Prev().Lexeme;
+ const auto length = lexeme.length();
+ assert(length >= 2);
+ auto value = lexeme.substr(1, length-2);
+ return IPLMakeSharePtr<LiteralString>(value);
+ }
+ else if (Match(TokenType::Null))
+ {
+ return IPLMakeSharePtr<LiteralNull>();
+ }
+ else if (Match(TokenType::Undefined))
+ {
+ return IPLMakeSharePtr<LiteralUndefined>();
+ }
+ else if (Match(TokenType::True))
+ {
+ bool t = true;
+ return IPLMakeSharePtr<LiteralBoolean>(t);
+ }
+ else if (Match(TokenType::False))
+ {
+ bool f = false;
+ return IPLMakeSharePtr<LiteralBoolean>(f);
+ }
+ else if (Match(TokenType::Identifier))
+ {
+ return IPLMakeSharePtr<IdentifierExpression>(Prev().Lexeme);
+ }
+ else if (auto al = ArrayLiteral())
+ {
+ return al;
+ }
+ else if (auto p = ParenthesizedExpression())
+ {
+ return p;
+ }
+ else
+ {
+ // TODO implement
+ return ExpressionPtr();
+ }
+}
+
+ExpressionPtr Parser::LeftSideExpression(NormalType a)
+{
+ ExpressionPtr result;
+ auto ss = Snapshot();
+ if ((result = CallExpression(a)))
+ {
+ return result;
+ }
+ Restore(ss);
+ if ((result = ShortNewExpression()))
+ {
+ return result;
+ }
+ // TODO error
+ return nullptr;
+}
+
+ExpressionPtr Parser::CallExpression(NormalType a)
+{
+ ExpressionPtr result;
+
+ auto ss = Snapshot();
+ if (auto pe = PrimaryExpression(a))
+ {
+ result = IPLMakeSharePtr<Call>(pe);
+ }
+ else
+ {
+ Restore(ss);
+ }
+ if (auto fne = FullNewExpression())
+ {
+ result = IPLMakeSharePtr<::Call>(fne);
+ }
+
+ ExpressionPtr right;
+ do
+ {
+ right = CallExpressionHelper(a);
+ if (right)
+ {
+ result = IPLMakeSharePtr<::Call>(result, right);
+ }
+ } while (right);
+
+ return result;
+}
+
+ExpressionPtr Parser::CallExpressionHelper(NormalType a)
+{
+ if (Match(TokenType::LeftSquareBracket))
+ {
+ auto expr = Expression(NormalType::Normal, AllowType::AllowIn);
+ if (Match(TokenType::RightSquareBracket))
+ {
+ // return meaningfull expr
+ auto next = CallExpressionHelper(a);
+ return nullptr;
+ }
+ // TODO error
+ return nullptr;
+ }
+ if (Match(TokenType::Dot))
+ {
+ if (Match(TokenType::Identifier))
+ {
+ return IPLMakeSharePtr<MemberAccess>(Prev().Lexeme);
+ }
+ // TODO error
+ return nullptr;
+ }
+
+ if (auto args = Arguments())
+ {
+ // return meaningfull expr
+ auto next = CallExpressionHelper(a);
+ return nullptr;
+ }
+
+ return nullptr;
+};
+
+ExpressionPtr Parser::ShortNewExpression()
+{
+ if (Match(TokenType::New))
+ {
+ return ShortNewSubexpression();
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::ShortNewSubexpression()
+{
+ ExpressionPtr result;
+ auto ss = Snapshot();
+ if ((result = FullNewSubexpression()))
+ {
+ return result;
+ }
+ Restore(ss);
+ if ((result = ShortNewExpression()))
+ {
+ return result;
+ }
+ // TODO error
+ return nullptr;
+}
+
+ExpressionPtr Parser::FullNewExpression()
+{
+ if (Match(TokenType::New))
+ {
+ auto subExpr = FullNewSubexpression();
+ auto arguments = Arguments();
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::FullNewSubexpression()
+{
+ ExpressionPtr result;
+ if ((result = PrimaryExpression(NormalType::Normal)))
+ {
+ return result;
+ }
+ NOT_IMPLEMENTED;
+ return nullptr;
+}
+
+ExpressionPtr Parser::Unary(NormalType a)
+{
+ if (MatchOneOf({
+ TokenType::Delete,
+ TokenType::MinusMinus,
+ TokenType::PlusPlus,
+ }))
+ {
+ auto op = Prev().Type;
+ auto ls = LeftSideExpression(NormalType::Normal);
+ auto suffix = false;
+ return IPLMakeSharePtr<UnaryExpression>(ls, op, suffix);
+ }
+ else if (MatchOneOf({
+ TokenType::Void,
+ TokenType::Typeof,
+ TokenType::Plus,
+ TokenType::Minus,
+ TokenType::BitwiseNot,
+ TokenType::Bang,
+ }))
+ {
+ auto type = Prev().Type;
+ auto ls = Unary(NormalType::Normal);
+ auto suffix = false;
+ return IPLMakeSharePtr<UnaryExpression>(ls, type, suffix);
+ }
+ else
+ {
+ auto leftSide = LeftSideExpression(a);
+ if (MatchOneOf({ TokenType::PlusPlus, TokenType::MinusMinus }))
+ {
+ auto suffix = true;
+ return IPLMakeSharePtr<UnaryExpression>(leftSide, Prev().Type, suffix);
+ }
+ return leftSide;
+ }
+}
+
+ExpressionPtr Parser::MultiplicativeExpression(NormalType a)
+{
+ auto left = Unary(a);
+
+ while(MatchOneOf({ TokenType::Star, TokenType::Division, TokenType::Modulo }))
+ {
+ auto type = Prev().Type;
+ auto right = Unary(a);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+}
+
+ExpressionPtr Parser::AdditiveExpression(NormalType a)
+{
+ auto left = MultiplicativeExpression(a);
+ while (MatchOneOf({ TokenType::Plus, TokenType::Minus}))
+ {
+ auto type = Prev().Type;
+ auto right = MultiplicativeExpression(a);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+}
+
+ExpressionPtr Parser::ShiftExpression(NormalType a)
+{
+ auto left = AdditiveExpression(a);
+ while (MatchOneOf({ TokenType::LeftShift, TokenType::RightShift }))
+ {
+ auto type = Prev().Type;
+ auto right = AdditiveExpression(a);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+}
+
+ExpressionPtr Parser::RelationalExpression(NormalType a, AllowType)
+{
+ auto left = ShiftExpression(a);
+ while (MatchOneOf({ TokenType::Less,
+ TokenType::Greater,
+ TokenType::LessEqual,
+ TokenType::GreaterEqual,
+ TokenType::Instanceof,
+ TokenType::In
+ }))
+ {
+ auto type = Prev().Type;
+ auto right = ShiftExpression(a);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+}
+
+ExpressionPtr Parser::EqualityExpression(NormalType a, AllowType b)
+{
+ auto left = RelationalExpression(a, b);
+ while (MatchOneOf({TokenType::EqualEqual,
+ TokenType::BangEqual,
+ TokenType::StrictEqual,
+ TokenType::StrictNotEqual,
+
+ }))
+ {
+ auto type = Prev().Type;
+ auto right = RelationalExpression(a, b);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+}
+
+ExpressionPtr Parser::BitwiseExpression(NormalType a, AllowType b)
+{
+ auto BitwiseAndExpression = [&](NormalType _a, AllowType _b) -> ExpressionPtr {
+ auto left = EqualityExpression(_a, _b);
+ while (Match(TokenType::BitwiseAnd))
+ {
+ auto type = Prev().Type;
+ auto right = EqualityExpression(_a, _b);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+ };
+
+ auto BitwiseXorExpression = [&](NormalType _a, AllowType _b) -> ExpressionPtr {
+ auto left = BitwiseAndExpression(_a, _b);
+ while (Match(TokenType::BitwiseXor))
+ {
+ auto type = Prev().Type;
+ auto right = BitwiseAndExpression(_a, _b);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+ };
+
+ auto BitwiseOrExpression = [&](NormalType _a, AllowType _b) -> ExpressionPtr {
+ auto left = BitwiseXorExpression(_a, _b);
+ while (Match(TokenType::BitwiseOr))
+ {
+ auto type = Prev().Type;
+ auto right = BitwiseXorExpression(_a, _b);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+ };
+
+ return BitwiseOrExpression(a, b);
+}
+
+
+ExpressionPtr Parser::LogicalExpression(NormalType a, AllowType b)
+{
+ std::function<ExpressionPtr(NormalType a, AllowType b)> LogicalAndExpression;
+ LogicalAndExpression = [&](NormalType a, AllowType b) -> ExpressionPtr {
+ auto left = BitwiseExpression(a, b);
+ while (Match(TokenType::LogicalAnd))
+ {
+ auto type = Prev().Type;
+ auto right = BitwiseExpression(a, b);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+ };
+
+ auto LogicalOrExpression = [&](NormalType a, AllowType b) -> ExpressionPtr {
+ auto left = LogicalAndExpression(a, b);
+ while (Match(TokenType::LogicalAnd))
+ {
+ auto type = Prev().Type;
+ auto right = LogicalAndExpression(a, b);
+ left = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ }
+ return left;
+ };
+
+ return LogicalOrExpression(a, b);
+}
+
+ExpressionPtr Parser::ConditionalExpression(NormalType a, AllowType b)
+{
+ auto condition = LogicalExpression(a, b);
+ if (Match(TokenType::QuestionMark))
+ {
+ auto trueExpr= AssignmentExpression(NormalType::Normal, b);
+ (void)trueExpr;
+ if (Match(TokenType::Colon))
+ {
+ auto falseExpr = AssignmentExpression(NormalType::Normal, b);
+ (void)falseExpr;
+ // TODO implement trinary operator
+ assert(false);
+ return ExpressionPtr();
+ }
+ // TODO log parsing error
+ assert(false);
+ }
+ return condition;
+}
+
+ExpressionPtr Parser::AssignmentExpression(NormalType a, AllowType b)
+{
+ auto location = GetLocation();
+
+ auto left = ConditionalExpression(a, b);
+ if (!left)
+ {
+ left = LeftSideExpression(a);
+ }
+
+ if (!left)
+ {
+ return nullptr;
+ }
+ if (MatchOneOf({ TokenType::Equal,
+ TokenType::StarEqual,
+ TokenType::DivideEqual,
+ TokenType::ModuloEqual,
+ TokenType::PlusEqual,
+ TokenType::MinusEqual,
+ TokenType::LeftShiftEqual,
+ TokenType::RightShiftEqual,
+ TokenType::BitwiseAndEqual,
+ TokenType::BitwiseXorEqual,
+ TokenType::BitwiseOrEqual }))
+ {
+ auto type = Prev().Type;
+ auto right = AssignmentExpression(NormalType::Normal, b);
+ auto be = IPLMakeSharePtr<BinaryExpression>(left, right, type);
+ if (be)
+ {
+ be->SetLocation(location.Line, location.Column);
+ }
+ return be;
+ }
+
+ return left;
+}
+
+ExpressionPtr Parser::Expression(NormalType a, AllowType b)
+{
+ auto ae = AssignmentExpression(a, b);
+ while (Match(TokenType::Comma))
+ {
+ auto type = Prev().Type;
+
+ auto next = AssignmentExpression(a, b);
+ if (!next)
+ {
+ next = AssignmentExpression(NormalType::Normal, b);
+ }
+
+ if (next)
+ {
+ ae = IPLMakeSharePtr<BinaryExpression>(ae, next, type);
+ }
+ else
+ {
+ // TODO log
+ assert(false);
+ }
+ }
+ return ae;
+}
+
+
+ExpressionPtr Parser::Statement()
+{
+ ExpressionPtr result;
+ if ((result = EmptyStatement())) return result;
+ if ((result = Expression(NormalType::Initial, AllowType::AllowIn))) return result;
+ if ((result = VariableDefinition(AllowType::AllowIn))) return result;
+ if ((result = Block())) return result;
+ if ((result = LabeledStatement())) return result;
+ if ((result = IfStatementfull())) return result;
+ if ((result = SwitchStatement())) return result;
+ if ((result = DoStatement())) return result;
+ if ((result = WhileStatement())) return result;
+ if ((result = ForStatement())) return result;
+ if ((result = WithStatement())) return result;
+ if ((result = ContinueStatement())) return result;
+ if ((result = BreakStatement())) return result;
+ if ((result = OptionalLabel())) return result;
+ if ((result = ReturnStatement())) return result;
+ if ((result = TryStatement())) return result;
+ return result;
+}
+
+ExpressionPtr Parser::EmptyStatement()
+{
+ if (Match(TokenType::Semicolon))
+ {
+ // Not sure what to do here;
+ // This just will consume ;
+ return nullptr;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::VariableDefinition(AllowType b)
+{
+ auto VariableDeclaration = [&]() -> ExpressionPtr {
+ auto location = GetLocation();
+ if (Match(TokenType::Identifier))
+ {
+ auto id = Prev().Lexeme;
+ auto ae = CreateEmptyExpression();
+ if (Match(TokenType::Equal))
+ {
+ ae = AssignmentExpression(NormalType::Normal, b);
+ }
+ auto vd = IPLMakeSharePtr<VariableDefinitionExpression>(id, ae);
+ vd->SetLocation(location.Line, location.Column);
+ return vd;
+ }
+ return nullptr;
+ };
+
+ auto VariableDeclarationList = [&]() -> ExpressionPtr {
+ auto vdList = IPLMakeSharePtr<ListExpression>();
+ vdList->GetValuesByRef().push_back(VariableDeclaration());
+ while (Match(TokenType::Comma))
+ {
+ vdList->GetValuesByRef().push_back(VariableDeclaration());
+ }
+ return vdList;
+ };
+
+ if (Match(TokenType::Var))
+ {
+ return VariableDeclarationList();
+ }
+
+ return nullptr;
+}
+
+ExpressionPtr Parser::Block()
+{
+ auto BlockStatementsPrefix = [&]() -> ExpressionPtr {
+ auto StatementsList = IPLMakeSharePtr<BlockStatement>();
+ while (auto s = Statement())
+ {
+ StatementsList->GetValuesByRef().push_back(s);
+ }
+ return StatementsList;
+ };
+
+ if (Match(TokenType::LeftBrace))
+ {
+ auto statements = BlockStatementsPrefix();
+ if (Match(TokenType::RightBrace))
+ {
+ return statements;
+ }
+ else
+ {
+ // TODO log error - empty block?
+ assert(false);
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::LabeledStatement()
+{
+ auto location = GetLocation();
+ if (Match(TokenType::Identifier))
+ {
+ auto identifier = Prev().Lexeme;
+ auto stament = Statement();
+ auto ls = IPLMakeSharePtr<::LabeledStatement>(identifier, stament);
+ ls->SetLocation(location.Line, location.Column);
+ return ls;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::IfStatementfull()
+{
+ auto location = GetLocation();
+ if (Match(TokenType::If))
+ {
+ auto cond = ParenthesizedExpression();
+ auto ifBody = Statement();
+ ExpressionPtr elseBody = nullptr;
+ if (Match(TokenType::Else))
+ {
+ elseBody = Statement();
+ }
+ auto is = IPLMakeSharePtr<::IfStatement>(cond, ifBody, elseBody);
+ is->SetLocation(location.Line, location.Column);
+ return is;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::SwitchStatement()
+{
+ if (Match(TokenType::Switch))
+ {
+ auto cond = ParenthesizedExpression();
+ IPLVector<ExpressionPtr> cases;
+ ExpressionPtr defaultCase = nullptr;
+ if (Match(TokenType::LeftBrace))
+ {
+
+ while (!Match(TokenType::RightBrace))
+ {
+ if (Match(TokenType::Case))
+ {
+ auto expr = Expression(NormalType::Normal, AllowType::AllowIn);
+ if (Match(TokenType::Colon))
+ {
+ auto statement = Statement();
+ cases.push_back(IPLMakeSharePtr<CaseStatement>(expr, statement));
+ }
+ }
+ else if (Match(TokenType::Default))
+ {
+ if (Match(TokenType::Colon))
+ {
+ defaultCase = Statement();
+ }
+ }
+ }
+ return IPLMakeSharePtr<::SwitchStatement>(cond, cases, defaultCase);
+ }
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::DoStatement()
+{
+ if(Match(TokenType::Do))
+ {
+ auto body = Statement();
+ if (Match(TokenType::While))
+ {
+ auto cond = ParenthesizedExpression();
+ auto isDoWhile = true;
+ return IPLMakeSharePtr<::WhileStatement>(cond, body, isDoWhile);
+ }
+ // TODO log error
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::WhileStatement()
+{
+ auto location = GetLocation();
+ if (Match(TokenType::While))
+ {
+ auto cond = ParenthesizedExpression();
+ auto body = Statement();
+ auto isDoWhile = false;
+ auto ws = IPLMakeSharePtr<::WhileStatement>(cond, body, isDoWhile);
+ ws->SetLocation(location.Line, location.Column);
+ return ws;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::ForStatement()
+{
+ auto location = GetLocation();
+ if (Match(TokenType::For))
+ {
+ if (!Match(TokenType::LeftParen))
+ {
+ assert(false);
+ }
+ auto initializer = Expression(NormalType::Normal, AllowType::AllowIn);
+ if (!initializer)
+ {
+ initializer = VariableDefinition(AllowType::AllowIn);
+ }
+ if (!Match(TokenType::Semicolon))
+ {
+ assert(false);
+ }
+
+ auto cond = OptionalExpression();
+ if (!Match(TokenType::Semicolon))
+ {
+ assert(false);
+ }
+ auto iteration = OptionalExpression();
+ if (!Match(TokenType::RightParen))
+ {
+ assert(false);
+ }
+ auto body = Statement();
+ auto fs = IPLMakeSharePtr<::ForStatement>(initializer, cond, iteration, body);
+ fs->SetLocation(location.Line, location.Column);
+ return fs;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::WithStatement()
+{
+ return nullptr;
+}
+
+ExpressionPtr Parser::ContinueStatement()
+{
+ if (Match(TokenType::Continue))
+ {
+ ExpressionPtr expr = OptionalLabel();
+ return IPLMakeSharePtr<Continue>();
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::BreakStatement()
+{
+ if (Match(TokenType::Break))
+ {
+ ExpressionPtr expr = OptionalLabel();
+ return IPLMakeSharePtr<Break>();
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::OptionalLabel()
+{
+ if (Match(TokenType::Identifier))
+ {
+ return IPLMakeSharePtr<IdentifierExpression>(Prev().Lexeme);
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::ReturnStatement()
+{
+ if (Match(TokenType::Return))
+ {
+ auto type = TokenType::Return;
+ ExpressionPtr expr = OptionalExpression();
+ bool suffix = true;
+ return IPLMakeSharePtr<UnaryExpression>(expr, type, suffix);
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::TryStatement()
+{
+ return nullptr;
+}
+
+ExpressionPtr Parser::OptionalExpression()
+{
+ return Parser::Expression(NormalType::Normal, AllowType::AllowIn);
+}
+
+ExpressionPtr Parser::Arguments()
+{
+ if (Match(TokenType::LeftParen))
+ {
+ auto result = IPLMakeSharePtr<ListExpression>();
+ auto current = AssignmentExpression(NormalType::Normal, AllowType::AllowIn);
+ while (current)
+ {
+ result->GetValuesByRef().push_back(current);
+ if (Match(TokenType::Comma))
+ {
+ current = AssignmentExpression(NormalType::Normal, AllowType::AllowIn);
+ if (current)
+ {
+ // TODO error
+ return nullptr;
+ }
+ }
+ else
+ {
+ current = nullptr;
+ }
+ }
+
+ if (Match(TokenType::RightParen))
+ {
+ return result;
+ }
+ // TODO error
+ return nullptr;
+ }
+ return nullptr;
+}
+
+ExpressionPtr Parser::Parse()
+{
+ auto result = Parser::Program();
+ assert(m_Current + 1 == m_Tokens.size());
+ return result;
+}
+
+ExpressionPtr Parser::FunctionDefinition()
+{
+ auto FormalParameters = [&](IPLVector<IPLString>& identifiers) -> bool {
+ if (Match(TokenType::LeftParen))
+ {
+ while (Match(TokenType::Identifier))
+ {
+ identifiers.push_back(Prev().Lexeme);
+ if (!Match(TokenType::Comma))
+ {
+ break;
+ }
+ }
+
+ if (Match(TokenType::RightParen))
+ {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ auto Body = [&]() -> ExpressionPtr {
+
+ if (Match(TokenType::LeftBrace))
+ {
+ auto ts = TopStatements();
+ if (Match(TokenType::RightBrace))
+ {
+ return ts;
+ }
+ }
+ return nullptr;
+ };
+ auto location = GetLocation();
+ if (Match(TokenType::Function))
+ {
+ if (Match(TokenType::Identifier))
+ {
+ auto name = Prev().Lexeme;
+ IPLVector<IPLString> identifiers;
+ if (FormalParameters(identifiers))
+ {
+ if (auto body = Body())
+ {
+ auto fd = IPLMakeSharePtr<FunctionDeclaration>(name, identifiers, body);
+ fd->SetLocation(location.Line, location.Column);
+ return fd;
+ }
+ else
+ {
+ // TODO log error
+ return nullptr;
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+ExpressionPtr Parser::Program()
+{
+ return TopStatements();
+}
+
+ExpressionPtr Parser::TopStatements()
+{
+ auto statements = IPLMakeSharePtr<::TopStatements>();
+ while (auto ts = TopStatement())
+ {
+ statements->GetValuesByRef().push_back(ts);
+ }
+ return statements;
+}
+
+ExpressionPtr Parser::TopStatement()
+{
+ auto result = FunctionDefinition();
+ if (!result)
+ {
+ result = Statement();
+ }
+ return result;
+}
+
+ExpressionPtr Parse(const IPLVector<Token>& tokens, const std::function<void()>& onError)
+{
+ Parser p(tokens, onError);
+ return p.Parse();
+}
+
+Parser::InternalState Parser::Snapshot()
+{
+ return { m_Current };
+}
+
+void Parser::Restore(const InternalState& state)
+{
+ m_Current = state.Current;
+}