#include "Parser.hpp" #include "UnaryOperatorKind.hpp" #include "BinaryOperatorKind.hpp" ParsedScriptStatement* Parser::Parse() { vector statements; while (true){ auto next = this -> Next(); if (next->GetKind() == TokenKind::EndOfFile){ break; } if (next->GetKind() == TokenKind::WhiteSpace){ continue; } statements.push_back(this -> ParseStatement(next)); } return new ParsedScriptStatement(statements); } ParsedStatement* Parser::ParseStatement(IToken* current){ return new ParsedExpressionStatement(this -> ParseExpression(current)); } ParsedExpression* Parser::ParseExpression(IToken* current){ return this -> ParseBinaryExpression(current, OperatorPrecedence::No); } OperatorPrecedence GetUnaryPrecedence(TokenKind kind){ switch (kind){ case TokenKind::PlusToken: case TokenKind::MinusToken: case TokenKind::NotKeyword: return OperatorPrecedence::Unary; default: return OperatorPrecedence::No; } } UnaryOperatorKind GetUnaryOperatorKind(TokenKind kind){ switch (kind){ case TokenKind::PlusToken: return UnaryOperatorKind::Identity; case TokenKind::MinusToken: return UnaryOperatorKind::Negation; case TokenKind::NotKeyword: return UnaryOperatorKind::LogicalNegation; default: // This should never trigger, so throw. throw; } } BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind){ switch (kind){ case TokenKind::PlusToken: return BinaryOperatorKind ::Addition; case TokenKind::MinusToken: return BinaryOperatorKind ::Subtraction; case TokenKind::StarToken: return BinaryOperatorKind ::Multiplication; case TokenKind::SlashToken: return BinaryOperatorKind ::Division; case TokenKind::EqualityToken: return BinaryOperatorKind ::Equality; case TokenKind::AndKeyword: return BinaryOperatorKind ::LogicalAnd; case TokenKind::OrKeyword: return BinaryOperatorKind ::LogicalOr; default: // This should never trigger, so throw. throw; } } OperatorPrecedence GetBinaryPrecedence(TokenKind kind){ switch (kind){ case TokenKind::PlusToken: return OperatorPrecedence ::Additive; case TokenKind::MinusToken: return OperatorPrecedence ::Additive; case TokenKind::StarToken: return OperatorPrecedence ::Multiplication; case TokenKind::SlashToken: return OperatorPrecedence ::Multiplication; case TokenKind::EqualityToken: return OperatorPrecedence ::Equality; case TokenKind::AndKeyword: return OperatorPrecedence ::LogicalAnd; case TokenKind::OrKeyword: return OperatorPrecedence ::LogicalOr; default: return OperatorPrecedence::No; } } ParsedExpression* Parser::ParseBinaryExpression(IToken* current, OperatorPrecedence parentPrecedence){ OperatorPrecedence unaryPrecedence = GetUnaryPrecedence(current -> GetKind()); ParsedExpression* left; if (unaryPrecedence != OperatorPrecedence::No && unaryPrecedence >= parentPrecedence){ UnaryOperatorKind operatorKind = GetUnaryOperatorKind(current -> GetKind()); auto next = this -> Next(); auto operand = this -> ParseBinaryExpression(next, unaryPrecedence); auto startPos = current -> GetStartPosition(); left = new UnaryExpression(operatorKind, operand, startPos, operand -> GetEndPosition() - startPos); } else{ left = this -> ParsePrimaryExpression(current); } while (true){ auto next = this -> Peek(); OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind()); if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){ break; } auto operatorKind = GetBinaryOperatorKind(next -> GetKind()); this -> Next(); auto right = this -> ParseBinaryExpression(this -> Next(), binaryPrecedence); auto startPos = left -> GetStartPosition(); left = new BinaryExpression(operatorKind, left, right, startPos, right -> GetEndPosition() - startPos); } return left; } ParsedExpression *Parser::ParsePrimaryExpression(IToken *current) { switch (current -> GetKind()){ case TokenKind ::Integer: return new LiteralIntegerExpression((IntegerToken*)current); case TokenKind ::Float: return new LiteralFloatExpression((FloatToken*)current); case TokenKind ::String: return new LiteralStringExpression((StringToken*)current); case TokenKind ::TrueKeyword: return new LiteralBoolExpression(current); case TokenKind ::FalseKeyword: return new LiteralBoolExpression(current); case TokenKind ::OpenParenthesis: return this -> ParseParenthesizedExpression(current); // If we find a bad token here, we should have already logged it in the lexer, so don't log another error. case TokenKind ::BadToken: return new BadExpression(current->GetStartPosition(), current->GetLength()); default: this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(), current->GetLength()); return new BadExpression(current->GetStartPosition(), current->GetLength()); } } ParsedExpression *Parser::ParseParenthesizedExpression(IToken *current) { auto next = this -> Next(); auto expression = this -> ParseExpression(next); auto closeToken = this -> Next(); if (closeToken -> GetKind() != TokenKind::CloseParenthesis){ this -> ScriptData -> Diagnostics -> LogError(DiagnosticCode::UnexpectedToken, closeToken->GetStartPosition(), closeToken->GetLength()); return new BadExpression(closeToken->GetStartPosition(), closeToken->GetLength()); } auto start = current -> GetStartPosition(); return new ParenthesizedExpression(expression, start, closeToken->GetEndPosition() - start); } IToken *Parser::Peek() { return this -> _tokens[_position]; } IToken *Parser::Next() { this -> _position++; return this -> _tokens[_position - 1]; }