From a0c1724b2e908cd2f01073bc528145c9e92809ec Mon Sep 17 00:00:00 2001 From: ala89 Date: Thu, 4 Jan 2024 13:50:03 +0100 Subject: [PATCH] Rework stacktrace --- src/analysis.cpp | 18 +++++++++--------- src/errors.cpp | 12 ------------ src/include/errors.h | 15 +++------------ src/include/memory.h | 4 +++- src/include/types.h | 5 +++++ src/interpreter.cpp | 25 ++++++++++--------------- src/main.cpp | 5 +++-- src/memory.cpp | 31 ++++++++++++++++++++++++++----- 8 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/analysis.cpp b/src/analysis.cpp index 3fa6cc9..a367361 100644 --- a/src/analysis.cpp +++ b/src/analysis.cpp @@ -75,7 +75,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(token.data); if (!memory.contains(identifier)) - throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, identifier); + throw TypeError(ErrorType::UnknownIdentifier, token.pos, identifier); return memory.get(identifier).type; throw exception(); @@ -211,7 +211,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(token.data); if (memory.contains_top(identifier)) - throw RuntimeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); + throw TypeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); memory.declare(identifier, type); @@ -226,7 +226,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(token.data); if (memory.contains_top(identifier)) - throw RuntimeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); + throw TypeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); memory.declare(identifier, type); @@ -239,7 +239,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); if (!memory.contains(identifier)) - throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); + throw TypeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); Type type = memory.get(identifier).type; AnalysisResult res = analyze(node.children[1], memory); @@ -256,7 +256,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string identifier = get(identifierTok.data); if (!memory.contains(identifier)) - throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); + throw TypeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); return memory.get(identifier).type; } @@ -274,7 +274,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { try { memory.get_function_scope(); - throw RuntimeError(ErrorType::NestedFunction, token.pos, {}); + throw TypeError(ErrorType::NestedFunction, token.pos, {}); } catch (const InternalError& _) {} FunctionPrototype prototype = make_fn_prototype(node); @@ -310,12 +310,12 @@ AnalysisResult analyze(Node &ast, Memory &memory) { // Déclarée dans une fonction try { memory.get_function_scope(); - throw RuntimeError(ErrorType::NestedFunction, token.pos, {}); + throw TypeError(ErrorType::NestedFunction, token.pos, {}); } catch (const InternalError& _) {} // Corps de la fonction déjà déclaré if (memory.contains(function_name) && memory.get(function_name).initialized) - throw RuntimeError(ErrorType::FunctionRedefinition, token.pos, function_name); + throw TypeError(ErrorType::FunctionRedefinition, token.pos, function_name); FunctionPrototype prototype = make_fn_prototype(node); Type type = { @@ -356,7 +356,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { string function_name = get(token.data); if (!memory.contains(function_name)) - throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, function_name); + throw TypeError(ErrorType::UnknownIdentifier, token.pos, function_name); MemoryVar function = memory.get(function_name); diff --git a/src/errors.cpp b/src/errors.cpp index 7c0b51d..0503704 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -56,18 +56,6 @@ string UserError::get_message(void) const { } } -StackTrace& RuntimeError::get_trace(void) { - StackTraceEntry top = { "", lastPos }; - trace.push_back(top); - return trace; -} - -void RuntimeError::add_call(string callName, CodePosition callPos) { - StackTraceEntry entry = { callName, lastPos }; - trace.push_back(entry); - lastPos = callPos; -} - void print_error_position(vector history, CodePosition pos) { if (pos.column == -1 || pos.line == -1) return; diff --git a/src/include/errors.h b/src/include/errors.h index 3dc8a1e..408bc5a 100644 --- a/src/include/errors.h +++ b/src/include/errors.h @@ -56,9 +56,6 @@ enum class ErrorType { using ErrorData = variant; -using StackTraceEntry = tuple; -using StackTrace = vector; - class UserError : public exception { public: explicit UserError(ErrorType type, CodePosition pos, ErrorData data = {}) @@ -94,17 +91,11 @@ public: }; class RuntimeError : public UserError { -private: - StackTrace trace; - CodePosition lastPos; - public: - explicit RuntimeError(ErrorType type, CodePosition pos, ErrorData data = {}) - : UserError(type, pos, data), trace(), lastPos() {} + explicit RuntimeError(ErrorType type, CodePosition pos, StackTrace trace, ErrorData data = {}) + : UserError(type, pos, data), trace(trace) {} - StackTrace& get_trace(void); - - void add_call(string name, CodePosition pos); + const StackTrace trace; }; class InternalError : public exception { diff --git a/src/include/memory.h b/src/include/memory.h index c076484..eaa9062 100644 --- a/src/include/memory.h +++ b/src/include/memory.h @@ -13,7 +13,7 @@ class Memory { public: bool contains(string identifier); bool contains_top(string identifier); - void add_scope(ScopeType type, MemoryVar* fn = NULL); + void add_scope(ScopeType type, MemoryVar* fn = NULL, CodePosition entry_pos = { }); void remove_scope(void); MemoryVar& get(string identifier); @@ -21,6 +21,8 @@ class Memory { void declare(string identifier, Type type); void update(string identifier, EvalResult value); + StackTrace get_trace(CodePosition pos); + Scope& _debug_top(void); void _debug_print(void); diff --git a/src/include/types.h b/src/include/types.h index d639d38..3a19f87 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -50,6 +50,9 @@ struct Token { CodePosition pos; }; +using StackTraceEntry = tuple; +using StackTrace = vector; + /** Grammar: Prog -> Instruction Prog | Instruction @@ -206,6 +209,7 @@ struct MemoryVar { EvalResult value; Type type; bool initialized; + string identifier; }; struct Scope { @@ -213,6 +217,7 @@ struct Scope { int depth; ScopeType type; MemoryVar* fn; + CodePosition entry_pos; }; #endif \ No newline at end of file diff --git a/src/interpreter.cpp b/src/interpreter.cpp index fe96fc5..f82df65 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -185,7 +185,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) - throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier); vector argValues = {}; for (Node arg : args) { @@ -196,7 +196,7 @@ EvalResult eval(Node &ast, Memory &memory) { EvalResult res = {}; - memory.add_scope(ScopeType::Function, &var); + memory.add_scope(ScopeType::Function, &var, identifierTok.pos); try { for (size_t i = 1; i < prototype.size(); i++) { @@ -221,11 +221,6 @@ EvalResult eval(Node &ast, Memory &memory) { memory.remove_scope(); } - catch (RuntimeError& e) { - e.add_call(identifier, identifierTok.pos); - - throw; - } catch (...) { memory.remove_scope(); @@ -373,13 +368,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(ErrorType::DivisionByZero, node.pos); + if (d2 == 0) throw RuntimeError(ErrorType::DivisionByZero, node.pos, memory.get_trace(node.pos)); return d1 / d2; } else { int i1 = get(e1); int i2 = get(e2); - if (i2 == 0) throw RuntimeError(ErrorType::DivisionByZero, node.pos); + if (i2 == 0) throw RuntimeError(ErrorType::DivisionByZero, node.pos, memory.get_trace(node.pos)); return i1 / i2; } } break; @@ -389,7 +384,7 @@ EvalResult eval(Node &ast, Memory &memory) { int i1 = get(e1); int i2 = get(e2); - if (i2 == 0) throw RuntimeError(ErrorType::ModuloByZero, node.pos); + if (i2 == 0) throw RuntimeError(ErrorType::ModuloByZero, node.pos, memory.get_trace(node.pos)); return i1 % i2; } break; case NodeType::UnaryPlus: { @@ -468,7 +463,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier); } else if (var.type.type == TypeType::Int) { memory.update(identifier, get(var.value) + 1); @@ -485,7 +480,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier); } else if (var.type.type == TypeType::Int) { int oldVal = get(var.value); @@ -503,7 +498,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier); } else if (var.type.type == TypeType::Int) { memory.update(identifier, get(var.value) - 1); @@ -520,7 +515,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) { - throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); + throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier); } else if (var.type.type == TypeType::Int) { int oldVal = get(var.value); @@ -555,7 +550,7 @@ EvalResult eval(Node &ast, Memory &memory) { MemoryVar& var = memory.get(identifier); if (!var.initialized) - throw RuntimeError(ErrorType::UninitializedIdentifier, token.pos, identifier); + throw RuntimeError(ErrorType::UninitializedIdentifier, token.pos, memory.get_trace(token.pos), identifier); return var.value; } break; diff --git a/src/main.cpp b/src/main.cpp index cfdc764..a8fc983 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,10 +118,11 @@ int main(int argc, char* argv[]) { print_error_position(input, e.pos); cout << BOLD RED "Type Error: " RESET << e.get_message() << endl; - } catch (RuntimeError& e) { + } catch (const RuntimeError& e) { print_error_position(input, e.pos); cout << BOLD RED "Runtime Error: " RESET << e.get_message() << endl; - for (auto e : e.get_trace()) { + + for (StackTraceEntry e : e.trace) { cout << get<0>(e) << " " << (get<1>(e).line + 1) << endl; } } diff --git a/src/memory.cpp b/src/memory.cpp index 037879b..3ab6e9c 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -22,12 +22,13 @@ bool Memory::contains_top(string identifier) { return top.vars.contains(identifier); } -void Memory::add_scope(ScopeType type, MemoryVar* fn) { +void Memory::add_scope(ScopeType type, MemoryVar* fn, CodePosition entry_pos) { Scope& top = scopes.back(); - scopes.emplace_back(); - scopes.back().depth = top.depth + 1; - scopes.back().type = type; - scopes.back().fn = fn; + Scope& newScope = scopes.emplace_back(); + newScope.depth = top.depth + 1; + newScope.type = type; + newScope.fn = fn; + newScope.entry_pos = entry_pos; } void Memory::remove_scope(void) { @@ -56,6 +57,7 @@ Scope& Memory::get_function_scope(void) { void Memory::declare(string identifier, Type type) { Scope& top = scopes.back(); top.vars[identifier].type = type; + top.vars[identifier].identifier = identifier; } void Memory::update(string identifier, EvalResult value) { @@ -71,6 +73,25 @@ void Memory::update(string identifier, EvalResult value) { throw exception(); } +StackTrace Memory::get_trace(CodePosition pos) { + StackTrace trace = {}; + + for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { + Scope& scope = *rit; + if (scope.type == ScopeType::Function) { + MemoryVar fn = *(scope.fn); + StackTraceEntry entry = { fn.identifier, pos }; + trace.push_back(entry); + pos = scope.entry_pos; + } + } + + StackTraceEntry top = { "", pos }; + trace.push_back(top); + + return trace; +} + Scope& Memory::_debug_top(void) { Scope& top = scopes.back(); return top;