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{
UnexpectedCharacter,
UnexpectedToken,
};
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP

View File

@ -7,6 +7,8 @@
#include "../BinaryOperatorKind.hpp"
enum class ParsedExpressionKind{
Bad,
LiteralInteger,
LiteralFloat,
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{
long _value;
public:

View File

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

View File

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

View File

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