Adds support for parenthesized expressions
This commit is contained in:
parent
ae25598864
commit
aec07bd29a
|
@ -23,7 +23,7 @@ add_library(PorygonLang ${SRC_FILES})
|
||||||
add_executable(PorygonLangTests
|
add_executable(PorygonLangTests
|
||||||
${SRC_FILES}
|
${SRC_FILES}
|
||||||
src/Parser/LexerTests.cpp
|
src/Parser/LexerTests.cpp
|
||||||
integration_tests/integration_tests.cpp)
|
integration_tests/integration_tests.cpp src/Parser/ParserTests.cpp)
|
||||||
|
|
||||||
target_compile_definitions(PorygonLangTests PRIVATE TESTS_BUILD)
|
target_compile_definitions(PorygonLangTests PRIVATE TESTS_BUILD)
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,10 @@ IToken* Lexer::LexNext(char c){
|
||||||
return new SimpleToken(TokenKind::SlashToken, this -> Position - 1, 1);
|
return new SimpleToken(TokenKind::SlashToken, this -> Position - 1, 1);
|
||||||
case '*':
|
case '*':
|
||||||
return new SimpleToken(TokenKind::StarToken, this -> Position - 1, 1);
|
return new SimpleToken(TokenKind::StarToken, this -> Position - 1, 1);
|
||||||
|
case '(':
|
||||||
|
return new SimpleToken(TokenKind::OpenParenthesis, this -> Position - 1, 1);
|
||||||
|
case ')':
|
||||||
|
return new SimpleToken(TokenKind::CloseParenthesis, this -> Position - 1, 1);
|
||||||
case '=':
|
case '=':
|
||||||
if (Lexer::Peek() == '='){
|
if (Lexer::Peek() == '='){
|
||||||
Lexer::Next();
|
Lexer::Next();
|
||||||
|
|
|
@ -16,6 +16,7 @@ enum class ParsedExpressionKind{
|
||||||
|
|
||||||
Unary,
|
Unary,
|
||||||
Binary,
|
Binary,
|
||||||
|
Parenthesized,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParsedExpression {
|
class ParsedExpression {
|
||||||
|
@ -96,6 +97,23 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ParenthesizedExpression : public ParsedExpression{
|
||||||
|
ParsedExpression* _expression;
|
||||||
|
public:
|
||||||
|
ParsedExpressionKind GetKind() final{
|
||||||
|
return ParsedExpressionKind::Parenthesized;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ParenthesizedExpression(ParsedExpression* innerExpression, unsigned int start, unsigned int length)
|
||||||
|
: ParsedExpression(start, length){
|
||||||
|
_expression = innerExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedExpression* GetInnerExpression(){
|
||||||
|
return _expression;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class UnaryExpression : public ParsedExpression{
|
class UnaryExpression : public ParsedExpression{
|
||||||
UnaryOperatorKind _kind;
|
UnaryOperatorKind _kind;
|
||||||
ParsedExpression* _operand;
|
ParsedExpression* _operand;
|
||||||
|
|
|
@ -97,7 +97,7 @@ ParsedExpression* Parser::ParseBinaryExpression(IToken* current, OperatorPrecede
|
||||||
}
|
}
|
||||||
auto operatorKind = GetBinaryOperatorKind(next -> GetKind());
|
auto operatorKind = GetBinaryOperatorKind(next -> GetKind());
|
||||||
this -> Next();
|
this -> Next();
|
||||||
auto right = ParseBinaryExpression(this -> Next(), binaryPrecedence);
|
auto right = this -> ParseBinaryExpression(this -> Next(), binaryPrecedence);
|
||||||
auto startPos = left -> GetStartPosition();
|
auto startPos = left -> GetStartPosition();
|
||||||
left = new BinaryExpression(operatorKind, left, right, startPos, right -> GetEndPosition() - startPos);
|
left = new BinaryExpression(operatorKind, left, right, startPos, right -> GetEndPosition() - startPos);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,7 @@ ParsedExpression *Parser::ParsePrimaryExpression(IToken *current) {
|
||||||
case TokenKind ::Float: return new LiteralFloatExpression((FloatToken*)current);
|
case TokenKind ::Float: return new LiteralFloatExpression((FloatToken*)current);
|
||||||
case TokenKind ::TrueKeyword: return new LiteralBoolExpression(current);
|
case TokenKind ::TrueKeyword: return new LiteralBoolExpression(current);
|
||||||
case TokenKind ::FalseKeyword: 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.
|
// 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());
|
case TokenKind ::BadToken: return new BadExpression(current->GetStartPosition(), current->GetLength());
|
||||||
default:
|
default:
|
||||||
|
@ -118,6 +119,18 @@ ParsedExpression *Parser::ParsePrimaryExpression(IToken *current) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
IToken *Parser::Peek() {
|
||||||
return this -> _tokens[_position];
|
return this -> _tokens[_position];
|
||||||
|
@ -128,127 +141,3 @@ IToken *Parser::Next() {
|
||||||
return this -> _tokens[_position - 1];
|
return this -> _tokens[_position - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TESTS_BUILD
|
|
||||||
#include <catch.hpp>
|
|
||||||
|
|
||||||
TEST_CASE( "Parse single true keyword", "[parser]" ) {
|
|
||||||
vector<IToken*> v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};
|
|
||||||
Parser parser = Parser(v, nullptr);
|
|
||||||
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<IToken*> v {new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};
|
|
||||||
Parser parser = Parser(v, nullptr);
|
|
||||||
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<IToken*> 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 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<IToken*> v {
|
|
||||||
new SimpleToken(TokenKind::MinusToken,0,0),
|
|
||||||
new IntegerToken(10, 0, 0),
|
|
||||||
new SimpleToken(TokenKind::EndOfFile,0,0)
|
|
||||||
};
|
|
||||||
Parser parser = Parser(v, nullptr);
|
|
||||||
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( "Parse logical negation", "[parser]" ) {
|
|
||||||
vector<IToken*> 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 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::LogicalNegation);
|
|
||||||
auto operand = unary->GetOperand();
|
|
||||||
REQUIRE(operand->GetKind() == ParsedExpressionKind::LiteralBool);
|
|
||||||
CHECK(((LiteralBoolExpression*)operand)->GetValue() == false);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE( "Assert binary precedence", "[parser]" ) {
|
|
||||||
vector<IToken*> 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 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
|
|
|
@ -28,6 +28,7 @@ class Parser {
|
||||||
ParsedExpression* ParseExpression(IToken* current);
|
ParsedExpression* ParseExpression(IToken* current);
|
||||||
ParsedExpression* ParseBinaryExpression(IToken* current, OperatorPrecedence parentPrecedence);
|
ParsedExpression* ParseBinaryExpression(IToken* current, OperatorPrecedence parentPrecedence);
|
||||||
ParsedExpression* ParsePrimaryExpression(IToken* current);
|
ParsedExpression* ParsePrimaryExpression(IToken* current);
|
||||||
|
ParsedExpression* ParseParenthesizedExpression(IToken *current);
|
||||||
public:
|
public:
|
||||||
ParsedScriptStatement* Parse();
|
ParsedScriptStatement* Parse();
|
||||||
explicit Parser(vector<IToken*> tokens, Script* scriptData){
|
explicit Parser(vector<IToken*> tokens, Script* scriptData){
|
||||||
|
@ -35,6 +36,7 @@ public:
|
||||||
_position = 0;
|
_position = 0;
|
||||||
ScriptData = scriptData;
|
ScriptData = scriptData;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
|
||||||
|
#ifdef TESTS_BUILD
|
||||||
|
#include <catch.hpp>
|
||||||
|
#include "Parser.hpp"
|
||||||
|
|
||||||
|
TEST_CASE( "Parse single true keyword", "[parser]" ) {
|
||||||
|
vector<IToken*> v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};
|
||||||
|
Parser parser = Parser(v, nullptr);
|
||||||
|
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<IToken*> v {new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};
|
||||||
|
Parser parser = Parser(v, nullptr);
|
||||||
|
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<IToken*> 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 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<IToken*> v {
|
||||||
|
new SimpleToken(TokenKind::MinusToken,0,0),
|
||||||
|
new IntegerToken(10, 0, 0),
|
||||||
|
new SimpleToken(TokenKind::EndOfFile,0,0)
|
||||||
|
};
|
||||||
|
Parser parser = Parser(v, nullptr);
|
||||||
|
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( "Parse logical negation", "[parser]" ) {
|
||||||
|
vector<IToken*> 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 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::LogicalNegation);
|
||||||
|
auto operand = unary->GetOperand();
|
||||||
|
REQUIRE(operand->GetKind() == ParsedExpressionKind::LiteralBool);
|
||||||
|
CHECK(((LiteralBoolExpression*)operand)->GetValue() == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Are parenthesized expressions valid", "[parser]" ) {
|
||||||
|
vector<IToken*> 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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "Assert binary precedence", "[parser]" ) {
|
||||||
|
vector<IToken*> 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 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::Parenthesized);
|
||||||
|
auto innerExpression = ((ParenthesizedExpression*)expression) -> GetInnerExpression();
|
||||||
|
REQUIRE(innerExpression -> GetKind() == ParsedExpressionKind::LiteralInteger);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,6 +12,8 @@ enum class TokenKind{
|
||||||
StarToken,
|
StarToken,
|
||||||
AssignmentToken,
|
AssignmentToken,
|
||||||
EqualityToken,
|
EqualityToken,
|
||||||
|
OpenParenthesis,
|
||||||
|
CloseParenthesis,
|
||||||
|
|
||||||
Identifier,
|
Identifier,
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue