diff --git a/src/analysis.cpp b/src/analysis.cpp index 48d1bca..6cbb94c 100644 --- a/src/analysis.cpp +++ b/src/analysis.cpp @@ -9,7 +9,7 @@ bool bool_castable(AnalysisResult type) { void check_comparable(AnalysisResult res1, AnalysisResult res2, CodePosition pos) { if (holds_alternative(res1) || holds_alternative(res2)) { - throw TypeError("Incomparable values", pos); + throw TypeError(ErrorType::TypesNotComparable, pos); } Type type1 = get(res1); @@ -25,11 +25,11 @@ void check_comparable(AnalysisResult res1, AnalysisResult res2, CodePosition pos return; } default: - throw TypeError("Incomparable values", pos); + throw TypeError(ErrorType::TypesNotComparable, pos); } } default: - throw TypeError("Incomparable values", pos); + throw TypeError(ErrorType::TypesNotComparable, pos); } } @@ -53,7 +53,7 @@ Type try_string_to_type(string type_name, CodePosition pos) { Type type = string_to_type(type_name); return type; } catch (...) { - throw TypeError("Unknown type '"+type_name+"'", pos); + throw TypeError(ErrorType::UnknownType, pos, type_name); } } @@ -74,7 +74,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(token.data); if (!memory.contains(identifier)) - throw RuntimeError("Unknown identifier \""+identifier+"\"", token.pos); + throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, identifier); return memory.get(identifier).type; throw exception(); @@ -100,7 +100,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { case NodeType::If: case NodeType::IfElse: { if (!bool_castable(analyze(node.children[0], memory))) { - throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[0])); + throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } analyze(node.children[1], memory); @@ -111,7 +111,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { } break; case NodeType::While: { if (!bool_castable(analyze(node.children[0], memory))) { - throw TypeError("Can't find a cast to bool", get_node_pos(node.children[0])); + throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } analyze(node.children[1], memory); @@ -123,7 +123,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { analyze(node.children[0], memory); if (!bool_castable(analyze(node.children[1], memory))) { - throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[1])); + throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool"); } analyze(node.children[2], memory); @@ -142,17 +142,17 @@ AnalysisResult analyze(Node &ast, Memory &memory) { case NodeType::Lor: case NodeType::Land: { if (!bool_castable(analyze(node.children[0], memory))) { - throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[0])); + throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } if (!bool_castable(analyze(node.children[1], memory))) { - throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[1])); + throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool"); } return Type::Int; } break; case NodeType::Neg: { if (!bool_castable(analyze(node.children[0], memory))) { - throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[0])); + throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } return Type::Int; @@ -184,10 +184,10 @@ AnalysisResult analyze(Node &ast, Memory &memory) { AnalysisResult e2 = analyze(node.children[1], memory); if (holds_alternative(e1) || get(e1) != Type::Int) { - throw TypeError("Expression must have integral type", get_node_pos(node.children[0])); + throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[0])); } if (holds_alternative(e2) || get(e2) != Type::Int) { - throw TypeError("Expression must have integral type", get_node_pos(node.children[1])); + throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[1])); } return Type::Int; @@ -197,7 +197,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { AnalysisResult res = analyze(node.children[0], memory); if (holds_alternative(res) || !is_arithmetic_type(get(res))) { - throw TypeError("Expressions must have arithmetic type", get_node_pos(node.children[1])); + throw TypeError(ErrorType::ExpectedArithmeticType, get_node_pos(node.children[0])); } return get(res); @@ -210,7 +210,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(token.data); if (memory.contains_top(identifier)) - throw RuntimeError("Already defined identifier \""+identifier+"\"", token.pos); + throw RuntimeError(ErrorType::AlreadyDefinedIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); memory.declare(identifier, type); @@ -225,7 +225,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(token.data); if (memory.contains_top(identifier)) - throw TypeError("Already defined identifier \""+identifier+"\"", token.pos); + throw RuntimeError(ErrorType::AlreadyDefinedIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); memory.declare(identifier, type); @@ -238,7 +238,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); if (!memory.contains(identifier)) - throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); Type type = memory.get(identifier).type; AnalysisResult res = analyze(node.children[1], memory); @@ -255,7 +255,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(identifierTok.data); if (!memory.contains(identifier)) - throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); return memory.get(identifier).type; } diff --git a/src/include/interpreter.h b/src/include/interpreter.h index 2dec731..975699a 100644 --- a/src/include/interpreter.h +++ b/src/include/interpreter.h @@ -12,20 +12,16 @@ using namespace std; */ EvalResult eval(Node &ast, Memory& memory); -class BreakException : public runtime_error { +class BreakException : public InternalError { public: - explicit BreakException(const string& message, CodePosition pos) - : runtime_error(message), pos(pos) {} - - const CodePosition pos; + explicit BreakException(CodePosition pos) + : InternalError(pos) {} }; -class ContinueException : public runtime_error { +class ContinueException : public InternalError { public: - explicit ContinueException(const string& message, CodePosition pos) - : runtime_error(message), pos(pos) {} - - const CodePosition pos; + explicit ContinueException(CodePosition pos) + : InternalError(pos) {} }; #endif \ No newline at end of file diff --git a/src/include/parser.h b/src/include/parser.h index ad3f31c..b3e98c6 100644 --- a/src/include/parser.h +++ b/src/include/parser.h @@ -10,10 +10,10 @@ using namespace std; /** * Utilisé pour revenir en arrière quand quelque chose n'est pas reconnu */ -class ParseException : public std::exception { - const char* what() const noexcept override { - return "Parse Exception"; - } +class ParseException : public InternalError { +public: + explicit ParseException(CodePosition pos = {}) + : InternalError(pos) {} }; /** diff --git a/src/include/types.h b/src/include/types.h index ba75bd5..14156f5 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -183,26 +183,50 @@ struct Scope { /** * Errors */ -class SyntaxError : public runtime_error { +enum class ErrorType { DivisionByZero, ModuloByZero, ExpectedIntegralType, ExpectedArithmeticType, UninitializedIdentifier, UnknownIdentifier, AlreadyDefinedIdentifier, EmptyInput, UnknownToken, InvalidSyntax, ExceptedLParen, ExpectedRParen, ExpectedRCurlyBracket, ExpectedSemicolon, DependentDeclaration, TypesNotComparable, TypeNotCastable, UnknownType }; + +using ErrorData = variant; + +class UserError : public exception { public: - explicit SyntaxError(const string& message, CodePosition pos) - : runtime_error(message), pos(pos) {} + explicit UserError(ErrorType type, CodePosition pos, ErrorData data = {}) + : pos(pos), type(type), data(data) {} + + const char* what() const noexcept override { + return "User error occurred."; + } const CodePosition pos; + const ErrorType type; + const ErrorData data; }; -class TypeError : public runtime_error { +class SyntaxError : public UserError { public: - explicit TypeError(const string& message, CodePosition pos) - : runtime_error(message), pos(pos) {} - - const CodePosition pos; + explicit SyntaxError(ErrorType type, CodePosition pos, ErrorData data = {}) + : UserError(type, pos, data) {} }; -class RuntimeError : public runtime_error { +class TypeError : public UserError { public: - explicit RuntimeError(const string& message, CodePosition pos) - : runtime_error(message), pos(pos) {} + explicit TypeError(ErrorType type, CodePosition pos, ErrorData data = {}) + : UserError(type, pos, data) {} +}; + +class RuntimeError : public UserError { +public: + explicit RuntimeError(ErrorType type, CodePosition pos, ErrorData data = {}) + : UserError(type, pos, data) {} +}; + +class InternalError : public exception { +public: + explicit InternalError(CodePosition pos = {}) + : pos(pos) {} + + const char* what() const noexcept override { + return "Internal error occurred."; + } const CodePosition pos; }; diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 82a4f86..37303fe 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -241,13 +241,13 @@ EvalResult eval(Node &ast, Memory &memory) { if (holds_alternative(e1) || holds_alternative(e2)) { double d1 = double_cast(e1); double d2 = double_cast(e2); - if (d2 == 0) throw RuntimeError("Division by 0", node.pos); + if (d2 == 0) throw RuntimeError(ErrorType::DivisionByZero, node.pos); return d1 / d2; } else { int i1 = get(e1); int i2 = get(e2); - if (i2 == 0) throw RuntimeError("Division by 0", node.pos); + if (i2 == 0) throw RuntimeError(ErrorType::DivisionByZero, node.pos); return i1 / i2; } } break; @@ -257,7 +257,7 @@ EvalResult eval(Node &ast, Memory &memory) { int i1 = get(e1); int i2 = get(e2); - if (i2 == 0) throw RuntimeError("Modulo by 0", node.pos); + if (i2 == 0) throw RuntimeError(ErrorType::ModuloByZero, node.pos); return i1 % i2; } break; case NodeType::UnaryPlus: { @@ -332,7 +332,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); } else if (var.type == Type::Int) { memory.update(identifier, get(var.value) + 1); @@ -349,7 +349,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); } else if (var.type == Type::Int) { int oldVal = get(var.value); @@ -367,7 +367,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); } else if (var.type == Type::Int) { memory.update(identifier, get(var.value) - 1); @@ -384,7 +384,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); } else if (var.type == Type::Int) { int oldVal = get(var.value); @@ -396,7 +396,7 @@ EvalResult eval(Node &ast, Memory &memory) { } } default: { - throw RuntimeError("Not Implemented", node.pos); + throw exception(); } } } @@ -419,15 +419,15 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) - throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", token.pos); + throw RuntimeError(ErrorType::UninitializedIdentifier, token.pos, identifier); return var.value; } break; case TokenType::Break: { - throw BreakException("", token.pos); + throw BreakException(token.pos); } break; case TokenType::Continue: { - throw ContinueException("", token.pos); + throw ContinueException(token.pos); } break; default: throw exception(); diff --git a/src/parser.cpp b/src/parser.cpp index 936cdc6..2def335 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -55,14 +55,14 @@ Node parse(vector tokens) { reverse(tokens.begin(), tokens.end()); if (tokens.size() == 0) { - throw SyntaxError("Input must not be empty", null_pos); + throw SyntaxError(ErrorType::EmptyInput, null_pos); } ParseReturn ret = parse_prog(tokens); if (ret.tokens.size() != 0) { CodePosition pos = ret.tokens.back().pos; - throw SyntaxError("Unable to parse", pos); + throw SyntaxError(ErrorType::InvalidSyntax, pos); } return ret.node; @@ -169,7 +169,7 @@ ParseReturn parse_statement(vector tokens) { tokens.pop_back(); if (tokens.back().type != TokenType::Semicolon) - throw SyntaxError("Expected ';'", tokens.back().pos); + throw SyntaxError(ErrorType::ExpectedSemicolon, tokens.back().pos); tokens.pop_back(); return { @@ -195,7 +195,7 @@ ParseReturn parse_statement(vector tokens) { tokens.pop_back(); if (tokens.back().type != TokenType::LParenthese) // Opening ( - throw SyntaxError("Missing '('", tokens.back().pos); + throw SyntaxError(ErrorType::ExceptedLParen, tokens.back().pos); tokens.pop_back(); ParseReturn ret = parse_expr(tokens); // Expr @@ -203,7 +203,7 @@ ParseReturn parse_statement(vector tokens) { int nb_tok = ret.tokens.size(); // Closing ) if (nb_tok == 0 || ret.tokens.back().type != TokenType::RParenthese) throw SyntaxError( - "Missing ')'", + ErrorType::ExpectedRParen, nb_tok == 0 ? tokens.back().pos : ret.tokens.back().pos ); @@ -215,7 +215,7 @@ ParseReturn parse_statement(vector tokens) { ret = parse_instruction(tokens); // Instruction1 } catch (const ParseException& pex) { throw SyntaxError( - "Invalid Syntax", + ErrorType::InvalidSyntax, pos=tokens.back().pos ); } @@ -224,7 +224,7 @@ ParseReturn parse_statement(vector tokens) { ( get(ret.node).type == NodeType::AssignedDeclaration || get(ret.node).type == NodeType::Declaration ) ) throw SyntaxError( - "a dependent statement may not be a declaration", + ErrorType::DependentDeclaration, pos=tokens.back().pos ); @@ -263,7 +263,7 @@ ParseReturn parse_statement(vector tokens) { tokens.pop_back(); if (tokens.back().type != TokenType::LParenthese) // Opening ( - throw SyntaxError("Missing '('", tokens.back().pos); + throw SyntaxError(ErrorType::ExceptedLParen, tokens.back().pos); tokens.pop_back(); ParseReturn ret1; @@ -283,7 +283,7 @@ ParseReturn parse_statement(vector tokens) { int nb_tok = ret1.tokens.size(); // First ; if (nb_tok == 0 || ret1.tokens.back().type != TokenType::Semicolon) throw SyntaxError( - "Expected ';'", + ErrorType::ExpectedSemicolon, nb_tok == 0 ? tokens.back().pos : ret1.tokens.back().pos ); tokens = ret1.tokens; @@ -302,7 +302,7 @@ ParseReturn parse_statement(vector tokens) { nb_tok = ret2.tokens.size(); // Second ; if (nb_tok == 0 || ret2.tokens.back().type != TokenType::Semicolon) throw SyntaxError( - "Expected ';'", + ErrorType::ExpectedSemicolon, nb_tok == 0 ? tokens.back().pos : ret2.tokens.back().pos ); tokens = ret2.tokens; @@ -321,7 +321,7 @@ ParseReturn parse_statement(vector tokens) { nb_tok = ret3.tokens.size(); // Closing ) if (nb_tok == 0 || ret3.tokens.back().type != TokenType::RParenthese) throw SyntaxError( - "Missing ')'", + ErrorType::ExpectedRParen, nb_tok == 0 ? tokens.back().pos : ret3.tokens.back().pos ); tokens = ret3.tokens; @@ -351,14 +351,14 @@ ParseReturn parse_statement(vector tokens) { tokens.back().type != TokenType::RCurlyBracket ) throw SyntaxError( - "Invalid Syntax. Missing ';' ?", + ErrorType::InvalidSyntax, tokens.back().pos ); int nb_tok = ret.tokens.size(); if (nb_tok == 0 || ret.tokens.back().type != TokenType::RCurlyBracket) throw SyntaxError( - "Missing '}'", + ErrorType::ExpectedRCurlyBracket, nb_tok == 0 ? tokens.back().pos : ret.tokens.back().pos ); @@ -800,7 +800,7 @@ ParseReturn parse_val(vector tokens) { tokens=ret.tokens; if (tokens.size() < 1 || tokens.back().type != TokenType::RParenthese) - throw SyntaxError("Missing ')'", tokens.back().pos); + throw SyntaxError(ErrorType::ExpectedRParen, tokens.back().pos); tokens.pop_back(); diff --git a/src/tokenize.cpp b/src/tokenize.cpp index cc113fe..756703c 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -259,7 +259,7 @@ vector tokenize(vector input, int initial_line) { continue; } - throw SyntaxError("Unknown token", pos); + throw SyntaxError(ErrorType::UnknownToken, pos); } }