ability for functions that throw not bound by sol to catch and return lua errors that can be used by a handler function (for protected function).

This commit is contained in:
ThePhD 2016-03-02 20:45:52 -05:00
parent 6c070661a7
commit 923c774d5e
11 changed files with 65 additions and 42 deletions

View File

@ -131,7 +131,7 @@ script:
- echo "Configuration info:"
- export_compiler_vars
- ninja --version
- ./bootstrap.py --ci && ninja
- ./bootstrap.py --ci && ninja && ninja examples
notifications:
email:

View File

@ -1,5 +1,6 @@
#include <sol.hpp>
#include <cassert>
#include <iostream>
inline int my_add(int x, int y) {
return x + y;
@ -46,17 +47,27 @@ int main() {
// calling a stateful lambda modifies the value
lua.script("inc()");
assert(x == 10);
if (x == 10) {
// Do something based on this information
std::cout << "Yahoo!" << std::endl;
}
// this can be done as many times as you want
lua.script("inc()\ninc()\ninc()");
assert(x == 40);
if (x == 40) {
// Do something based on this information
std::cout << "Yahoo!" << std::endl;
}
// retrieval of a function is done similarly
// to other variables, using sol::function
sol::function add = lua["my_add"];
int value = add(10, 11);
assert(add.call<int>(10, 11) == 21);
assert(value == 21);
if (value == 21) {
std::cout << "Woo, it's 21!" << std::endl;
}
// multi-return functions are supported using
// std::tuple as the interface.
@ -76,8 +87,7 @@ int main() {
// you can even overload functions
// just pass in the different functions
// you want to pack into a single name:
// make SURE they take different number of
// arguments/different types!
// make SURE they take different types!
lua.set_function("func", sol::overload([](int x) { return x; }, make_string, my_add));

View File

@ -18,9 +18,6 @@ int main() {
"}");
auto t2 = lua.get<sol::table>("table2");
auto nestedTable = t2.get<sol::table>("nestedTable");
/* Shorter Syntax: */
// using the values stored in table1
/*std::cout << (std::string)lua["table1"][1] << " "
@ -29,18 +26,19 @@ int main() {
// some retrieval of values from the nested table
// the cleaner way of doing things
// chain off the the get<>() / [] results
auto t2 = lua.get<sol::table>("table2");
auto nestedTable = t2.get<sol::table>("nestedTable");
// Alternatively:
//sol::table t2 = lua["table2"];
//sol::table nestedTable = t2["nestedTable"];
std::string x = lua["table2"]["nestedTable"]["key2"];
std::cout << "nested table: key1 : " << nestedTable.get<std::string>("key1") << ", key2: "
<< x
<< '\n';
std::cout << "name of t2: " << t2.get<std::string>("name") << '\n';
#ifndef _MSC_VER
// VC++ has a bug in its implementation and
// I've filed a bug against the compiler at Microsoft,
// but the following
// works on g++ and clang++
std::cout << "name of t2: " << (std::string)t2["name"] << '\n';
#endif // VC++ being a dumb
std::string t2name = t2["name"];
std::cout << "name of t2: " << t2name << '\n';
/* Longer Syntax: */
// using the values stored in table1

View File

@ -60,7 +60,7 @@ int main() {
"y = x:test(10)");
auto y = lua.get<int>("y");
assert(y == 14);
std::cout << y << std::endl; // show 14
// if you want a class to have more than one constructor
// the way to do so is through set_userdata and creating

View File

@ -1,5 +1,5 @@
#include <sol.hpp>
#include <cassert>
#include <iostream>
int main() {
sol::state lua;
@ -26,9 +26,9 @@ int main() {
std::string y2;
std::tie(x2, y2) = lua.get<int, std::string>("x", "y");
// assert the values
assert(x == 10);
assert(y == "hello");
assert(x2 == 10);
assert(y2 == "hello");
// show the values
std::cout << x << std::endl;
std::cout << y << std::endl;
std::cout << x2 << std::endl;
std::cout << y2 << std::endl;
}

View File

@ -163,26 +163,33 @@ private:
int firstreturn = std::max(1, stacksize - static_cast<int>(n) - 1);
int returncount = 0;
call_status code = call_status::ok;
#ifdef SOL_NO_EXCEPTIONS
code = static_cast<call_status>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop(lua_state());
returncount = poststacksize - firstreturn;
#else
#ifndef SOL_NO_EXCEPTIONS
auto onexcept = [&](const char* error) {
h.stackindex = 0;
if (h.target.valid()) {
h.target.push();
stack::push(lua_state(), error);
lua_call(lua_state(), 1, 1);
}
else {
stack::push(lua_state(), error);
}
};
try {
#endif // No Exceptions
code = static_cast<call_status>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop(lua_state());
returncount = poststacksize - firstreturn;
#ifndef SOL_NO_EXCEPTIONS
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const char* error) {
h.stackindex = 0;
stack::push(lua_state(), error);
onexcept(error);
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
catch (const std::exception& error) {
h.stackindex = 0;
stack::push(lua_state(), error.what());
onexcept(error.what());
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
@ -347,7 +354,7 @@ struct pusher<function_sig<Sigs...>> {
template<typename... Args>
static int push(lua_State* L, Args&&... args) {
// Set will always place one thing (function) on the stack
set(L, std::forward<Args>(args)...);
set<Sigs...>(L, std::forward<Args>(args)...);
return 1;
}
};

View File

@ -35,8 +35,6 @@ public:
template<typename T>
decltype(auto) as() const {
push();
type actual = stack::get<type>(lua_state());
type_assert(lua_state(), -1, type_of<T>(), actual);
return stack::pop<T>(lua_state());
}

View File

@ -313,10 +313,7 @@ struct getter<const char*> {
template<>
struct getter<nil_t> {
static nil_t get(lua_State* L, int index = -1) {
if(lua_isnil(L, index) == 0) {
throw error("not nil");
}
static nil_t get(lua_State*, int = -1) {
return nil_t{ };
}
};
@ -869,7 +866,6 @@ inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, Fx&& fx, lua_St
}
inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
type metatype = stack::get<type>(L);
luaL_getmetatable(L, meta.c_str());
if (lua_compare(L, -1, -2, LUA_OPEQ) == 1) {
lua_pop(L, 1);

View File

@ -29,9 +29,13 @@
namespace sol {
namespace detail {
inline int atpanic(lua_State* L) {
#ifdef SOL_NO_EXCEPTIONS
(void)L;
#else
const char* message = lua_tostring(L, -1);
std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic";
throw error(err);
#endif
}
} // detail

View File

@ -237,7 +237,7 @@ private:
// Insert bubble to keep with compile-time argument count (simpler and cheaper to do)
functions.push_back(nullptr);
constructfunc = function_detail::construct<T, Args...>;
metafunctiontable.push_back({ functionnames.back().c_str(), constructfunc });
metafunctiontable.push_back({ name.c_str(), constructfunc });
}
template<std::size_t N>

View File

@ -1193,12 +1193,16 @@ TEST_CASE( "functions/function_result-protected_function_result", "Function resu
+ "end"
);
lua.set("nontrampoline", (lua_CFunction)[](lua_State*) -> int { throw "x";});
sol::protected_function doom = lua[ "doom" ];
sol::protected_function luadoom = lua["luadoom"];
sol::protected_function nontrampoline = lua["nontrampoline"];
sol::function luahandler = lua["luahandler"];
sol::function cpphandler = lua[ "cpphandler" ];
doom.error_handler = luahandler;
luadoom.error_handler = cpphandler;
nontrampoline.error_handler = cpphandler;
{
sol::protected_function_result result = doom();
@ -1212,6 +1216,12 @@ TEST_CASE( "functions/function_result-protected_function_result", "Function resu
std::string errorstring = result;
REQUIRE(errorstring == handlederrormessage);
}
{
sol::protected_function_result result = nontrampoline();
REQUIRE(!result.valid());
std::string errorstring = result;
REQUIRE(errorstring == handlederrormessage);
}
}
TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction happens") {
@ -1289,7 +1299,7 @@ TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction h
REQUIRE(last_call == static_call);
}
REQUIRE(created == 1);
REQUIRE(destroyed == 2);
REQUIRE(destroyed == 1);
}
}