Add support for diagnostics to parser

This commit is contained in:
Deukhoofd 2019-05-21 14:00:14 +02:00
parent 2b35da3a7b
commit 99f50b6471
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
5 changed files with 40 additions and 24 deletions

View File

@ -4,6 +4,7 @@
enum class DiagnosticCode{ enum class DiagnosticCode{
UnexpectedCharacter, UnexpectedCharacter,
UnexpectedToken,
}; };
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP #endif //PORYGONLANG_DIAGNOSTICCODE_HPP

View File

@ -7,6 +7,8 @@
#include "../BinaryOperatorKind.hpp" #include "../BinaryOperatorKind.hpp"
enum class ParsedExpressionKind{ enum class ParsedExpressionKind{
Bad,
LiteralInteger, LiteralInteger,
LiteralFloat, LiteralFloat,
LiteralString, LiteralString,
@ -40,6 +42,15 @@ public:
} }
}; };
class BadExpression : public ParsedExpression{
public:
BadExpression(unsigned int position, unsigned int length) : ParsedExpression(position, length){}
ParsedExpressionKind GetKind() final{
return ParsedExpressionKind::Bad;
}
};
class LiteralIntegerExpression : public ParsedExpression{ class LiteralIntegerExpression : public ParsedExpression{
long _value; long _value;
public: public:

View File

@ -7,24 +7,24 @@
ParsedScriptStatement* Parser::Parse() { ParsedScriptStatement* Parser::Parse() {
vector<ParsedStatement*> statements; vector<ParsedStatement*> statements;
while (true){ while (true){
auto next = Parser::Next(); auto next = this -> Next();
if (next->GetKind() == TokenKind::EndOfFile){ if (next->GetKind() == TokenKind::EndOfFile){
break; break;
} }
if (next->GetKind() == TokenKind::WhiteSpace){ if (next->GetKind() == TokenKind::WhiteSpace){
continue; continue;
} }
statements.push_back(Parser::ParseStatement(next)); statements.push_back(this -> ParseStatement(next));
} }
return new ParsedScriptStatement(statements); return new ParsedScriptStatement(statements);
} }
ParsedStatement* Parser::ParseStatement(IToken* current){ ParsedStatement* Parser::ParseStatement(IToken* current){
return new ParsedExpressionStatement(Parser::ParseExpression(current)); return new ParsedExpressionStatement(this -> ParseExpression(current));
} }
ParsedExpression* Parser::ParseExpression(IToken* current){ ParsedExpression* Parser::ParseExpression(IToken* current){
return Parser::ParseBinaryExpression(current, OperatorPrecedence::No); return this -> ParseBinaryExpression(current, OperatorPrecedence::No);
} }
@ -44,7 +44,7 @@ UnaryOperatorKind GetUnaryOperatorKind(TokenKind kind){
case TokenKind::PlusToken: return UnaryOperatorKind::Identity; case TokenKind::PlusToken: return UnaryOperatorKind::Identity;
case TokenKind::MinusToken: return UnaryOperatorKind::Negation; case TokenKind::MinusToken: return UnaryOperatorKind::Negation;
case TokenKind::NotKeyword: return UnaryOperatorKind::LogicalNegation; case TokenKind::NotKeyword: return UnaryOperatorKind::LogicalNegation;
default: default: // This should never trigger, so throw.
throw; throw;
} }
} }
@ -58,7 +58,7 @@ BinaryOperatorKind GetBinaryOperatorKind(TokenKind kind){
case TokenKind::EqualityToken: return BinaryOperatorKind ::Equality; case TokenKind::EqualityToken: return BinaryOperatorKind ::Equality;
case TokenKind::AndKeyword: return BinaryOperatorKind ::LogicalAnd; case TokenKind::AndKeyword: return BinaryOperatorKind ::LogicalAnd;
case TokenKind::OrKeyword: return BinaryOperatorKind ::LogicalOr; case TokenKind::OrKeyword: return BinaryOperatorKind ::LogicalOr;
default: default: // This should never trigger, so throw.
throw; throw;
} }
} }
@ -82,22 +82,22 @@ ParsedExpression* Parser::ParseBinaryExpression(IToken* current, OperatorPrecede
ParsedExpression* left; ParsedExpression* left;
if (unaryPrecedence != OperatorPrecedence::No && unaryPrecedence >= parentPrecedence){ if (unaryPrecedence != OperatorPrecedence::No && unaryPrecedence >= parentPrecedence){
UnaryOperatorKind operatorKind = GetUnaryOperatorKind(current -> GetKind()); UnaryOperatorKind operatorKind = GetUnaryOperatorKind(current -> GetKind());
auto next = Parser::Next(); auto next = this -> Next();
auto operand = Parser::ParseBinaryExpression(next, unaryPrecedence); auto operand = this -> ParseBinaryExpression(next, unaryPrecedence);
auto startPos = current -> GetStartPosition(); auto startPos = current -> GetStartPosition();
left = new UnaryExpression(operatorKind, operand, startPos, operand -> GetEndPosition() - startPos); left = new UnaryExpression(operatorKind, operand, startPos, operand -> GetEndPosition() - startPos);
} else{ } else{
left = Parser::ParsePrimaryExpression(current); left = this -> ParsePrimaryExpression(current);
} }
while (true){ while (true){
auto next = Parser::Peek(); auto next = this -> Peek();
OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind()); OperatorPrecedence binaryPrecedence = GetBinaryPrecedence(next -> GetKind());
if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){ if (binaryPrecedence == OperatorPrecedence::No || binaryPrecedence <= parentPrecedence){
break; break;
} }
auto operatorKind = GetBinaryOperatorKind(next -> GetKind()); auto operatorKind = GetBinaryOperatorKind(next -> GetKind());
Parser::Next(); this -> Next();
auto right = ParseBinaryExpression(Parser::Next(), binaryPrecedence); auto right = 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);
} }
@ -111,18 +111,19 @@ ParsedExpression *Parser::ParsePrimaryExpression(IToken *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);
default: default:
throw; this -> ScriptData -> Diagnostics.LogError(DiagnosticCode::UnexpectedToken, current->GetStartPosition(), current->GetLength());
return new BadExpression(current->GetStartPosition(), current->GetLength());
} }
} }
IToken *Parser::Peek() { IToken *Parser::Peek() {
return Parser::_tokens[_position]; return this -> _tokens[_position];
} }
IToken *Parser::Next() { IToken *Parser::Next() {
Parser::_position++; this -> _position++;
return Parser::_tokens[_position - 1]; return this -> _tokens[_position - 1];
} }
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
@ -130,7 +131,7 @@ IToken *Parser::Next() {
TEST_CASE( "Parse single true keyword", "[parser]" ) { TEST_CASE( "Parse single true keyword", "[parser]" ) {
vector<IToken*> v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)}; vector<IToken*> v {new SimpleToken(TokenKind::TrueKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};
Parser parser = Parser(v); Parser parser = Parser(v, nullptr);
auto parsedStatements = parser.Parse() -> GetStatements(); auto parsedStatements = parser.Parse() -> GetStatements();
REQUIRE(parsedStatements.size() == 1); REQUIRE(parsedStatements.size() == 1);
auto firstStatement = parsedStatements[0]; auto firstStatement = parsedStatements[0];
@ -143,7 +144,7 @@ TEST_CASE( "Parse single true keyword", "[parser]" ) {
TEST_CASE( "Parse single false keyword", "[parser]" ) { TEST_CASE( "Parse single false keyword", "[parser]" ) {
vector<IToken*> v {new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)}; vector<IToken*> v {new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::EndOfFile,0,0)};
Parser parser = Parser(v); Parser parser = Parser(v, nullptr);
auto parsedStatements = parser.Parse() -> GetStatements(); auto parsedStatements = parser.Parse() -> GetStatements();
REQUIRE(parsedStatements.size() == 1); REQUIRE(parsedStatements.size() == 1);
auto firstStatement = parsedStatements[0]; auto firstStatement = parsedStatements[0];
@ -161,7 +162,7 @@ TEST_CASE( "Parse simple addition", "[parser]" ) {
new IntegerToken(10, 0, 0), new IntegerToken(10, 0, 0),
new SimpleToken(TokenKind::EndOfFile,0,0) new SimpleToken(TokenKind::EndOfFile,0,0)
}; };
Parser parser = Parser(v); Parser parser = Parser(v, nullptr);
auto parsedStatements = parser.Parse() -> GetStatements(); auto parsedStatements = parser.Parse() -> GetStatements();
REQUIRE(parsedStatements.size() == 1); REQUIRE(parsedStatements.size() == 1);
auto firstStatement = parsedStatements[0]; auto firstStatement = parsedStatements[0];
@ -184,7 +185,7 @@ TEST_CASE( "Parse simple negation", "[parser]" ) {
new IntegerToken(10, 0, 0), new IntegerToken(10, 0, 0),
new SimpleToken(TokenKind::EndOfFile,0,0) new SimpleToken(TokenKind::EndOfFile,0,0)
}; };
Parser parser = Parser(v); Parser parser = Parser(v, nullptr);
auto parsedStatements = parser.Parse() -> GetStatements(); auto parsedStatements = parser.Parse() -> GetStatements();
REQUIRE(parsedStatements.size() == 1); REQUIRE(parsedStatements.size() == 1);
auto firstStatement = parsedStatements[0]; auto firstStatement = parsedStatements[0];
@ -204,7 +205,7 @@ TEST_CASE( "Parse logical negation", "[parser]" ) {
new SimpleToken(TokenKind::FalseKeyword,0,0), new SimpleToken(TokenKind::FalseKeyword,0,0),
new SimpleToken(TokenKind::EndOfFile,0,0) new SimpleToken(TokenKind::EndOfFile,0,0)
}; };
Parser parser = Parser(v); Parser parser = Parser(v, nullptr);
auto parsedStatements = parser.Parse() -> GetStatements(); auto parsedStatements = parser.Parse() -> GetStatements();
REQUIRE(parsedStatements.size() == 1); REQUIRE(parsedStatements.size() == 1);
auto firstStatement = parsedStatements[0]; auto firstStatement = parsedStatements[0];
@ -227,7 +228,7 @@ TEST_CASE( "Assert binary precedence", "[parser]" ) {
new IntegerToken(6, 0, 0), new IntegerToken(6, 0, 0),
new SimpleToken(TokenKind::EndOfFile,0,0) new SimpleToken(TokenKind::EndOfFile,0,0)
}; };
Parser parser = Parser(v); Parser parser = Parser(v, nullptr);
auto parsedStatements = parser.Parse() -> GetStatements(); auto parsedStatements = parser.Parse() -> GetStatements();
REQUIRE(parsedStatements.size() == 1); REQUIRE(parsedStatements.size() == 1);
auto firstStatement = parsedStatements[0]; auto firstStatement = parsedStatements[0];

View File

@ -5,6 +5,7 @@
#include "ParsedStatements/ParsedStatement.hpp" #include "ParsedStatements/ParsedStatement.hpp"
#include "../Script.hpp"
enum class OperatorPrecedence { enum class OperatorPrecedence {
No, No,
@ -19,6 +20,7 @@ enum class OperatorPrecedence {
class Parser { class Parser {
vector<IToken*> _tokens; vector<IToken*> _tokens;
unsigned int _position; unsigned int _position;
Script* ScriptData;
IToken* Peek(); IToken* Peek();
IToken* Next(); IToken* Next();
@ -28,9 +30,10 @@ class Parser {
ParsedExpression* ParsePrimaryExpression(IToken* current); ParsedExpression* ParsePrimaryExpression(IToken* current);
public: public:
ParsedScriptStatement* Parse(); ParsedScriptStatement* Parse();
explicit Parser(vector<IToken*> tokens){ explicit Parser(vector<IToken*> tokens, Script* scriptData){
_tokens = std::move(tokens); _tokens = std::move(tokens);
_position = 0; _position = 0;
ScriptData = scriptData;
} }
}; };

View File

@ -14,7 +14,7 @@ Script Script::Create(string script) {
void Script::Parse(string script) { void Script::Parse(string script) {
auto lexer = Lexer(std::move(script), this); auto lexer = Lexer(std::move(script), this);
auto lexResult = lexer.Lex(); auto lexResult = lexer.Lex();
auto parser = Parser(lexResult); auto parser = Parser(lexResult, this);
auto parseResult = parser.Parse(); auto parseResult = parser.Parse();
for (auto token : lexResult){ for (auto token : lexResult){
delete token; delete token;