upgrade checkers and handlers to take a semi-optional "reason" type (const char* c-string desired)

add constructor_handler in same vein of handlers
add argument_handler in same vein of handlers
rewrite env_t checkers
This commit is contained in:
ThePhD 2017-08-31 20:47:09 -04:00
parent 3549bfa8ae
commit 54bcda140c
21 changed files with 482 additions and 299 deletions

View File

@ -55,7 +55,7 @@ members
:caption: function: call_lua :caption: function: call_lua
:name: stack-call-lua :name: stack-call-lua
template<bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs> template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs); inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs);
This function is helpful for when you bind to a raw C function but need sol's abstractions to save you the agony of setting up arguments and know how `calling C functions works`_. The ``start`` parameter tells the function where to start pulling arguments from. The parameter ``fx`` is what's supposed to be called. Extra arguments are passed to the function directly. There are intermediate versions of this (``sol::stack::call_into_lua`` and similar) for more advanced users, but they are not documented as they are subject to change to improve performance or adjust the API accordingly in later iterations of sol2. Use the more advanced versions at your own peril. This function is helpful for when you bind to a raw C function but need sol's abstractions to save you the agony of setting up arguments and know how `calling C functions works`_. The ``start`` parameter tells the function where to start pulling arguments from. The parameter ``fx`` is what's supposed to be called. Extra arguments are passed to the function directly. There are intermediate versions of this (``sol::stack::call_into_lua`` and similar) for more advanced users, but they are not documented as they are subject to change to improve performance or adjust the API accordingly in later iterations of sol2. Use the more advanced versions at your own peril.
@ -97,7 +97,7 @@ Checks if the object at ``index`` is of type ``T``. If it is not, it will call t
template <typename T, typename Handler> template <typename T, typename Handler>
auto check_get( lua_State* L, int index, Handler&& handler, record& tracking ) auto check_get( lua_State* L, int index, Handler&& handler, record& tracking )
Retrieves the value of the object at ``index`` in the stack, but does so safely. It returns an ``optional<U>``, where ``U`` in this case is the return type deduced from ``stack::get<T>``. This allows a person to properly check if the type they're getting is what they actually want, and gracefully handle errors when working with the stack if they so choose to. You can define ``SOL_CHECK_ARGUMENTS`` to turn on additional :doc:`safety<../safety>`, in which ``stack::get`` will default to calling this version of the function with a handler of ``type_panic`` to strongly alert for errors and help you track bugs if you suspect something might be going wrong in your system. Retrieves the value of the object at ``index`` in the stack, but does so safely. It returns an ``optional<U>``, where ``U`` in this case is the return type deduced from ``stack::get<T>``. This allows a person to properly check if the type they're getting is what they actually want, and gracefully handle errors when working with the stack if they so choose to. You can define ``SOL_CHECK_ARGUMENTS`` to turn on additional :doc:`safety<../safety>`, in which ``stack::get`` will default to calling this version of the function with some variant on a handler of ``sol::type_panic_string`` to strongly alert for errors and help you track bugs if you suspect something might be going wrong in your system.
.. code-block:: cpp .. code-block:: cpp
:caption: function: push :caption: function: push
@ -237,8 +237,9 @@ This is an SFINAE-friendly struct that is meant to expose static function ``push
// if the object in the Lua stack at index is a T, return true // if the object in the Lua stack at index is a T, return true
if ( ... ) return true; if ( ... ) return true;
// otherwise, call the handler function, // otherwise, call the handler function,
// with the required 4 arguments, then return false // with the required 5 arguments, then return false
handler(L, index, expected, indextype); //
handler(L, index, expected, indextype, "optional message");
return false; return false;
} }
}; };

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2017-08-30 20:09:44.279724 UTC // Generated 2017-09-01 00:38:40.996447 UTC
// This header was generated with sol v2.18.1 (revision dea0ec0) // This header was generated with sol v2.18.1 (revision 3549bfa)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -4568,37 +4568,6 @@ namespace sol {
return static_cast<type>(lua_type(L, index)); return static_cast<type>(lua_type(L, index));
} }
inline int type_panic(lua_State* L, int index, type expected, type actual) noexcept(false) {
return luaL_error(L, "stack index %d, expected %s, received %s", index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
actual == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual))
);
}
// Specify this function as the handler for lua::check if you know there's nothing wrong
inline int no_panic(lua_State*, int, type, type) noexcept {
return 0;
}
inline void type_error(lua_State* L, int expected, int actual) noexcept(false) {
luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual));
}
inline void type_error(lua_State* L, type expected, type actual) noexcept(false) {
type_error(L, static_cast<int>(expected), static_cast<int>(actual));
}
inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) {
if (expected != type::poly && expected != actual) {
type_panic(L, index, expected, actual);
}
}
inline void type_assert(lua_State* L, int index, type expected) {
type actual = type_of(L, index);
type_assert(L, index, expected, actual);
}
inline std::string type_name(lua_State* L, type t) { inline std::string type_name(lua_State* L, type t) {
return lua_typename(L, static_cast<int>(t)); return lua_typename(L, static_cast<int>(t));
} }
@ -5045,6 +5014,82 @@ namespace sol {
// end of sol/types.hpp // end of sol/types.hpp
// beginning of sol/error_handler.hpp
namespace sol {
inline int type_panic_string(lua_State* L, int index, type expected, type actual, const std::string& message = "") noexcept(false) {
const char* err = message.empty() ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s with message %s";
return luaL_error(L, err, index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
actual == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual)),
message.c_str()
);
}
inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {
const char* err = message == nullptr || (std::char_traits<char>::length(message) == 0) ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s with message %s";
return luaL_error(L, err, index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
actual == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual)),
message
);
}
struct type_panic_t {
int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) {
return type_panic_c_str(L, index, expected, actual, nullptr);
}
int operator()(lua_State* L, int index, type expected, type actual, const char* message) const noexcept(false) {
return type_panic_c_str(L, index, expected, actual, message);
}
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message);
}
};
const type_panic_t type_panic = {};
struct constructor_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (type check failed in constructor)");
}
};
struct argument_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (bad argument to variable or function call)");
}
};
// Specify this function as the handler for lua::check if you know there's nothing wrong
inline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept {
return 0;
}
inline void type_error(lua_State* L, int expected, int actual) noexcept(false) {
luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual));
}
inline void type_error(lua_State* L, type expected, type actual) noexcept(false) {
type_error(L, static_cast<int>(expected), static_cast<int>(actual));
}
inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) {
if (expected != type::poly && expected != actual) {
type_panic_c_str(L, index, expected, actual, nullptr);
}
}
inline void type_assert(lua_State* L, int index, type expected) {
type actual = type_of(L, index);
type_assert(L, index, expected, actual);
}
} // sol
// end of sol/error_handler.hpp
// beginning of sol/reference.hpp // beginning of sol/reference.hpp
// beginning of sol/stack_reference.hpp // beginning of sol/stack_reference.hpp
@ -5893,7 +5938,7 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
template <typename T> template <typename T>
inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) { inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
auto op = check_get<T>(L, index, type_panic, tracking); auto op = check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op); return *std::move(op);
} }
#else #else
@ -6208,7 +6253,7 @@ namespace sol {
bool success = check_func(L, index) == 1; bool success = check_func(L, index) == 1;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, expected, type_of(L, index)); handler(L, index, expected, type_of(L, index), "");
} }
return success; return success;
} }
@ -6223,8 +6268,8 @@ namespace sol {
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
bool success = expected == indextype; bool success = expected == indextype;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type, message
handler(L, index, expected, indextype); handler(L, index, expected, indextype, "");
} }
return success; return success;
} }
@ -6249,7 +6294,7 @@ namespace sol {
#endif // If numbers are enabled, use the imprecise check #endif // If numbers are enabled, use the imprecise check
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index), "not a numeric type");
} }
return success; return success;
#else #else
@ -6258,7 +6303,7 @@ namespace sol {
type t = type_of(L, index); type t = type_of(L, index);
if (t != type::number) { if (t != type::number) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a numeric type");
return false; return false;
} }
#endif // Do not allow strings to be numbers #endif // Do not allow strings to be numbers
@ -6268,9 +6313,9 @@ namespace sol {
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
#ifndef SOL_STRINGS_ARE_NUMBERS #ifndef SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a numeric type");
#else #else
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
#endif #endif
} }
return success; return success;
@ -6283,19 +6328,19 @@ namespace sol {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
#ifdef SOL_STRINGS_ARE_NUMBERS #ifndef SOL_STRINGS_ARE_NUMBERS
type t = type_of(L, index); type t = type_of(L, index);
bool success = t == type::number; bool success = t == type::number;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a numeric type");
} }
return success; return success;
#else #else
bool success = lua_isnumber(L, index) == 1; bool success = lua_isnumber(L, index) == 1;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
} }
return success; return success;
#endif #endif
@ -6315,7 +6360,7 @@ namespace sol {
success = lua_isnone(L, index); success = lua_isnone(L, index);
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, expected, type_of(L, index)); handler(L, index, expected, type_of(L, index), "");
} }
return success; return success;
} }
@ -6368,7 +6413,7 @@ namespace sol {
bool success = !lua_isnone(L, index); bool success = !lua_isnone(L, index);
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::none, type_of(L, index)); handler(L, index, type::none, type_of(L, index), "");
} }
return success; return success;
} }
@ -6383,7 +6428,7 @@ namespace sol {
bool success = t == type::userdata || t == type::lightuserdata; bool success = t == type::userdata || t == type::lightuserdata;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::lightuserdata, t); handler(L, index, type::lightuserdata, t, "");
} }
return success; return success;
} }
@ -6398,7 +6443,7 @@ namespace sol {
bool success = t == type::userdata; bool success = t == type::userdata;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::userdata, t); handler(L, index, type::userdata, t, "");
} }
return success; return success;
} }
@ -6436,25 +6481,25 @@ namespace sol {
return true; return true;
} }
if (t != type::userdata && t != type::table) { if (t != type::userdata && t != type::table) {
handler(L, index, type::function, t); handler(L, index, type::function, t, "must be a function or table or a userdata");
return false; return false;
} }
// Do advanced check for call-style userdata? // Do advanced check for call-style userdata?
static const auto& callkey = to_string(meta_function::call); static const auto& callkey = to_string(meta_function::call);
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
// No metatable, no __call key possible // No metatable, no __call key possible
handler(L, index, type::function, t); handler(L, index, type::function, t, "value is not a function and does not have overriden metatable");
return false; return false;
} }
if (lua_isnoneornil(L, -1)) { if (lua_isnoneornil(L, -1)) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::function, t); handler(L, index, type::function, t, "value is not a function and does not have valid metatable");
return false; return false;
} }
lua_getfield(L, -1, &callkey[0]); lua_getfield(L, -1, &callkey[0]);
if (lua_isnoneornil(L, -1)) { if (lua_isnoneornil(L, -1)) {
lua_pop(L, 2); lua_pop(L, 2);
handler(L, index, type::function, t); handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
return false; return false;
} }
// has call, is definitely a function // has call, is definitely a function
@ -6473,7 +6518,7 @@ namespace sol {
return true; return true;
} }
if (t != type::userdata) { if (t != type::userdata) {
handler(L, index, type::table, t); handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
return false; return false;
} }
return true; return true;
@ -6495,7 +6540,7 @@ namespace sol {
} }
if (t != type::userdata) { if (t != type::userdata) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, expected, t); handler(L, index, expected, t, "value does not have a valid metatable");
return false; return false;
} }
return true; return true;
@ -6507,19 +6552,11 @@ namespace sol {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
if (lua_getmetatable(L, index) == 0) { type t = type_of(L, index);
if (t == type::table || t == type::none || t == type::nil || t == type::userdata) {
return true; return true;
} }
type t = type_of(L, -1); handler(L, index, type::table, t, "value cannot not have a valid environment");
if (t == type::table || t == type::none || t == type::nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, type::table, t);
return false;
}
return true; return true;
} }
}; };
@ -6539,7 +6576,7 @@ namespace sol {
} }
if (t != type::userdata) { if (t != type::userdata) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::table, t); handler(L, index, type::table, t, "value does not have a valid metatable");
return false; return false;
} }
return true; return true;
@ -6552,7 +6589,7 @@ namespace sol {
static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) { static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
if (indextype != type::userdata) { if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is not a valid userdata");
return false; return false;
} }
if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value) if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
@ -6582,7 +6619,7 @@ namespace sol {
} }
if (!success) { if (!success) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is not a valid sol userdata of any kind");
return false; return false;
} }
lua_pop(L, 1); lua_pop(L, 1);
@ -6621,7 +6658,7 @@ namespace sol {
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
tracking.use(1); tracking.use(1);
if (indextype != type::userdata) { if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is not a userdata");
return false; return false;
} }
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
@ -6634,12 +6671,12 @@ namespace sol {
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(static_cast<void*>(pointerpointer + 1)); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(static_cast<void*>(pointerpointer + 1));
bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx; bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx;
if (!success) { if (!success) {
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
} }
return success; return success;
} }
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
return false; return false;
} }
}; };
@ -6698,7 +6735,7 @@ namespace sol {
return true; return true;
} }
tracking.use(1); tracking.use(1);
handler(L, index, type::poly, type_of(L, index)); handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant");
return false; return false;
} }
@ -7538,7 +7575,7 @@ namespace sol {
int isnum = 0; int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum); const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) { if (isnum != 0) {
#if 1 // defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = llround(value); const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) { if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1); tracking.use(1);
@ -7551,7 +7588,7 @@ namespace sol {
} }
const type t = type_of(L, index); const type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t); handler(L, index, type::number, t, "not an integer");
return nullopt; return nullopt;
} }
}; };
@ -7565,7 +7602,7 @@ namespace sol {
if (isnum == 0) { if (isnum == 0) {
type t = type_of(L, index); type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a valid enumeration value");
return nullopt; return nullopt;
} }
tracking.use(1); tracking.use(1);
@ -7582,7 +7619,7 @@ namespace sol {
if (isnum == 0) { if (isnum == 0) {
type t = type_of(L, index); type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a valid floating point number");
return nullopt; return nullopt;
} }
tracking.use(1); tracking.use(1);
@ -7614,7 +7651,7 @@ namespace sol {
typedef std::variant_alternative_t<0, V> T; typedef std::variant_alternative_t<0, V> T;
// This should never be reached... // This should never be reached...
// please check your code and understand what you did to bring yourself here // please check your code and understand what you did to bring yourself here
handler(L, index, type::poly, type_of(L, index)); handler(L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong");
return nullopt; return nullopt;
} }
@ -7837,10 +7874,13 @@ namespace sol {
#endif #endif
#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) { if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {
#ifndef SOL_NO_EXCEPTIONS #ifdef SOL_NO_EXCEPTIONS
throw sol::error("The integer will be misrepresented in lua."); // Is this really worth it?
assert(false && "integer value will be misrepresented in lua");
lua_pushnumber(L, static_cast<lua_Number>(value));
return 1;
#else #else
assert(false && "The integer will be misrepresented in lua."); throw error(detail::direct_error, "integer value will be misrepresented in lua");
#endif #endif
} }
#endif #endif
@ -8910,7 +8950,8 @@ namespace sol {
#ifndef _MSC_VER #ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
#endif // This compiler make me so fucking sad #endif // This compiler make me so fucking sad
multi_check<checkargs, Args...>(L, start, type_panic); argument_handler handler{};
multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
@ -8920,7 +8961,8 @@ namespace sol {
#ifndef _MSC_VER #ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
#endif // This compiler make me so fucking sad #endif // This compiler make me so fucking sad
multi_check<checkargs, Args...>(L, start, type_panic); argument_handler handler{};
multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
@ -11394,7 +11436,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_function<meta::unqualified_t<T>>::value) { if (!is_function<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_function>(lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_function>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -11408,13 +11451,15 @@ namespace sol {
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {} basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
basic_function(lua_State* L, int index = -1) : base_t(L, index) { basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_function(lua_State* L, ref_index index) : base_t(L, index) { basic_function(lua_State* L, ref_index index) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_function>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_function>(L, -1, handler);
#endif // Safety #endif // Safety
} }
@ -11466,7 +11511,7 @@ namespace sol {
decltype(auto) tagged_get(types<T>) const { decltype(auto) tagged_get(types<T>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!valid()) { if (!valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none);
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return stack::get<T>(L, index); return stack::get<T>(L, index);
@ -11482,7 +11527,7 @@ namespace sol {
error tagged_get(types<error>) const { error tagged_get(types<error>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (valid()) { if (valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none);
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return error(detail::direct_error, stack::get<std::string>(L, index)); return error(detail::direct_error, stack::get<std::string>(L, index));
@ -11573,29 +11618,29 @@ namespace sol {
} }
template <bool b, typename target_t = reference> template <bool b, typename target_t = reference>
struct handler { struct protected_handler {
typedef std::is_base_of<stack_reference, target_t> is_stack; typedef std::is_base_of<stack_reference, target_t> is_stack;
const target_t& target; const target_t& target;
int stackindex; int stackindex;
handler(std::false_type, const target_t& target) : target(target), stackindex(0) { protected_handler(std::false_type, const target_t& target) : target(target), stackindex(0) {
if (b) { if (b) {
stackindex = lua_gettop(target.lua_state()) + 1; stackindex = lua_gettop(target.lua_state()) + 1;
target.push(); target.push();
} }
} }
handler(std::true_type, const target_t& target) : target(target), stackindex(0) { protected_handler(std::true_type, const target_t& target) : target(target), stackindex(0) {
if (b) { if (b) {
stackindex = target.stack_index(); stackindex = target.stack_index();
} }
} }
handler(const target_t& target) : handler(is_stack(), target) {} protected_handler(const target_t& target) : protected_handler(is_stack(), target) {}
bool valid() const noexcept { return b; } bool valid() const noexcept { return b; }
~handler() { ~protected_handler() {
if (!is_stack::value && stackindex != 0) { if (!is_stack::value && stackindex != 0) {
lua_remove(target.lua_state(), stackindex); lua_remove(target.lua_state(), stackindex);
} }
@ -11638,29 +11683,29 @@ namespace sol {
private: private:
template <bool b> template <bool b>
call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler<b, handler_t>& h) const { call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::protected_handler<b, handler_t>& h) const {
return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr)); return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr));
} }
template<std::size_t... I, bool b, typename... Ret> template<std::size_t... I, bool b, typename... Ret>
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
luacall(n, sizeof...(Ret), h); luacall(n, sizeof...(Ret), h);
return stack::pop<std::tuple<Ret...>>(lua_state()); return stack::pop<std::tuple<Ret...>>(lua_state());
} }
template<std::size_t I, bool b, typename Ret> template<std::size_t I, bool b, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
luacall(n, 1, h); luacall(n, 1, h);
return stack::pop<Ret>(lua_state()); return stack::pop<Ret>(lua_state());
} }
template <std::size_t I, bool b> template <std::size_t I, bool b>
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
luacall(n, 0, h); luacall(n, 0, h);
} }
template <bool b> template <bool b>
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
int stacksize = lua_gettop(lua_state()); int stacksize = lua_gettop(lua_state());
int poststacksize = stacksize; int poststacksize = stacksize;
int firstreturn = 1; int firstreturn = 1;
@ -11722,7 +11767,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_function<meta::unqualified_t<T>>::value) { if (!is_function<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -11757,26 +11803,30 @@ namespace sol {
basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, -1, handler);
#endif // Safety #endif // Safety
} }
@ -11795,13 +11845,13 @@ namespace sol {
if (!aligned) { if (!aligned) {
// we do not expect the function to already be on the stack: push it // we do not expect the function to already be on the stack: push it
if (error_handler.valid()) { if (error_handler.valid()) {
detail::handler<true, handler_t> h(error_handler); detail::protected_handler<true, handler_t> h(error_handler);
base_t::push(); base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }
else { else {
detail::handler<false, handler_t> h(error_handler); detail::protected_handler<false, handler_t> h(error_handler);
base_t::push(); base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
@ -11817,7 +11867,7 @@ namespace sol {
// so, we need to remove the function at the top and then dump the handler out ourselves // so, we need to remove the function at the top and then dump the handler out ourselves
base_t::push(); base_t::push();
} }
detail::handler<true, handler_t> h(error_handler); detail::protected_handler<true, handler_t> h(error_handler);
if (!is_stack_handler::value) { if (!is_stack_handler::value) {
lua_replace(lua_state(), -3); lua_replace(lua_state(), -3);
h.stackindex = lua_absindex(lua_state(), -2); h.stackindex = lua_absindex(lua_state(), -2);
@ -11826,7 +11876,7 @@ namespace sol {
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }
else { else {
detail::handler<false, handler_t> h(error_handler); detail::protected_handler<false, handler_t> h(error_handler);
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }
@ -12215,13 +12265,15 @@ namespace sol {
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_userdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_userdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_userdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_userdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
}; };
@ -12252,13 +12304,15 @@ namespace sol {
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_lightuserdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_lightuserdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_lightuserdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_lightuserdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
}; };
@ -16096,13 +16150,15 @@ namespace sol {
} }
basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_table_core>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_table_core>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_table_core>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_table_core>(L, -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
@ -16110,7 +16166,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_table<meta::unqualified_t<T>>::value) { if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_table_core>(base_t::lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_table_core>(base_t::lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -16449,25 +16506,29 @@ namespace sol {
basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<env_t>(this->lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<env_t>(this->lua_state(), -1, handler);
#endif // Safety #endif // Safety
lua_pop(this->lua_state(), 2); lua_pop(this->lua_state(), 2);
} }
basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<env_t>(this->lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<env_t>(this->lua_state(), -1, handler);
#endif // Safety #endif // Safety
lua_pop(this->lua_state(), 2); lua_pop(this->lua_state(), 2);
} }
basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_environment>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_environment>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_environment>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_environment>(L, -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
@ -16475,7 +16536,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_environment<meta::unqualified_t<T>>::value) { if (!is_environment<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_environment>(lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_environment>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -16607,7 +16669,7 @@ namespace sol {
decltype(auto) tagged_get(types<T>) const { decltype(auto) tagged_get(types<T>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!valid()) { if (!valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none, "");
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return stack::get<T>(L, index); return stack::get<T>(L, index);
@ -16623,7 +16685,7 @@ namespace sol {
error tagged_get(types<error>) const { error tagged_get(types<error>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (valid()) { if (valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none);
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return error(detail::direct_error, stack::get<std::string>(L, index)); return error(detail::direct_error, stack::get<std::string>(L, index));
@ -17104,6 +17166,15 @@ namespace sol {
return safe_script_file(filename, env, script_default_on_error, mode); return safe_script_file(filename, env, script_default_on_error, mode);
} }
#ifdef SOL_SAFE_FUNCTIONS
protected_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, chunkname, mode);
}
protected_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {
return safe_script_file(filename, mode);
}
#else
function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return unsafe_script(code, chunkname, mode); return unsafe_script(code, chunkname, mode);
} }
@ -17111,7 +17182,7 @@ namespace sol {
function_result script_file(const std::string& filename, load_mode mode = load_mode::any) { function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {
return unsafe_script_file(filename, mode); return unsafe_script_file(filename, mode);
} }
#endif
load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
char basechunkname[17] = {}; char basechunkname[17] = {};
const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);
@ -17475,7 +17546,7 @@ namespace sol {
optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) { optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) {
lua_thread_state lts{ lua_tothread(L, index) }; lua_thread_state lts{ lua_tothread(L, index) };
if (lts.L == nullptr) { if (lts.L == nullptr) {
handler(L, index, type::thread, type_of(L, index)); handler(L, index, type::thread, type_of(L, index), "value does is not a valid thread type");
return nullopt; return nullopt;
} }
tracking.use(1); tracking.use(1);
@ -17628,13 +17699,15 @@ namespace sol {
coroutine(lua_State* L, T&& r) : coroutine(L, sol::ref_index(r.registry_index())) {} coroutine(lua_State* L, T&& r) : coroutine(L, sol::ref_index(r.registry_index())) {}
coroutine(lua_State* L, int index = -1) : reference(L, index) { coroutine(lua_State* L, int index = -1) : reference(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<coroutine>(L, index, type_panic); constructor_handler handler{};
stack::check<coroutine>(L, index, handler);
#endif // Safety #endif // Safety
} }
coroutine(lua_State* L, ref_index index) : reference(L, index) { coroutine(lua_State* L, ref_index index) : reference(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<coroutine>(L, -1, type_panic); constructor_handler handler{};
stack::check<coroutine>(L, -1, handler);
#endif // Safety #endif // Safety
} }

View File

@ -84,13 +84,15 @@ namespace sol {
coroutine(lua_State* L, T&& r) : coroutine(L, sol::ref_index(r.registry_index())) {} coroutine(lua_State* L, T&& r) : coroutine(L, sol::ref_index(r.registry_index())) {}
coroutine(lua_State* L, int index = -1) : reference(L, index) { coroutine(lua_State* L, int index = -1) : reference(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<coroutine>(L, index, type_panic); constructor_handler handler{};
stack::check<coroutine>(L, index, handler);
#endif // Safety #endif // Safety
} }
coroutine(lua_State* L, ref_index index) : reference(L, index) { coroutine(lua_State* L, ref_index index) : reference(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<coroutine>(L, -1, type_panic); constructor_handler handler{};
stack::check<coroutine>(L, -1, handler);
#endif // Safety #endif // Safety
} }

View File

@ -52,25 +52,29 @@ namespace sol {
basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<env_t>(this->lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<env_t>(this->lua_state(), -1, handler);
#endif // Safety #endif // Safety
lua_pop(this->lua_state(), 2); lua_pop(this->lua_state(), 2);
} }
basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<env_t>(this->lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<env_t>(this->lua_state(), -1, handler);
#endif // Safety #endif // Safety
lua_pop(this->lua_state(), 2); lua_pop(this->lua_state(), 2);
} }
basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_environment>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_environment>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_environment>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_environment>(L, -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
@ -78,7 +82,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_environment<meta::unqualified_t<T>>::value) { if (!is_environment<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_environment>(lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_environment>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }

99
sol/error_handler.hpp Normal file
View File

@ -0,0 +1,99 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 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_ERROR_HANDLER_HPP
#define SOL_ERROR_HANDLER_HPP
#include "types.hpp"
namespace sol {
inline int type_panic_string(lua_State* L, int index, type expected, type actual, const std::string& message = "") noexcept(false) {
const char* err = message.empty() ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s with message %s";
return luaL_error(L, err, index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
actual == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual)),
message.c_str()
);
}
inline int type_panic_c_str(lua_State* L, int index, type expected, type actual, const char* message = nullptr) noexcept(false) {
const char* err = message == nullptr || (std::char_traits<char>::length(message) == 0) ? "stack index %d, expected %s, received %s" : "stack index %d, expected %s, received %s with message %s";
return luaL_error(L, err, index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
actual == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual)),
message
);
}
struct type_panic_t {
int operator()(lua_State* L, int index, type expected, type actual) const noexcept(false) {
return type_panic_c_str(L, index, expected, actual, nullptr);
}
int operator()(lua_State* L, int index, type expected, type actual, const char* message) const noexcept(false) {
return type_panic_c_str(L, index, expected, actual, message);
}
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message);
}
};
const type_panic_t type_panic = {};
struct constructor_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (type check failed in constructor)");
}
};
struct argument_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (bad argument to variable or function call)");
}
};
// Specify this function as the handler for lua::check if you know there's nothing wrong
inline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept {
return 0;
}
inline void type_error(lua_State* L, int expected, int actual) noexcept(false) {
luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual));
}
inline void type_error(lua_State* L, type expected, type actual) noexcept(false) {
type_error(L, static_cast<int>(expected), static_cast<int>(actual));
}
inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) {
if (expected != type::poly && expected != actual) {
type_panic_c_str(L, index, expected, actual, nullptr);
}
}
inline void type_assert(lua_State* L, int index, type expected) {
type actual = type_of(L, index);
type_assert(L, index, expected, actual);
}
} // sol
#endif // SOL_ERROR_HANDLER_HPP

View File

@ -48,7 +48,7 @@ namespace sol {
decltype(auto) tagged_get(types<T>) const { decltype(auto) tagged_get(types<T>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!valid()) { if (!valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none, "");
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return stack::get<T>(L, index); return stack::get<T>(L, index);
@ -64,7 +64,7 @@ namespace sol {
error tagged_get(types<error>) const { error tagged_get(types<error>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (valid()) { if (valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none);
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return error(detail::direct_error, stack::get<std::string>(L, index)); return error(detail::direct_error, stack::get<std::string>(L, index));

View File

@ -37,29 +37,29 @@ namespace sol {
} }
template <bool b, typename target_t = reference> template <bool b, typename target_t = reference>
struct handler { struct protected_handler {
typedef std::is_base_of<stack_reference, target_t> is_stack; typedef std::is_base_of<stack_reference, target_t> is_stack;
const target_t& target; const target_t& target;
int stackindex; int stackindex;
handler(std::false_type, const target_t& target) : target(target), stackindex(0) { protected_handler(std::false_type, const target_t& target) : target(target), stackindex(0) {
if (b) { if (b) {
stackindex = lua_gettop(target.lua_state()) + 1; stackindex = lua_gettop(target.lua_state()) + 1;
target.push(); target.push();
} }
} }
handler(std::true_type, const target_t& target) : target(target), stackindex(0) { protected_handler(std::true_type, const target_t& target) : target(target), stackindex(0) {
if (b) { if (b) {
stackindex = target.stack_index(); stackindex = target.stack_index();
} }
} }
handler(const target_t& target) : handler(is_stack(), target) {} protected_handler(const target_t& target) : protected_handler(is_stack(), target) {}
bool valid() const noexcept { return b; } bool valid() const noexcept { return b; }
~handler() { ~protected_handler() {
if (!is_stack::value && stackindex != 0) { if (!is_stack::value && stackindex != 0) {
lua_remove(target.lua_state(), stackindex); lua_remove(target.lua_state(), stackindex);
} }
@ -102,29 +102,29 @@ namespace sol {
private: private:
template <bool b> template <bool b>
call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler<b, handler_t>& h) const { call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::protected_handler<b, handler_t>& h) const {
return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr)); return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr));
} }
template<std::size_t... I, bool b, typename... Ret> template<std::size_t... I, bool b, typename... Ret>
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
luacall(n, sizeof...(Ret), h); luacall(n, sizeof...(Ret), h);
return stack::pop<std::tuple<Ret...>>(lua_state()); return stack::pop<std::tuple<Ret...>>(lua_state());
} }
template<std::size_t I, bool b, typename Ret> template<std::size_t I, bool b, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
luacall(n, 1, h); luacall(n, 1, h);
return stack::pop<Ret>(lua_state()); return stack::pop<Ret>(lua_state());
} }
template <std::size_t I, bool b> template <std::size_t I, bool b>
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
luacall(n, 0, h); luacall(n, 0, h);
} }
template <bool b> template <bool b>
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler<b, handler_t>& h) const { protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::protected_handler<b, handler_t>& h) const {
int stacksize = lua_gettop(lua_state()); int stacksize = lua_gettop(lua_state());
int poststacksize = stacksize; int poststacksize = stacksize;
int firstreturn = 1; int firstreturn = 1;
@ -186,7 +186,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_function<meta::unqualified_t<T>>::value) { if (!is_function<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -221,26 +222,30 @@ namespace sol {
basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_protected_function>(L, -1, handler);
#endif // Safety #endif // Safety
} }
@ -259,13 +264,13 @@ namespace sol {
if (!aligned) { if (!aligned) {
// we do not expect the function to already be on the stack: push it // we do not expect the function to already be on the stack: push it
if (error_handler.valid()) { if (error_handler.valid()) {
detail::handler<true, handler_t> h(error_handler); detail::protected_handler<true, handler_t> h(error_handler);
base_t::push(); base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }
else { else {
detail::handler<false, handler_t> h(error_handler); detail::protected_handler<false, handler_t> h(error_handler);
base_t::push(); base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
@ -281,7 +286,7 @@ namespace sol {
// so, we need to remove the function at the top and then dump the handler out ourselves // so, we need to remove the function at the top and then dump the handler out ourselves
base_t::push(); base_t::push();
} }
detail::handler<true, handler_t> h(error_handler); detail::protected_handler<true, handler_t> h(error_handler);
if (!is_stack_handler::value) { if (!is_stack_handler::value) {
lua_replace(lua_state(), -3); lua_replace(lua_state(), -3);
h.stackindex = lua_absindex(lua_state(), -2); h.stackindex = lua_absindex(lua_state(), -2);
@ -290,7 +295,7 @@ namespace sol {
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }
else { else {
detail::handler<false, handler_t> h(error_handler); detail::protected_handler<false, handler_t> h(error_handler);
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...); int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h); return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
} }

View File

@ -49,7 +49,7 @@ namespace sol {
decltype(auto) tagged_get(types<T>) const { decltype(auto) tagged_get(types<T>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!valid()) { if (!valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none);
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return stack::get<T>(L, index); return stack::get<T>(L, index);
@ -65,7 +65,7 @@ namespace sol {
error tagged_get(types<error>) const { error tagged_get(types<error>) const {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (valid()) { if (valid()) {
type_panic(L, index, type_of(L, index), type::none); type_panic_c_str(L, index, type_of(L, index), type::none);
} }
#endif // Check Argument Safety #endif // Check Argument Safety
return error(detail::direct_error, stack::get<std::string>(L, index)); return error(detail::direct_error, stack::get<std::string>(L, index));

View File

@ -113,7 +113,8 @@ namespace sol {
#ifndef _MSC_VER #ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
#endif // This compiler make me so fucking sad #endif // This compiler make me so fucking sad
multi_check<checkargs, Args...>(L, start, type_panic); argument_handler handler{};
multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }
@ -123,7 +124,8 @@ namespace sol {
#ifndef _MSC_VER #ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
#endif // This compiler make me so fucking sad #endif // This compiler make me so fucking sad
multi_check<checkargs, Args...>(L, start, type_panic); argument_handler handler{};
multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
} }

View File

@ -59,7 +59,7 @@ namespace sol {
bool success = check_func(L, index) == 1; bool success = check_func(L, index) == 1;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, expected, type_of(L, index)); handler(L, index, expected, type_of(L, index), "");
} }
return success; return success;
} }
@ -74,8 +74,8 @@ namespace sol {
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
bool success = expected == indextype; bool success = expected == indextype;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type, message
handler(L, index, expected, indextype); handler(L, index, expected, indextype, "");
} }
return success; return success;
} }
@ -100,7 +100,7 @@ namespace sol {
#endif // If numbers are enabled, use the imprecise check #endif // If numbers are enabled, use the imprecise check
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index), "not a numeric type");
} }
return success; return success;
#else #else
@ -109,7 +109,7 @@ namespace sol {
type t = type_of(L, index); type t = type_of(L, index);
if (t != type::number) { if (t != type::number) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a numeric type");
return false; return false;
} }
#endif // Do not allow strings to be numbers #endif // Do not allow strings to be numbers
@ -119,9 +119,9 @@ namespace sol {
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
#ifndef SOL_STRINGS_ARE_NUMBERS #ifndef SOL_STRINGS_ARE_NUMBERS
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a numeric type");
#else #else
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
#endif #endif
} }
return success; return success;
@ -134,19 +134,19 @@ namespace sol {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
#ifdef SOL_STRINGS_ARE_NUMBERS #ifndef SOL_STRINGS_ARE_NUMBERS
type t = type_of(L, index); type t = type_of(L, index);
bool success = t == type::number; bool success = t == type::number;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a numeric type");
} }
return success; return success;
#else #else
bool success = lua_isnumber(L, index) == 1; bool success = lua_isnumber(L, index) == 1;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::number, type_of(L, index)); handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
} }
return success; return success;
#endif #endif
@ -166,7 +166,7 @@ namespace sol {
success = lua_isnone(L, index); success = lua_isnone(L, index);
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, expected, type_of(L, index)); handler(L, index, expected, type_of(L, index), "");
} }
return success; return success;
} }
@ -219,7 +219,7 @@ namespace sol {
bool success = !lua_isnone(L, index); bool success = !lua_isnone(L, index);
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::none, type_of(L, index)); handler(L, index, type::none, type_of(L, index), "");
} }
return success; return success;
} }
@ -234,7 +234,7 @@ namespace sol {
bool success = t == type::userdata || t == type::lightuserdata; bool success = t == type::userdata || t == type::lightuserdata;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::lightuserdata, t); handler(L, index, type::lightuserdata, t, "");
} }
return success; return success;
} }
@ -249,7 +249,7 @@ namespace sol {
bool success = t == type::userdata; bool success = t == type::userdata;
if (!success) { if (!success) {
// expected type, actual type // expected type, actual type
handler(L, index, type::userdata, t); handler(L, index, type::userdata, t, "");
} }
return success; return success;
} }
@ -287,25 +287,25 @@ namespace sol {
return true; return true;
} }
if (t != type::userdata && t != type::table) { if (t != type::userdata && t != type::table) {
handler(L, index, type::function, t); handler(L, index, type::function, t, "must be a function or table or a userdata");
return false; return false;
} }
// Do advanced check for call-style userdata? // Do advanced check for call-style userdata?
static const auto& callkey = to_string(meta_function::call); static const auto& callkey = to_string(meta_function::call);
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
// No metatable, no __call key possible // No metatable, no __call key possible
handler(L, index, type::function, t); handler(L, index, type::function, t, "value is not a function and does not have overriden metatable");
return false; return false;
} }
if (lua_isnoneornil(L, -1)) { if (lua_isnoneornil(L, -1)) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::function, t); handler(L, index, type::function, t, "value is not a function and does not have valid metatable");
return false; return false;
} }
lua_getfield(L, -1, &callkey[0]); lua_getfield(L, -1, &callkey[0]);
if (lua_isnoneornil(L, -1)) { if (lua_isnoneornil(L, -1)) {
lua_pop(L, 2); lua_pop(L, 2);
handler(L, index, type::function, t); handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
return false; return false;
} }
// has call, is definitely a function // has call, is definitely a function
@ -324,7 +324,7 @@ namespace sol {
return true; return true;
} }
if (t != type::userdata) { if (t != type::userdata) {
handler(L, index, type::table, t); handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
return false; return false;
} }
return true; return true;
@ -346,7 +346,7 @@ namespace sol {
} }
if (t != type::userdata) { if (t != type::userdata) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, expected, t); handler(L, index, expected, t, "value does not have a valid metatable");
return false; return false;
} }
return true; return true;
@ -358,19 +358,11 @@ namespace sol {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
if (lua_getmetatable(L, index) == 0) { type t = type_of(L, index);
if (t == type::table || t == type::none || t == type::nil || t == type::userdata) {
return true; return true;
} }
type t = type_of(L, -1); handler(L, index, type::table, t, "value cannot not have a valid environment");
if (t == type::table || t == type::none || t == type::nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, type::table, t);
return false;
}
return true; return true;
} }
}; };
@ -390,7 +382,7 @@ namespace sol {
} }
if (t != type::userdata) { if (t != type::userdata) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::table, t); handler(L, index, type::table, t, "value does not have a valid metatable");
return false; return false;
} }
return true; return true;
@ -403,7 +395,7 @@ namespace sol {
static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) { static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
if (indextype != type::userdata) { if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is not a valid userdata");
return false; return false;
} }
if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value) if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
@ -433,7 +425,7 @@ namespace sol {
} }
if (!success) { if (!success) {
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is not a valid sol userdata of any kind");
return false; return false;
} }
lua_pop(L, 1); lua_pop(L, 1);
@ -472,7 +464,7 @@ namespace sol {
const type indextype = type_of(L, index); const type indextype = type_of(L, index);
tracking.use(1); tracking.use(1);
if (indextype != type::userdata) { if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is not a userdata");
return false; return false;
} }
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
@ -485,12 +477,12 @@ namespace sol {
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(static_cast<void*>(pointerpointer + 1)); detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(static_cast<void*>(pointerpointer + 1));
bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx; bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx;
if (!success) { if (!success) {
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
} }
return success; return success;
} }
lua_pop(L, 1); lua_pop(L, 1);
handler(L, index, type::userdata, indextype); handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
return false; return false;
} }
}; };
@ -549,7 +541,7 @@ namespace sol {
return true; return true;
} }
tracking.use(1); tracking.use(1);
handler(L, index, type::poly, type_of(L, index)); handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant");
return false; return false;
} }

View File

@ -66,7 +66,7 @@ namespace sol {
int isnum = 0; int isnum = 0;
const lua_Number value = lua_tonumberx(L, index, &isnum); const lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum != 0) { if (isnum != 0) {
#if 1 // defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
const auto integer_value = llround(value); const auto integer_value = llround(value);
if (static_cast<lua_Number>(integer_value) == value) { if (static_cast<lua_Number>(integer_value) == value) {
tracking.use(1); tracking.use(1);
@ -79,7 +79,7 @@ namespace sol {
} }
const type t = type_of(L, index); const type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t); handler(L, index, type::number, t, "not an integer");
return nullopt; return nullopt;
} }
}; };
@ -93,7 +93,7 @@ namespace sol {
if (isnum == 0) { if (isnum == 0) {
type t = type_of(L, index); type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a valid enumeration value");
return nullopt; return nullopt;
} }
tracking.use(1); tracking.use(1);
@ -110,7 +110,7 @@ namespace sol {
if (isnum == 0) { if (isnum == 0) {
type t = type_of(L, index); type t = type_of(L, index);
tracking.use(static_cast<int>(t != type::none)); tracking.use(static_cast<int>(t != type::none));
handler(L, index, type::number, t); handler(L, index, type::number, t, "not a valid floating point number");
return nullopt; return nullopt;
} }
tracking.use(1); tracking.use(1);
@ -142,7 +142,7 @@ namespace sol {
typedef std::variant_alternative_t<0, V> T; typedef std::variant_alternative_t<0, V> T;
// This should never be reached... // This should never be reached...
// please check your code and understand what you did to bring yourself here // please check your code and understand what you did to bring yourself here
handler(L, index, type::poly, type_of(L, index)); handler(L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong");
return nullopt; return nullopt;
} }

View File

@ -23,6 +23,7 @@
#define SOL_STACK_CORE_HPP #define SOL_STACK_CORE_HPP
#include "types.hpp" #include "types.hpp"
#include "error_handler.hpp"
#include "reference.hpp" #include "reference.hpp"
#include "stack_reference.hpp" #include "stack_reference.hpp"
#include "tuple.hpp" #include "tuple.hpp"
@ -299,7 +300,7 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
template <typename T> template <typename T>
inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) { inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
auto op = check_get<T>(L, index, type_panic, tracking); auto op = check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op); return *std::move(op);
} }
#else #else

View File

@ -226,10 +226,13 @@ namespace sol {
#endif #endif
#if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION) #if defined(SOL_CHECK_ARGUMENTS) && !defined(SOL_NO_CHECK_NUMBER_PRECISION)
if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) { if (static_cast<T>(llround(static_cast<lua_Number>(value))) != value) {
#ifndef SOL_NO_EXCEPTIONS #ifdef SOL_NO_EXCEPTIONS
throw sol::error("The integer will be misrepresented in lua."); // Is this really worth it?
assert(false && "integer value will be misrepresented in lua");
lua_pushnumber(L, static_cast<lua_Number>(value));
return 1;
#else #else
assert(false && "The integer will be misrepresented in lua."); throw error(detail::direct_error, "integer value will be misrepresented in lua");
#endif #endif
} }
#endif #endif

View File

@ -435,6 +435,15 @@ namespace sol {
return safe_script_file(filename, env, script_default_on_error, mode); return safe_script_file(filename, env, script_default_on_error, mode);
} }
#ifdef SOL_SAFE_FUNCTIONS
protected_function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, chunkname, mode);
}
protected_function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {
return safe_script_file(filename, mode);
}
#else
function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return unsafe_script(code, chunkname, mode); return unsafe_script(code, chunkname, mode);
} }
@ -442,7 +451,7 @@ namespace sol {
function_result script_file(const std::string& filename, load_mode mode = load_mode::any) { function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {
return unsafe_script_file(filename, mode); return unsafe_script_file(filename, mode);
} }
#endif
load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
char basechunkname[17] = {}; char basechunkname[17] = {};
const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname);

View File

@ -185,13 +185,15 @@ namespace sol {
} }
basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_table_core>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_table_core>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_table_core>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_table_core>(L, -1, handler);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
@ -199,7 +201,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_table<meta::unqualified_t<T>>::value) { if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_table_core>(base_t::lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_table_core>(base_t::lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }

View File

@ -61,7 +61,7 @@ namespace sol {
optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) { optional<lua_thread_state> get(lua_State* L, int index, Handler&& handler, record& tracking) {
lua_thread_state lts{ lua_tothread(L, index) }; lua_thread_state lts{ lua_tothread(L, index) };
if (lts.L == nullptr) { if (lts.L == nullptr) {
handler(L, index, type::thread, type_of(L, index)); handler(L, index, type::thread, type_of(L, index), "value does is not a valid thread type");
return nullopt; return nullopt;
} }
tracking.use(1); tracking.use(1);

View File

@ -667,37 +667,6 @@ namespace sol {
return static_cast<type>(lua_type(L, index)); return static_cast<type>(lua_type(L, index));
} }
inline int type_panic(lua_State* L, int index, type expected, type actual) noexcept(false) {
return luaL_error(L, "stack index %d, expected %s, received %s", index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
actual == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual))
);
}
// Specify this function as the handler for lua::check if you know there's nothing wrong
inline int no_panic(lua_State*, int, type, type) noexcept {
return 0;
}
inline void type_error(lua_State* L, int expected, int actual) noexcept(false) {
luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual));
}
inline void type_error(lua_State* L, type expected, type actual) noexcept(false) {
type_error(L, static_cast<int>(expected), static_cast<int>(actual));
}
inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) {
if (expected != type::poly && expected != actual) {
type_panic(L, index, expected, actual);
}
}
inline void type_assert(lua_State* L, int index, type expected) {
type actual = type_of(L, index);
type_assert(L, index, expected, actual);
}
inline std::string type_name(lua_State* L, type t) { inline std::string type_name(lua_State* L, type t) {
return lua_typename(L, static_cast<int>(t)); return lua_typename(L, static_cast<int>(t));
} }

View File

@ -71,7 +71,8 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_function<meta::unqualified_t<T>>::value) { if (!is_function<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_function>(lua_state(), -1, type_panic); constructor_handler handler{};
stack::check<basic_function>(lua_state(), -1, handler);
} }
#endif // Safety #endif // Safety
} }
@ -85,13 +86,15 @@ namespace sol {
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {} basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
basic_function(lua_State* L, int index = -1) : base_t(L, index) { basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_function>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_function>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_function(lua_State* L, ref_index index) : base_t(L, index) { basic_function(lua_State* L, ref_index index) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_function>(L, -1, type_panic); constructor_handler handler{};
stack::check<basic_function>(L, -1, handler);
#endif // Safety #endif // Safety
} }

View File

@ -52,13 +52,15 @@ namespace sol {
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_userdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_userdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_userdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_userdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
}; };
@ -89,13 +91,15 @@ namespace sol {
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_lightuserdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_lightuserdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_lightuserdata>(L, index, type_panic); constructor_handler handler{};
stack::check<basic_lightuserdata>(L, index, handler);
#endif // Safety #endif // Safety
} }
}; };

View File

@ -1164,82 +1164,94 @@ TEST_CASE("functions/pointer nullptr + nil", "ensure specific semantics for hand
REQUIRE_FALSE(result.valid()); REQUIRE_FALSE(result.valid());
} }
SECTION("throw ref") { SECTION("throw ref") {
REQUIRE_THROWS([&]() { {
sol::state lua; sol::state lua;
lua["v1"] = sptr; lua["v1"] = sptr;
nil_test& v1 = lua["v1"]; sol::object o = lua["v1"];
(void)(&v1 == sptr.get()); bool isp = o.is<nil_test&>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v2"] = std::unique_ptr<nil_test>(); lua["v2"] = std::unique_ptr<nil_test>();
nil_test& v2 = lua["v2"]; sol::object o = lua["v2"];
(void)(&v2 == uptr.get()); bool isp = o.is<nil_test&>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v3"] = rptr; lua["v3"] = rptr;
nil_test& v3 = lua["v3"]; sol::object o = lua["v3"];
(void)(&v3 == rptr); bool isp = o.is<nil_test&>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v4"] = vptr; lua["v4"] = vptr;
nil_test& v4 = lua["v4"]; sol::object o = lua["v4"];
(void)(&v4 == vptr); bool isp = o.is<nil_test&>();
}()); REQUIRE_FALSE(isp);
}
} }
SECTION("throw unique") { SECTION("throw unique") {
REQUIRE_THROWS([&]() { {
sol::state lua; sol::state lua;
lua["v1"] = sptr; lua["v1"] = sptr;
std::unique_ptr<nil_test>& v1 = lua["v1"]; sol::object o = lua["v1"];
(void)(v1.get() == sptr.get()); bool isp = o.is<std::unique_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v2"] = std::unique_ptr<nil_test>(); lua["v2"] = std::unique_ptr<nil_test>();
std::unique_ptr<nil_test>& v2 = lua["v2"]; sol::object o = lua["v2"];
(void)(v2.get() == uptr.get()); bool isp = o.is<std::unique_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v3"] = rptr; lua["v3"] = rptr;
std::unique_ptr<nil_test>& v3 = lua["v3"]; sol::object o = lua["v3"];
(void)(v3.get() == rptr); bool isp = o.is<std::unique_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { };
{
sol::state lua; sol::state lua;
lua["v4"] = vptr; lua["v4"] = vptr;
std::unique_ptr<nil_test>& v4 = lua["v4"]; sol::object o = lua["v4"];
(void)(v4.get() == vptr); bool isp = o.is<std::unique_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
};
} }
SECTION("throw shared") { SECTION("throw shared") {
REQUIRE_THROWS([&]() { {
sol::state lua; sol::state lua;
lua["v1"] = sptr; lua["v1"] = sptr;
std::shared_ptr<nil_test>& v1 = lua["v1"]; sol::object o = lua["v1"];
(void)(v1.get() == sptr.get()); bool isp = o.is<std::shared_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v2"] = std::unique_ptr<nil_test>(); lua["v2"] = std::unique_ptr<nil_test>();
std::shared_ptr<nil_test>& v2 = lua["v2"]; sol::object o = lua["v2"];
(void)(v2.get() == uptr.get()); bool isp = o.is<std::shared_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v3"] = rptr; lua["v3"] = rptr;
std::shared_ptr<nil_test>& v3 = lua["v3"]; sol::object o = lua["v3"];
(void)(v3.get() == rptr); bool isp = o.is<std::shared_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
REQUIRE_THROWS([&]() { }
{
sol::state lua; sol::state lua;
lua["v4"] = vptr; lua["v4"] = vptr;
std::shared_ptr<nil_test>& v4 = lua["v4"]; sol::object o = lua["v4"];
(void)(v4.get() == vptr); bool isp = o.is<std::shared_ptr<nil_test>>();
}()); REQUIRE_FALSE(isp);
}
} }
} }

View File

@ -427,7 +427,7 @@ TEST_CASE("operators/container-like", "test that generic begin/end and iterator
} }
} }
#else #else
REQUIRE(true); SUCCEED("");
#endif #endif
} }