#include "Parser.hpp" #include "UnaryOperatorKind.hpp" #include "BinaryOperatorKind.hpp" ParsedScriptStatement* Parser::Parse() { vector statements; while (true){ auto next = Parser::Next(); if (next->GetKind() == TokenKind::EndOfFile){ break; } if (next->GetKind() == TokenKind::WhiteSpace){ continue; } statements.push_back(Parser::ParseStatement(next)); } return new ParsedScriptStatement(statements); } ParsedStatement* Parser::ParseStatement(IToken* current){ return new ParsedExpressionStatement(Parser::ParseExpression(current)); } ParsedExpression* Parser::ParseExpression(IToken* current){ return Parser::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: 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: 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 = Parser::Next(); auto operand = Parser::ParseBinaryExpression(next, unaryPrecedence); auto startPos = current -> GetStartPosition(); left = new UnaryExpression(operatorKind, operand, startPos, operand -> GetEndPosition() - startPos); } else{ left = Parser::ParsePrimaryExpression(current); } while (true){ auto next = Parser::Peek(); OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind()); if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){ break; } auto operatorKind = GetBinaryOperatorKind(next -> GetKind()); Parser::Next(); auto right = ParseBinaryExpression(Parser::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 ::TrueKeyword: return new LiteralBoolExpression(current); case TokenKind ::FalseKeyword: return new LiteralBoolExpression(current); default: throw; } } IToken *Parser::Peek() { return Parser::_tokens[_position]; } IToken *Parser::Next() { Parser::_position++; return Parser::_tokens[_position - 1]; } #ifdef TESTS_BUILD #include TEST_CASE( "Parse single true keyword", "[parser]" ) { vector v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)}; Parser parser = Parser(v); auto parsedStatements = parser.Parse() -> GetStatements(); REQUIRE(parsedStatements.size() == 1); auto firstStatement = parsedStatements[0]; REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::LiteralBool); auto boolean = ((LiteralBoolExpression*)expression); REQUIRE(boolean->GetValue() == true); } TEST_CASE( "Parse single false keyword", "[parser]" ) { vector v {new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)}; Parser parser = Parser(v); auto parsedStatements = parser.Parse() -> GetStatements(); REQUIRE(parsedStatements.size() == 1); auto firstStatement = parsedStatements[0]; REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::LiteralBool); auto boolean = ((LiteralBoolExpression*)expression); REQUIRE(boolean->GetValue() == false); } TEST_CASE( "Parse simple addition", "[parser]" ) { vector v { new IntegerToken(5, 0, 0), new SimpleToken(TokenKind::PlusToken,0,0), new IntegerToken(10, 0, 0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v); auto parsedStatements = parser.Parse() -> GetStatements(); REQUIRE(parsedStatements.size() == 1); auto firstStatement = parsedStatements[0]; REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::Binary); auto binary = ((BinaryExpression*)expression); CHECK(binary -> GetOperatorKind() == BinaryOperatorKind::Addition); auto left = binary->GetLeft(); auto right = binary->GetRight(); REQUIRE(left->GetKind() == ParsedExpressionKind::LiteralInteger); REQUIRE(right->GetKind() == ParsedExpressionKind::LiteralInteger); CHECK(((LiteralIntegerExpression*)left)->GetValue() == 5); CHECK(((LiteralIntegerExpression*)right)->GetValue() == 10); } TEST_CASE( "Parse simple negation", "[parser]" ) { vector v { new SimpleToken(TokenKind::MinusToken,0,0), new IntegerToken(10, 0, 0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v); auto parsedStatements = parser.Parse() -> GetStatements(); REQUIRE(parsedStatements.size() == 1); auto firstStatement = parsedStatements[0]; REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::Unary); auto unary = ((UnaryExpression*)expression); CHECK(unary -> GetOperatorKind() == UnaryOperatorKind::Negation); auto operand = unary->GetOperand(); REQUIRE(operand->GetKind() == ParsedExpressionKind::LiteralInteger); CHECK(((LiteralIntegerExpression*)operand)->GetValue() == 10); } TEST_CASE( "Assert binary precedence", "[parser]" ) { vector v { new IntegerToken(5, 0, 0), new SimpleToken(TokenKind::PlusToken,0,0), new IntegerToken(10, 0, 0), new SimpleToken(TokenKind::StarToken,0,0), new IntegerToken(6, 0, 0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v); auto parsedStatements = parser.Parse() -> GetStatements(); REQUIRE(parsedStatements.size() == 1); auto firstStatement = parsedStatements[0]; REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::Binary); auto binary = ((BinaryExpression*)expression); CHECK(binary -> GetOperatorKind() == BinaryOperatorKind::Addition); auto left = binary->GetLeft(); auto right = binary->GetRight(); REQUIRE(left->GetKind() == ParsedExpressionKind::LiteralInteger); REQUIRE(right->GetKind() == ParsedExpressionKind::Binary); CHECK(((LiteralIntegerExpression*)left)->GetValue() == 5); left = ((BinaryExpression*)right)->GetLeft(); right = ((BinaryExpression*)right)->GetRight(); CHECK(((LiteralIntegerExpression*)left)->GetValue() == 10); CHECK(((LiteralIntegerExpression*)right)->GetValue() == 6); } #endif