diff --git a/.gitignore b/.gitignore index 2cf6d7dd..2ea95f2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,8 @@ obj/* bin/* -*.ninja* demacro.txt Shinobi2 dev.* -main.cpp -sol.scratch.cpp lua-5.2.2/ Debug/ Release/ @@ -18,3 +15,6 @@ x64/ *.sln *.gitattributes liblua.a +sol/include/ +.ninja* +include/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..1c1a2167 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Catch"] + path = Catch + url = https://github.com/philsquared/Catch.git diff --git a/Catch b/Catch new file mode 160000 index 00000000..a6d74bd5 --- /dev/null +++ b/Catch @@ -0,0 +1 @@ +Subproject commit a6d74bd55aeff9a2506906e451305364f7a02d34 diff --git a/build.ninja b/build.ninja new file mode 100644 index 00000000..e574064c --- /dev/null +++ b/build.ninja @@ -0,0 +1,27 @@ +# This file has been generated by shinobi version 0.9.5 + +ninja_required_version = 1.3 +builddir = bin +objdir = obj +cxx = g++ +cxxflags = -std=c++11 -pedantic -pedantic-errors -Wextra -Wall -O2 -DNDEBUG +incflags = -I"." -I"./include" -I"." -I"/usr/include/lua5.2" -I"./lua-5.2.2/src/" -I"./Catch/include/" +linkflags = -static -L"./lib" -llua5.2 -ldl + +rule compile + command = $cxx -MMD -MF $out.d $cxxflags -c $in -o $out $incflags + deps = gcc + depfile = $out.d + description = Compiling $in + +rule link + command = $cxx $in -o $out $linkflags + description = Creating $out + +build $objdir/sol.scratch.o: compile sol.scratch.cpp + +build $builddir/sol.scratch: link $objdir/sol.scratch.o + +build install: phony $builddir/sol.scratch + +default install diff --git a/sol.scratch.cpp b/sol.scratch.cpp new file mode 100644 index 00000000..3600df44 --- /dev/null +++ b/sol.scratch.cpp @@ -0,0 +1,197 @@ +#define CATCH_CONFIG_MAIN +#include +#include + +std::string free_function() { + std::cout << "free_function()" << std::endl; + return "test"; +} + +struct object { + + std::string operator() () { + std::cout << "member_test()" << std::endl; + return "test"; + } + +}; + +int plop_xyz(int x, int y, std::string z) { + std::cout << x << " " << y << " " << z << std::endl; + return 11; +} + +TEST_CASE("simple/set_global", "Check if the set_global works properly.") { + sol::state lua; + + lua.set("a", 9); + REQUIRE_NOTHROW(lua.script("if a ~= 9 then error('wrong value') end")); + + lua.set("d", "hello"); + REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end")); + + lua.set("e", std::string("hello")); + REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end")); + + lua.set("f", true); + REQUIRE_NOTHROW(lua.script("if f ~= true then error('wrong value') end")); +} + +TEST_CASE("simple/get", "Tests if the get function works properly.") { + sol::state lua; + + lua.script("a = 9"); + auto a = lua.get("a"); + REQUIRE(a == 9.0); + + lua.script("b = nil"); + REQUIRE_NOTHROW(lua.get("b")); + + lua.script("d = 'hello'"); + auto d = lua.get("d"); + REQUIRE(d == "hello"); + + lua.script("e = true"); + auto e = lua.get("e"); + REQUIRE(e == true); +} + +TEST_CASE("simple/addition", "") { + sol::state lua; + + lua.set("b", 0.2); + lua.script("c = 9 + b"); + auto c = lua.get("c"); + + REQUIRE(c == 9.2); +} + +TEST_CASE("simple/if", "") { + sol::state lua; + + std::string program = "if true then f = 0.1 else f = 'test' end"; + lua.script(program); + auto f = lua.get("f"); + + REQUIRE(f == 0.1); +} + +TEST_CASE("simple/callWithParameters", "Lua function is called with a few parameters from C++") { + sol::state lua; + + REQUIRE_NOTHROW(lua.script("function my_add(i, j, k) return i + j + k end")); + auto f = lua.get("my_add"); + int a; + REQUIRE_NOTHROW(a = f.call(1, 2, 3)); + REQUIRE(a == 6); + REQUIRE_THROWS(a = f.call(1, 2, "arf")); +} + +TEST_CASE("simple/callCppFunction", "C++ function is called from lua") { + sol::state lua; + + lua.set_function("plop_xyz", plop_xyz); + lua.script("x = plop_xyz(2, 6, 'hello')"); + + REQUIRE(lua.get("x") == 11); +} + +TEST_CASE("simple/callLambda", "A C++ lambda is exposed to lua and called") { + sol::state lua; + + int x = 0; + + lua.set_function("foo", [ &x ] { x = 1; }); + + lua.script("foo()"); + + REQUIRE(x == 1); +} + +TEST_CASE("advanced/callLambdaReturns", "Checks for lambdas returning values") { + sol::state lua; + + lua.set_function("a", [ ] { return 42; }); + lua.set_function("b", [ ] { return 42u; }); + lua.set_function("c", [ ] { return 3.14; }); + lua.set_function("d", [ ] { return 6.28f; }); + lua.set_function("e", [ ] { return "lol"; }); + lua.set_function("f", [ ] { return true; }); + lua.set_function("g", [ ] { return std::string("str"); }); + lua.set_function("h", [ ] { }); + lua.set_function("i", [ ] { return sol::nil; }); +} + +TEST_CASE("advanced/callLambda2", "A C++ lambda is exposed to lua and called") { + sol::state lua; + + int x = 0; + lua.set_function("set_x", [ &] (int new_x) { + x = new_x; + return 0; + }); + + lua.script("set_x(9)"); + REQUIRE(x == 9); +} + +TEST_CASE("negative/basicError", "Check if error handling works correctly") { + sol::state lua; + + REQUIRE_THROWS(lua.script("nil[5]")); +} + +TEST_CASE("libraries", "Check if we can open libraries through sol") { + sol::state lua; + REQUIRE_NOTHROW(lua.open_libraries(sol::lib::base, sol::lib::os)); +} + +TEST_CASE("tables/variables", "Check if tables and variables work as intended") { + sol::state lua; + lua.open_libraries(sol::lib::base, sol::lib::os); + lua.get("os").set("name", "windows"); + REQUIRE_NOTHROW(lua.script("assert(os.name == \"windows\")")); +} + +TEST_CASE("tables/functions_variables", "Check if tables and function calls work as intended") { + sol::state lua; + lua.open_libraries(sol::lib::base, sol::lib::os); + auto run_script = [ ] (sol::state& lua) -> void { + lua.script("assert(os.fun() == \"test\")"); + }; + + lua.get("os").set_function("fun", + [ ] () { + std::cout << "stateless lambda()" << std::endl; + return "test"; + } + ); + REQUIRE_NOTHROW(run_script(lua)); + + lua.get("os").set_function("fun", &free_function); + REQUIRE_NOTHROW(run_script(lua)); + + // l-value, can optomize + auto lval = object(); + lua.get("os").set_function("fun", &object::operator(), lval); + REQUIRE_NOTHROW((lua)); + + // stateful lambda: non-convertible, unoptomizable + int breakit = 50; + lua.get("os").set_function("fun", + [ &breakit ] () { + std::cout << "stateless lambda()" << std::endl; + return "test"; + } + ); + REQUIRE_NOTHROW(run_script(lua)); + + // r-value, cannot optomize + lua.get("os").set_function("fun", &object::operator(), object()); + REQUIRE_NOTHROW(run_script(lua)); + + // r-value, cannot optomize + auto rval = object(); + lua.get("os").set_function("fun", &object::operator(), std::move(rval)); + REQUIRE_NOTHROW(run_script(lua)); +} \ No newline at end of file diff --git a/sol/function.hpp b/sol/function.hpp index fcdedc47..49319308 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -29,24 +29,28 @@ namespace sol { class function : virtual public reference { private: + void luacall (std::size_t argcount, std::size_t resultcount) { + lua_call(state(), static_cast(argcount), static_cast(resultcount)); + } + template - std::tuple call(types, std::size_t n) { - lua_pcall(state(), n, sizeof...(Ret), 0); - return stack::pop_call(state(), std::make_tuple, types()); + std::tuple invoke(types, std::size_t n) { + luacall(n, sizeof...(Ret)); + return stack::pop_call(state(), std::make_tuple, types()); } template - Ret call(types, std::size_t n) { - lua_pcall(state(), n, 1, 0); + Ret invoke(types, std::size_t n) { + luacall(n, 1); return stack::pop(state()); } - void call(types, std::size_t n) { - lua_pcall(state(), n, 0, 0); + void invoke(types, std::size_t n) { + luacall(n, 0); } - void call(types<>, std::size_t n) { - lua_pcall(state(), n, 0, 0); + void invoke(types<>, std::size_t n) { + luacall(n, 0); } public: @@ -56,10 +60,10 @@ public: } template - auto invoke(Args&&... args) -> decltype(call(types(), sizeof...(Args))) { + auto call(Args&&... args) -> decltype(invoke(types(), sizeof...(Args))) { push(); stack::push_args(state(), std::forward(args)...); - return call(types(), sizeof...(Args)); + return invoke(types(), sizeof...(Args)); } }; } // sol diff --git a/sol/functional.hpp b/sol/functional.hpp index 653864db..0ede1e5a 100644 --- a/sol/functional.hpp +++ b/sol/functional.hpp @@ -19,11 +19,11 @@ // 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. -#include "tuple.hpp" - #ifndef SOL_FUNCTIONAL_HPP #define SOL_FUNCTIONAL_HPP +#include "tuple.hpp" + namespace sol { namespace detail { diff --git a/sol/lua_function.hpp b/sol/lua_function.hpp index 61a5249d..d98e553b 100644 --- a/sol/lua_function.hpp +++ b/sol/lua_function.hpp @@ -29,32 +29,32 @@ namespace sol { namespace detail { template -void get_upvalue_ptr( lua_State* L, T*& data, std::size_t datasize, std::array voiddata, int& upvalue ) { - for ( std::size_t i = 0, d = 0; d < datasize; ++i, d += sizeof( void* ) ) { - voiddata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); - } - data = reinterpret_cast( static_cast( voiddata.data( ) ) ); +void get_upvalue_ptr(lua_State* L, T*& data, std::size_t datasize, std::array voiddata, int& upvalue) { + for (std::size_t i = 0, d = 0; d < datasize; ++i, d += sizeof(void*)) { + voiddata[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++)); + } + data = reinterpret_cast(static_cast(voiddata.data())); } template -void get_upvalue_ptr( lua_State* L, T*& data, std::array voiddata, int& upvalue ) { - get_upvalue_ptr( L, data, sizeof( T ), voiddata, upvalue ); +void get_upvalue_ptr(lua_State* L, T*& data, std::array voiddata, int& upvalue) { + get_upvalue_ptr(L, data, sizeof(T), voiddata, upvalue); } template -void get_upvalue_ptr( lua_State* L, T*& data, int& upvalue ) { - const static std::size_t data_t_count = ( sizeof(T)+( sizeof(void*)-1 ) ) / sizeof( void* ); - typedef std::array data_t; - data_t voiddata{{}}; - return get_upvalue_ptr(L, data, voiddata, upvalue); +void get_upvalue_ptr(lua_State* L, T*& data, int& upvalue) { + const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*); + typedef std::array data_t; + data_t voiddata{{}}; + return get_upvalue_ptr(L, data, voiddata, upvalue); } template -void get_upvalue( lua_State* L, T& data, int& upvalue ) { - const static std::size_t data_t_count = ( sizeof(T)+( sizeof(void*)-1 ) ) / sizeof( void* ); - typedef std::array data_t; - data_t voiddata{ { } }; - for ( std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof( void* ) ) { - voiddata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); - } - data = *reinterpret_cast( static_cast( voiddata.data( ) ) ); +void get_upvalue(lua_State* L, T& data, int& upvalue) { + const static std::size_t data_t_count = (sizeof(T)+(sizeof(void*)-1)) / sizeof(void*); + typedef std::array data_t; + data_t voiddata{ { } }; + for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { + voiddata[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++)); + } + data = *reinterpret_cast(static_cast(voiddata.data())); } } // detail @@ -80,7 +80,7 @@ struct static_lua_func { static int call(lua_State* L) { int upvalue = 1; fx_t* fx; - detail::get_upvalue( L, fx, upvalue ); + detail::get_upvalue(L, fx, upvalue); int r = typed_call(tuple_types(), typename fx_traits::args_type(), fx, L); return r; } @@ -105,8 +105,8 @@ struct static_object_lua_func { template static int typed_call(types, types, T& item, fx_t& ifx, lua_State* L) { auto fx = [ &item, &ifx ] (Args&&... args) -> TR { - return (item.*ifx)(std::forward(args)...); - }; + return (item.*ifx)(std::forward(args)...); + }; auto r = stack::pop_call(L, fx, types()); stack::push(L, std::move(r)); return 1; @@ -121,19 +121,19 @@ struct static_object_lua_func { } static int call(lua_State* L) { - const static std::size_t data_t_count = ( sizeof(fx_t)+( sizeof(void*)-1 ) ) / sizeof( void* ); - typedef std::array data_t; - int upvalue = 1; - data_t data = { { } }; - fx_t* fxptr; - for ( std::size_t i = 0, d = 0; d < sizeof(fx_t*); ++i, d += sizeof( void* ) ) { - data[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); - } - fxptr = reinterpret_cast( static_cast( data.data( ) ) ); - fx_t& mem_ptr = *fxptr; - void* objectdata = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); - T& obj = *static_cast( objectdata ); - int r = typed_call( tuple_types( ), typename fx_traits::args_type( ), obj, mem_ptr, L ); + const static std::size_t data_t_count = (sizeof(fx_t)+(sizeof(void*)-1)) / sizeof(void*); + typedef std::array data_t; + int upvalue = 1; + data_t data = { { } }; + fx_t* fxptr; + for (std::size_t i = 0, d = 0; d < sizeof(fx_t*); ++i, d += sizeof(void*)) { + data[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++)); + } + fxptr = reinterpret_cast(static_cast(data.data())); + fx_t& mem_ptr = *fxptr; + void* objectdata = lua_touserdata(L, lua_upvalueindex(upvalue++)); + T& obj = *static_cast(objectdata); + int r = typed_call(tuple_types(), typename fx_traits::args_type(), obj, mem_ptr, L); return r; } diff --git a/sol/stack.hpp b/sol/stack.hpp index 1fa8a024..b301072a 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -45,7 +45,7 @@ inline T get_unsigned(lua_State* L, std::true_type, int index = -1) { template inline T get_unsigned(lua_State* L, std::false_type, int index = -1) { - return lua_tointeger(L, index); + return static_cast(lua_tointeger(L, index)); } template @@ -61,11 +61,23 @@ inline T get_arithmetic(lua_State* L, std::true_type, int index = -1) { } template -inline T get_helper(lua_State* L, std::true_type, int index = -1) { +inline T get_nil(lua_State* L, std::true_type, int index = -1) { + if (lua_isnil(L, index) == 0) + throw sol::sol_error("not nil"); + return nil_t{}; +} + +template +inline T get_nil(lua_State* L, std::false_type, int index = -1) { // T is a class type return T(L, index); } +template +inline T get_helper(lua_State* L, std::true_type, int index = -1) { + return get_nil(L, std::is_same(), index); +} + template inline T get_helper(lua_State* L, std::false_type, int index = -1) { // T is a fundamental type @@ -184,19 +196,19 @@ inline void push(lua_State* L, const std::array& data) { } } -template -inline int push_user( lua_State* L, T& item ) { - typedef typename std::decay::type TValue; - const static std::size_t itemsize = sizeof( TValue ); - const static std::size_t voidsize = sizeof( void* ); - const static std::size_t voidsizem1 = voidsize - 1; - const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; - typedef std::array data_t; +template +inline int push_user(lua_State* L, T& item) { + typedef typename std::decay::type TValue; + const static std::size_t itemsize = sizeof(TValue); + const static std::size_t voidsize = sizeof(void*); + const static std::size_t voidsizem1 = voidsize - 1; + const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; + typedef std::array data_t; - data_t data{{}}; - std::memcpy( std::addressof( data[ 0 ] ), std::addressof( item ), itemsize ); - push( L, data ); - return data_t_count; + data_t data{{}}; + std::memcpy(std::addressof(data[ 0 ]), std::addressof(item), itemsize); + push(L, data); + return data_t_count; } namespace detail { @@ -215,7 +227,7 @@ auto ltr_pop(lua_State* L, F&& f, types, Vs&&... vs) -> decltype(ltr_pop(L return ltr_pop(L, std::forward(f), types<>(), std::forward(vs)..., pop(L)); } template -auto ltr_pop(lua_State* L, F&& f, types, Vs&&... vs) -> decltype(ltr_pop(L, std::forward(f), types(), std::forward(vs)..., pop(L))) { +auto ltr_pop(lua_State* L, F&& f, types, Vs&&... vs) -> decltype(f(std::forward(vs)..., std::declval(), std::declval()...)) { return ltr_pop(L, std::forward(f), types(), std::forward(vs)..., pop(L)); } } // detail diff --git a/sol/state.hpp b/sol/state.hpp index ebd4ced7..a6888cb0 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -121,8 +121,8 @@ public: } } - void open_file(const std::string& filename) { - if(luaL_dofile(L.get(), filename.c_str())) { + void script_file(const std::string& filename) { + if (luaL_dofile(L.get(), filename.c_str())) { lua_error(L.get()); } } diff --git a/sol/table.hpp b/sol/table.hpp index bcf635bb..14120adc 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -170,7 +170,7 @@ private: push(); - int upvalues = stack::push_user( state( ), target ); + int upvalues = stack::push_user(state(), target); luaL_setfuncs(state(), funcreg, upvalues); lua_pop(state(), 1); @@ -199,7 +199,7 @@ private: lua_settable(state(), -3); } - push(); + push(); stack::push_user(state(), userdata, metatablename); luaL_setfuncs(state(), funcreg, 1);