#ifdef TESTS_BUILD #include #include "../../src/Parser/Parser.hpp" using namespace Porygon::Parser; 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, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::LiteralBool); auto boolean = ((LiteralBoolExpression*)expression); REQUIRE(boolean->GetValue()); for (auto t : v){ delete t; } delete parsedScript; } 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, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::LiteralBool); auto boolean = ((LiteralBoolExpression*)expression); REQUIRE_FALSE(boolean->GetValue()); for (auto t : v){ delete t; } delete parsedScript; } 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, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(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); for (auto t : v){ delete t; } delete parsedScript; } 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, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(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); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Parse logical negation", "[parser]" ) { vector v { new SimpleToken(TokenKind::NotKeyword,0,0), new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::Unary); auto unary = ((UnaryExpression*)expression); CHECK(unary -> GetOperatorKind() == UnaryOperatorKind::LogicalNegation); auto operand = unary->GetOperand(); REQUIRE(operand->GetKind() == ParsedExpressionKind::LiteralBool); CHECK_FALSE(((LiteralBoolExpression*)operand)->GetValue()); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Are parenthesized expressions valid", "[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, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(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); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Assert binary precedence", "[parser]" ) { vector v { new SimpleToken(TokenKind::OpenParenthesis,0,0), new IntegerToken(10, 0, 0), new SimpleToken(TokenKind::CloseParenthesis,0,0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::Parenthesized); auto innerExpression = ((ParenthesizedExpression*)expression) -> GetInnerExpression(); REQUIRE(innerExpression -> GetKind() == ParsedExpressionKind::LiteralInteger); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Parse String Tokens", "[parser]" ) { vector v {new StringToken(u"foo bar", 0,0), new SimpleToken(TokenKind::EndOfFile,0,0)}; Parser parser = Parser(v, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Expression); auto expression = ((ParsedExpressionStatement*)firstStatement)->GetExpression(); REQUIRE(expression -> GetKind() == ParsedExpressionKind::LiteralString); auto boolean = ((LiteralStringExpression*)expression); REQUIRE(boolean->GetValue() == u"foo bar"); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Parse Global Assignment", "[parser]" ) { vector v { new IdentifierToken(HashedString::CreateLookup(u"foo"),0,0), new SimpleToken(TokenKind::AssignmentToken,0,0), new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Assignment); auto assignment = (ParsedAssignmentStatement*)firstStatement; REQUIRE(!assignment -> IsLocal()); REQUIRE(assignment->GetIdentifier().GetHash() == HashedString::CreateLookup(u"foo").GetHash()); REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Parse local Assignment", "[parser]" ) { vector v { new SimpleToken(TokenKind::LocalKeyword,0,0), new IdentifierToken(HashedString(new u16string(u"foo")),0,0), new SimpleToken(TokenKind::AssignmentToken,0,0), new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0) }; Parser parser = Parser(v, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Assignment); auto assignment = (ParsedAssignmentStatement*)firstStatement; REQUIRE(assignment -> IsLocal()); REQUIRE(assignment->GetIdentifier().GetHash() == HashedString::CreateLookup(u"foo").GetHash()); REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); for (auto t : v){ delete t; } delete parsedScript; } TEST_CASE( "Parse function declaration", "[parser]" ){ vector v { new SimpleToken(TokenKind::FunctionKeyword,0,0), new IdentifierToken(HashedString(new u16string(u"foo")),0,0), new SimpleToken(TokenKind::OpenParenthesis,0,0), new IdentifierToken(HashedString(new u16string(u"number")),0,0), new IdentifierToken(HashedString(new u16string(u"bar")),0,0), new SimpleToken(TokenKind::CommaToken,0,0), new IdentifierToken(HashedString(new u16string(u"number")),0,0), new IdentifierToken(HashedString(new u16string(u"par")),0,0), new SimpleToken(TokenKind::CloseParenthesis,0,0), new IdentifierToken(HashedString(new u16string(u"bar")),0,0), new SimpleToken(TokenKind::PlusToken,0,0), new IdentifierToken(HashedString(new u16string(u"par")),0,0), new SimpleToken(TokenKind::EndKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0), }; Parser parser = Parser(v, nullptr); auto parsedScript = parser.Parse(); auto parsedStatements = parsedScript -> GetStatements(); REQUIRE(parsedStatements->size() == 1); auto firstStatement = parsedStatements -> at(0); REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::FunctionDeclaration); auto functionDeclaration = (ParsedFunctionDeclarationStatement*)firstStatement; REQUIRE(functionDeclaration->GetIdentifier() == HashedString::CreateLookup(u"foo")); auto parameters = functionDeclaration->GetParameters(); CHECK(*parameters -> at(0) ->GetType() == HashedString::CreateLookup(u"number")); CHECK(*parameters -> at(0) ->GetIdentifier() == HashedString::CreateLookup(u"bar")); CHECK(*parameters -> at(1) ->GetType() == HashedString::CreateLookup(u"number")); CHECK(*parameters -> at(1) ->GetIdentifier() == HashedString::CreateLookup(u"par")); for (auto t : v){ delete t; } delete parsedScript; } #endif