2019-05-20 15:45:03 +00:00
|
|
|
|
|
|
|
#include "Parser.hpp"
|
|
|
|
#include "UnaryOperatorKind.hpp"
|
|
|
|
#include "BinaryOperatorKind.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
ParsedScriptStatement* Parser::Parse() {
|
|
|
|
vector<ParsedStatement*> statements;
|
|
|
|
while (true){
|
2019-05-21 12:00:14 +00:00
|
|
|
auto next = this -> Next();
|
2019-05-20 15:45:03 +00:00
|
|
|
if (next->GetKind() == TokenKind::EndOfFile){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (next->GetKind() == TokenKind::WhiteSpace){
|
|
|
|
continue;
|
|
|
|
}
|
2019-05-21 12:00:14 +00:00
|
|
|
statements.push_back(this -> ParseStatement(next));
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
return new ParsedScriptStatement(statements);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParsedStatement* Parser::ParseStatement(IToken* current){
|
2019-05-21 12:00:14 +00:00
|
|
|
return new ParsedExpressionStatement(this -> ParseExpression(current));
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ParsedExpression* Parser::ParseExpression(IToken* current){
|
2019-05-21 12:00:14 +00:00
|
|
|
return this -> ParseBinaryExpression(current, OperatorPrecedence::No);
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
2019-05-21 12:00:14 +00:00
|
|
|
default: // This should never trigger, so throw.
|
2019-05-20 15:45:03 +00:00
|
|
|
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;
|
2019-05-21 12:00:14 +00:00
|
|
|
default: // This should never trigger, so throw.
|
2019-05-20 15:45:03 +00:00
|
|
|
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());
|
2019-05-21 12:00:14 +00:00
|
|
|
auto next = this -> Next();
|
|
|
|
auto operand = this -> ParseBinaryExpression(next, unaryPrecedence);
|
2019-05-20 15:45:03 +00:00
|
|
|
auto startPos = current -> GetStartPosition();
|
|
|
|
left = new UnaryExpression(operatorKind, operand, startPos, operand -> GetEndPosition() - startPos);
|
|
|
|
} else{
|
2019-05-21 12:00:14 +00:00
|
|
|
left = this -> ParsePrimaryExpression(current);
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
while (true){
|
2019-05-21 12:00:14 +00:00
|
|
|
auto next = this -> Peek();
|
2019-05-20 15:45:03 +00:00
|
|
|
OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind());
|
|
|
|
if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
auto operatorKind = GetBinaryOperatorKind(next -> GetKind());
|
2019-05-21 12:00:14 +00:00
|
|
|
this -> Next();
|
|
|
|
auto right = ParseBinaryExpression(this -> Next(), binaryPrecedence);
|
2019-05-20 15:45:03 +00:00
|
|
|
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:
|
2019-05-21 12:00:14 +00:00
|
|
|
this -> ScriptData -> Diagnostics.LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(), current->GetLength());
|
|
|
|
return new BadExpression(current->GetStartPosition(), current->GetLength());
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IToken *Parser::Peek() {
|
2019-05-21 12:00:14 +00:00
|
|
|
return this -> _tokens[_position];
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
IToken *Parser::Next() {
|
2019-05-21 12:00:14 +00:00
|
|
|
this -> _position++;
|
|
|
|
return this -> _tokens[_position - 1];
|
2019-05-20 15:45:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#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)};
|
2019-05-21 12:00:14 +00:00
|
|
|
Parser parser = Parser(v, nullptr);
|
2019-05-20 15:45:03 +00:00
|
|
|
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)};
|
2019-05-21 12:00:14 +00:00
|
|
|
Parser parser = Parser(v, nullptr);
|
2019-05-20 15:45:03 +00:00
|
|
|
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)
|
|
|
|
};
|
2019-05-21 12:00:14 +00:00
|
|
|
Parser parser = Parser(v, nullptr);
|
2019-05-20 15:45:03 +00:00
|
|
|
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)
|
|
|
|
};
|
2019-05-21 12:00:14 +00:00
|
|
|
Parser parser = Parser(v, nullptr);
|
2019-05-20 15:45:03 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-05-21 10:59:15 +00:00
|
|
|
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)
|
|
|
|
};
|
2019-05-21 12:00:14 +00:00
|
|
|
Parser parser = Parser(v, nullptr);
|
2019-05-21 10:59:15 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-05-20 15:45:03 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
};
|
2019-05-21 12:00:14 +00:00
|
|
|
Parser parser = Parser(v, nullptr);
|
2019-05-20 15:45:03 +00:00
|
|
|
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
|