Added Result class for error handling while parsing

This commit is contained in:
apio 2022-08-03 14:44:35 +00:00
parent 582ce26776
commit 77317650f5
5 changed files with 41 additions and 26 deletions

View File

@ -1 +1 @@
1+2+3*5 2+2*6+

View File

@ -170,6 +170,9 @@ TokenStream Lexer::lex(const std::string& text)
case ']': case ']':
result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text)); result.push_back(Token::make_with_line({TT_Exclamation, loc}, current_line_text));
break; break;
case '\377':
result.push_back(Token(TT_EOF,loc));
return result;
default: default:
Error::throw_error(loc, current_line_text, "unknown character"); Error::throw_error(loc, current_line_text, "unknown character");
} }

View File

@ -15,7 +15,9 @@ std::shared_ptr<Parser> Parser::new_parser(const TokenStream& tokens)
std::shared_ptr<ASTNode> Parser::parse() std::shared_ptr<ASTNode> Parser::parse()
{ {
advance(); advance();
return expr(); auto result = expr();
if(result.is_error()) result.ethrow();
return result.get();
} }
int Parser::advance() int Parser::advance()
@ -28,45 +30,51 @@ int Parser::advance()
return 1; return 1;
} }
std::shared_ptr<NumberNode> Parser::factor() Result<ExprNode> Parser::factor()
{ {
Token token = *current_token; Token& token = *current_token;
if (token.tk_type == TT_Number) if (token.tk_type == TT_Number)
{ {
advance(); advance();
return std::make_shared<IntegerNode>(token.int_value); return Ok<ExprNode>(new IntegerNode(token.int_value),&token);
} }
if (token.tk_type == TT_Float) if (token.tk_type == TT_Float)
{ {
advance(); advance();
return std::make_shared<FloatNode>(token.float_value); return Ok<ExprNode>(new FloatNode(token.float_value),&token);
} }
return Err<ExprNode>("expected a number",&token);
} }
std::shared_ptr<ExprNode> Parser::term() Result<ExprNode> Parser::term()
{ {
std::shared_ptr<ExprNode> left = factor(); Result<ExprNode> left = factor();
if(left.is_error()) return left;
while (current_token->tk_type == TT_Mul || current_token->tk_type == TT_Div) while (current_token->tk_type == TT_Mul || current_token->tk_type == TT_Div)
{ {
Token op = *current_token; Token& op = *current_token;
advance(); advance();
std::shared_ptr<ExprNode> right = factor(); Result<ExprNode> right = factor();
left = std::make_shared<MulNode>(left, right, op.tk_type == TT_Mul ? '*' : '/'); if(right.is_error()) return right;
left = Ok<ExprNode>(new MulNode(left.get(), right.get(), op.tk_type == TT_Mul ? '*' : '/'), &op);
} }
return left; return left;
} }
std::shared_ptr<ExprNode> Parser::expr() Result<ExprNode> Parser::expr()
{ {
std::shared_ptr<ExprNode> left = term(); Result<ExprNode> left = term();
if(left.is_error()) return left;
while (current_token->tk_type == TT_Plus || current_token->tk_type == TT_Minus) while (current_token->tk_type == TT_Plus || current_token->tk_type == TT_Minus)
{ {
Token op = *current_token; Token& op = *current_token;
advance(); advance();
std::shared_ptr<ExprNode> right = term(); Result<ExprNode> right = term();
left = std::make_shared<SumNode>(left, right, op.tk_type == TT_Plus ? '+' : '-'); if(right.is_error()) return right;
left = Ok<ExprNode>(new SumNode(left.get(), right.get(), op.tk_type == TT_Plus ? '+' : '-'),&op);
} }
return left; return left;
} }

View File

@ -3,6 +3,7 @@
#include "AST/SumNode.h" #include "AST/SumNode.h"
#include "Error.h" #include "Error.h"
#include "Lexer.h" #include "Lexer.h"
#include "Result.h"
#include "sapphirepch.h" #include "sapphirepch.h"
/* Parser class for the Sapphire compiler. */ /* Parser class for the Sapphire compiler. */
@ -15,9 +16,9 @@ class Parser
int advance(); int advance();
Token* current_token; Token* current_token;
std::shared_ptr<NumberNode> factor(); Result<ExprNode> factor();
std::shared_ptr<ExprNode> expr(); Result<ExprNode> expr();
std::shared_ptr<ExprNode> term(); Result<ExprNode> term();
public: public:
/* Construct a new Parser with the given TokenStream. */ /* Construct a new Parser with the given TokenStream. */

View File

@ -9,27 +9,30 @@ class Result
public: public:
Result() = default; Result() = default;
bool is_error() const { return m_is_error; } bool is_error() const { return m_is_error; }
void ethrow(); void ethrow() { std::exit(1); }
std::shared_ptr<T> get() { return m_result; } std::shared_ptr<T> get()
{
return m_result;
}
protected: protected:
std::shared_ptr<Token> m_token; Token* m_token;
std::shared_ptr<T> m_result; std::shared_ptr<T> m_result;
bool m_is_error; bool m_is_error;
std::string m_error; std::string m_error;
Result(T* result, Token* token) : m_result(result), m_token(token) {} Result(T* result, Token* token) : m_result(result), m_token(token), m_is_error(false) {}
Result(const std::string& error, Token* token) : m_error(std::move(error)), m_token(token) {} Result(const std::string& error, Token* token) : m_error(std::move(error)), m_token(token), m_is_error(true) {}
}; };
template<typename T> template<typename T>
class Ok : public Result<T> class Ok final : public Result<T>
{ {
public: public:
Ok(T* result, Token* token) : Result<T>(result,token) {} Ok(T* result, Token* token) : Result<T>(result,token) {}
}; };
template<typename T> template<typename T>
class Err : public Result<T> class Err final : public Result<T>
{ {
public: public:
Err(const std::string& error, Token* token) : Result<T>(std::move(error),token) {} Err(const std::string& error, Token* token) : Result<T>(std::move(error),token) {}