104 lines
3.0 KiB
C++
104 lines
3.0 KiB
C++
|
#define SOL_ALL_SAFETIES_ON 1
|
||
|
#include <sol/sol.hpp>
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
int main(int, char**) {
|
||
|
std::cout << "=== script error handling ===" << std::endl;
|
||
|
|
||
|
sol::state lua;
|
||
|
|
||
|
std::string code = R"(
|
||
|
bad&$#*$syntax
|
||
|
bad.code = 2
|
||
|
return 24
|
||
|
)";
|
||
|
|
||
|
/* OPTION 1 */
|
||
|
// Handling code like this can be robust
|
||
|
// If you disable exceptions, then obviously you would
|
||
|
// remove the try-catch branches, and then rely on the
|
||
|
// `lua_atpanic` function being called and trapping errors
|
||
|
// there before exiting the application
|
||
|
{
|
||
|
// script_default_on_error throws / panics when the
|
||
|
// code is bad: trap the error
|
||
|
try {
|
||
|
int value = lua.script(
|
||
|
code, sol::script_default_on_error);
|
||
|
// This will never be reached
|
||
|
std::cout << value << std::endl;
|
||
|
SOL_ASSERT(value == 24);
|
||
|
}
|
||
|
catch (const sol::error& err) {
|
||
|
std::cout << "Something went horribly wrong: "
|
||
|
"thrown error"
|
||
|
<< "\n\t" << err.what() << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* OPTION 2 */
|
||
|
// Use the script_pass_on_error handler
|
||
|
// this simply passes through the protected_function_result,
|
||
|
// rather than throwing it or calling panic
|
||
|
// This will check code validity and also whether or not it
|
||
|
// runs well
|
||
|
{
|
||
|
sol::protected_function_result result
|
||
|
= lua.script(code, sol::script_pass_on_error);
|
||
|
SOL_ASSERT(!result.valid());
|
||
|
if (!result.valid()) {
|
||
|
sol::error err = result;
|
||
|
sol::call_status status = result.status();
|
||
|
std::cout << "Something went horribly wrong: "
|
||
|
<< sol::to_string(status) << " error"
|
||
|
<< "\n\t" << err.what() << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* OPTION 3 */
|
||
|
// This is a lower-level, more explicit way to load code
|
||
|
// This explicitly loads the code, giving you access to any
|
||
|
// errors plus the load status then, it turns the loaded
|
||
|
// code into a sol::protected_function which is then called
|
||
|
// so that the code can run you can then check that too, for
|
||
|
// any errors The two previous approaches are recommended
|
||
|
{
|
||
|
sol::load_result loaded_chunk = lua.load(code);
|
||
|
SOL_ASSERT(!loaded_chunk.valid());
|
||
|
if (!loaded_chunk.valid()) {
|
||
|
sol::error err = loaded_chunk;
|
||
|
sol::load_status status = loaded_chunk.status();
|
||
|
std::cout << "Something went horribly wrong "
|
||
|
"loading the code: "
|
||
|
<< sol::to_string(status) << " error"
|
||
|
<< "\n\t" << err.what() << std::endl;
|
||
|
}
|
||
|
else {
|
||
|
// Because the syntax is bad, this will never be
|
||
|
// reached
|
||
|
SOL_ASSERT(false);
|
||
|
// If there is a runtime error (lua GC memory
|
||
|
// error, nil access, etc.) it will be caught here
|
||
|
sol::protected_function script_func
|
||
|
= loaded_chunk
|
||
|
.get<sol::protected_function>();
|
||
|
sol::protected_function_result result
|
||
|
= script_func();
|
||
|
if (!result.valid()) {
|
||
|
sol::error err = result;
|
||
|
sol::call_status status = result.status();
|
||
|
std::cout
|
||
|
<< "Something went horribly wrong "
|
||
|
"running the code: "
|
||
|
<< sol::to_string(status) << " error"
|
||
|
<< "\n\t" << err.what() << std::endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::cout << std::endl;
|
||
|
|
||
|
return 0;
|
||
|
}
|