mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-05-01 11:29:25 +08:00
Address review: add rethrow_typed and boxed_value accessors to eval_error
eval_error now stores the original Boxed_Value from script-thrown exceptions, accessible via has_boxed_value() and boxed_value(). The new rethrow_typed<Types...>(engine) method provides auto-unboxing without requiring exception_specification to be passed to eval(). This delivers the API simplification envisioned in issue #63: users can catch eval_error, inspect the call stack, and rethrow as typed exceptions in a single catch block. 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
2c80c2a55a
commit
97e8b0a251
@ -340,8 +340,24 @@ namespace chaiscript {
|
||||
, reason(t_why) {
|
||||
}
|
||||
|
||||
eval_error(const std::string &t_why, Boxed_Value t_bv) noexcept
|
||||
: std::runtime_error("Error: \"" + t_why + "\" ")
|
||||
, reason(t_why)
|
||||
, 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(); }
|
||||
const Boxed_Value &boxed_value() const noexcept { return m_boxed_value; }
|
||||
|
||||
template<typename... Types, typename Engine>
|
||||
void rethrow_typed(const Engine &t_engine) const {
|
||||
if (has_boxed_value()) {
|
||||
(try_rethrow<Types>(t_engine), ...);
|
||||
}
|
||||
}
|
||||
|
||||
std::string pretty_print() const {
|
||||
std::ostringstream ss;
|
||||
|
||||
@ -365,6 +381,16 @@ namespace chaiscript {
|
||||
~eval_error() noexcept override = default;
|
||||
|
||||
private:
|
||||
Boxed_Value m_boxed_value;
|
||||
|
||||
template<typename T, typename Engine>
|
||||
void try_rethrow(const Engine &t_engine) const {
|
||||
try {
|
||||
throw t_engine.template boxed_cast<T>(m_boxed_value);
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static AST_Node_Type id(const T &t) noexcept {
|
||||
return t.identifier;
|
||||
|
||||
@ -695,7 +695,7 @@ namespace chaiscript {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw exception::eval_error("Exception thrown during evaluation");
|
||||
throw exception::eval_error("Exception thrown during evaluation", bv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -256,6 +256,70 @@ TEST_CASE("eval_error includes nested exception for script-thrown exceptions") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error stores boxed_value for script-thrown exceptions") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(42);");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.has_boxed_value());
|
||||
CHECK(chai.boxed_cast<int>(ee.boxed_value()) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error rethrow_typed auto-unboxes runtime_error") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(runtime_error(\"typed error\"));");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.has_boxed_value());
|
||||
try {
|
||||
ee.rethrow_typed<int, double, const std::runtime_error &>(chai);
|
||||
REQUIRE(false);
|
||||
} catch (const std::runtime_error &e) {
|
||||
CHECK(e.what() == std::string("typed error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error rethrow_typed auto-unboxes int") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(42);");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.has_boxed_value());
|
||||
try {
|
||||
ee.rethrow_typed<int, double>(chai);
|
||||
REQUIRE(false);
|
||||
} catch (const int e) {
|
||||
CHECK(e == 42);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error rethrow_typed with no match does not throw") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(\"a string\");");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.has_boxed_value());
|
||||
ee.rethrow_typed<int, double>(chai);
|
||||
CHECK(true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error without boxed_value has_boxed_value returns false") {
|
||||
const chaiscript::exception::eval_error ee("plain error");
|
||||
CHECK_FALSE(ee.has_boxed_value());
|
||||
}
|
||||
|
||||
TEST_CASE("Deduction of pointer return types") {
|
||||
int val = 5;
|
||||
int *val_ptr = &val;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user