mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
Address review: add call stack and filename to wrapped script exceptions
- Catch Boxed_Value in AST_Node_Impl::eval() and wrap in eval_error so call stack accumulates as the exception propagates through the AST chain - Add eval_error constructor accepting filename + Boxed_Value - Populate filename on wrapped eval_error in chaiscript_engine::eval() - Extract original boxed value in Try_AST_Node for script try/catch semantics - Unwrap boxed value in internal_eval/internal_eval_file to preserve script-level exception identity across nested eval() calls - Add tests for call stack presence, filename population, and exception_specification backward compatibility Requested by @lefticus in PR #682 review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
754304314a
commit
5cebd2cd22
@ -341,11 +341,18 @@ namespace chaiscript {
|
||||
}
|
||||
|
||||
eval_error(const std::string &t_why, Boxed_Value t_bv) noexcept
|
||||
: std::runtime_error("Error: \"" + t_why + "\" ")
|
||||
: std::runtime_error(format_why(t_why) + " " + format_filename("__EVAL__"))
|
||||
, reason(t_why)
|
||||
, m_boxed_value(std::move(t_bv)) {
|
||||
}
|
||||
|
||||
eval_error(const std::string &t_why, const std::string &t_fname, Boxed_Value t_bv) noexcept
|
||||
: std::runtime_error(format_why(t_why) + " " + format_filename(t_fname))
|
||||
, reason(t_why)
|
||||
, filename(t_fname)
|
||||
, m_boxed_value(std::move(t_bv)) {
|
||||
}
|
||||
|
||||
eval_error(const eval_error &) = default;
|
||||
|
||||
bool has_boxed_value() const noexcept { return !m_boxed_value.is_undef(); }
|
||||
|
||||
@ -100,6 +100,9 @@ namespace chaiscript {
|
||||
} catch (const exception::file_not_found_error &) {
|
||||
// failed to load, try the next path
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
if (t_ee.has_boxed_value()) {
|
||||
throw Boxed_Value(t_ee.boxed_value());
|
||||
}
|
||||
throw Boxed_Value(t_ee);
|
||||
}
|
||||
}
|
||||
@ -113,6 +116,9 @@ namespace chaiscript {
|
||||
try {
|
||||
return do_eval(t_e, "__EVAL__", true);
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
if (t_ee.has_boxed_value()) {
|
||||
throw Boxed_Value(t_ee.boxed_value());
|
||||
}
|
||||
throw Boxed_Value(t_ee);
|
||||
}
|
||||
}
|
||||
@ -691,11 +697,21 @@ namespace chaiscript {
|
||||
eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename = "__EVAL__") {
|
||||
try {
|
||||
return do_eval(t_input, t_filename);
|
||||
} catch (exception::eval_error &ee) {
|
||||
if (ee.has_boxed_value()) {
|
||||
if (ee.filename.empty()) {
|
||||
ee.filename = t_filename;
|
||||
}
|
||||
if (t_handler) {
|
||||
t_handler->handle(ee.boxed_value(), m_engine);
|
||||
}
|
||||
}
|
||||
throw;
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw exception::eval_error("Exception thrown during evaluation", bv);
|
||||
throw exception::eval_error("Exception thrown during evaluation", t_filename, bv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -142,6 +142,10 @@ namespace chaiscript {
|
||||
} catch (exception::eval_error &ee) {
|
||||
ee.call_stack.push_back(*this);
|
||||
throw;
|
||||
} catch (const Boxed_Value &bv) {
|
||||
exception::eval_error ee("Exception thrown during evaluation", bv);
|
||||
ee.call_stack.push_back(*this);
|
||||
throw ee;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1358,7 +1362,11 @@ namespace chaiscript {
|
||||
try {
|
||||
retval = this->children[0]->eval(t_ss);
|
||||
} catch (const exception::eval_error &e) {
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
if (e.has_boxed_value()) {
|
||||
retval = handle_exception(t_ss, e.boxed_value());
|
||||
} else {
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
}
|
||||
} catch (const std::runtime_error &e) {
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
} catch (const std::out_of_range &e) {
|
||||
|
||||
@ -320,6 +320,43 @@ TEST_CASE("eval_error without boxed_value has_boxed_value returns false") {
|
||||
CHECK_FALSE(ee.has_boxed_value());
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error wrapping script throw includes call stack") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("def foo() { throw(42); } \n foo();");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.has_boxed_value());
|
||||
CHECK_FALSE(ee.call_stack.empty());
|
||||
const auto pretty = ee.pretty_print();
|
||||
CHECK(pretty.find("foo") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error wrapping script throw includes filename") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(99);", chaiscript::Exception_Handler(), "test_script.chai");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.has_boxed_value());
|
||||
CHECK(ee.filename == "test_script.chai");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("exception_specification still auto-unboxes for backward compatibility") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(1)", chaiscript::exception_specification<int>());
|
||||
REQUIRE(false);
|
||||
} catch (const int e) {
|
||||
CHECK(e == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Deduction of pointer return types") {
|
||||
int val = 5;
|
||||
int *val_ptr = &val;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user