PorygonLang/src/Parser/Parser.cpp

144 lines
5.9 KiB
C++

#include "Parser.hpp"
#include "UnaryOperatorKind.hpp"
#include "BinaryOperatorKind.hpp"
ParsedScriptStatement* Parser::Parse() {
vector<ParsedStatement*> 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 ::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];
}