From 67116a67f952cccc5e62ae5d085bb4ed087ae940 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 17 Feb 2018 00:18:26 -0500 Subject: [PATCH] Fixes #588 Tentatively supports (?) #589 with sol::yielding and sol::yielding_t Added Catch as a cmake module --- CMakeLists.txt | 18 +-- appveyor.yml | 10 +- cmake/Modules/FindCatch.cmake | 79 +++++++++++ cmake/Modules/FindLuaBuild/LuaVanilla.cmake | 8 +- examples/require_dll_example/CMakeLists.txt | 10 +- sol/coroutine.hpp | 126 +++++++++++++++--- sol/function_types.hpp | 140 ++++++++++++-------- sol/function_types_core.hpp | 10 +- sol/function_types_stateful.hpp | 47 +++++-- sol/function_types_stateless.hpp | 74 ++++++++--- sol/protected_function.hpp | 69 +--------- sol/protected_handler.hpp | 108 +++++++++++++++ sol/proxy.hpp | 6 +- sol/types.hpp | 27 ++++ tests/CMakeLists.txt | 23 +++- tests/test_abort_clean.cpp | 2 +- tests/test_coroutines.cpp | 52 ++++++++ tests/test_sol.hpp | 5 + 18 files changed, 616 insertions(+), 198 deletions(-) create mode 100644 cmake/Modules/FindCatch.cmake create mode 100644 sol/protected_handler.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bfe4aefa..520e92c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,29 +69,25 @@ endif() # # # General project flags if (MSVC) - add_definitions(/DUNICODE /D_UNICODE /D_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING /D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING /D_CRT_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_DEPRECATE) + add_definitions(/DUNICODE /D_UNICODE /D_CRT_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_DEPRECATE) # Warning level, exceptions add_compile_options(/W4 /EHsc) if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(/MP) endif() else() - if (IS_X86) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") - endif() add_compile_options(-Wno-unknown-warning -Wno-unknown-warning-option -Wall -Wextra -Wpedantic -pedantic -pedantic-errors) endif() # # # General project output locations if (IS_X86 OR CMAKE_SIZEOF_VOID_P EQUAL 4) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x86/lib") - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x86/bin") - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x86/bin") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x86/lib") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x86/bin") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x86/bin") else() - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64/lib") - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64/bin") - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/x64/bin") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/lib") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/bin") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/bin") endif() # # # Modules diff --git a/appveyor.yml b/appveyor.yml index c34089b7..1f7c3c74 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,6 +47,8 @@ environment: # apparently, I can't quite make LLVM work right now... #- LUA_VERSION: 5.3.4 # LLVM_VERSION: 4.0.0 + - LUA_VERSION: 5.3.4 + MINGW_VERSION: 7.2.0 - LUA_VERSION: 5.3.4 MINGW_VERSION: 6.3.0 - LUA_VERSION: luajit-2.0.5 @@ -56,8 +58,8 @@ environment: - LUA_VERSION: 5.3.4 - LUA_VERSION: 5.2.4 - LUA_VERSION: 5.1.5 - #- LUA_VERSION: luajit-2.0.5 - #- LUA_VERSION: luajit-2.1.0-beta3 + - LUA_VERSION: luajit-2.0.5 + - LUA_VERSION: luajit-2.1.0-beta3 matrix: allow_failures: @@ -82,6 +84,8 @@ matrix: LUA_VERSION: 5.2.4 - platform: x86 LUA_VERSION: 5.1.5 + - platform: x86 + MINGW_VERSION: 7.2.0 # Get rid of redundant Visual Studio 2015 builds - image: Visual Studio 2015 LUA_VERSION: 5.1.5 @@ -107,6 +111,7 @@ init: - set llvm_path= - if "%MINGW_VERSION%"=="5.3.0" (set mingw_path=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin) - if "%MINGW_VERSION%"=="6.3.0" (if "%PLATFORM%"=="x64" (set mingw_path=C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin) else ( set mingw_path=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin)) +- if "%MINGW_VERSION%"=="6.3.0" (if "%PLATFORM%"=="x64" (set mingw_path=C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin) else ( set mingw_path=C:\mingw-w64\i686-7.2.0-posix-seh-rt_v5-rev1\mingw32\bin)) - if "%LLVM_VERSION%"=="4.0.0" (set llvm_path=C:\Program Files\LLVM\bin) - if "%PLATFORM%"=="x64" (set python_path=C:\Python36-x64) - set PATH=%python_path%;%PATH% @@ -128,6 +133,7 @@ init: - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (set CMAKE_GENERATOR=Visual Studio 14 2015%arch%&&set parallelism=/maxcpucount&&set logger=/verbosity:quiet /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll") - if "%MINGW_VERSION%"=="5.3.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) - if "%MINGW_VERSION%"=="6.3.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) +- if "%MINGW_VERSION%"=="7.2.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_C_COMPILER=gcc.exe) - if "%LLVM_VERSION%"=="4.0.0" (set CMAKE_GENERATOR=Ninja&&set parallelism= &&set logger= &&set build_type=-DCMAKE_BUILD_TYPE=Release&&set build_compiler=-DCMAKE_CXX_COMPILER=clang-cl.exe -DCMAKE_C_COMPILER=clang-cl.exe) # # Last printouts # print out generator information diff --git a/cmake/Modules/FindCatch.cmake b/cmake/Modules/FindCatch.cmake new file mode 100644 index 00000000..9421fba1 --- /dev/null +++ b/cmake/Modules/FindCatch.cmake @@ -0,0 +1,79 @@ +# # # # sol2 +# 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. + +include(ExternalProject) +include(FindPackageHandleStandardArgs) +include(Common/Core) + +# # Base variables +if (CATCH_VERSION) + set(catch_version ${CATCH_VERSION}) +else() + set(catch_version 2.0.1) +endif() + +set(catch_lib catch_lib_${catch_version}) + +# # Useful locations +set(catch_build_toplevel "${CMAKE_BINARY_DIR}/vendor/catch_${catch_version}") +set(catch_include_dirs "${catch_build_toplevel}") + +# # catch library sources +set(catch_sources catch.hpp) +prepend(catch_sources "${catch_build_toplevel}/" ${catch_sources}) + +# # External project to get sources +ExternalProject_Add(CATCH_BUILD_SOURCE + BUILD_IN_SOURCE TRUE + BUILD_ALWAYS FALSE + DOWNLOAD_NO_EXTRACT TRUE + URL https://github.com/catchorg/Catch2/releases/download/v${catch_version}/catch.hpp + TLS_VERIFY TRUE + PREFIX ${catch_build_toplevel} + SOURCE_DIR ${catch_build_toplevel} + DOWNLOAD_DIR ${catch_build_toplevel} + TMP_DIR "${catch_build_toplevel}-tmp" + STAMP_DIR "${catch_build_toplevel}-stamp" + INSTALL_DIR "${catch_build_toplevel}/local" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + BUILD_BYPRODUCTS "${catch_sources}") + +add_library(${catch_lib} INTERFACE) +add_dependencies(${catch_lib} CATCH_BUILD_SOURCE) +target_include_directories(${catch_lib} INTERFACE ${catch_include_dirs}) + +if (MSVC) + target_add_compile_options(${catch_lib} INTERFACE + /D_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING) +endif() + +set(CATCH_FOUND TRUE) +set(CATCH_LIBRARIES ${catch_lib}) +set(CATCH_INCLUDE_DIRS ${catch_include_dirs}) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Catch + FOUND_VAR CATCH_FOUND + REQUIRED_VARS CATCH_LIBRARIES CATCH_INCLUDE_DIRS + VERSION_VAR catch_version) diff --git a/cmake/Modules/FindLuaBuild/LuaVanilla.cmake b/cmake/Modules/FindLuaBuild/LuaVanilla.cmake index ce1ac3c3..0bf8c39c 100644 --- a/cmake/Modules/FindLuaBuild/LuaVanilla.cmake +++ b/cmake/Modules/FindLuaBuild/LuaVanilla.cmake @@ -285,11 +285,9 @@ set_target_properties(${liblua} LIBRARY_OUTPUT_NAME ${LUA_BUILD_LIBNAME} ARCHIVE_OUTPUT_NAME ${LUA_BUILD_LIBNAME}) target_include_directories(${liblua} - PRIVATE ${LUA_VANILLA_SOURCE_DIR} PUBLIC ${LUA_VANILLA_SOURCE_DIR}) target_compile_definitions(${liblua} - PUBLIC LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE} - PRIVATE LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE}) + PUBLIC LUA_COMPAT_ALL ${LUA_VANILLA_DLL_DEFINE}) if (MSVC) target_compile_options(${liblua} PRIVATE /W1) @@ -298,8 +296,8 @@ else() PRIVATE -w) endif() if (WIN32) - #target_compile_definitions(${liblua} - # PRIVATE LUA_USE_WINDOWS) + target_compile_definitions(${liblua} + PRIVATE LUA_USE_WINDOWS) else() target_compile_definitions(${liblua} PRIVATE LUA_USE_LINUX) diff --git a/examples/require_dll_example/CMakeLists.txt b/examples/require_dll_example/CMakeLists.txt index bdd6034e..2a4e3b61 100644 --- a/examples/require_dll_example/CMakeLists.txt +++ b/examples/require_dll_example/CMakeLists.txt @@ -65,9 +65,17 @@ function(make_require_from_dll_example target_lib is_single) target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES}) endif() else() - target_link_libraries(${example_lib_name} PUBLIC ${LUA_LIBRARIES}) + if (lua_lib_type MATCHES "STATIC") + target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES}) + set_target_properties(${example_lib_name} PROPERTIES + WINDOWS_EXPORT_ALL_SYMBOLS TRUE + LINK_FLAGS "/OPT:NOREF /WHOLEARCHIVE:lua-5.2.4.lib") + else() + target_link_libraries(${example_lib_name} PRIVATE ${LUA_LIBRARIES}) + endif() endif() target_link_libraries(${example_lib_name} PRIVATE ${target_lib}) + target_include_directories(${example_lib_name} PUBLIC "${LUA_INCLUDE_DIRS}") # add executable target that represents require_from_dll program add_executable(${example_name} ${require_from_dll_sources}) diff --git a/sol/coroutine.hpp b/sol/coroutine.hpp index 5e05bd46..e75efce6 100644 --- a/sol/coroutine.hpp +++ b/sol/coroutine.hpp @@ -28,10 +28,15 @@ #include "stack.hpp" #include "function_result.hpp" #include "thread.hpp" +#include "protected_handler.hpp" namespace sol { template class basic_coroutine : public base_t { + public: + typedef reference handler_t; + handler_t error_handler; + private: call_status stats = call_status::yielded; @@ -59,53 +64,130 @@ namespace sol { protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) { int firstreturn = 1; luacall(n, LUA_MULTRET); - int poststacksize = lua_gettop(lua_state()); + int poststacksize = lua_gettop(this->lua_state()); int returncount = poststacksize - (firstreturn - 1); if (error()) { - return protected_function_result(lua_state(), lua_absindex(lua_state(), -1), 1, returncount, status()); + if (error_handler.valid()) { + string_view err = stack::get(this->lua_state(), poststacksize); + error_handler.push(); + stack::push(this->lua_state(), err); + lua_call(lua_state(), 1, 1); + } + return protected_function_result(this->lua_state(), lua_absindex(this->lua_state(), -1), 1, returncount, status()); } - return protected_function_result(lua_state(), firstreturn, returncount, returncount, status()); + return protected_function_result(this->lua_state(), firstreturn, returncount, returncount, status()); } public: using base_t::lua_state; - - basic_coroutine() noexcept = default; - basic_coroutine(const basic_coroutine&) noexcept = default; - basic_coroutine(basic_coroutine&&) noexcept = default; - basic_coroutine& operator=(const basic_coroutine&) noexcept = default; - basic_coroutine& operator=(basic_coroutine&&) noexcept = default; - template , basic_coroutine>>, is_lua_reference>> = meta::enabler> - basic_coroutine(T&& r) - : base_t(std::forward(r)) { + + basic_coroutine() = default; + template , basic_coroutine>>, meta::neg>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> + basic_coroutine(T&& r) noexcept + : base_t(std::forward(r)), error_handler(detail::get_default_handler::value>(r.lua_state())) { +#ifdef SOL_SAFE_REFERENCES + if (!is_function>::value) { + auto pp = stack::push_pop(*this); + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); + } +#endif // Safety } - basic_coroutine(lua_nil_t r) - : base_t(r) { + basic_coroutine(const basic_coroutine&) = default; + basic_coroutine& operator=(const basic_coroutine&) = default; + basic_coroutine(basic_coroutine&&) = default; + basic_coroutine& operator=(basic_coroutine&&) = default; + basic_coroutine(const basic_function& b) + : basic_coroutine(b, detail::get_default_handler::value>(b.lua_state())) { } - basic_coroutine(const stack_reference& r) noexcept - : basic_coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(basic_function&& b) + : basic_coroutine(std::move(b), detail::get_default_handler::value>(b.lua_state())) { } - basic_coroutine(stack_reference&& r) noexcept - : basic_coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(const basic_function& b, handler_t eh) + : base_t(b), error_handler(std::move(eh)) { } + basic_coroutine(basic_function&& b, handler_t eh) + : base_t(std::move(b)), error_handler(std::move(eh)) { + } + basic_coroutine(const stack_reference& r) + : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler::value>(r.lua_state())) { + } + basic_coroutine(stack_reference&& r) + : basic_coroutine(r.lua_state(), r.stack_index(), detail::get_default_handler::value>(r.lua_state())) { + } + basic_coroutine(const stack_reference& r, handler_t eh) + : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { + } + basic_coroutine(stack_reference&& r, handler_t eh) + : basic_coroutine(r.lua_state(), r.stack_index(), std::move(eh)) { + } + + template + basic_coroutine(const proxy_base& p) + : basic_coroutine(p, detail::get_default_handler::value>(p.lua_state())) { + } + template + basic_coroutine(proxy_base&& p) + : basic_coroutine(std::move(p), detail::get_default_handler::value>(p.lua_state())) { + } + template >, meta::neg>>> = meta::enabler> + basic_coroutine(Proxy&& p, Handler&& eh) + : basic_coroutine(detail::force_cast(p), std::forward(eh)) { + } + template >> = meta::enabler> basic_coroutine(lua_State* L, T&& r) - : base_t(L, std::forward(r)) { + : basic_coroutine(L, std::forward(r), detail::get_default_handler::value>(L)) { + } + template >> = meta::enabler> + basic_coroutine(lua_State* L, T&& r, handler_t eh) + : base_t(L, std::forward(r)), error_handler(std::move(eh)) { #ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; stack::check(lua_state(), -1, handler); #endif // Safety } + + basic_coroutine(lua_nil_t n) + : base_t(n), error_handler(n) { + } + basic_coroutine(lua_State* L, int index = -1) - : base_t(L, index) { + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, int index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_SAFE_REFERENCES constructor_handler handler{}; - stack::check(lua_state(), index, handler); + stack::check(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, absolute_index index) + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, absolute_index index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES + constructor_handler handler{}; + stack::check(L, index, handler); +#endif // Safety + } + basic_coroutine(lua_State* L, raw_index index) + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, raw_index index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { +#ifdef SOL_SAFE_REFERENCES + constructor_handler handler{}; + stack::check(L, index, handler); #endif // Safety } basic_coroutine(lua_State* L, ref_index index) - : base_t(L, index) { + : basic_coroutine(L, index, detail::get_default_handler::value>(L)) { + } + basic_coroutine(lua_State* L, ref_index index, handler_t eh) + : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_SAFE_REFERENCES auto pp = stack::push_pop(*this); constructor_handler handler{}; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 91619f40..4ce3242e 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -39,50 +39,51 @@ namespace sol { struct call_indicator {}; } // namespace function_detail + namespace stack { template struct pusher> { - template + template static void select_convertible(std::false_type, types, lua_State* L, Fx&& fx, Args&&... args) { typedef std::remove_pointer_t> clean_fx; - typedef function_detail::functor_function F; - set_fx(L, std::forward(fx), std::forward(args)...); + typedef function_detail::functor_function F; + set_fx(L, std::forward(fx), std::forward(args)...); } - template + template static void select_convertible(std::true_type, types, lua_State* L, Fx&& fx, Args&&... args) { using fx_ptr_t = R (*)(A...); fx_ptr_t fxptr = detail::unwrap(std::forward(fx)); - select_function(std::true_type(), L, fxptr, std::forward(args)...); + select_function(std::true_type(), L, fxptr, std::forward(args)...); } - template + template static void select_convertible(types t, lua_State* L, Fx&& fx, Args&&... args) { typedef std::decay_t> raw_fx_t; typedef R (*fx_ptr_t)(A...); typedef std::is_convertible is_convertible; - select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); + select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); } - template + template static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { typedef meta::function_signature_t> Sig; - select_convertible(types(), L, std::forward(fx), std::forward(args)...); + select_convertible(types(), L, std::forward(fx), std::forward(args)...); } - template + template static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::remove_pointer_t> clean_fx; - typedef function_detail::member_variable, clean_fx> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); + typedef function_detail::member_variable, clean_fx, is_yielding> F; + set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::decay_t dFx; dFx memfxptr(std::forward(fx)); auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t>::call; + lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t, is_yielding>::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -91,49 +92,51 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_convertible(types(), L, std::forward(fx), std::forward(args)...); + select_convertible(types(), L, std::forward(fx), std::forward(args)...); } - template >> = meta::enabler> + template >> = meta::enabler> static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef meta::boolean>::value || std::is_pointer::value> is_reference; - select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); + select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::decay_t clean_fx; - typedef function_detail::member_function, clean_fx> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); + typedef function_detail::member_function, clean_fx, is_yielding> F; + set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef std::decay_t dFx; dFx memfxptr(std::forward(fx)); auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t>::call; + lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t, is_yielding>::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -142,45 +145,47 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); + select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); } - template >> = meta::enabler> + template >> = meta::enabler> static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { typedef meta::boolean>::value || std::is_pointer::value> is_reference; - select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); + select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); } - template + template static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; + int upvalues = 0; upvalues += stack::push(L, nullptr); upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } - template + template static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); + select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); } - template + template static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { std::decay_t target(std::forward(fx), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_free_function::call; + lua_CFunction freefunc = &function_detail::upvalue_free_function::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -188,29 +193,34 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } + template static void select_function(std::true_type, lua_State* L, lua_CFunction f) { + // TODO: support yielding stack::push(L, f); } #ifdef SOL_NOEXCEPT_FUNCTION_TYPE + template static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { + // TODO: support yielding stack::push(L, f); } #endif // noexcept function type - template >> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx, Args&&... args) { - select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); + select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); } - template >> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx) { + // TODO: hoist into lambda in this case?? stack::push(L, std::forward(fx)); } - template + template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call, 2>; + lua_CFunction freefunc = function_detail::call, 2, is_yielding>; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -218,12 +228,36 @@ namespace sol { stack::push(L, c_closure(freefunc, upvalues)); } - template - static int push(lua_State* L, Args&&... args) { + template >> = meta::enabler> + static int push(lua_State* L, Arg0&& arg0, Args&&... args) { // Set will always place one thing (function) on the stack - select(L, std::forward(args)...); + select(L, std::forward(arg0), std::forward(args)...); return 1; } + + template + static int push(lua_State* L, detail::yield_tag_t, Args&&... args) { + // Set will always place one thing (function) on the stack + select(L, std::forward(args)...); + return 1; + } + }; + + template + struct pusher> { + template + static int push(lua_State* L, const yielding_t& f, Args&&... args) { + pusher> p{}; + (void)p; + return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + } + + template + static int push(lua_State* L, yielding_t&& f, Args&&... args) { + pusher> p{}; + (void)p; + return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + } }; template @@ -257,7 +291,9 @@ namespace sol { struct pusher::value>> { template static int push(lua_State* L, F&& f, Args&&... args) { - return pusher>{}.push(L, std::forward(f), std::forward(args)...); + pusher> p{}; + (void)p; + return p.push(L, std::forward(f), std::forward(args)...); } }; @@ -352,25 +388,25 @@ namespace sol { struct pusher> { static int push(lua_State* L, const factory_wrapper& fw) { typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, fw.functions); + pusher>{}.set_fx(L, fw.functions); return 1; } static int push(lua_State* L, factory_wrapper&& fw) { typedef function_detail::overloaded_function<0, Functions...> F; - pusher>{}.set_fx(L, std::move(fw.functions)); + pusher>{}.set_fx(L, std::move(fw.functions)); return 1; } static int push(lua_State* L, const factory_wrapper& set, function_detail::call_indicator) { typedef function_detail::overloaded_function<1, Functions...> F; - pusher>{}.set_fx(L, set.functions); + pusher>{}.set_fx(L, set.functions); return 1; } static int push(lua_State* L, factory_wrapper&& set, function_detail::call_indicator) { typedef function_detail::overloaded_function<1, Functions...> F; - pusher>{}.set_fx(L, std::move(set.functions)); + pusher>{}.set_fx(L, std::move(set.functions)); return 1; } }; diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index c7cf9452..f9db65b2 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -30,10 +30,16 @@ namespace sol { namespace function_detail { - template + template inline int call(lua_State* L) { Fx& fx = stack::get>(L, upvalue_index(start)); - return fx(L); + int nr = fx(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } } } // namespace sol::function_detail diff --git a/sol/function_types_stateful.hpp b/sol/function_types_stateful.hpp index 9b851242..dc1e2eb6 100644 --- a/sol/function_types_stateful.hpp +++ b/sol/function_types_stateful.hpp @@ -28,7 +28,7 @@ namespace sol { namespace function_detail { - template + template struct functor_function { typedef std::decay_t> function_type; function_type fx; @@ -39,7 +39,13 @@ namespace function_detail { } int call(lua_State* L) { - return call_detail::call_wrapped(L, fx); + int nr = call_detail::call_wrapped(L, fx); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -48,7 +54,7 @@ namespace function_detail { } }; - template + template struct member_function { typedef std::remove_pointer_t> function_type; typedef meta::function_return_t return_type; @@ -62,7 +68,13 @@ namespace function_detail { } int call(lua_State* L) { - return call_detail::call_wrapped(L, invocation, detail::unwrap(detail::deref(member))); + int nr = call_detail::call_wrapped(L, invocation, detail::unwrap(detail::deref(member))); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -71,7 +83,7 @@ namespace function_detail { } }; - template + template struct member_variable { typedef std::remove_pointer_t> function_type; typedef typename meta::bind_traits::return_type return_type; @@ -86,14 +98,23 @@ namespace function_detail { } int call(lua_State* L) { - M mem = detail::unwrap(detail::deref(member)); - switch (lua_gettop(L)) { - case 0: - return call_detail::call_wrapped(L, var, mem); - case 1: - return call_detail::call_wrapped(L, var, mem); - default: - return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + int nr; + { + M mem = detail::unwrap(detail::deref(member)); + switch (lua_gettop(L)) { + case 0: + nr = call_detail::call_wrapped(L, var, mem); + case 1: + nr = call_detail::call_wrapped(L, var, mem); + default: + nr = luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; } } diff --git a/sol/function_types_stateless.hpp b/sol/function_types_stateless.hpp index e60b93fd..68d7cc07 100644 --- a/sol/function_types_stateless.hpp +++ b/sol/function_types_stateless.hpp @@ -28,7 +28,7 @@ namespace sol { namespace function_detail { - template + template struct upvalue_free_function { typedef std::remove_pointer_t> function_type; typedef meta::bind_traits traits_type; @@ -40,7 +40,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -48,7 +54,7 @@ namespace function_detail { } }; - template + template struct upvalue_member_function { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -67,7 +73,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -75,7 +87,7 @@ namespace function_detail { } }; - template + template struct upvalue_member_variable { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -101,7 +113,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -109,8 +127,8 @@ namespace function_detail { } }; - template - struct upvalue_member_variable> { + template + struct upvalue_member_variable, is_yielding> { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -133,7 +151,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -141,7 +165,7 @@ namespace function_detail { } }; - template + template struct upvalue_this_member_function { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -155,7 +179,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -163,7 +193,7 @@ namespace function_detail { } }; - template + template struct upvalue_this_member_variable { typedef std::remove_pointer_t> function_type; @@ -183,7 +213,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { @@ -191,8 +227,8 @@ namespace function_detail { } }; - template - struct upvalue_this_member_variable> { + template + struct upvalue_this_member_variable, is_yielding> { typedef std::remove_pointer_t> function_type; typedef lua_bind_traits traits_type; @@ -210,7 +246,13 @@ namespace function_detail { } static int call(lua_State* L) { - return detail::typed_static_trampoline(L); + int nr = detail::typed_static_trampoline(L); + if (is_yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } } int operator()(lua_State* L) { diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp index aba83398..6c6c776d 100644 --- a/sol/protected_function.hpp +++ b/sol/protected_function.hpp @@ -28,86 +28,23 @@ #include "stack.hpp" #include "protected_function_result.hpp" #include "unsafe_function.hpp" +#include "protected_handler.hpp" #include #include namespace sol { - namespace detail { - inline const char (&default_handler_name())[9] { - static const char name[9] = "sol.\xF0\x9F\x94\xA9"; - return name; - } - - template - struct protected_handler { - typedef is_stack_based is_stack; - const target_t& target; - int stackindex; - - protected_handler(std::false_type, const target_t& target) - : target(target), stackindex(0) { - if (b) { - stackindex = lua_gettop(target.lua_state()) + 1; - target.push(); - } - } - - protected_handler(std::true_type, const target_t& target) - : target(target), stackindex(0) { - if (b) { - stackindex = target.stack_index(); - } - } - - protected_handler(const target_t& target) - : protected_handler(is_stack(), target) { - } - - bool valid() const noexcept { - return b; - } - - ~protected_handler() { - if (!is_stack::value && stackindex != 0) { - lua_remove(target.lua_state(), stackindex); - } - } - }; - - template - basic_function force_cast(T& p) { - return p; - } - } // namespace detail - template class basic_protected_function : public base_t { public: typedef is_stack_based is_stack_handler; static handler_t get_default_handler(lua_State* L) { - if (is_stack_handler::value || L == nullptr) - return handler_t(L, lua_nil); - L = is_main_threaded::value ? main_thread(L, L) : L; - lua_getglobal(L, detail::default_handler_name()); - auto pp = stack::pop_n(L, 1); - return handler_t(L, -1); + return detail::get_default_handler::value>(L); } template static void set_default_handler(const T& ref) { - if (ref.lua_state() == nullptr) { - return; - } - lua_State* L = ref.lua_state(); - if (!ref.valid()) { - lua_pushnil(L); - lua_setglobal(L, detail::default_handler_name()); - } - else { - ref.push(); - lua_setglobal(L, detail::default_handler_name()); - } + detail::set_default_handler(ref.lua_state(), ref); } private: diff --git a/sol/protected_handler.hpp b/sol/protected_handler.hpp new file mode 100644 index 00000000..64721c69 --- /dev/null +++ b/sol/protected_handler.hpp @@ -0,0 +1,108 @@ +// sol2 + +// 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_PROTECTED_HANDLER_HPP +#define SOL_PROTECTED_HANDLER_HPP + +#include "reference.hpp" +#include "stack.hpp" +#include "protected_function_result.hpp" +#include "unsafe_function.hpp" +#include + +namespace sol { + namespace detail { + inline const char(&default_handler_name())[9]{ + static const char name[9] = "sol.\xF0\x9F\x94\xA9"; + return name; + } + + template + struct protected_handler { + typedef is_stack_based is_stack; + const target_t& target; + int stackindex; + + protected_handler(std::false_type, const target_t& target) + : target(target), stackindex(0) { + if (b) { + stackindex = lua_gettop(target.lua_state()) + 1; + target.push(); + } + } + + protected_handler(std::true_type, const target_t& target) + : target(target), stackindex(0) { + if (b) { + stackindex = target.stack_index(); + } + } + + protected_handler(const target_t& target) + : protected_handler(is_stack(), target) { + } + + bool valid() const noexcept { + return b; + } + + ~protected_handler() { + if (!is_stack::value && stackindex != 0) { + lua_remove(target.lua_state(), stackindex); + } + } + }; + + template + basic_function force_cast(T& p) { + return p; + } + + template + static Reference get_default_handler(lua_State* L) { + if (is_stack_based::value || L == nullptr) + return Reference(L, lua_nil); + L = is_main_ref ? main_thread(L, L) : L; + lua_getglobal(L, default_handler_name()); + auto pp = stack::pop_n(L, 1); + return Reference(L, -1); + } + + template + static void set_default_handler(lua_State* L, const T& ref) { + if (L == nullptr) { + return; + } + if (!ref.valid()) { + lua_pushnil(L); + lua_setglobal(L, default_handler_name()); + } + else { + ref.push(L); + lua_setglobal(L, default_handler_name()); + } + } + } // namespace detail +} // namespace sol + +#endif // SOL_PROTECTED_HANDLER_HPP diff --git a/sol/proxy.hpp b/sol/proxy.hpp index ef464054..e2a24124 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -146,7 +146,11 @@ namespace sol { } int push() const noexcept { - return get().push(lua_state()); + return push(this->lua_state()); + } + + int push(lua_State* L) const noexcept { + return get().push(L); } type get_type() const { diff --git a/sol/types.hpp b/sol/types.hpp index ec19f20c..ebc96e19 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -200,6 +200,9 @@ namespace sol { struct unchecked_t {}; const unchecked_t unchecked = unchecked_t{}; + + struct yield_tag_t {}; + const yield_tag_t yield_tag = yield_tag_t{}; } // namespace detail struct lua_nil_t {}; @@ -224,6 +227,30 @@ namespace sol { struct no_metatable_t {}; const no_metatable_t no_metatable = {}; + template + struct yielding_t { + T func; + + yielding_t() = default; + yielding_t(const yielding_t&) = default; + yielding_t(yielding_t&&) = default; + yielding_t& operator=(const yielding_t&) = default; + yielding_t& operator=(yielding_t&&) = default; + template , yielding_t>>, meta::neg>>> = meta::enabler> + yielding_t(Arg&& arg) + : func(std::forward(arg)) { + } + template + yielding_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) + : func(std::forward(arg0), std::forward(arg1), std::forward(args)...) { + } + }; + + template + inline yielding_t> yielding(F&& f) { + return yielding_t>(std::forward(f)); + } + typedef std::remove_pointer_t lua_CFunction_ref; template diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f6a429d4..2a7e0ef5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,10 +22,10 @@ # # # # sol2 tests +find_package(CATCH 2.0.1 REQUIRED) + file(GLOB SOL2_TEST_SOURCES test*.cpp) source_group(test_sources FILES ${SOL2_TEST_SOURCES}) -file(DOWNLOAD https://github.com/catchorg/Catch2/releases/download/v2.0.1/catch.hpp ${CMAKE_BINARY_DIR}/vendor/Catch/include/catch.hpp) -#file(DOWNLOAD https://github.com/catchorg/Catch2/releases/download/v1.11.0/catch.hpp ${CMAKE_BINARY_DIR}/vendor/Catch/include/catch.hpp) function(CREATE_TEST test_target_name test_name is_single) if (is_single) @@ -46,8 +46,6 @@ function(CREATE_TEST test_target_name test_name is_single) target_link_libraries(${test_target_name} sol2) endif() - target_include_directories(${test_target_name} - PRIVATE "${LUA_INCLUDE_DIR}" "${CMAKE_BINARY_DIR}/vendor/Catch/include/") if (MSVC) if (NOT CMAKE_COMPILER_ID MATCHES "Clang") target_compile_options(${test_target_name} @@ -63,9 +61,22 @@ function(CREATE_TEST test_target_name test_name is_single) endif() target_compile_features(${test_target_name} PRIVATE ${CXX_FEATURES}) - # if CMAKE_DL_LIBS is empty, then that just resolves to nothingness + if (CMAKE_DL_LIBS) + target_link_libraries(${test_target_name} + ${CMAKE_DL_LIBS}) + endif() target_link_libraries(${test_target_name} - Threads::Threads ${LUA_LIBRARIES} ${CMAKE_DL_LIBS}) + Threads::Threads ${LUA_LIBRARIES} ${CATCH_LIBRARIES}) + + if (IS_X86) + target_compile_options(${test_target_name} BEFORE PRIVATE -m32) + endif() + + if(MINGW AND IS_X86) + #set_target_properties(${test_target_name} + # PROPERTIES + # LINK_FLAGS -static-libstdc++) + endif() add_test(NAME ${test_name} COMMAND ${test_target_name}) install(TARGETS ${test_target_name} RUNTIME DESTINATION bin) diff --git a/tests/test_abort_clean.cpp b/tests/test_abort_clean.cpp index 6ed2a0dc..7baee995 100644 --- a/tests/test_abort_clean.cpp +++ b/tests/test_abort_clean.cpp @@ -3,7 +3,7 @@ struct pre_main { pre_main() { #ifdef SOL2_CI - #ifdef _MSC_VER +#ifdef _MSC_VER _set_abort_behavior(0, _WRITE_ABORT_MSG); #endif #endif diff --git a/tests/test_coroutines.cpp b/tests/test_coroutines.cpp index 0506f90a..9b5d482a 100644 --- a/tests/test_coroutines.cpp +++ b/tests/test_coroutines.cpp @@ -530,3 +530,55 @@ end REQUIRE(s4 == 0); REQUIRE(s5 == 0); } + +TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when marked yieldable") { + sol::state lua; + lua.open_libraries(sol::lib::base, sol::lib::coroutine); + + int i = 0; + auto func = [&i]() { + ++i; + return i; + }; + + struct h { + int x = 500; + int func() const { + return x; + } + } hobj{}; + + lua["f"] = sol::yielding(func); + lua["g"] = sol::yielding([]() { return 300; }); + lua["h"] = sol::yielding(&h::func); + lua["hobj"] = &hobj; + + sol::string_view code = R"( + co1 = coroutine.create(f) + success1, value1 = coroutine.resume(co1) + co2 = coroutine.create(g) + success2, value2 = coroutine.resume(co2) + co3 = coroutine.create(function() + h(hobj) + end) + success3, value3 = coroutine.resume(co3) + )"; + + auto result = lua.safe_script(code); + REQUIRE(result.valid()); + + bool success1 = lua["success1"]; + int value1 = lua["value1"]; + REQUIRE(success1); + REQUIRE(value1 == 1); + + bool success2 = lua["success2"]; + int value2 = lua["value2"]; + REQUIRE(success2); + REQUIRE(value2 == 300); + + bool success3 = lua["success3"]; + int value3 = lua["value3"]; + REQUIRE(success3); + REQUIRE(value3 == 500); +} diff --git a/tests/test_sol.hpp b/tests/test_sol.hpp index c366f6f4..b4dc776e 100644 --- a/tests/test_sol.hpp +++ b/tests/test_sol.hpp @@ -23,6 +23,9 @@ #pragma once +#ifndef SOL_TEST_SOL_HPP +#define SOL_TEST_SOL_HPP + #ifndef SOL_CHECK_ARGUMENTS #define SOL_CHECK_ARGUMENTS 1 #endif // SOL_CHECK_ARGUMENTS @@ -60,3 +63,5 @@ struct test_stack_guard { endtop = lua_gettop(L); } }; + +#endif // SOL_TEST_SOL_HPP