mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-05-01 03:19:28 +08:00
Fix #63: Derive eval_error from std::nested_exception and wrap thrown exceptions
eval_error now inherits from both std::runtime_error and std::nested_exception, enabling users to access the original exception via rethrow_nested() or nested_ptr(). The engine's eval() method wraps uncaught Boxed_Value exceptions in eval_error, nesting the original Boxed_Value so it can be recovered. exception_specification continues to work for typed exception unboxing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
362e93fb29
commit
2c80c2a55a
@ -11,6 +11,7 @@
|
||||
#define CHAISCRIPT_COMMON_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
@ -296,7 +297,7 @@ namespace chaiscript {
|
||||
};
|
||||
|
||||
/// Errors generated during parsing or evaluation
|
||||
struct eval_error : std::runtime_error {
|
||||
struct eval_error : std::runtime_error, std::nested_exception {
|
||||
std::string reason;
|
||||
File_Position start_position;
|
||||
std::string filename;
|
||||
|
||||
@ -695,7 +695,7 @@ namespace chaiscript {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw;
|
||||
throw exception::eval_error("Exception thrown during evaluation");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -166,9 +166,15 @@ TEST_CASE("Generic exception handling with C++") {
|
||||
try {
|
||||
chai.eval("throw(runtime_error(\"error\"));");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::Boxed_Value &bv) {
|
||||
const std::exception &e = chai.boxed_cast<const std::exception &>(bv);
|
||||
CHECK(e.what() == std::string("error"));
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.nested_ptr() != nullptr);
|
||||
try {
|
||||
ee.rethrow_nested();
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::Boxed_Value &bv) {
|
||||
const std::exception &e = chai.boxed_cast<const std::exception &>(bv);
|
||||
CHECK(e.what() == std::string("error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,6 +200,62 @@ TEST_CASE("Throw int or double") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error derives from std::nested_exception") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
static_assert(std::is_base_of_v<std::nested_exception, chaiscript::exception::eval_error>,
|
||||
"eval_error must derive from std::nested_exception");
|
||||
|
||||
try {
|
||||
chai.eval("throw(runtime_error(\"inner error\"));");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
CHECK(ee.nested_ptr() != nullptr);
|
||||
try {
|
||||
ee.rethrow_nested();
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::Boxed_Value &bv) {
|
||||
const std::exception &nested = chai.boxed_cast<const std::exception &>(bv);
|
||||
CHECK(nested.what() == std::string("inner error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error wraps non-eval exceptions with nested exception") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("throw(42);");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
CHECK(ee.nested_ptr() != nullptr);
|
||||
try {
|
||||
ee.rethrow_nested();
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::Boxed_Value &) {
|
||||
CHECK(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("eval_error includes nested exception for script-thrown exceptions") {
|
||||
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
|
||||
|
||||
try {
|
||||
chai.eval("def foo() { throw(runtime_error(\"from foo\")); } \n foo();");
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
CHECK(ee.nested_ptr() != nullptr);
|
||||
try {
|
||||
ee.rethrow_nested();
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::Boxed_Value &bv) {
|
||||
const std::exception &nested = chai.boxed_cast<const std::exception &>(bv);
|
||||
CHECK(nested.what() == std::string("from foo"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Deduction of pointer return types") {
|
||||
int val = 5;
|
||||
int *val_ptr = &val;
|
||||
@ -259,10 +321,8 @@ TEST_CASE("Throw unhandled type") {
|
||||
REQUIRE(false);
|
||||
} catch (float) {
|
||||
REQUIRE(false);
|
||||
} catch (const std::exception &) {
|
||||
REQUIRE(false);
|
||||
} catch (const chaiscript::Boxed_Value &) {
|
||||
REQUIRE(true);
|
||||
} catch (const chaiscript::exception::eval_error &ee) {
|
||||
REQUIRE(ee.nested_ptr() != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user