Rework stacktrace
This commit is contained in:
parent
dda04d8859
commit
a0c1724b2e
@ -75,7 +75,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
||||
string identifier = get<string>(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<string>(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<string>(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<Token>(node.children[0]);
|
||||
string identifier = get<string>(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<string>(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<string>(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);
|
||||
|
||||
|
@ -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) {
|
||||
if (pos.column == -1 || pos.line == -1)
|
||||
return;
|
||||
|
@ -56,9 +56,6 @@ enum class ErrorType {
|
||||
|
||||
using ErrorData = variant<monostate, string, int>;
|
||||
|
||||
using StackTraceEntry = tuple<string, CodePosition>;
|
||||
using StackTrace = vector<StackTraceEntry>;
|
||||
|
||||
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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -50,6 +50,9 @@ struct Token {
|
||||
CodePosition pos;
|
||||
};
|
||||
|
||||
using StackTraceEntry = tuple<string, CodePosition>;
|
||||
using StackTrace = vector<StackTraceEntry>;
|
||||
|
||||
/** 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
|
@ -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<EvalResult> 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<double>(e1) || holds_alternative<double>(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<int>(e1);
|
||||
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;
|
||||
}
|
||||
} break;
|
||||
@ -389,7 +384,7 @@ EvalResult eval(Node &ast, Memory &memory) {
|
||||
|
||||
int i1 = get<int>(e1);
|
||||
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;
|
||||
} 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<int>(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<int>(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<int>(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<int>(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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 = { "<repl>", pos };
|
||||
trace.push_back(top);
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
Scope& Memory::_debug_top(void) {
|
||||
Scope& top = scopes.back();
|
||||
return top;
|
||||
|
Loading…
Reference in New Issue
Block a user