Implement printing backtraces on VM execution errors
This commit is contained in:
parent
6126c7b8eb
commit
bb71669c83
4 changed files with 87 additions and 22 deletions
|
@ -436,6 +436,46 @@ Result<StackFrame> StackFrame::ret(uint64_t regnum) const {
|
||||||
return std::move(parent_stack);
|
return std::move(parent_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> StackFrame::backtrace(uint64_t indent) const {
|
||||||
|
String res = TRY(String::create(""));
|
||||||
|
|
||||||
|
StackFrame cur = TRY(copy());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Value par = TRY(cur.parent());
|
||||||
|
// If parent frame is empty - we are at the top-level. Top-level is always
|
||||||
|
// <unnamed>, so let's just skip it
|
||||||
|
if (par.is<Nil>()) break;
|
||||||
|
|
||||||
|
auto fun = TRY(cur.fun());
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < indent; i++) {
|
||||||
|
res = TRY(res.concat(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
res = TRY(res.concat("Function "));
|
||||||
|
if (fun.is<Function>()) {
|
||||||
|
Function& f = *fun.to<Function>();
|
||||||
|
auto name = TRY(f.name());
|
||||||
|
if (!name.is<Symbol>()) {
|
||||||
|
name = Value(TRY(String::create("<unnamed>")));
|
||||||
|
} else {
|
||||||
|
name = Value(TRY(String::create(*name.to<Symbol>())));
|
||||||
|
}
|
||||||
|
res = TRY(res.concat(*name.to<String>()));
|
||||||
|
} else if (fun.is<StdlibFunction>()) {
|
||||||
|
StdlibFunction& f = *fun.to<StdlibFunction>();
|
||||||
|
auto name = TRY(String::create(TRY(f.name())));
|
||||||
|
res = TRY(res.concat(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
res = TRY(res.concat("\n"));
|
||||||
|
|
||||||
|
cur = TRY(par.to<StackFrame>()->copy());
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
Result<Value> Error::copy_value() const {
|
Result<Value> Error::copy_value() const {
|
||||||
return Value(Error(TRY(_value.copy())));
|
return Value(Error(TRY(_value.copy())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1144,6 +1144,8 @@ class StackFrame : public Object {
|
||||||
virtual Result<Value> copy_value() const final;
|
virtual Result<Value> copy_value() const final;
|
||||||
Result<StackFrame> copy() const;
|
Result<StackFrame> copy() const;
|
||||||
|
|
||||||
|
Result<String> backtrace(uint64_t indent = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GcRoot<PodStackFrame> _value;
|
GcRoot<PodStackFrame> _value;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,23 +13,7 @@
|
||||||
|
|
||||||
StaticArena<64 * 1024 * 1024> arena;
|
StaticArena<64 * 1024 * 1024> arena;
|
||||||
|
|
||||||
Result<Value> run_string(const String& fname, const String& src) {
|
Result<void> print_error(const Result<Value>& res, const String& backtrace) {
|
||||||
auto parsed = TRY(read_multiple(src));
|
|
||||||
|
|
||||||
TRY(arena_gc());
|
|
||||||
|
|
||||||
auto compiled = TRY(compile(fname, parsed));
|
|
||||||
Module& mod = *compiled.to<Module>();
|
|
||||||
|
|
||||||
Dict globals = TRY(Dict::create());
|
|
||||||
auto vm = TRY(VM::create(mod, globals));
|
|
||||||
|
|
||||||
auto res = TRY(vm.run());
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<void> print_error(const Result<Value>& res) {
|
|
||||||
if (res.has_error()) {
|
if (res.has_error()) {
|
||||||
auto errobj = TRY(geterrobj().copy());
|
auto errobj = TRY(geterrobj().copy());
|
||||||
if (errobj.is<Nil>()) {
|
if (errobj.is<Nil>()) {
|
||||||
|
@ -39,11 +23,46 @@ Result<void> print_error(const Result<Value>& res) {
|
||||||
print_string(*message.to<String>());
|
print_string(*message.to<String>());
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TRY(backtrace.size()) > 0) {
|
||||||
|
print_string(backtrace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result<void>();
|
return Result<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Value> run_string(const String& fname, const String& src) {
|
||||||
|
auto maybe_parsed = read_multiple(src);
|
||||||
|
auto empty_backtrace = TRY(String::create(""));
|
||||||
|
if (maybe_parsed.has_error()) {
|
||||||
|
print_error(maybe_parsed, empty_backtrace);
|
||||||
|
return maybe_parsed;
|
||||||
|
}
|
||||||
|
auto parsed = maybe_parsed.release_value();
|
||||||
|
|
||||||
|
auto maybe_compiled = compile(fname, parsed);
|
||||||
|
if (maybe_compiled.has_error()) {
|
||||||
|
print_error(maybe_compiled, empty_backtrace);
|
||||||
|
return maybe_compiled;
|
||||||
|
}
|
||||||
|
auto compiled = maybe_compiled.release_value();
|
||||||
|
|
||||||
|
Module& mod = *compiled.to<Module>();
|
||||||
|
|
||||||
|
Dict globals = TRY(Dict::create());
|
||||||
|
auto vm = TRY(VM::create(mod, globals));
|
||||||
|
|
||||||
|
auto maybe_res = vm.run();
|
||||||
|
|
||||||
|
if (maybe_res.has_error()) {
|
||||||
|
auto backtrace = TRY(vm.backtrace(2));
|
||||||
|
print_error(maybe_res, backtrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maybe_res.release_value();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> run_repl() {
|
Result<void> run_repl() {
|
||||||
Dict globals = TRY(Dict::create());
|
Dict globals = TRY(Dict::create());
|
||||||
|
|
||||||
|
@ -51,15 +70,16 @@ Result<void> run_repl() {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto src = TRY(read_line("valeri> "));
|
auto src = TRY(read_line("valeri> "));
|
||||||
auto maybe_parsed = read_multiple(src);
|
auto maybe_parsed = read_multiple(src);
|
||||||
|
auto empty_backtrace = TRY(String::create(""));
|
||||||
if (maybe_parsed.has_error()) {
|
if (maybe_parsed.has_error()) {
|
||||||
print_error(maybe_parsed);
|
print_error(maybe_parsed, empty_backtrace);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parsed = maybe_parsed.release_value();
|
auto parsed = maybe_parsed.release_value();
|
||||||
auto maybe_compiled = compile(fname, parsed);
|
auto maybe_compiled = compile(fname, parsed);
|
||||||
if (maybe_compiled.has_error()) {
|
if (maybe_compiled.has_error()) {
|
||||||
print_error(maybe_compiled);
|
print_error(maybe_compiled, empty_backtrace);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto compiled = maybe_compiled.release_value();
|
auto compiled = maybe_compiled.release_value();
|
||||||
|
@ -77,7 +97,8 @@ Result<void> run_repl() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Need to print the error
|
// Need to print the error
|
||||||
print_error(maybe_res);
|
auto backtrace = TRY(vm.backtrace(2));
|
||||||
|
print_error(maybe_res, backtrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +117,6 @@ Result<void> run(int argc, const char* argv[]) {
|
||||||
auto fname = TRY(String::create("<stdin>"));
|
auto fname = TRY(String::create("<stdin>"));
|
||||||
auto res = run_string(fname, src);
|
auto res = run_string(fname, src);
|
||||||
if (res.has_error()) {
|
if (res.has_error()) {
|
||||||
print_error(res);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +125,6 @@ Result<void> run(int argc, const char* argv[]) {
|
||||||
auto fname = TRY(String::create(argv[1]));
|
auto fname = TRY(String::create(argv[1]));
|
||||||
auto res = run_string(fname, src);
|
auto res = run_string(fname, src);
|
||||||
if (res.has_error()) {
|
if (res.has_error()) {
|
||||||
print_error(res);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,10 @@ class VM {
|
||||||
return fun.to<Function>()->closure();
|
return fun.to<Function>()->closure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<String> backtrace(uint64_t indent = 0) {
|
||||||
|
return _stack.backtrace(indent);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StackFrame _stack;
|
StackFrame _stack;
|
||||||
Dict _globals;
|
Dict _globals;
|
||||||
|
|
Loading…
Reference in a new issue