mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-11-09 23:00:06 +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) {
|
, 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;
|
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::string pretty_print() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
||||||
@ -365,6 +381,16 @@ namespace chaiscript {
|
|||||||
~eval_error() noexcept override = default;
|
~eval_error() noexcept override = default;
|
||||||
|
|
||||||
private:
|
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>
|
template<typename T>
|
||||||
static AST_Node_Type id(const T &t) noexcept {
|
static AST_Node_Type id(const T &t) noexcept {
|
||||||
return t.identifier;
|
return t.identifier;
|
||||||
|
|||||||
@ -695,7 +695,7 @@ namespace chaiscript {
|
|||||||
if (t_handler) {
|
if (t_handler) {
|
||||||
t_handler->handle(bv, m_engine);
|
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") {
|
TEST_CASE("Deduction of pointer return types") {
|
||||||
int val = 5;
|
int val = 5;
|
||||||
int *val_ptr = &val;
|
int *val_ptr = &val;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user