mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
add exception trampoline support to sol2 and add an example on how to use it
This commit is contained in:
parent
560b5b2673
commit
623a38e80e
|
@ -22,11 +22,14 @@ The majority of the members between ``state_view`` and :doc:`sol::table<table>`
|
||||||
|
|
||||||
One last thing you should understand: constructing a ``sol::state`` does a few things behind-the-scenes for you, mostly to ensure compatibility and good error handler/error handling. The function it uses to do this is ``set_default_state``. They are as follows:
|
One last thing you should understand: constructing a ``sol::state`` does a few things behind-the-scenes for you, mostly to ensure compatibility and good error handler/error handling. The function it uses to do this is ``set_default_state``. They are as follows:
|
||||||
|
|
||||||
* set a default panic handler with ``state_view::set_panic``
|
* set a default panic handler with ``state_view::set_panic``/``lua_atpnic``
|
||||||
* set a default ``sol::protected_function`` handler with ``sol::protected_function::set_default_handler``, using a ``sol::reference`` to ``&sol::detail::default_traceback_error_handler`` as the default handler function
|
* set a default ``sol::protected_function`` handler with ``sol::protected_function::set_default_handler``, using a ``sol::reference`` to ``&sol::detail::default_traceback_error_handler`` as the default handler function
|
||||||
|
* set a default exception handler to ``&sol::detail::default_exception_handler``
|
||||||
* register the state as the main thread (only does something for Lua 5.1, which does not have a way to get the main thread) using ``sol::stack::register_main_thread(L)``
|
* register the state as the main thread (only does something for Lua 5.1, which does not have a way to get the main thread) using ``sol::stack::register_main_thread(L)``
|
||||||
* register the LuaJIT C function exception handler with ``stack::luajit_exception_handler(L)``
|
* register the LuaJIT C function exception handler with ``stack::luajit_exception_handler(L)``
|
||||||
|
|
||||||
|
You can read up on the various panic and exception handlers on the :ref:`exceptions page<lua-handlers>`.
|
||||||
|
|
||||||
sol::state_view does none of these things for you. If you want to make sure your self-created or self-managed state has the same properties, please apply this function once to the state. Please note that it will override your panic handler and, if using LuaJIT, your LuaJIT C function handler.
|
sol::state_view does none of these things for you. If you want to make sure your self-created or self-managed state has the same properties, please apply this function once to the state. Please note that it will override your panic handler and, if using LuaJIT, your LuaJIT C function handler.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
|
@ -5,7 +5,7 @@ since somebody is going to ask about it...
|
||||||
|
|
||||||
Yes, you can turn off exceptions in Sol with ``#define SOL_NO_EXCEPTIONS`` before including or by passing the command line argument that defines ``SOL_NO_EXCEPTIONS``. We don't recommend it unless you're playing with a Lua distro that also doesn't play nice with exceptions (like non-x64 versions of :ref:`LuaJIT<LuaJIT and exceptions>` ).
|
Yes, you can turn off exceptions in Sol with ``#define SOL_NO_EXCEPTIONS`` before including or by passing the command line argument that defines ``SOL_NO_EXCEPTIONS``. We don't recommend it unless you're playing with a Lua distro that also doesn't play nice with exceptions (like non-x64 versions of :ref:`LuaJIT<LuaJIT and exceptions>` ).
|
||||||
|
|
||||||
If you turn this off, the default `at_panic`_ function :doc:`state<api/state>` set for you will not throw (see :ref:`sol::state automatic handlers<state-automatic-handlers>` for more details). Instead, the default Lua behavior of aborting will take place (and give you no chance of escape unless you implement your own at_panic function and decide to try ``longjmp`` out).
|
If you turn this off, the default `at_panic`_ function :doc:`state<api/state>` set for you will not throw (see :ref:`sol::state's automatic handlers<state-automatic-handlers>` for more details). Instead, the default Lua behavior of aborting will take place (and give you no chance of escape unless you implement your own at_panic function and decide to try ``longjmp`` out).
|
||||||
|
|
||||||
To make this not be the case, you can set a panic function directly with ``lua_atpanic( lua, my_panic_function );`` or when you create the ``sol::state`` with ``sol::state lua(my_panic_function);``. Here's an example ``my_panic_function`` you can have that prints out its errors:
|
To make this not be the case, you can set a panic function directly with ``lua_atpanic( lua, my_panic_function );`` or when you create the ``sol::state`` with ``sol::state lua(my_panic_function);``. Here's an example ``my_panic_function`` you can have that prints out its errors:
|
||||||
|
|
||||||
|
@ -15,10 +15,30 @@ To make this not be the case, you can set a panic function directly with ``lua_a
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
||||||
|
|
||||||
Note that ``SOL_NO_EXCEPTIONS`` will also disable :doc:`protected_function<api/protected_function>`'s ability to catch C++ errors you throw from C++ functions bound to Lua that you are calling through that API. So, only turn off exceptions in Sol if you're sure you're never going to use exceptions ever. Of course, if you are ALREADY not using Exceptions, you don't have to particularly worry about this and now you can use Sol!
|
Note that ``SOL_NO_EXCEPTIONS`` will also disable :doc:`sol::protected_function<api/protected_function>`'s ability to catch C++ errors you throw from C++ functions bound to Lua that you are calling through that API. So, only turn off exceptions in Sol if you're sure you're never going to use exceptions ever. Of course, if you are ALREADY not using Exceptions, you don't have to particularly worry about this and now you can use Sol!
|
||||||
|
|
||||||
If there is a place where a throw statement is called or a try/catch is used and it is not hidden behind a ``#ifndef SOL_NO_EXCEPTIONS`` block, please file an issue at `issue`_ or submit your very own pull request so everyone can benefit!
|
If there is a place where a throw statement is called or a try/catch is used and it is not hidden behind a ``#ifndef SOL_NO_EXCEPTIONS`` block, please file an issue at `issue`_ or submit your very own pull request so everyone can benefit!
|
||||||
|
|
||||||
|
.. _lua-handlers:
|
||||||
|
|
||||||
|
various sol and lua handlers
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Lua comes with two kind of built-in handlers that sol provides easy opt-ins for. One is the ``panic`` function, as :ref:`demonstrated above<typical-panic-function>`. Another is the ``pcall`` error handler, used with :doc:`sol::protected_function<api/protected_function>`. It is any function that takes a single argument. The single argument is the error type being passed around: in Lua, this is a single string message:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/protected_functions.cpp
|
||||||
|
:caption: regular panic function
|
||||||
|
:name: typical-panic-function
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
|
||||||
|
The other handler is specific to sol2. If you open a ``sol::state``, or open the default state handlers for your ``lua_State*`` (see :ref:`sol::state's automatic handlers<state-automatic-handlers>` for more details), there is a ``sol::exception_handler_function`` type. It allows you to register a function in the event that an exception happens that bubbles out of your functions. The function requires that you push 1 item onto the stack that will be used with a call to `lua_error`_
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/exception_handler.cpp
|
||||||
|
:caption: exception serialization and hadling
|
||||||
|
:name: typical-panic-function
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
|
||||||
.. _LuaJIT and exceptions:
|
.. _LuaJIT and exceptions:
|
||||||
|
|
||||||
|
@ -48,6 +68,7 @@ Currently, the only known platform to do this is the listed "Full" `platforms fo
|
||||||
|
|
||||||
.. _issue: https://github.com/ThePhD/sol2/issues/
|
.. _issue: https://github.com/ThePhD/sol2/issues/
|
||||||
.. _at_panic: http://www.Lua.org/manual/5.3/manual.html#4.6
|
.. _at_panic: http://www.Lua.org/manual/5.3/manual.html#4.6
|
||||||
|
.. _lua_error: https://www.lua.org/manual/5.3/manual.html#lua_error
|
||||||
.. _caveats regarding exceptions: http://luajit.org/extensions.html#exceptions
|
.. _caveats regarding exceptions: http://luajit.org/extensions.html#exceptions
|
||||||
.. _platforms for LuaJIT: http://luajit.org/extensions.html#exceptions
|
.. _platforms for LuaJIT: http://luajit.org/extensions.html#exceptions
|
||||||
.. _this closed issue: https://github.com/ThePhD/sol2/issues/28
|
.. _this closed issue: https://github.com/ThePhD/sol2/issues/28
|
||||||
|
|
|
@ -80,6 +80,10 @@ Feature Config
|
||||||
* Attempts to use ``boost::optional`` instead of sol's own ``optional``
|
* Attempts to use ``boost::optional`` instead of sol's own ``optional``
|
||||||
* **Not** turned on by default under any settings: *this MUST be turned on manually*
|
* **Not** turned on by default under any settings: *this MUST be turned on manually*
|
||||||
|
|
||||||
|
``SOL_PRINT_ERRORS`` triggers the following change:
|
||||||
|
* Includes ``<iostream>`` and prints all exceptions and errors to ``std::cerr``, for you to see
|
||||||
|
* **Not** turned on by default under any settings: *this MUST be turned on manually*
|
||||||
|
|
||||||
``SOL_ENABLE_INTEROP`` triggers the following change:
|
``SOL_ENABLE_INTEROP`` triggers the following change:
|
||||||
* Allows the use of ``extensible<T>`` to be used with ``userdata_checker`` and ``userdata_getter`` to retrieve non-sol usertypes
|
* Allows the use of ``extensible<T>`` to be used with ``userdata_checker`` and ``userdata_getter`` to retrieve non-sol usertypes
|
||||||
- Particularly enables non-sol usertypes to be used in overloads
|
- Particularly enables non-sol usertypes to be used in overloads
|
||||||
|
|
54
examples/exception_handler.cpp
Normal file
54
examples/exception_handler.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#define SOL_CHECK_ARGUMENTS 1
|
||||||
|
#include <sol.hpp>
|
||||||
|
|
||||||
|
#include "assert.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int my_exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description) {
|
||||||
|
// L is the lua state, which you can wrap in a state_view if necessary
|
||||||
|
// maybe_exception will contain exception, if it exists
|
||||||
|
// description will either be the what() of the exception or a description saying that we hit the general-case catch(...)
|
||||||
|
std::cout << "An exception occurred in a function, here's what it says ";
|
||||||
|
if (maybe_exception) {
|
||||||
|
std::cout << "(straight from the exception): ";
|
||||||
|
const std::exception& ex = *maybe_exception;
|
||||||
|
std::cout << ex.what() << std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "(from the description parameter): ";
|
||||||
|
std::cout.write(description.data(), description.size());
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// you must push 1 element onto the stack to be
|
||||||
|
// transported through as the error object in Lua
|
||||||
|
// note that Lua -- and 99.5% of all Lua users and libraries -- expects a string
|
||||||
|
// so we push a single string (in our case, the description of the error)
|
||||||
|
return sol::stack::push(L, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
void will_throw() {
|
||||||
|
throw std::exception("oh no not an exception!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "=== exception_handler example ===" << std::endl;
|
||||||
|
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries(sol::lib::base);
|
||||||
|
lua.set_exception_handler(&my_exception_handler);
|
||||||
|
|
||||||
|
lua.set_function("will_throw", &will_throw);
|
||||||
|
|
||||||
|
sol::protected_function_result pfr = lua.safe_script("will_throw()", &sol::script_pass_on_error);
|
||||||
|
|
||||||
|
c_assert(!pfr.valid());
|
||||||
|
|
||||||
|
sol::error err = pfr;
|
||||||
|
std::cout << err.what() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -26,9 +26,7 @@ int main() {
|
||||||
)");
|
)");
|
||||||
|
|
||||||
// Get a protected function out of Lua
|
// Get a protected function out of Lua
|
||||||
sol::protected_function f = lua["f"];
|
sol::protected_function f(lua["f"], lua["handler"]);
|
||||||
// Set a non-default error handler
|
|
||||||
f.error_handler = lua["handler"];
|
|
||||||
|
|
||||||
sol::protected_function_result result = f(-500);
|
sol::protected_function_result result = f(-500);
|
||||||
if (result.valid()) {
|
if (result.valid()) {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "protect.hpp"
|
#include "protect.hpp"
|
||||||
#include "wrapper.hpp"
|
#include "wrapper.hpp"
|
||||||
|
#include "trampoline.hpp"
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
#include "filters.hpp"
|
#include "filters.hpp"
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
|
|
|
@ -78,15 +78,15 @@ namespace sol {
|
||||||
int returncount = 0;
|
int returncount = 0;
|
||||||
call_status code = call_status::ok;
|
call_status code = call_status::ok;
|
||||||
#ifndef SOL_NO_EXCEPTIONS
|
#ifndef SOL_NO_EXCEPTIONS
|
||||||
auto onexcept = [&](const char* error) {
|
auto onexcept = [&](optional<const std::exception&> maybe_ex, const char* error) {
|
||||||
h.stackindex = 0;
|
h.stackindex = 0;
|
||||||
if (b) {
|
if (b) {
|
||||||
h.target.push();
|
h.target.push();
|
||||||
stack::push(lua_state(), error);
|
detail::call_exception_handler(lua_state(), maybe_ex, error);
|
||||||
lua_call(lua_state(), 1, 1);
|
lua_call(lua_state(), 1, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
stack::push(lua_state(), error);
|
detail::call_exception_handler(lua_state(), maybe_ex, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || defined(SOL_LUAJIT)
|
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || defined(SOL_LUAJIT)
|
||||||
|
@ -102,17 +102,17 @@ namespace sol {
|
||||||
}
|
}
|
||||||
// Handle C++ errors thrown from C++ functions bound inside of lua
|
// Handle C++ errors thrown from C++ functions bound inside of lua
|
||||||
catch (const char* error) {
|
catch (const char* error) {
|
||||||
onexcept(error);
|
onexcept(optional<const std::exception&>(nullopt), error);
|
||||||
firstreturn = lua_gettop(lua_state());
|
firstreturn = lua_gettop(lua_state());
|
||||||
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
||||||
}
|
}
|
||||||
catch (const std::string& error) {
|
catch (const std::string& error) {
|
||||||
onexcept(error.c_str());
|
onexcept(optional<const std::exception&>(nullopt), error.c_str());
|
||||||
firstreturn = lua_gettop(lua_state());
|
firstreturn = lua_gettop(lua_state());
|
||||||
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
||||||
}
|
}
|
||||||
catch (const std::exception& error) {
|
catch (const std::exception& error) {
|
||||||
onexcept(error.what());
|
onexcept(optional<const std::exception&>(error), error.what());
|
||||||
firstreturn = lua_gettop(lua_state());
|
firstreturn = lua_gettop(lua_state());
|
||||||
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ namespace sol {
|
||||||
// but LuaJIT will swallow all C++ errors
|
// but LuaJIT will swallow all C++ errors
|
||||||
// if we don't at least catch std::exception ones
|
// if we don't at least catch std::exception ones
|
||||||
catch (...) {
|
catch (...) {
|
||||||
onexcept("caught (...) unknown error during protected_function call");
|
onexcept(optional<const std::exception&>(nullopt), "caught (...) unknown error during protected_function call");
|
||||||
firstreturn = lua_gettop(lua_state());
|
firstreturn = lua_gettop(lua_state());
|
||||||
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#ifndef SOL_STACK_HPP
|
#ifndef SOL_STACK_HPP
|
||||||
#define SOL_STACK_HPP
|
#define SOL_STACK_HPP
|
||||||
|
|
||||||
|
#include "trampoline.hpp"
|
||||||
#include "stack_core.hpp"
|
#include "stack_core.hpp"
|
||||||
#include "stack_reference.hpp"
|
#include "stack_reference.hpp"
|
||||||
#include "stack_check.hpp"
|
#include "stack_check.hpp"
|
||||||
|
|
|
@ -24,10 +24,15 @@
|
||||||
#ifndef SOL_STATE_DEFAULT_HPP
|
#ifndef SOL_STATE_DEFAULT_HPP
|
||||||
#define SOL_STATE_DEFAULT_HPP
|
#define SOL_STATE_DEFAULT_HPP
|
||||||
|
|
||||||
|
#include "trampoline.hpp"
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
#include "function.hpp"
|
#include "function.hpp"
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
|
|
||||||
|
#ifdef SOL_PRINT_ERRORS
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
inline void register_main_thread(lua_State* L) {
|
inline void register_main_thread(lua_State* L) {
|
||||||
#if SOL_LUA_VERSION < 502
|
#if SOL_LUA_VERSION < 502
|
||||||
|
@ -53,6 +58,11 @@ namespace sol {
|
||||||
if (message) {
|
if (message) {
|
||||||
std::string err(message, messagesize);
|
std::string err(message, messagesize);
|
||||||
lua_settop(L, 0);
|
lua_settop(L, 0);
|
||||||
|
#ifdef SOL_PRINT_ERRORS
|
||||||
|
std::cerr << "[sol2] An error occurred and panic has been invoked: ";
|
||||||
|
std::cerr << err;
|
||||||
|
std::cerr << std::endl;
|
||||||
|
#endif
|
||||||
throw error(err);
|
throw error(err);
|
||||||
}
|
}
|
||||||
lua_settop(L, 0);
|
lua_settop(L, 0);
|
||||||
|
@ -62,23 +72,29 @@ namespace sol {
|
||||||
|
|
||||||
inline int default_traceback_error_handler(lua_State* L) {
|
inline int default_traceback_error_handler(lua_State* L) {
|
||||||
std::string msg = "An unknown error has triggered the default error handler";
|
std::string msg = "An unknown error has triggered the default error handler";
|
||||||
sol::optional<sol::string_view> maybetopmsg = stack::check_get<string_view>(L, 1);
|
optional<string_view> maybetopmsg = stack::check_get<string_view>(L, 1);
|
||||||
if (maybetopmsg) {
|
if (maybetopmsg) {
|
||||||
const string_view& topmsg = maybetopmsg.value();
|
const string_view& topmsg = maybetopmsg.value();
|
||||||
msg.assign(topmsg.data(), topmsg.size());
|
msg.assign(topmsg.data(), topmsg.size());
|
||||||
}
|
}
|
||||||
luaL_traceback(L, L, msg.c_str(), 1);
|
luaL_traceback(L, L, msg.c_str(), 1);
|
||||||
optional<sol::string_view> maybetraceback = stack::check_get<string_view>(L, -1);
|
optional<string_view> maybetraceback = stack::check_get<string_view>(L, -1);
|
||||||
if (maybetraceback) {
|
if (maybetraceback) {
|
||||||
const sol::string_view& traceback = maybetraceback.value();
|
const string_view& traceback = maybetraceback.value();
|
||||||
msg.assign(traceback.data(), traceback.size());
|
msg.assign(traceback.data(), traceback.size());
|
||||||
}
|
}
|
||||||
|
#ifdef SOL_PRINT_ERRORS
|
||||||
|
std::cerr << "[sol2] An error occurred: ";
|
||||||
|
std::cerr << msg;
|
||||||
|
std::cerr << std::endl;
|
||||||
|
#endif
|
||||||
return stack::push(L, msg);
|
return stack::push(L, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set_default_state(lua_State* L, lua_CFunction panic_function = &default_at_panic, lua_CFunction traceback_function = c_call<decltype(&default_traceback_error_handler), &default_traceback_error_handler>) {
|
inline void set_default_state(lua_State* L, lua_CFunction panic_function = &default_at_panic, lua_CFunction traceback_function = c_call<decltype(&default_traceback_error_handler), &default_traceback_error_handler>, exception_handler_function exf = detail::default_exception_handler) {
|
||||||
lua_atpanic(L, panic_function);
|
lua_atpanic(L, panic_function);
|
||||||
protected_function::set_default_handler(object(L, in_place, traceback_function));
|
protected_function::set_default_handler(object(L, in_place, traceback_function));
|
||||||
|
set_default_exception_handler(L, exf);
|
||||||
register_main_thread(L);
|
register_main_thread(L);
|
||||||
stack::luajit_exception_handler(L);
|
stack::luajit_exception_handler(L);
|
||||||
}
|
}
|
||||||
|
@ -128,6 +144,11 @@ namespace sol {
|
||||||
string_view serr = stack::get<string_view>(L, result.stack_index());
|
string_view serr = stack::get<string_view>(L, result.stack_index());
|
||||||
err.append(serr.data(), serr.size());
|
err.append(serr.data(), serr.size());
|
||||||
}
|
}
|
||||||
|
#ifdef SOL_PRINT_ERRORS
|
||||||
|
std::cerr << "[sol2] An error occurred and has been passed to an error handler: ";
|
||||||
|
std::cerr << err;
|
||||||
|
std::cerr << std::endl;
|
||||||
|
#endif
|
||||||
#ifdef SOL_NO_EXCEPTIONS
|
#ifdef SOL_NO_EXCEPTIONS
|
||||||
// replacing information of stack error into pfr
|
// replacing information of stack error into pfr
|
||||||
int target = result.stack_index();
|
int target = result.stack_index();
|
||||||
|
|
|
@ -478,7 +478,11 @@ namespace sol {
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_panic(lua_CFunction panic) {
|
void set_panic(lua_CFunction panic) {
|
||||||
lua_atpanic(L, panic);
|
lua_atpanic(lua_state(), panic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exception_handler(exception_handler_function handler) {
|
||||||
|
set_default_exception_handler(lua_state(), handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args, typename... Keys>
|
template <typename... Args, typename... Keys>
|
||||||
|
|
216
sol/trampoline.hpp
Normal file
216
sol/trampoline.hpp
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
// sol2
|
||||||
|
|
||||||
|
// The MIT License (MIT)
|
||||||
|
|
||||||
|
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
// subject to the following conditions:
|
||||||
|
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef SOL_TRAMPOLINE_HPP
|
||||||
|
#define SOL_TRAMPOLINE_HPP
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "traits.hpp"
|
||||||
|
#include <exception>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#ifdef SOL_PRINT_ERRORS
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace sol {
|
||||||
|
// must push a single object to be the error object
|
||||||
|
// NOTE: the VAST MAJORITY of all Lua libraries -- C or otherwise -- expect a string for the type of error
|
||||||
|
// break this convention at your own risk
|
||||||
|
using exception_handler_function = int(*)(lua_State*, optional<const std::exception&>, string_view);
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
inline const char(&default_exception_handler_name())[11]{
|
||||||
|
static const char name[11] = "sol.\xE2\x98\xA2\xE2\x98\xA2";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must push at least 1 object on the stack
|
||||||
|
inline int default_exception_handler(lua_State* L, optional<const std::exception&>, string_view what) {
|
||||||
|
#ifdef SOL_PRINT_ERRORS
|
||||||
|
std::cerr << "[sol2] An exception occurred: ";
|
||||||
|
std::cerr.write(what.data(), what.size());
|
||||||
|
std::cerr << std::endl;
|
||||||
|
#endif
|
||||||
|
lua_pushlstring(L, what.data(), what.size());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int call_exception_handler(lua_State* L, optional<const std::exception&> maybe_ex, string_view what) {
|
||||||
|
lua_getglobal(L, default_exception_handler_name());
|
||||||
|
type t = static_cast<type>(lua_type(L, -1));
|
||||||
|
if (t != type::lightuserdata) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return default_exception_handler(L, std::move(maybe_ex), std::move(what));
|
||||||
|
}
|
||||||
|
void* vfunc = lua_touserdata(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
if (vfunc == nullptr) {
|
||||||
|
return default_exception_handler(L, std::move(maybe_ex), std::move(what));
|
||||||
|
}
|
||||||
|
exception_handler_function exfunc = reinterpret_cast<exception_handler_function>(vfunc);
|
||||||
|
return exfunc(L, std::move(maybe_ex), std::move(what));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SOL_NO_EXCEPTIONS
|
||||||
|
template <lua_CFunction f>
|
||||||
|
int static_trampoline(lua_State* L) noexcept {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
|
||||||
|
template <lua_CFunction_noexcept f>
|
||||||
|
int static_trampoline_noexcept(lua_State* L) noexcept {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <lua_CFunction f>
|
||||||
|
int static_trampoline_noexcept(lua_State* L) noexcept {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename Fx, typename... Args>
|
||||||
|
int trampoline(lua_State* L, Fx&& f, Args&&... args) noexcept {
|
||||||
|
return f(L, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int c_trampoline(lua_State* L, lua_CFunction f) noexcept {
|
||||||
|
return trampoline(L, f);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <lua_CFunction f>
|
||||||
|
int static_trampoline(lua_State* L) {
|
||||||
|
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
|
||||||
|
return f(L);
|
||||||
|
|
||||||
|
#else
|
||||||
|
try {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
catch (const char* cs) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs));
|
||||||
|
}
|
||||||
|
catch (const std::string& s) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size()));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(e), e.what());
|
||||||
|
}
|
||||||
|
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
|
||||||
|
// LuaJIT cannot have the catchall when the safe propagation is on
|
||||||
|
// but LuaJIT will swallow all C++ errors
|
||||||
|
// if we don't at least catch std::exception ones
|
||||||
|
catch (...) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(nullopt), "caught (...) exception");
|
||||||
|
}
|
||||||
|
#endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it
|
||||||
|
return lua_error(L);
|
||||||
|
#endif // Safe exceptions
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
|
||||||
|
#if 0
|
||||||
|
// impossible: g++/clang++ choke as they think this function is ambiguous:
|
||||||
|
// to fix, wait for template <auto X> and then switch on no-exceptness of the function
|
||||||
|
template <lua_CFunction_noexcept f>
|
||||||
|
int static_trampoline(lua_State* L) noexcept {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <lua_CFunction_noexcept f>
|
||||||
|
int static_trampoline_noexcept(lua_State* L) noexcept {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
#endif // impossible
|
||||||
|
|
||||||
|
#else
|
||||||
|
template <lua_CFunction f>
|
||||||
|
int static_trampoline_noexcept(lua_State* L) noexcept {
|
||||||
|
return f(L);
|
||||||
|
}
|
||||||
|
#endif // noexcept lua_CFunction type
|
||||||
|
|
||||||
|
template <typename Fx, typename... Args>
|
||||||
|
int trampoline(lua_State* L, Fx&& f, Args&&... args) {
|
||||||
|
if (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) {
|
||||||
|
return f(L, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
|
||||||
|
return f(L, std::forward<Args>(args)...);
|
||||||
|
#else
|
||||||
|
try {
|
||||||
|
return f(L, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
catch (const char* cs) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(cs));
|
||||||
|
}
|
||||||
|
catch (const std::string& s) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(nullopt), string_view(s.c_str(), s.size()));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(e), e.what());
|
||||||
|
}
|
||||||
|
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
|
||||||
|
// LuaJIT cannot have the catchall when the safe propagation is on
|
||||||
|
// but LuaJIT will swallow all C++ errors
|
||||||
|
// if we don't at least catch std::exception ones
|
||||||
|
catch (...) {
|
||||||
|
call_exception_handler(L, optional<const std::exception&>(nullopt), "caught (...) exception");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return lua_error(L);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int c_trampoline(lua_State* L, lua_CFunction f) {
|
||||||
|
return trampoline(L, f);
|
||||||
|
}
|
||||||
|
#endif // Exceptions vs. No Exceptions
|
||||||
|
|
||||||
|
template <typename F, F fx>
|
||||||
|
inline int typed_static_trampoline_raw(std::true_type, lua_State* L) {
|
||||||
|
return static_trampoline_noexcept<fx>(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, F fx>
|
||||||
|
inline int typed_static_trampoline_raw(std::false_type, lua_State* L) {
|
||||||
|
return static_trampoline<fx>(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, F fx>
|
||||||
|
inline int typed_static_trampoline(lua_State* L) {
|
||||||
|
return typed_static_trampoline_raw<F, fx>(std::integral_constant<bool, meta::bind_traits<F>::is_noexcept>(), L);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
inline void set_default_exception_handler(lua_State* L, exception_handler_function exf = &detail::default_exception_handler) {
|
||||||
|
static_assert(sizeof(void*) >= sizeof(exception_handler_function), "void* storage is too small to transport the exception handler: please file a bug on the issue tracker");
|
||||||
|
void* storage;
|
||||||
|
std::memcpy(&storage, &exf, sizeof(exception_handler_function));
|
||||||
|
lua_pushlightuserdata(L, storage);
|
||||||
|
lua_setglobal(L, detail::default_exception_handler_name());
|
||||||
|
}
|
||||||
|
} // sol
|
||||||
|
|
||||||
|
#endif // SOL_TRAMPOLINE_HPP
|
128
sol/types.hpp
128
sol/types.hpp
|
@ -50,134 +50,6 @@ namespace sol {
|
||||||
typedef int(*lua_CFunction_noexcept)(lua_State* L);
|
typedef int(*lua_CFunction_noexcept)(lua_State* L);
|
||||||
#endif // noexcept function type for lua_CFunction
|
#endif // noexcept function type for lua_CFunction
|
||||||
|
|
||||||
#ifdef SOL_NO_EXCEPTIONS
|
|
||||||
template <lua_CFunction f>
|
|
||||||
int static_trampoline(lua_State* L) noexcept {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
|
|
||||||
template <lua_CFunction_noexcept f>
|
|
||||||
int static_trampoline_noexcept(lua_State* L) noexcept {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template <lua_CFunction f>
|
|
||||||
int static_trampoline_noexcept(lua_State* L) noexcept {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
|
||||||
int trampoline(lua_State* L, Fx&& f, Args&&... args) noexcept {
|
|
||||||
return f(L, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int c_trampoline(lua_State* L, lua_CFunction f) noexcept {
|
|
||||||
return trampoline(L, f);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template <lua_CFunction f>
|
|
||||||
int static_trampoline(lua_State* L) {
|
|
||||||
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
|
|
||||||
return f(L);
|
|
||||||
|
|
||||||
#else
|
|
||||||
try {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
catch (const char* cs) {
|
|
||||||
lua_pushstring(L, cs);
|
|
||||||
}
|
|
||||||
catch (const std::string& s) {
|
|
||||||
lua_pushlstring(L, s.c_str(), s.size());
|
|
||||||
}
|
|
||||||
catch (const std::exception& e) {
|
|
||||||
lua_pushstring(L, e.what());
|
|
||||||
}
|
|
||||||
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
|
|
||||||
// LuaJIT cannot have the catchall when the safe propagation is on
|
|
||||||
// but LuaJIT will swallow all C++ errors
|
|
||||||
// if we don't at least catch std::exception ones
|
|
||||||
catch (...) {
|
|
||||||
lua_pushstring(L, "caught (...) exception");
|
|
||||||
}
|
|
||||||
#endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it
|
|
||||||
return lua_error(L);
|
|
||||||
#endif // Safe exceptions
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
|
|
||||||
#if 0
|
|
||||||
// impossible: g++/clang++ choke as they think this function is ambiguous:
|
|
||||||
// to fix, wait for template <auto X> and then switch on no-exceptness of the function
|
|
||||||
template <lua_CFunction_noexcept f>
|
|
||||||
int static_trampoline(lua_State* L) noexcept {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
template <lua_CFunction_noexcept f>
|
|
||||||
int static_trampoline_noexcept(lua_State* L) noexcept {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
#endif // impossible
|
|
||||||
|
|
||||||
#else
|
|
||||||
template <lua_CFunction f>
|
|
||||||
int static_trampoline_noexcept(lua_State* L) noexcept {
|
|
||||||
return f(L);
|
|
||||||
}
|
|
||||||
#endif // noexcept lua_CFunction type
|
|
||||||
|
|
||||||
template <typename Fx, typename... Args>
|
|
||||||
int trampoline(lua_State* L, Fx&& f, Args&&... args) {
|
|
||||||
if (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) {
|
|
||||||
return f(L, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
|
|
||||||
return f(L, std::forward<Args>(args)...);
|
|
||||||
#else
|
|
||||||
try {
|
|
||||||
return f(L, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
catch (const char* s) {
|
|
||||||
lua_pushstring(L, s);
|
|
||||||
}
|
|
||||||
catch (const std::exception& e) {
|
|
||||||
lua_pushstring(L, e.what());
|
|
||||||
}
|
|
||||||
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
|
|
||||||
// LuaJIT cannot have the catchall when the safe propagation is on
|
|
||||||
// but LuaJIT will swallow all C++ errors
|
|
||||||
// if we don't at least catch std::exception ones
|
|
||||||
catch (...) {
|
|
||||||
lua_pushstring(L, "caught (...) exception");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return lua_error(L);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int c_trampoline(lua_State* L, lua_CFunction f) {
|
|
||||||
return trampoline(L, f);
|
|
||||||
}
|
|
||||||
#endif // Exceptions vs. No Exceptions
|
|
||||||
|
|
||||||
template <typename F, F fx>
|
|
||||||
inline int typed_static_trampoline_raw(std::true_type, lua_State* L) {
|
|
||||||
return static_trampoline_noexcept<fx>(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F, F fx>
|
|
||||||
inline int typed_static_trampoline_raw(std::false_type, lua_State* L) {
|
|
||||||
return static_trampoline<fx>(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F, F fx>
|
|
||||||
inline int typed_static_trampoline(lua_State* L) {
|
|
||||||
return typed_static_trampoline_raw<F, fx>(std::integral_constant<bool, meta::bind_traits<F>::is_noexcept>(), L);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct unique_usertype {};
|
struct unique_usertype {};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user