mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
add a new kind of error handling script call, updating docs and examples
This commit is contained in:
parent
1e367ab80c
commit
59b196a1db
|
@ -58,9 +58,34 @@ This function takes a number of :ref:`sol::lib<lib-enum>` as arguments and opens
|
|||
sol::function_result script(const std::string& code);
|
||||
sol::function_result script_file(const std::string& filename);
|
||||
|
||||
template <typename Func>
|
||||
sol::protected_function_result script(const std::string& code, Func&& func);
|
||||
template <typename Func>
|
||||
sol::protected_function_result script_file(const std::string& filename, Func&& func);
|
||||
|
||||
These functions run the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It will not run isolated: any scripts or code run will affect code in the ``lua_State*`` the object uses as well (unless ``local`` is applied to a variable declaration, as specified by the Lua language). Code ran in this fashion is not isolated. If you need isolation, consider creating a new state or traditional Lua sandboxing techniques.
|
||||
|
||||
If your script returns a value, you can capture it from the returned :ref:`function_result<function-result>`.
|
||||
If your script returns a value, you can capture it from the returned :ref:`sol::function_result<function-result>`/:ref:`sol::protected_function_result<protected-function-result>`.
|
||||
|
||||
To handle errors when using the second overload, provide a callable function/object that takes a ``lua_State*`` as its first argument and a ``sol::protected_function_result`` as its second argument. Then, handle the errors any way you like:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: running code safely
|
||||
:name: state-script-safe
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
// the default handler panics or throws, depending on your settings
|
||||
auto result1 = lua.script("bad.code", &sol::default_on_error);
|
||||
auto result2 = lua.script("123 bad.code", [](lua_State* L, sol::protected_function_result pfr) {
|
||||
// pfr will contain things that went wrong, for either loading or executing the script
|
||||
// the user can do whatever they like here, including throw. Otherwise,
|
||||
// they need to return the protected_function_result
|
||||
|
||||
// You can also just return it, and let the call-site handle the error if necessary.
|
||||
return pfr;
|
||||
});
|
||||
}
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: function: require / require_file
|
||||
|
|
|
@ -5,6 +5,10 @@ how to handle exceptions or other errors
|
|||
|
||||
Here is some advice and some tricks for common errors about iteration, compile time / linker errors, and other pitfalls, especially when dealing with thrown exceptions, error conditions and the like in Sol.
|
||||
|
||||
Running Scripts
|
||||
---------------
|
||||
|
||||
Scripts can have syntax errors, can load from the file system wrong, or have runtime issues. Knowing which one can be troublesome. There are various small building blocks to load and run code, but to check errors you can use the overloaded :ref:`script/script_file functions on sol::state/sol::state_view<state-script-function>`
|
||||
|
||||
Linker Errors
|
||||
-------------
|
||||
|
|
|
@ -47,6 +47,23 @@ running lua code
|
|||
int value = lua.script("return 54");
|
||||
// value == 54
|
||||
|
||||
To run Lua code but have an error handler in case things go wrong:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
sol::state lua;
|
||||
|
||||
// the default handler panics or throws, depending on your settings
|
||||
auto result1 = lua.script("bad.code", &sol::default_on_error);
|
||||
|
||||
auto result2 = lua.script("123 herp.derp", [](lua_State* L, sol::protected_function_result pfr) {
|
||||
// pfr will contain things that went wrong, for either loading or executing the script
|
||||
// Can throw your own custom error
|
||||
// You can also just return it, and let the call-site handle the error if necessary.
|
||||
return pfr;
|
||||
});
|
||||
|
||||
|
||||
To check the success of a loading operation:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
@ -54,16 +71,24 @@ To check the success of a loading operation:
|
|||
// load file without execute
|
||||
sol::load_result script1 = lua.load_file("path/to/luascript.lua");
|
||||
script1(); //execute
|
||||
|
||||
// load string without execute
|
||||
sol::load_result script2 = lua.load("a = 'test'");
|
||||
script2(); //execute
|
||||
sol::protected_function_result script2result = script2(); //execute
|
||||
// optionally, check if it worked
|
||||
if (script2result.valid()) {
|
||||
// yay!
|
||||
}
|
||||
else {
|
||||
// aww
|
||||
}
|
||||
|
||||
sol::load_result script3 = lua.load("return 24");
|
||||
int value2 = script3(); // execute, get return value
|
||||
// value2 == 24
|
||||
|
||||
|
||||
To check whether a script was successfully run or not (after loading is assumed to be successful):
|
||||
To check whether a script was successfully run or not (if the actual loading is successful):
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
|
|
|
@ -38,7 +38,9 @@ Or using your favorite IDE / tool after setting up your include paths and librar
|
|||
|
||||
If you get an avalanche of errors (particularly referring to ``auto``), you may not have enabled C++14 / C++17 mode for your compiler. Add one of ``std=c++14``, ``std=c++1z`` OR ``std=c++1y`` to your compiler options. By default, this is always-on for VC++ compilers in Visual Studio and friends, but g++ and clang++ require a flag (unless you're on `GCC 6.0`_).
|
||||
|
||||
If this works, you're ready to start! The first line creates the ``lua_State`` and will hold onto it for the duration of the scope its declared in (e.g., from the opening ``{`` to the closing ``}``). It will automatically close / cleanup that lua state when it gets destructed. The second line opens a single lua-provided library, "base". There are several other libraries that come with lua that you can open by default, and those are included in the :ref:`sol::lib<lib-enum>` enumeration. You can open multiple base libraries by specifying multiple ``sol::lib`` arguments:
|
||||
If this works, you're ready to start! The first line creates the ``lua_State`` and will hold onto it for the duration of the scope its declared in (e.g., from the opening ``{`` to the closing ``}``). It will automatically close / cleanup that lua state when it gets destructed.
|
||||
|
||||
The second line opens a single lua-provided library, "base". There are several other libraries that come with lua that you can open by default, and those are included in the :ref:`sol::lib<lib-enum>` enumeration. You can open multiple base libraries by specifying multiple ``sol::lib`` arguments:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
@ -59,6 +61,8 @@ If this works, you're ready to start! The first line creates the ``lua_State`` a
|
|||
|
||||
If you're interested in integrating Sol with a project that already uses some other library or Lua in the codebase, check out the :doc:`existing example<existing>` to see how to work with Sol when you add it to a project (the existing example covers ``require`` as well)!
|
||||
|
||||
Some more ways of loading scripts and handling errors is shown `in this example`_!
|
||||
|
||||
Next, let's start :doc:`reading/writing some variables<variables>` from Lua into C++, and vice-versa!
|
||||
|
||||
|
||||
|
@ -77,3 +81,5 @@ Next, let's start :doc:`reading/writing some variables<variables>` from Lua into
|
|||
.. _github repository here: https://github.com/ThePhD/sol2
|
||||
|
||||
.. _Lua page on getting started: https://www.lua.org/start.html
|
||||
|
||||
.. _in this example: https://github.com/ThePhD/sol2/blob/develop/examples/basic.cpp
|
|
@ -3,6 +3,7 @@
|
|||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== basic example ===" << std::endl;
|
||||
// create an empty lua state
|
||||
sol::state lua;
|
||||
|
||||
|
@ -10,10 +11,31 @@ int main() {
|
|||
// you can open libraries by using open_libraries
|
||||
// the libraries reside in the sol::lib enum class
|
||||
lua.open_libraries(sol::lib::base);
|
||||
// you can open all libraries by passing no arguments
|
||||
//lua.open_libraries();
|
||||
|
||||
// call lua code directly
|
||||
std::cout << "=== basic example ===" << std::endl;
|
||||
lua.script("print('hello world')");
|
||||
|
||||
// call lua code, and check to make sure it has loaded and run properly:
|
||||
auto handler = &sol::default_on_error;
|
||||
lua.script("print('hello again, world')", handler);
|
||||
|
||||
// Use a custom error handler if you need it
|
||||
// This gets called when the result is bad
|
||||
auto simple_handler = [](lua_State*, sol::protected_function_result result) {
|
||||
// You can just pass it through to let the call-site handle it
|
||||
return result;
|
||||
};
|
||||
auto result = lua.script("print('hello hello again, world') \n return 24", simple_handler);
|
||||
if (result.valid()) {
|
||||
std::cout << "the code worked, and a double-hello statement should appear above this one!" << std::endl;
|
||||
int value = result;
|
||||
assert(value == 24);
|
||||
}
|
||||
else {
|
||||
std::cout << "the code failed, check the result type for more information!" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
|
@ -20,8 +20,8 @@
|
|||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// This file was generated with a script.
|
||||
// Generated 2017-03-30 18:11:26.562402 UTC
|
||||
// This header was generated with sol v2.16.0 (revision 92d31b3)
|
||||
// Generated 2017-03-31 21:37:49.518087 UTC
|
||||
// This header was generated with sol v2.16.0 (revision 1e367ab)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
|
@ -3324,7 +3324,9 @@ namespace sol {
|
|||
runtime = LUA_ERRRUN,
|
||||
memory = LUA_ERRMEM,
|
||||
handler = LUA_ERRERR,
|
||||
gc = LUA_ERRGCMM
|
||||
gc = LUA_ERRGCMM,
|
||||
syntax = LUA_ERRSYNTAX,
|
||||
file = LUA_ERRFILE,
|
||||
};
|
||||
|
||||
enum class thread_status : int {
|
||||
|
@ -3363,6 +3365,61 @@ namespace sol {
|
|||
table | boolean | function | userdata | lightuserdata
|
||||
};
|
||||
|
||||
inline const std::string& to_string(call_status c) {
|
||||
static const std::array<std::string, 8> names{{
|
||||
"ok",
|
||||
"yielded",
|
||||
"runtime",
|
||||
"memory",
|
||||
"handler",
|
||||
"gc",
|
||||
"syntax",
|
||||
"file",
|
||||
}};
|
||||
switch (c) {
|
||||
case call_status::ok:
|
||||
return names[0];
|
||||
case call_status::yielded:
|
||||
return names[1];
|
||||
case call_status::runtime:
|
||||
return names[2];
|
||||
case call_status::memory:
|
||||
return names[3];
|
||||
case call_status::handler:
|
||||
return names[4];
|
||||
case call_status::gc:
|
||||
return names[5];
|
||||
case call_status::syntax:
|
||||
return names[6];
|
||||
case call_status::file:
|
||||
return names[7];
|
||||
}
|
||||
return names[0];
|
||||
}
|
||||
|
||||
inline const std::string& to_string(load_status c) {
|
||||
static const std::array<std::string, 8> names{ {
|
||||
"ok",
|
||||
"memory",
|
||||
"gc",
|
||||
"syntax",
|
||||
"file",
|
||||
} };
|
||||
switch (c) {
|
||||
case load_status::ok:
|
||||
return names[0];
|
||||
case load_status::memory:
|
||||
return names[1];
|
||||
case load_status::gc:
|
||||
return names[2];
|
||||
case load_status::syntax:
|
||||
return names[3];
|
||||
case load_status::file:
|
||||
return names[4];
|
||||
}
|
||||
return names[0];
|
||||
}
|
||||
|
||||
enum class meta_function {
|
||||
construct,
|
||||
index,
|
||||
|
@ -12674,6 +12731,25 @@ namespace sol {
|
|||
return kb;
|
||||
}
|
||||
|
||||
inline protected_function_result default_on_error( lua_State* L, const protected_function_result& pfr ) {
|
||||
type t = type_of(L, pfr.stack_index());
|
||||
std::string err = to_string(pfr.status()) + " error";
|
||||
if (t == type::string) {
|
||||
err += " ";
|
||||
err += stack::get<std::string>(L, pfr.stack_index());
|
||||
}
|
||||
#ifdef SOL_NO_EXCEPTIONS
|
||||
if (t != type::nil) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
stack::push(L, err);
|
||||
lua_error(L);
|
||||
#else
|
||||
throw error(detail::direct_error, err);
|
||||
#endif
|
||||
return pfr;
|
||||
}
|
||||
|
||||
class state_view {
|
||||
private:
|
||||
lua_State* L;
|
||||
|
@ -12856,15 +12932,41 @@ namespace sol {
|
|||
}
|
||||
|
||||
protected_function_result do_string(const std::string& code) {
|
||||
sol::protected_function pf = load(code);
|
||||
load_status x = static_cast<load_status>(luaL_loadstring(L, code.c_str()));
|
||||
if (x != load_status::ok) {
|
||||
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
|
||||
}
|
||||
protected_function pf(L, -1);
|
||||
return pf();
|
||||
}
|
||||
|
||||
protected_function_result do_file(const std::string& filename) {
|
||||
sol::protected_function pf = load_file(filename);
|
||||
load_status x = static_cast<load_status>(luaL_loadfile(L, filename.c_str()));
|
||||
if (x != load_status::ok) {
|
||||
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
|
||||
}
|
||||
protected_function pf(L, -1);
|
||||
return pf();
|
||||
}
|
||||
|
||||
template <typename Fx>
|
||||
protected_function_result script(const std::string& code, Fx&& on_error) {
|
||||
protected_function_result pfr = do_string(code);
|
||||
if (!pfr.valid()) {
|
||||
return on_error(L, pfr);
|
||||
}
|
||||
return pfr;
|
||||
}
|
||||
|
||||
template <typename Fx>
|
||||
protected_function_result script_file(const std::string& filename, Fx&& on_error) {
|
||||
protected_function_result pfr = do_file(filename);
|
||||
if (!pfr.valid()) {
|
||||
return on_error(L, pfr);
|
||||
}
|
||||
return pfr;
|
||||
}
|
||||
|
||||
function_result script(const std::string& code) {
|
||||
int index = lua_gettop(L);
|
||||
stack::script(L, code);
|
||||
|
|
|
@ -52,6 +52,25 @@ namespace sol {
|
|||
return kb;
|
||||
}
|
||||
|
||||
inline protected_function_result default_on_error( lua_State* L, const protected_function_result& pfr ) {
|
||||
type t = type_of(L, pfr.stack_index());
|
||||
std::string err = to_string(pfr.status()) + " error";
|
||||
if (t == type::string) {
|
||||
err += " ";
|
||||
err += stack::get<std::string>(L, pfr.stack_index());
|
||||
}
|
||||
#ifdef SOL_NO_EXCEPTIONS
|
||||
if (t != type::nil) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
stack::push(L, err);
|
||||
lua_error(L);
|
||||
#else
|
||||
throw error(detail::direct_error, err);
|
||||
#endif
|
||||
return pfr;
|
||||
}
|
||||
|
||||
class state_view {
|
||||
private:
|
||||
lua_State* L;
|
||||
|
@ -234,15 +253,41 @@ namespace sol {
|
|||
}
|
||||
|
||||
protected_function_result do_string(const std::string& code) {
|
||||
sol::protected_function pf = load(code);
|
||||
load_status x = static_cast<load_status>(luaL_loadstring(L, code.c_str()));
|
||||
if (x != load_status::ok) {
|
||||
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
|
||||
}
|
||||
protected_function pf(L, -1);
|
||||
return pf();
|
||||
}
|
||||
|
||||
protected_function_result do_file(const std::string& filename) {
|
||||
sol::protected_function pf = load_file(filename);
|
||||
load_status x = static_cast<load_status>(luaL_loadfile(L, filename.c_str()));
|
||||
if (x != load_status::ok) {
|
||||
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
|
||||
}
|
||||
protected_function pf(L, -1);
|
||||
return pf();
|
||||
}
|
||||
|
||||
template <typename Fx>
|
||||
protected_function_result script(const std::string& code, Fx&& on_error) {
|
||||
protected_function_result pfr = do_string(code);
|
||||
if (!pfr.valid()) {
|
||||
return on_error(L, pfr);
|
||||
}
|
||||
return pfr;
|
||||
}
|
||||
|
||||
template <typename Fx>
|
||||
protected_function_result script_file(const std::string& filename, Fx&& on_error) {
|
||||
protected_function_result pfr = do_file(filename);
|
||||
if (!pfr.valid()) {
|
||||
return on_error(L, pfr);
|
||||
}
|
||||
return pfr;
|
||||
}
|
||||
|
||||
function_result script(const std::string& code) {
|
||||
int index = lua_gettop(L);
|
||||
stack::script(L, code);
|
||||
|
|
|
@ -345,7 +345,9 @@ namespace sol {
|
|||
runtime = LUA_ERRRUN,
|
||||
memory = LUA_ERRMEM,
|
||||
handler = LUA_ERRERR,
|
||||
gc = LUA_ERRGCMM
|
||||
gc = LUA_ERRGCMM,
|
||||
syntax = LUA_ERRSYNTAX,
|
||||
file = LUA_ERRFILE,
|
||||
};
|
||||
|
||||
enum class thread_status : int {
|
||||
|
@ -384,6 +386,61 @@ namespace sol {
|
|||
table | boolean | function | userdata | lightuserdata
|
||||
};
|
||||
|
||||
inline const std::string& to_string(call_status c) {
|
||||
static const std::array<std::string, 8> names{{
|
||||
"ok",
|
||||
"yielded",
|
||||
"runtime",
|
||||
"memory",
|
||||
"handler",
|
||||
"gc",
|
||||
"syntax",
|
||||
"file",
|
||||
}};
|
||||
switch (c) {
|
||||
case call_status::ok:
|
||||
return names[0];
|
||||
case call_status::yielded:
|
||||
return names[1];
|
||||
case call_status::runtime:
|
||||
return names[2];
|
||||
case call_status::memory:
|
||||
return names[3];
|
||||
case call_status::handler:
|
||||
return names[4];
|
||||
case call_status::gc:
|
||||
return names[5];
|
||||
case call_status::syntax:
|
||||
return names[6];
|
||||
case call_status::file:
|
||||
return names[7];
|
||||
}
|
||||
return names[0];
|
||||
}
|
||||
|
||||
inline const std::string& to_string(load_status c) {
|
||||
static const std::array<std::string, 8> names{ {
|
||||
"ok",
|
||||
"memory",
|
||||
"gc",
|
||||
"syntax",
|
||||
"file",
|
||||
} };
|
||||
switch (c) {
|
||||
case load_status::ok:
|
||||
return names[0];
|
||||
case load_status::memory:
|
||||
return names[1];
|
||||
case load_status::gc:
|
||||
return names[2];
|
||||
case load_status::syntax:
|
||||
return names[3];
|
||||
case load_status::file:
|
||||
return names[4];
|
||||
}
|
||||
return names[0];
|
||||
}
|
||||
|
||||
enum class meta_function {
|
||||
construct,
|
||||
index,
|
||||
|
|
Loading…
Reference in New Issue
Block a user