From a2eced863f1dc8a98a8853f2a98e8958df34fc17 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 23 Apr 2016 18:18:02 -0400 Subject: [PATCH] shiny new `load_result` type, and thusly we're ready for `2.5`. --- docs/source/api/state.rst | 7 +- docs/source/api/types.rst | 26 ++++- docs/source/tutorial/all-the-things.rst | 29 +++-- sol/load_result.hpp | 139 ++++++++++++++++++++++++ sol/protected_function_result.hpp | 4 +- sol/stack_reference.hpp | 9 ++ sol/state_view.hpp | 13 ++- sol/thread.hpp | 2 +- sol/types.hpp | 20 +++- 9 files changed, 216 insertions(+), 33 deletions(-) create mode 100644 sol/load_result.hpp diff --git a/docs/source/api/state.rst b/docs/source/api/state.rst index bf178c96..27e8d210 100644 --- a/docs/source/api/state.rst +++ b/docs/source/api/state.rst @@ -60,11 +60,12 @@ These functions run the desired blob of either code that is in a string, or code .. code-block:: cpp :caption: function: load / load_file + :name: state-load-code - sol::stack_proxy load(const std::string& code); - sol::stack_proxy load_file(const std::string& filename); + sol::load_result load(const std::string& code); + sol::load_result load_file(const std::string& filename); -These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It will not run: it returns a proxy that can be called, turned into a `sol::function`,. or similar, will run the loaded code. +These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. It will not run: it returns a ``load_result`` proxy that can be called, turned into a `sol::function`,. or similar, will run the loaded code. .. code-block:: cpp :caption: function: global table / registry table diff --git a/docs/source/api/types.rst b/docs/source/api/types.rst index 2b361daf..2aa126d3 100644 --- a/docs/source/api/types.rst +++ b/docs/source/api/types.rst @@ -40,17 +40,31 @@ This strongly-typed enumeration contains the errors potentially generated by a c :name: thread-status enum class thread_status : int { - normal = LUA_OK, - yielded = LUA_YIELD, - error_runtime = LUA_ERRRUN, - error_memory = LUA_ERRMEM, - error_gc = LUA_ERRGCMM, - error_handler = LUA_ERRERR, + ok = LUA_OK, + yielded = LUA_YIELD, + runtime = LUA_ERRRUN, + memory = LUA_ERRMEM, + gc = LUA_ERRGCMM, + handler = LUA_ERRERR, dead, }; This enumeration contains the status of a thread. The ``thread_status::dead`` state is generated when the thread has nothing on its stack and it is not running anything. +.. code-block:: cpp + :caption: status of a Lua load operation + :name: load-status + + enum class load_status : int { + ok = LUA_OK, + runtime = LUA_ERRSYNTAX, + memory = LUA_ERRMEM, + gc = LUA_ERRGCMM, + file = LUA_ERRFILE, + }; + +This enumeration contains the status of a load operation from :ref:`state::load(_file)`. The ``thread_status::dead`` state is generated when the thread has nothing on its stack and it is not running anything. + .. code-block:: cpp :caption: type enumeration :name: type-enum diff --git a/docs/source/tutorial/all-the-things.rst b/docs/source/tutorial/all-the-things.rst index e8634e80..80b90664 100644 --- a/docs/source/tutorial/all-the-things.rst +++ b/docs/source/tutorial/all-the-things.rst @@ -34,6 +34,8 @@ For your system/game that already has lua, but you'd like something nice: running lua code ---------------- +.. code-block:: cpp + sol::state lua; // load and execute from string lua.script("a = 'test'"); @@ -57,17 +59,26 @@ You can set/get everything. sol::lua_state lua; - lua.set("number", 24); // integer types - lua["number2"] = 24.5; // floating point numbers - lua["important_string"] = "woof woof"; // becomes string - lua["myuserdata"] = some_class(); // non-recognized types is stored as userdata - lua["a_function"] = [](){ return 100; }; // is callable, therefore gets stored as a function + // integer types + lua.set("number", 24); + // floating point numbers + lua["number2"] = 24.5; + // string types + lua["important_string"] = "woof woof"; + // non-recognized types is stored as userdata + lua["myuserdata"] = some_class(); + // is callable, therefore gets stored as a function + lua["a_function"] = [](){ return 100; }; - int number = lua["number"]; // implicit conversion - auto number2 = lua.get("number2"); // explicit get - std::string important_string = lua["important_string"]; // strings too + // implicit conversion + int number = lua["number"]; + // explicit get + auto number2 = lua.get("number2"); + // strings too + std::string important_string = lua["important_string"]; - some_class& myuserdata = lua["myuserdata"]; // returns a plain reference + // returns a plain reference + some_class& myuserdata = lua["myuserdata"]; // myuserdata.some_variable = 20 WILL (!!) modify // data inside of lua VM as well, if you get a pointer or a reference diff --git a/sol/load_result.hpp b/sol/load_result.hpp new file mode 100644 index 00000000..6cd0c6da --- /dev/null +++ b/sol/load_result.hpp @@ -0,0 +1,139 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 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_LOAD_RESULT_HPP +#define SOL_LOAD_RESULT_HPP + +#include "stack.hpp" +#include "function.hpp" +#include "proxy_base.hpp" +#include + +namespace sol { + struct load_result : public proxy_base { + private: + lua_State* L; + int index; + int returncount; + int popcount; + load_status err; + + template + decltype(auto) tagged_get(types>) const { + if (!valid()) { + return sol::optional(nullopt); + } + return stack::get>(L, index); + } + + template + decltype(auto) tagged_get(types) const { +#ifdef SOL_CHECK_ARGUMENTS + if (!valid()) { + type_panic(L, index, type_of(L, index), type::none); + } +#endif // Check Argument Safety + return stack::get(L, index); + } + + sol::optional tagged_get(types>) const { + if (valid()) { + return nullopt; + } + return sol::error(detail::direct_error, stack::get(L, index)); + } + + sol::error tagged_get(types) const { +#ifdef SOL_CHECK_ARGUMENTS + if (valid()) { + type_panic(L, index, type_of(L, index), type::none); + } +#endif // Check Argument Safety + return sol::error(detail::direct_error, stack::get(L, index)); + } + + public: + load_result() = default; + load_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, load_status err = load_status::ok) : L(L), index(index), returncount(returncount), popcount(popcount), err(err) { + + } + load_result(const load_result&) = default; + load_result& operator=(const load_result&) = default; + load_result(load_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), err(o.err) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.err = load_status::syntax; + } + load_result& operator=(load_result&& o) { + L = o.L; + index = o.index; + returncount = o.returncount; + popcount = o.popcount; + err = o.err; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.err = load_status::syntax; + return *this; + } + + load_status error() const { + return err; + } + + bool valid() const { + return error() == load_status::ok; + } + + template + T get() const { + return tagged_get(types>()); + } + + template + decltype(auto) call(Args&&... args) { + return get().template call(std::forward(args)...); + } + + template + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward(args)...); + } + + lua_State* lua_state() const { return L; }; + int stack_index() const { return index; }; + + ~load_result() { + stack::remove(L, index, popcount); + } + }; +} // sol + +#endif // SOL_LOAD_RESULT_HPP diff --git a/sol/protected_function_result.hpp b/sol/protected_function_result.hpp index 9957d25c..8971ebda 100644 --- a/sol/protected_function_result.hpp +++ b/sol/protected_function_result.hpp @@ -73,7 +73,7 @@ private: public: protected_function_result() = default; - protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), err(error) { + protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status err = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), err(err) { } protected_function_result(const protected_function_result&) = default; @@ -127,4 +127,4 @@ public: }; } // sol -#endif // SOL_FUNCTION_RESULT_HPP +#endif // SOL_PROTECTED_FUNCTION_RESULT_HPP diff --git a/sol/stack_reference.hpp b/sol/stack_reference.hpp index 1debc401..38cb1bff 100644 --- a/sol/stack_reference.hpp +++ b/sol/stack_reference.hpp @@ -46,6 +46,10 @@ public: return 1; } + void pop(int n = 1) const noexcept { + lua_pop(lua_state( ), n); + } + int stack_index () const noexcept { return index; } @@ -58,6 +62,11 @@ public: lua_State* lua_state() const noexcept { return L; } + + bool valid () const noexcept { + type t = get_type(); + return t != type::nil && t != type::none; + } }; } // sol diff --git a/sol/state_view.hpp b/sol/state_view.hpp index 89c6306d..d1cee143 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -24,6 +24,7 @@ #include "error.hpp" #include "table.hpp" +#include "load_result.hpp" #include namespace sol { @@ -157,14 +158,14 @@ public: } } - stack_proxy load(const std::string& code) { - luaL_loadstring(L, code.c_str()); - return stack_proxy(L, -1); + load_result load(const std::string& code) { + load_status x = static_cast(luaL_loadstring(L, code.c_str())); + return load_result(L, -1, 1, 1, x); } - stack_proxy load_file(const std::string& filename) { - luaL_loadfile(L, filename.c_str()); - return stack_proxy(L, -1); + load_result load_file(const std::string& filename) { + load_status x = static_cast(luaL_loadfile(L, filename.c_str())); + return load_result(L, -1, 1, 1, x); } iterator begin () const { diff --git a/sol/thread.hpp b/sol/thread.hpp index 97e465e4..1e482fd9 100644 --- a/sol/thread.hpp +++ b/sol/thread.hpp @@ -52,7 +52,7 @@ public: thread_status status () const { lua_State* lthread = thread_state(); thread_status lstat = static_cast(lua_status(lthread)); - if (lstat != thread_status::normal && lua_gettop(lthread) == 0) { + if (lstat != thread_status::ok && lua_gettop(lthread) == 0) { // No thing on the thread's stack means its dead return thread_status::dead; } diff --git a/sol/types.hpp b/sol/types.hpp index 93f67160..f0ba49e6 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -158,15 +158,23 @@ enum class call_status : int { }; enum class thread_status : int { - normal = LUA_OK, - yielded = LUA_YIELD, - error_runtime = LUA_ERRRUN, - error_memory = LUA_ERRMEM, - error_gc = LUA_ERRGCMM, - error_handler = LUA_ERRERR, + ok = LUA_OK, + yielded = LUA_YIELD, + runtime = LUA_ERRRUN, + memory = LUA_ERRMEM, + gc = LUA_ERRGCMM, + handler = LUA_ERRERR, dead, }; +enum class load_status : int { + ok = LUA_OK, + syntax = LUA_ERRSYNTAX, + memory = LUA_ERRMEM, + gc = LUA_ERRGCMM, + file = LUA_ERRFILE, +}; + enum class type : int { none = LUA_TNONE, nil = LUA_TNIL,