Rework stacktrace

This commit is contained in:
ala89 2024-01-04 13:50:03 +01:00
parent dda04d8859
commit a0c1724b2e
8 changed files with 59 additions and 56 deletions

View File

@ -75,7 +75,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
string identifier = get<string>(token.data); string identifier = get<string>(token.data);
if (!memory.contains(identifier)) if (!memory.contains(identifier))
throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, identifier); throw TypeError(ErrorType::UnknownIdentifier, token.pos, identifier);
return memory.get(identifier).type; return memory.get(identifier).type;
throw exception(); throw exception();
@ -211,7 +211,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
string identifier = get<string>(token.data); string identifier = get<string>(token.data);
if (memory.contains_top(identifier)) 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); Type type = try_string_to_type(type_string, type_token.pos);
memory.declare(identifier, type); memory.declare(identifier, type);
@ -226,7 +226,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
string identifier = get<string>(token.data); string identifier = get<string>(token.data);
if (memory.contains_top(identifier)) 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); Type type = try_string_to_type(type_string, type_token.pos);
memory.declare(identifier, type); memory.declare(identifier, type);
@ -239,7 +239,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
Token identifierTok = get<Token>(node.children[0]); Token identifierTok = get<Token>(node.children[0]);
string identifier = get<string>(identifierTok.data); string identifier = get<string>(identifierTok.data);
if (!memory.contains(identifier)) if (!memory.contains(identifier))
throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); throw TypeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier);
Type type = memory.get(identifier).type; Type type = memory.get(identifier).type;
AnalysisResult res = analyze(node.children[1], memory); AnalysisResult res = analyze(node.children[1], memory);
@ -256,7 +256,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
string identifier = get<string>(identifierTok.data); string identifier = get<string>(identifierTok.data);
if (!memory.contains(identifier)) if (!memory.contains(identifier))
throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); throw TypeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier);
return memory.get(identifier).type; return memory.get(identifier).type;
} }
@ -274,7 +274,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
try { try {
memory.get_function_scope(); memory.get_function_scope();
throw RuntimeError(ErrorType::NestedFunction, token.pos, {}); throw TypeError(ErrorType::NestedFunction, token.pos, {});
} catch (const InternalError& _) {} } catch (const InternalError& _) {}
FunctionPrototype prototype = make_fn_prototype(node); FunctionPrototype prototype = make_fn_prototype(node);
@ -310,12 +310,12 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
// Déclarée dans une fonction // Déclarée dans une fonction
try { try {
memory.get_function_scope(); memory.get_function_scope();
throw RuntimeError(ErrorType::NestedFunction, token.pos, {}); throw TypeError(ErrorType::NestedFunction, token.pos, {});
} catch (const InternalError& _) {} } catch (const InternalError& _) {}
// Corps de la fonction déjà déclaré // Corps de la fonction déjà déclaré
if (memory.contains(function_name) && memory.get(function_name).initialized) 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); FunctionPrototype prototype = make_fn_prototype(node);
Type type = { Type type = {
@ -356,7 +356,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
string function_name = get<string>(token.data); string function_name = get<string>(token.data);
if (!memory.contains(function_name)) 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); MemoryVar function = memory.get(function_name);

View File

@ -56,18 +56,6 @@ string UserError::get_message(void) const {
} }
} }
StackTrace& RuntimeError::get_trace(void) {
StackTraceEntry top = { "<repl>", 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<string> history, CodePosition pos) { void print_error_position(vector<string> history, CodePosition pos) {
if (pos.column == -1 || pos.line == -1) if (pos.column == -1 || pos.line == -1)
return; return;

View File

@ -56,9 +56,6 @@ enum class ErrorType {
using ErrorData = variant<monostate, string, int>; using ErrorData = variant<monostate, string, int>;
using StackTraceEntry = tuple<string, CodePosition>;
using StackTrace = vector<StackTraceEntry>;
class UserError : public exception { class UserError : public exception {
public: public:
explicit UserError(ErrorType type, CodePosition pos, ErrorData data = {}) explicit UserError(ErrorType type, CodePosition pos, ErrorData data = {})
@ -94,17 +91,11 @@ public:
}; };
class RuntimeError : public UserError { class RuntimeError : public UserError {
private:
StackTrace trace;
CodePosition lastPos;
public: public:
explicit RuntimeError(ErrorType type, CodePosition pos, ErrorData data = {}) explicit RuntimeError(ErrorType type, CodePosition pos, StackTrace trace, ErrorData data = {})
: UserError(type, pos, data), trace(), lastPos() {} : UserError(type, pos, data), trace(trace) {}
StackTrace& get_trace(void); const StackTrace trace;
void add_call(string name, CodePosition pos);
}; };
class InternalError : public exception { class InternalError : public exception {

View File

@ -13,7 +13,7 @@ class Memory {
public: public:
bool contains(string identifier); bool contains(string identifier);
bool contains_top(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); void remove_scope(void);
MemoryVar& get(string identifier); MemoryVar& get(string identifier);
@ -21,6 +21,8 @@ class Memory {
void declare(string identifier, Type type); void declare(string identifier, Type type);
void update(string identifier, EvalResult value); void update(string identifier, EvalResult value);
StackTrace get_trace(CodePosition pos);
Scope& _debug_top(void); Scope& _debug_top(void);
void _debug_print(void); void _debug_print(void);

View File

@ -50,6 +50,9 @@ struct Token {
CodePosition pos; CodePosition pos;
}; };
using StackTraceEntry = tuple<string, CodePosition>;
using StackTrace = vector<StackTraceEntry>;
/** Grammar: /** Grammar:
Prog -> Instruction Prog | Instruction Prog -> Instruction Prog | Instruction
@ -206,6 +209,7 @@ struct MemoryVar {
EvalResult value; EvalResult value;
Type type; Type type;
bool initialized; bool initialized;
string identifier;
}; };
struct Scope { struct Scope {
@ -213,6 +217,7 @@ struct Scope {
int depth; int depth;
ScopeType type; ScopeType type;
MemoryVar* fn; MemoryVar* fn;
CodePosition entry_pos;
}; };
#endif #endif

View File

@ -185,7 +185,7 @@ EvalResult eval(Node &ast, Memory &memory) {
MemoryVar& var = memory.get(identifier); MemoryVar& var = memory.get(identifier);
if (!var.initialized) if (!var.initialized)
throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, identifier); throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier);
vector<EvalResult> argValues = {}; vector<EvalResult> argValues = {};
for (Node arg : args) { for (Node arg : args) {
@ -196,7 +196,7 @@ EvalResult eval(Node &ast, Memory &memory) {
EvalResult res = {}; EvalResult res = {};
memory.add_scope(ScopeType::Function, &var); memory.add_scope(ScopeType::Function, &var, identifierTok.pos);
try { try {
for (size_t i = 1; i < prototype.size(); i++) { for (size_t i = 1; i < prototype.size(); i++) {
@ -221,11 +221,6 @@ EvalResult eval(Node &ast, Memory &memory) {
memory.remove_scope(); memory.remove_scope();
} }
catch (RuntimeError& e) {
e.add_call(identifier, identifierTok.pos);
throw;
}
catch (...) { catch (...) {
memory.remove_scope(); memory.remove_scope();
@ -373,13 +368,13 @@ EvalResult eval(Node &ast, Memory &memory) {
if (holds_alternative<double>(e1) || holds_alternative<double>(e2)) { if (holds_alternative<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1); double d1 = double_cast(e1);
double d2 = double_cast(e2); 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; return d1 / d2;
} }
else { else {
int i1 = get<int>(e1); int i1 = get<int>(e1);
int i2 = get<int>(e2); int i2 = get<int>(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; return i1 / i2;
} }
} break; } break;
@ -389,7 +384,7 @@ EvalResult eval(Node &ast, Memory &memory) {
int i1 = get<int>(e1); int i1 = get<int>(e1);
int i2 = get<int>(e2); int i2 = get<int>(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; return i1 % i2;
} break; } break;
case NodeType::UnaryPlus: { case NodeType::UnaryPlus: {
@ -468,7 +463,7 @@ EvalResult eval(Node &ast, Memory &memory) {
MemoryVar& var = memory.get(identifier); MemoryVar& var = memory.get(identifier);
if (!var.initialized) { 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) { else if (var.type.type == TypeType::Int) {
memory.update(identifier, get<int>(var.value) + 1); memory.update(identifier, get<int>(var.value) + 1);
@ -485,7 +480,7 @@ EvalResult eval(Node &ast, Memory &memory) {
MemoryVar& var = memory.get(identifier); MemoryVar& var = memory.get(identifier);
if (!var.initialized) { 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) { else if (var.type.type == TypeType::Int) {
int oldVal = get<int>(var.value); int oldVal = get<int>(var.value);
@ -503,7 +498,7 @@ EvalResult eval(Node &ast, Memory &memory) {
MemoryVar& var = memory.get(identifier); MemoryVar& var = memory.get(identifier);
if (!var.initialized) { 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) { else if (var.type.type == TypeType::Int) {
memory.update(identifier, get<int>(var.value) - 1); memory.update(identifier, get<int>(var.value) - 1);
@ -520,7 +515,7 @@ EvalResult eval(Node &ast, Memory &memory) {
MemoryVar& var = memory.get(identifier); MemoryVar& var = memory.get(identifier);
if (!var.initialized) { 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) { else if (var.type.type == TypeType::Int) {
int oldVal = get<int>(var.value); int oldVal = get<int>(var.value);
@ -555,7 +550,7 @@ EvalResult eval(Node &ast, Memory &memory) {
MemoryVar& var = memory.get(identifier); MemoryVar& var = memory.get(identifier);
if (!var.initialized) 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; return var.value;
} break; } break;

View File

@ -118,10 +118,11 @@ int main(int argc, char* argv[]) {
print_error_position(input, e.pos); print_error_position(input, e.pos);
cout << BOLD RED "Type Error: " RESET << e.get_message() << endl; cout << BOLD RED "Type Error: " RESET << e.get_message() << endl;
} catch (RuntimeError& e) { } catch (const RuntimeError& e) {
print_error_position(input, e.pos); print_error_position(input, e.pos);
cout << BOLD RED "Runtime Error: " RESET << e.get_message() << endl; 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; cout << get<0>(e) << " " << (get<1>(e).line + 1) << endl;
} }
} }

View File

@ -22,12 +22,13 @@ bool Memory::contains_top(string identifier) {
return top.vars.contains(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(); Scope& top = scopes.back();
scopes.emplace_back(); Scope& newScope = scopes.emplace_back();
scopes.back().depth = top.depth + 1; newScope.depth = top.depth + 1;
scopes.back().type = type; newScope.type = type;
scopes.back().fn = fn; newScope.fn = fn;
newScope.entry_pos = entry_pos;
} }
void Memory::remove_scope(void) { void Memory::remove_scope(void) {
@ -56,6 +57,7 @@ Scope& Memory::get_function_scope(void) {
void Memory::declare(string identifier, Type type) { void Memory::declare(string identifier, Type type) {
Scope& top = scopes.back(); Scope& top = scopes.back();
top.vars[identifier].type = type; top.vars[identifier].type = type;
top.vars[identifier].identifier = identifier;
} }
void Memory::update(string identifier, EvalResult value) { void Memory::update(string identifier, EvalResult value) {
@ -71,6 +73,25 @@ void Memory::update(string identifier, EvalResult value) {
throw exception(); 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 = { "<repl>", pos };
trace.push_back(top);
return trace;
}
Scope& Memory::_debug_top(void) { Scope& Memory::_debug_top(void) {
Scope& top = scopes.back(); Scope& top = scopes.back();
return top; return top;