LibJS: Consolidate exception function names and source ranges
Instead of storing the function names (in a badly named Vector<String>) and source ranges separately, consolidate them into a new struct: TracebackFrame. This makes it both easier to use now and easier to extend in the future. Unlike before we now keep each call frame's current node source range in the traceback frame next to the function name, meaning we can display line and column numbers outside of the VM and after the call stack is emptied.
This commit is contained in:
parent
0cf04d07aa
commit
97d49cb92b
Notes:
sideshowbarker
2024-07-18 19:09:18 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/97d49cb92ba Pull-request: https://github.com/SerenityOS/serenity/pull/6616
5 changed files with 39 additions and 33 deletions
|
@ -35,7 +35,8 @@ void CellSyntaxHighlighter::rehighlight(const Palette& palette)
|
||||||
false);
|
false);
|
||||||
|
|
||||||
if (m_cell && m_cell->exception()) {
|
if (m_cell && m_cell->exception()) {
|
||||||
auto range = m_cell->exception()->source_ranges().first();
|
auto& traceback = m_cell->exception()->traceback();
|
||||||
|
auto& range = traceback.first().source_range;
|
||||||
GUI::TextRange text_range { { range.start.line - 1, range.start.column }, { range.end.line - 1, range.end.column - 1 } };
|
GUI::TextRange text_range { { range.start.line - 1, range.start.column }, { range.end.line - 1, range.end.column - 1 } };
|
||||||
m_client->spans().prepend(
|
m_client->spans().prepend(
|
||||||
GUI::TextDocumentSpan {
|
GUI::TextDocumentSpan {
|
||||||
|
|
|
@ -55,10 +55,13 @@ Sheet::Sheet(Workbook& workbook)
|
||||||
parser.print_errors();
|
parser.print_errors();
|
||||||
} else {
|
} else {
|
||||||
interpreter().run(global_object(), parser.parse_program());
|
interpreter().run(global_object(), parser.parse_program());
|
||||||
if (auto exc = interpreter().exception()) {
|
if (auto* exception = interpreter().exception()) {
|
||||||
warnln("Spreadsheet: Failed to run runtime code: ");
|
warnln("Spreadsheet: Failed to run runtime code:");
|
||||||
for (auto& t : exc->trace())
|
for (auto& traceback_frame : exception->traceback()) {
|
||||||
warnln("{}", t);
|
auto& function_name = traceback_frame.function_name;
|
||||||
|
auto& source_range = traceback_frame.source_range;
|
||||||
|
dbgln(" {} at {}:{}:{}", function_name, source_range.filename, source_range.start.line, source_range.start.column);
|
||||||
|
}
|
||||||
interpreter().vm().clear_exception();
|
interpreter().vm().clear_exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -16,23 +17,16 @@ Exception::Exception(Value value)
|
||||||
: m_value(value)
|
: m_value(value)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
auto& call_stack = vm.call_stack();
|
m_traceback.ensure_capacity(vm.call_stack().size());
|
||||||
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) {
|
for (auto* call_frame : vm.call_stack()) {
|
||||||
String function_name = call_stack[i]->function_name;
|
auto function_name = call_frame->function_name;
|
||||||
if (function_name.is_empty())
|
if (function_name.is_empty())
|
||||||
function_name = "<anonymous>";
|
function_name = "<anonymous>";
|
||||||
m_trace.append(function_name);
|
m_traceback.prepend({
|
||||||
|
.function_name = move(function_name),
|
||||||
|
.source_range = call_frame->current_node->source_range(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* interpreter = vm.interpreter_if_exists()) {
|
|
||||||
for (auto* node_chain = interpreter->executing_ast_node_chain(); node_chain; node_chain = node_chain->previous) {
|
|
||||||
m_source_ranges.append(node_chain->node.source_range());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Exception::~Exception()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exception::visit_edges(Visitor& visitor)
|
void Exception::visit_edges(Visitor& visitor)
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/FlyString.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibJS/Runtime/Cell.h>
|
#include <LibJS/Runtime/Cell.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
@ -13,22 +15,25 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
struct TracebackFrame {
|
||||||
|
FlyString function_name;
|
||||||
|
SourceRange source_range;
|
||||||
|
};
|
||||||
|
|
||||||
class Exception : public Cell {
|
class Exception : public Cell {
|
||||||
public:
|
public:
|
||||||
explicit Exception(Value);
|
explicit Exception(Value);
|
||||||
virtual ~Exception() override;
|
virtual ~Exception() override = default;
|
||||||
|
|
||||||
Value value() const { return m_value; }
|
Value value() const { return m_value; }
|
||||||
const Vector<String>& trace() const { return m_trace; }
|
const Vector<TracebackFrame>& traceback() const { return m_traceback; }
|
||||||
const Vector<SourceRange>& source_ranges() const { return m_source_ranges; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char* class_name() const override { return "Exception"; }
|
virtual const char* class_name() const override { return "Exception"; }
|
||||||
virtual void visit_edges(Visitor&) override;
|
virtual void visit_edges(Visitor&) override;
|
||||||
|
|
||||||
Value m_value;
|
Value m_value;
|
||||||
Vector<String> m_trace;
|
Vector<TracebackFrame> m_traceback;
|
||||||
Vector<SourceRange> m_source_ranges;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -489,24 +489,27 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
|
||||||
vm->clear_exception();
|
vm->clear_exception();
|
||||||
out("Uncaught exception: ");
|
out("Uncaught exception: ");
|
||||||
print(exception->value());
|
print(exception->value());
|
||||||
auto& trace = exception->trace();
|
auto& traceback = exception->traceback();
|
||||||
if (trace.size() > 1) {
|
if (traceback.size() > 1) {
|
||||||
unsigned repetitions = 0;
|
unsigned repetitions = 0;
|
||||||
for (size_t i = 0; i < trace.size(); ++i) {
|
for (size_t i = 0; i < traceback.size(); ++i) {
|
||||||
auto& function_name = trace[i];
|
auto& traceback_frame = traceback[i];
|
||||||
if (i + 1 < trace.size() && trace[i + 1] == function_name) {
|
if (i + 1 < traceback.size()) {
|
||||||
|
auto& next_traceback_frame = traceback[i + 1];
|
||||||
|
if (next_traceback_frame.function_name == traceback_frame.function_name) {
|
||||||
repetitions++;
|
repetitions++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (repetitions > 4) {
|
if (repetitions > 4) {
|
||||||
// If more than 5 (1 + >4) consecutive function calls with the same name, print
|
// If more than 5 (1 + >4) consecutive function calls with the same name, print
|
||||||
// the name only once and show the number of repetitions instead. This prevents
|
// the name only once and show the number of repetitions instead. This prevents
|
||||||
// printing ridiculously large call stacks of recursive functions.
|
// printing ridiculously large call stacks of recursive functions.
|
||||||
outln(" -> {}", function_name);
|
outln(" -> {}", traceback_frame.function_name);
|
||||||
outln(" {} more calls", repetitions);
|
outln(" {} more calls", repetitions);
|
||||||
} else {
|
} else {
|
||||||
for (size_t j = 0; j < repetitions + 1; ++j)
|
for (size_t j = 0; j < repetitions + 1; ++j)
|
||||||
outln(" -> {}", function_name);
|
outln(" -> {}", traceback_frame.function_name);
|
||||||
}
|
}
|
||||||
repetitions = 0;
|
repetitions = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue