From 923c774d5e7b67dcd2117c2cbf254eae92cc375c Mon Sep 17 00:00:00 2001 From: ThePhD Date: Wed, 2 Mar 2016 20:45:52 -0500 Subject: [PATCH] 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). --- .travis.yml | 2 +- examples/functions.cpp | 16 +++++++++++++--- examples/tables.cpp | 18 ++++++++---------- examples/usertype.cpp | 2 +- examples/variables.cpp | 12 ++++++------ sol/function.hpp | 27 +++++++++++++++++---------- sol/object.hpp | 2 -- sol/stack.hpp | 6 +----- sol/state_view.hpp | 4 ++++ sol/usertype.hpp | 2 +- tests.cpp | 16 +++++++++++++--- 11 files changed, 65 insertions(+), 42 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e1ebb5f..055e1828 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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: diff --git a/examples/functions.cpp b/examples/functions.cpp index 0b3c0843..d06a92f6 100644 --- a/examples/functions.cpp +++ b/examples/functions.cpp @@ -1,5 +1,6 @@ #include #include +#include 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(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)); diff --git a/examples/tables.cpp b/examples/tables.cpp index 98db99cc..2f9b6080 100644 --- a/examples/tables.cpp +++ b/examples/tables.cpp @@ -18,9 +18,6 @@ int main() { "}"); - auto t2 = lua.get("table2"); - auto nestedTable = t2.get("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("table2"); + auto nestedTable = t2.get("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("key1") << ", key2: " << x << '\n'; std::cout << "name of t2: " << t2.get("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 diff --git a/examples/usertype.cpp b/examples/usertype.cpp index 01c90d5a..b34309b3 100644 --- a/examples/usertype.cpp +++ b/examples/usertype.cpp @@ -60,7 +60,7 @@ int main() { "y = x:test(10)"); auto y = lua.get("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 diff --git a/examples/variables.cpp b/examples/variables.cpp index d627980d..38af0d39 100644 --- a/examples/variables.cpp +++ b/examples/variables.cpp @@ -1,5 +1,5 @@ #include -#include +#include int main() { sol::state lua; @@ -26,9 +26,9 @@ int main() { std::string y2; std::tie(x2, y2) = lua.get("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; } \ No newline at end of file diff --git a/sol/function.hpp b/sol/function.hpp index 6fcb7555..a770d08c 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -163,26 +163,33 @@ private: int firstreturn = std::max(1, stacksize - static_cast(n) - 1); int returncount = 0; call_status code = call_status::ok; -#ifdef SOL_NO_EXCEPTIONS - code = static_cast(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(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> { template static int push(lua_State* L, Args&&... args) { // Set will always place one thing (function) on the stack - set(L, std::forward(args)...); + set(L, std::forward(args)...); return 1; } }; diff --git a/sol/object.hpp b/sol/object.hpp index 0d602a16..60dafe3d 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -35,8 +35,6 @@ public: template decltype(auto) as() const { push(); - type actual = stack::get(lua_state()); - type_assert(lua_state(), -1, type_of(), actual); return stack::pop(lua_state()); } diff --git a/sol/stack.hpp b/sol/stack.hpp index 6ce25537..8cdcc1d3 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -313,10 +313,7 @@ struct getter { template<> struct getter { - 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, types ta, Fx&& fx, lua_St } inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) { - type metatype = stack::get(L); luaL_getmetatable(L, meta.c_str()); if (lua_compare(L, -1, -2, LUA_OPEQ) == 1) { lua_pop(L, 1); diff --git a/sol/state_view.hpp b/sol/state_view.hpp index 69129812..c6cb7027 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -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 diff --git a/sol/usertype.hpp b/sol/usertype.hpp index 09b204d2..5b1f383e 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -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; - metafunctiontable.push_back({ functionnames.back().c_str(), constructfunc }); + metafunctiontable.push_back({ name.c_str(), constructfunc }); } template diff --git a/tests.cpp b/tests.cpp index 8547810e..df4cefba 100644 --- a/tests.cpp +++ b/tests.cpp @@ -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::function luahandler = lua[ "luahandler" ]; + 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); } }