diff --git a/docs/source/api/function.rst b/docs/source/api/function.rst index bfe0e2a7..dbd49ef9 100644 --- a/docs/source/api/function.rst +++ b/docs/source/api/function.rst @@ -24,13 +24,13 @@ Calls the constructor and creates this type, straight from the stack. For exampl .. literalinclude:: ../../../examples/tie.cpp :caption: funcs.lua - :lines: 7-11 + :lines: 9-13 :linenos: The following C++ code will call this function from this file and retrieve the return value: .. literalinclude:: ../../../examples/tie.cpp - :lines: 16-22 + :lines: 1-7,16-22 :linenos: The call ``woof(20)`` generates a :ref:`unsafe_function_result`, which is then implicitly converted to an ``double`` after being called. The intermediate temporary ``function_result`` is then destructed, popping the Lua function call results off the Lua stack. diff --git a/docs/source/api/protected_function.rst b/docs/source/api/protected_function.rst index 4c78515f..5edf668e 100644 --- a/docs/source/api/protected_function.rst +++ b/docs/source/api/protected_function.rst @@ -11,101 +11,33 @@ Inspired by a request from `starwing`_ in the :doc:`old sol repository<../origin When called without the return types being specified by either a ``sol::types<...>`` list or a ``call( ... )`` template type list, it generates a :doc:`protected_function_result` class that gets implicitly converted to the requested return type. For example: -.. code-block:: lua - :caption: pfunc_barks.lua +.. literalinclude:: ../../../examples/error_handler.cpp :linenos: - - bark_power = 11; - - function got_problems( error_msg ) - return "got_problems handler: " .. error_msg - end - - function woof ( bark_energy ) - if bark_energy < 20 - error("*whine*") - end - return (bark_energy * (bark_power / 4)) - end - - function woofers ( bark_energy ) - if bark_energy < 10 - error("*whine*") - end - return (bark_energy * (bark_power / 4)) - end + :lines: 10-28 The following C++ code will call this function from this file and retrieve the return value, unless an error occurs, in which case you can bind an error handling function like so: -.. code-block:: cpp +.. literalinclude:: ../../../examples/error_handler.cpp :linenos: + :lines: 1-6,30-66 - sol::state lua; - - lua.script_file( "pfunc_barks.lua" ); - - sol::protected_function problematicwoof = lua["woof"]; - problematicwoof.error_handler = lua["got_problems"]; - - auto firstwoof = problematic_woof(20); - if ( firstwoof.valid() ) { - // Can work with contents - double numwoof = first_woof; - } - else{ - // An error has occured - sol::error err = first_woof; - } - - // errors, calls handler and then returns a string error from Lua at the top of the stack - auto secondwoof = problematic_woof(19); - if (secondwoof.valid()) { - // Call succeeded - double numwoof = secondwoof; - } - else { - // Call failed - // Note that if the handler was successfully called, this will include - // the additional appended error message information of - // "got_problems handler: " ... - sol::error err = secondwoof; - std::string what = err.what(); - } This code is much more long-winded than its :doc:`function` counterpart but allows a person to check for errors. The type here for ``auto`` are ``sol::protected_function_result``. They are implicitly convertible to result types, like all :doc:`proxy-style` types are. Alternatively, with a bad or good function call, you can use ``sol::optional`` to check if the call succeeded or failed: -.. code-block:: cpp +.. literalinclude:: ../../../examples/error_handler.cpp :linenos: + :lines: 67- - sol::state lua; - - lua.script_file( "pfunc_barks.lua" ); - - sol::protected_function problematicwoof = lua["woof"]; - problematicwoof.error_handler = lua["got_problems"]; - - sol::optional maybevalue = problematicwoof(19); - if (maybevalue) { - // Have a value, use it - double numwoof = maybevalue.value(); - } - else { - // No value! - } That makes the code a bit more concise and easy to reason about if you don't want to bother with reading the error. Thankfully, unlike ``sol::unsafe_function_result``, you can save ``sol::protected_function_result`` in a variable and push/pop things above it on the stack where its returned values are. This makes it a bit more flexible than the rigid, performant ``sol::unsafe_function_result`` type that comes from calling :doc:`sol::unsafe_function`. -If you're confident the result succeeded, you can also just put the type you want (like ``double`` or ``std::string`` right there and it will get it. But, if it doesn't work out, sol can throw and/or panic if you have the :doc:`safety<../safety>` features turned on: +If you're confident the result succeeded, you can also just put the type you want (like ``double`` or ``std::string``) right there and it will get it. But, if it doesn't work out, sol can throw and/or panic if you have the :doc:`safety<../safety>` features turned on: .. code-block:: cpp :linenos: - sol::state lua; - - lua.script_file( "pfunc_barks.lua" ); - // construct with function + error handler // shorter than old syntax sol::protected_function problematicwoof(lua["woof"], lua["got_problems"]); @@ -119,9 +51,6 @@ Finally, it is *important* to note you can set a default handler. The function i .. code-block:: cpp :linenos: - sol::state lua; - - lua.script_file( "pfunc_barks.lua" ); // sets got_problems as the default // handler for all protected_function errors sol::protected_function::set_default_handler(lua["got_problems"]); diff --git a/docs/source/api/proxy.rst b/docs/source/api/proxy.rst index 6092dd3e..c31edcb6 100644 --- a/docs/source/api/proxy.rst +++ b/docs/source/api/proxy.rst @@ -25,55 +25,23 @@ These classes provide implicit assignment operator ``operator=`` (for ``set``) a proxy ----- -``proxy`` is returned by lookups into :doc:`sol::table` and table-like entities. Because it is templated on key and table type, it would be hard to spell: you can capture it using the word ``auto`` if you feel like you need to carry it around for some reason before using it. ``proxy`` evaluates its arguments lazily, when you finally call ``get`` or ``set`` on it. Here are some examples given the following lua script. +``proxy`` is returned by lookups into :doc:`sol::table
` and table-like entities. Because it is templated on key and table type, it would be hard to spell: you can capture it using the word ``auto`` if you feel like you need to carry it around for some reason before using it. ``proxy`` evaluates its arguments lazily, when you finally call ``get`` or ``set`` on it. Here are some examples given the following lua script: -.. code-block:: lua +.. literalinclude:: ../../../examples/table_proxy.cpp :linenos: - :caption: lua nested table script - - bark = { - woof = { - [2] = "arf!" - } - } - + :lines: 11-15 After loading that file in or putting it in a string and reading the string directly in lua (see :doc:`state`), you can start kicking around with it in C++ like so: -.. code-block:: c++ +.. literalinclude:: ../../../examples/table_proxy.cpp :linenos: + :lines: 1-8,18-40 - sol::state lua; +We don't recommend using ``proxy`` lazy evaluation the above to be used across classes or between function: it's more of something you can do to save a reference to a value you like, call a script or run a lua function, and then get it afterwards. You can also set functions (and function objects) this way, and retrieve them as well: - // produces proxy, implicitly converts to std::string, quietly destroys proxy - std::string x = lua["bark"]["woof"][2]; - - -``proxy`` lazy evaluation: - -.. code-block:: c++ +.. literalinclude:: ../../../examples/table_proxy.cpp :linenos: - :caption: multi-get - - auto x = lua["bark"]; - auto y = x["woof"]; - auto z = x[2]; - // retrivies value inside of lua table above - std::string value = z; // "arf!" - // Can change the value later... - z = 20; - // Yay, lazy-evaluation! - int changed_value = z; // now it's 20! - - -We don't recommend the above to be used across classes or between function: it's more of something you can do to save a reference to a value you like, call a script or run a lua function, and then get it afterwards. You can also set functions (and function objects) this way, and retrieve them as well. - -.. code-block:: c++ - :linenos: - - lua["bark_value"] = 24; - lua["chase_tail"] = floof::chase_tail; // chase_tail is a free function - + :lines: 41- members ------- @@ -192,30 +160,5 @@ on function objects and proxies .. note:: - As of recent versions of sol2 (2.18.2 and above), this is no longer an issue, as even bound classes will have any detectable function call operator automatically bound to the object, to allow this to work without having to use ``.set`` or ``.set_function``. The note here is kept for posterity and information for older versions. + As of recent versions of sol2 (2.18.2 and above), this is no longer an issue, as even bound classes will have any detectable function call operator automatically bound to the object, to allow this to work without having to use ``.set`` or ``.set_function``. The note here is kept for posterity and information for older versions. There are only some small caveats, see: :ref:`this note here`. - -.. warning:: - - *The below information is outdated.* - - -Consider the following: - -.. code-block:: cpp - :linenos: - :caption: Note 1 Case - - struct doge { - int bark; - - void operator()() { - bark += 1; - } - }; - - sol::state lua; - lua["object"] = doge{}; // bind constructed doge to "object" - // but it binds as a function - -When you use the ``lua["object"] = doge{};`` from above, keep in mind that Sol detects if this is a function *callable with any kind of arguments*. Since ``doge`` has overriden ``return_type operator()( argument_types... )`` on itself, it results in satisfying the ``requires`` constraint from above. This means that if you have a user-defined type you want to bind as a :doc:`userdata with usertype semantics` with this syntax, it might get bound as a function and not as a user-defined type (d'oh!). use ``lua["object"].set(doge)`` directly to avoid this, or ``lua["object"].set_function(doge{})`` to perform this explicitly. \ No newline at end of file diff --git a/docs/source/api/stack.rst b/docs/source/api/stack.rst index 330828e0..cfa4b179 100644 --- a/docs/source/api/stack.rst +++ b/docs/source/api/stack.rst @@ -298,7 +298,7 @@ This is an SFINAE-friendly struct that is meant to expose a function ``check=`` .. note:: - You must turn it on with ``SOL_ENABLE_INTEROP``, as described in the :ref:`config and safety section`. + You must turn this feature on with ``SOL_ENABLE_INTEROP``, as described in the :ref:`config and safety section`. .. code-block:: cpp diff --git a/docs/source/api/state.rst b/docs/source/api/state.rst index 95a2a751..a58789a3 100644 --- a/docs/source/api/state.rst +++ b/docs/source/api/state.rst @@ -100,29 +100,10 @@ If your script returns a value, you can capture it from the returned :ref:`sol:: To handle errors when using the second overload, provide a callable function/object that takes a ``lua_State*`` as its first argument and a ``sol::protected_function_result`` as its second argument. ``sol::script_default_on_error`` and ``sol::script_pass_on_error`` are 2 functions provided by sol that will either generate a traceback error to return / throw (if throwing is allowed); or, pass the error on through and return it to the user (respectively). An example of having your: -.. code-block:: cpp - :caption: running code safely +.. literalinclude:: ../../../examples/docs/state_script_safe.cpp + :linenos: :name: state-script-safe - int main () { - sol::state lua; - // uses sol::script_default_on_error, which either panics or throws, - // depending on your configuration and compiler settings - auto result1 = lua.safe_script("bad.code"); - - // a custom handler that you write yourself - // is only called when an error happens with loading or running the script - auto result2 = lua.safe_script("123 bad.code", [](lua_State* L, sol::protected_function_result pfr) { - // pfr will contain things that went wrong, for either loading or executing the script - // the user can do whatever they like here, including throw. Otherwise... - sol::error err = pfr; - std::cout << err.what() << std::endl; - - // ... they need to return the protected_function_result - return pfr; - }); - } - You can also pass a :doc:`sol::environment` to ``script``/``script_file`` to have the script have sandboxed / contained in a way inside of a state. This is useful for runnig multiple different "perspectives" or "views" on the same state, and even has fallback support. See the :doc:`sol::environment` documentation for more details. .. code-block:: cpp diff --git a/docs/source/api/this_state.rst b/docs/source/api/this_state.rst index 0aa61404..c0779058 100644 --- a/docs/source/api/this_state.rst +++ b/docs/source/api/this_state.rst @@ -9,23 +9,5 @@ this_state This class is a transparent type that is meant to be gotten in functions to get the current lua state a bound function or usertype method is being called from. It does not actually retrieve anything from lua nor does it increment the argument count, making it "invisible" to function calls in lua and calls through ``std::function<...>`` and :doc:`sol::function` on this type. It can be put in any position in the argument list of a function: -.. code-block:: cpp +.. literalinclude:: ../../../examples/this_state.cpp :linenos: - - sol::state lua; - - lua.set_function("bark", []( sol::this_state s, int a, int b ){ - lua_State* L = s; // current state - return a + b + lua_gettop(L); - }); - - lua.script("first = bark(2, 2)"); // only takes 2 arguments, NOT 3 - - // Can be at the end, too, or in the middle: doesn't matter - lua.set_function("bark", []( int a, int b, sol::this_state s ){ - lua_State* L = s; // current state - return a + b + lua_gettop(L); - }); - - lua.script("second = bark(2, 2)"); // only takes 2 arguments - \ No newline at end of file diff --git a/docs/source/api/tie.rst b/docs/source/api/tie.rst index 2074d9e0..df9151cd 100644 --- a/docs/source/api/tie.rst +++ b/docs/source/api/tie.rst @@ -1,6 +1,6 @@ tie === -*improved version of ``std::tie``* +*improved version of std::tie* `std::tie()`_ does not work well with :doc:`sol::function`'s ``sol::function_result`` returns. Use ``sol::tie`` instead. Because they're both named `tie`, you'll need to be explicit when you use Sol's by naming it with the namespace (``sol::tie``), even with a ``using namespace sol;``. Here's an example: diff --git a/docs/source/api/usertype.rst b/docs/source/api/usertype.rst index 9905c733..54c4748a 100644 --- a/docs/source/api/usertype.rst +++ b/docs/source/api/usertype.rst @@ -3,92 +3,11 @@ usertype *structures and classes from C++ made available to Lua code* -*Note: ``T`` refers to the type being turned into a usertype.* - -While other frameworks extend lua's syntax or create Data Structure Languages (DSLs) to create classes in Lua, :doc:`Sol<../index>` instead offers the ability to generate easy bindings. These use metatables and userdata in Lua for their implementation. Usertypes are also `runtime extensible`_. If you need a usertype that has less compiler crunch-time to it, try the :doc:`simple version of this after reading these docs` Given this C++ class: - -.. code-block:: cpp - :linenos: +.. note:: - struct ship { - int bullets = 20; - int life = 100; - - bool shoot () { - if (bullets > 0) { - --bullets; - // successfully shot - return true; - } - // cannot shoot - return false; - } - - bool hurt (int by) { - life -= by; - // have we died? - return life < 1; - } - }; - -You can bind the it to Lua using the following C++ code: - -.. code-block:: cpp - :linenos: - - sol::state lua; - - lua.new_usertype( "ship", // the name of the class, as you want it to be used in lua - // List the member functions you wish to bind: - // "name_of_item", &class_name::function_or_variable - "shoot", &ship::shoot, - "hurt", &ship::hurt, - // bind variable types, too - "life", &ship::life, - // names in lua don't have to be the same as C++, - // but it probably helps if they're kept the same, - // here we change it just to show its possible - "bullet_count", &ship::bullets - ); - - -Equivalently, you can also write: - -.. code-block:: cpp - :linenos: - :emphasize-lines: 4,12 - - sol::state lua; - - // Use constructor directly - usertype shiptype( - "shoot", &ship::shoot, - "hurt", &ship::hurt, - "life", &ship::life, - "bullet_count", &ship::bullets - ); - - // set usertype explicitly, with the given name - lua.set_usertype( "ship", shiptype ); - - // the shiptype variable is now a useless skeleton type, just let it destruct naturally and don't use it again. - - -Note that here, because the C++ class is default-constructible, it will automatically generate a creation function that can be called in lua called "new" that takes no arguments. You can use it like this in lua code: - -.. code-block:: lua - :linenos: - - fwoosh = ship.new() - -- note the ":" that is there: this is mandatory for member function calls - -- ":" means "pass self" in Lua - local success = fwoosh:shoot() - local is_dead = fwoosh:hurt(20) - -- check if it works - print(is_dead) -- the ship is not dead at this point - print(fwoosh.life .. "life left") -- 80 life left - print(fwoosh.bullet_count) -- 19 + ``T`` refers to the type being turned into a usertype. +While other frameworks extend lua's syntax or create Data Structure Languages (DSLs) to create classes in Lua, :doc:`Sol<../index>` instead offers the ability to generate easy bindings that pile on performance. You can see a `small starter example here`_. These use metatables and userdata in Lua for their implementation. Usertypes are also `runtime extensible`_. There are more advanced use cases for how to create and use a usertype, which are all based on how to use its constructor (see below). @@ -329,7 +248,7 @@ Register the base classes explicitly. :caption: inheritance.cpp :name: inheritance-example :linenos: - :emphasize-lines: 5 + :emphasize-lines: 23 .. note:: @@ -384,5 +303,6 @@ performance note .. _destructible: http://en.cppreference.com/w/cpp/types/is_destructible .. _default_constructible: http://en.cppreference.com/w/cpp/types/is_constructible +.. _small starter example here: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_basics.cpp .. _runtime extensible: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_advanced.cpp#L81 .. _the metamethods in the Lua manual: https://www.lua.org/manual/5.3/manual.html#2.4 diff --git a/docs/source/api/usertype_memory.rst b/docs/source/api/usertype_memory.rst index 63e6338a..f675cba0 100644 --- a/docs/source/api/usertype_memory.rst +++ b/docs/source/api/usertype_memory.rst @@ -12,12 +12,12 @@ In general, we always insert a ``T*`` in the first ``sizeof(T*)`` bytes, so the .. warning:: - The layout of memory described below does **not** take into account alignment. sol2 now takes alignment into account and aligns memory, which is important for misbehaving allocators and types that do not align well to the size of a pointer on their system. If you need to obtain proper alignments for usertypes stored in userdata pointers, **please** use the detail functions named ``sol::detail::align_usertype_pointer``, ``sol::detail::align_usertype``, and ``sol::detail::align_usertype_unique``. This will shift a ``void*`` pointer by the appropriate amount to reach a certain section in memory. For almost all use cases, please use ``void* memory = lua_touserdata(L, index);``, followed by ``memory = sol::detail::align_usertype_pointer( memory );`` to adjust the pointer to be at the right place. + The layout of memory described below does **not** take into account alignment. sol2 now takes alignment into account and aligns memory, which is important for misbehaving allocators and types that do not align well to the size of a pointer on their system. If you need to obtain proper alignments for usertypes stored in userdata pointers, **please** use the detail functions named ``sol::detail::align_usertype_pointer``, ``sol::detail::align_usertype``, and ``sol::detail::align_usertype_unique``. This will shift a ``void*`` pointer by the appropriate amount to reach a certain section in memory. For almost all other use cases, please use ``void* memory = lua_touserdata(L, index);``, followed by ``memory = sol::detail::align_usertype_pointer( memory );`` to adjust the pointer to be at the right place. .. warning:: - The code from below is only guaranteed to work 100% of the time if you define :ref:`SOL_NO_MEMORY_ALIGNMENT`. + The diagrams and explanations from below is only guaranteed to work 100% of the time if you define :ref:`SOL_NO_MEMORY_ALIGNMENT`. Be aware that this may result in unaligned reads/writes, which can crash some older processors and trigger static analyzer/instrumentation tool warnings, like Clang's Address Sanitizer (ASan). To retrieve a ``T`` diff --git a/docs/source/api/var.rst b/docs/source/api/var.rst index 762772cc..cf8df970 100644 --- a/docs/source/api/var.rst +++ b/docs/source/api/var.rst @@ -5,45 +5,5 @@ var The sole purpose of this tagging type is to work with :doc:`usertypes` to provide ``my_class.my_static_var`` access, and to also provide reference-based access as well. -.. code-block:: cpp - - #include - - struct test { - static int muh_variable; - }; - int test::muh_variable = 25; - - - int main () { - sol::state lua; - lua.open_libraries(); - lua.new_usertype("test", - "direct", sol::var(2), - "global", sol::var(test::muh_variable), - "ref_global", sol::var(std::ref(test::muh_variable)) - ); - - int direct_value = lua["test"]["direct"]; - // direct_value == 2 - - int global = lua["test"]["global"]; - // global == 25 - int global2 = lua["test"]["ref_global"]; - // global2 == 25 - - test::muh_variable = 542; - - global = lua["test"]["global"]; - // global == 25 - // global is its own memory: was passed by value - - global2 = lua["test"]["ref_global"]; - // global2 == 542 - // global2 was passed through std::ref - // global2 holds a reference to muh_variable - // if muh_variable goes out of scope or is deleted - // problems could arise, so be careful! - - return 0; - } +.. literalinclude:: ../../../examples/usertype_var.cpp + :linenos: diff --git a/docs/source/api/variadic_args.rst b/docs/source/api/variadic_args.rst index 8ff7dc4f..7d230665 100644 --- a/docs/source/api/variadic_args.rst +++ b/docs/source/api/variadic_args.rst @@ -11,116 +11,15 @@ This class is meant to represent every single argument at its current index and ``variadic_args`` also has ``begin()`` and ``end()`` functions that return (almost) random-acess iterators. These return a proxy type that can be implicitly converted to a type you want, much like the :doc:`table proxy type`. -.. code-block:: cpp +.. literalinclude:: ../../../examples/variadic_args.cpp :linenos: - #include +You can also "save" arguments and the like later, by stuffing them into a ``std::vector`` or something similar that serializes them into the registry. Below is an example of saving all of the arguments provided by ``sol::variadic_args`` in a lambda capture variable called ``args``. - int main () { - - sol::state lua; - lua.open_libraries(sol::lib::base); - - // Function requires 2 arguments - // rest can be variadic, but: - // va will include everything after "a" argument, - // which means "b" will be part of the varaidic_args list too - // at position 0 - lua.set_function("v", [](int a, sol::variadic_args va, int b) { - int r = 0; - for (auto v : va) { - int value = v; // get argument out (implicit conversion) - // can also do int v = va.get(i); with index i - r += value; - } - // Only have to add a, b was included - return r + a; - }); - - lua.script("x = v(25, 25)"); - lua.script("x2 = v(25, 25, 100, 50, 250, 150)"); - lua.script("x3 = v(1, 2, 3, 4, 5, 6)"); - // will error: not enough arguments - //lua.script("x4 = v(1)"); - - lua.script("print(x)"); // 50 - lua.script("print(x2)"); // 600 - lua.script("print(x3)"); // 21 - - return 0; - } - -You can also "save" arguments and the like later, by stuffing them into a ``std::vector`` or something similar that pulls out all the arguments. Below is an example of saving all of the arguments provided by ``sol::variadic_args`` in a lambda capture variable called ``args``. - -.. code-block:: cpp +.. literalinclude:: ../../../examples/variadic_args_storage.cpp :linenos: - #include "sol.hpp" - #include +Finally, note that you can use ``sol::variadic_args`` constructor to "offset"/"shift over" the arguments being viewed: - std::function function_storage; - - void store_routine(const sol::function& f, const sol::variadic_args& va) { - function_storage = [=, args = std::vector(va.begin(), va.end())]() { - f(sol::as_args(args)); - }; - } - - int main() { - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.set_function("store_routine", &store_routine); - - lua.script(R"( - function a(name) - print(name) - end - store_routine(a, "some name") - )"); - function_storage(); - - lua.script(R"( - function b(number, text) - print(number, "of", text) - end - store_routine(b, 20, "these apples") - )"); - function_storage(); - - return 0; - } - - -Finally, note that you can use ``sol::variadic_args`` constructor to "offset" which arguments you want: - -.. code-block:: cpp +.. literalinclude:: ../../../examples/variadic_args_shifted.cpp :linenos: - - #include - - int main () { - - sol::state lua; - lua.open_libraries(sol::lib::base); - - lua.set_function("f", [](sol::variadic_args va) { - int r = 0; - sol::variadic_args shifted_va(va.lua_state(), 3); - for (auto v : shifted_va) { - int value = v; - r += value; - } - return r; - }); - - lua.script("x = f(1, 2, 3, 4)"); - lua.script("x2 = f(8, 200, 3, 4)"); - lua.script("x3 = f(1, 2, 3, 4, 5, 6)"); - - lua.script("print(x)"); // 7 - lua.script("print(x2)"); // 7 - lua.script("print(x3)"); // 18 - - return 0; - } diff --git a/docs/source/cmake.rst b/docs/source/cmake.rst index 2d9e378d..b62d1326 100644 --- a/docs/source/cmake.rst +++ b/docs/source/cmake.rst @@ -1,6 +1,13 @@ CMake Script ============ +sol2 comes with a CMake script in the top level. It is primarily made for building and running the examples and tests, but it includes exported and configured targets (``sol2``, ``sol2_single``) for your use. If you have any problems with it or its targets, please do file a report, or a pull request because CMake is not my forte. + + +.. warning:: + + The below is slightly outdated, but will probably still work for you! + Thanks to `Kevin Brightwell`_, you can drop this CMake Script into your CMake Projects to have Sol part of one of its builds: .. code-block:: cmake diff --git a/docs/source/origin.rst b/docs/source/origin.rst index cc2e3d72..fa90844a 100644 --- a/docs/source/origin.rst +++ b/docs/source/origin.rst @@ -1,17 +1,19 @@ origin ====== -In the beginning, there was Sir Dennis Ritchie. And Ritchie saw the void, and outstretched his hand, and commanded "Let there be water." And lo, it was so, and there was the C. And with the C, other entities dared to venture on the void given form. Lord Bjarne Stroustrup too did outstretch his hands and say "Let there be an abundance." And lo, into the sea was cast a double portion of surplus of all the things that swam. And for a while, it was good. But other entities were still curious about what yet lay undefined, and one such pantheon, PUC-RIO, saw that it fitting to create the moon. And with the waters and sea made and the moon cast in a starry night sky, PUC-RIO and Dennis and Stroustrup saw that they did good. They oversaw the moon and the sea and gave sound council and it grew. But as the time grew, humanity grew... discontent. No longer were the simple fishing rods and the flowing tides and the dark sky enough lit by a pale moon, no matter how miraculously they were made, enough. They sought out more. +In the beginning, there was Sir Dennis Ritchie. And Ritchie saw the void, and outstretched his hand, and commanded "Let there be water." And lo, it was so, and there was the C. And with the C, other entities dared to venture on the void given form. Lord Bjarne Stroustrup too did outstretch his hands and say "Let there be an abundance." And lo, into the sea was cast a double portion of surplus of all the things that swam. And for a while, it was good. But other entities were still curious about what yet lay undefined, and one such pantheon, PUC-RIO, saw that it fitting to create. And thusly, they banded together and declared "Let there be a Moon". And thusly, the moon was born into the sky. + +And with the waters and sea made and the moon cast in a starry night sky, PUC-RIO and Ritchie and Stroustrup saw that they did good. They oversaw the moon and the sea and all its abundance, and gave sound council and it overflowed wonderfully. But as the time grew, life grew... discontent. No longer were the simple fishing rods and the flowing tides and the dark sky enough lit by a pale moon and stars enough, no matter how miraculously they were made. They sought out more. They sought out the light. -And lo, `Danny Y., Rapptz`_ did stand firm in the sea and cast his hands to the sky and said "Let there be Light!". And in the sky was cast a sun. It was an early sun, a growing sun, and many gathered to its warmth, marveling at a life they never knew. And he saw that it was good... +And lo, `Danny Y., Rapptz`_ did stand firm in the sea and cast his hands to the sky and said "Let there be Light!". And in the sky was cast a Sun. It was an early sun, a growing sun, and many gathered to its warmth, marveling at a life they never knew. And he saw that it was good... seriously --------- -Sol was originally started by many moon cycles ago to interop with Lua and C++. `Rapptz`_ It was very successful and many rejoiced at having an easy to use abstraction on top of the Lua API. Rapptz continued to make a number of great projects and has been busy with other things, so upon seeing the repository grow stagnant and tired in the last very long while (over a year), `ThePhD`_ forked it into Sol2 and rebooted the code with the hopes of reaching the Milestone and the documentation you have today. +Sol was originally started by many moon cycles ago to interop with Lua and C++, by `Rapptz`_. It was very successful and many rejoiced at having an easy to use abstraction on top of the Lua API. Rapptz continued to make a number of great projects and has been busy with other things, so upon seeing the repository grow stagnant and tired in the last very long while (over a year), `ThePhD`_ forked it into Sol2 and rebooted the code with the hopes of reaching the Milestone and the documentation you have today. To get to the old repo, head over `here`_. @@ -19,7 +21,7 @@ To get to the old repo, head over `here`_. the name -------- -Sol means sun. The moon (Lua) needs a sun, because without it only the bleak night of copy-paste programming and off-by-one errors would prevail. +Sol means sun. The moon (Lua) needs a sun, because without it only the bleak night of copy-paste programming and off-by-one errors would prevail. ... Or something. .. _here: https://github.com/Rapptz/sol diff --git a/docs/source/tutorial/all-the-things.rst b/docs/source/tutorial/all-the-things.rst index 809ba643..248d8e99 100644 --- a/docs/source/tutorial/all-the-things.rst +++ b/docs/source/tutorial/all-the-things.rst @@ -55,7 +55,7 @@ To run Lua code but have an error handler in case things go wrong: .. literalinclude:: ../../../examples/tutorials/quick_n_dirty/running_lua_code.cpp :linenos: - :lines: 28-40 + :lines: 28-39,47-49 running lua code (low-level) @@ -70,7 +70,7 @@ You can use the individual load and function call operator to load, check, and t .. literalinclude:: ../../../examples/tutorials/quick_n_dirty/running_lua_code_low_level.cpp :linenos: - :lines: 1-10, 16-41 + :lines: 1-10, 16-40, 47-49 set and get variables --------------------- diff --git a/examples/docs/state_script_safe.cpp b/examples/docs/state_script_safe.cpp new file mode 100644 index 00000000..550933cc --- /dev/null +++ b/examples/docs/state_script_safe.cpp @@ -0,0 +1,35 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include + +int main () { + + std::cout << "=== safe_script usage ===" << std::endl; + + sol::state lua; + // uses sol::script_default_on_error, which either panics or throws, + // depending on your configuration and compiler settings + try { + auto result1 = lua.safe_script("bad.code"); + } + catch( const sol::error& e ) { + std::cout << "an expected error has occurred: " << e.what() << std::endl; + } + + // a custom handler that you write yourself + // is only called when an error happens with loading or running the script + auto result2 = lua.safe_script("123 bad.code", [](lua_State*, sol::protected_function_result pfr) { + // pfr will contain things that went wrong, for either loading or executing the script + // the user can do whatever they like here, including throw. Otherwise... + sol::error err = pfr; + std::cout << "An error (an expected one) occurred: " << err.what() << std::endl; + + // ... they need to return the protected_function_result + return pfr; + }); + + std::cout << std::endl; + + return 0; +} diff --git a/examples/error_handler.cpp b/examples/error_handler.cpp new file mode 100644 index 00000000..7e32815b --- /dev/null +++ b/examples/error_handler.cpp @@ -0,0 +1,82 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include + +int main () { + + const auto& code = R"( + bark_power = 11; + + function got_problems( error_msg ) + return "got_problems handler: " .. error_msg + end + + function woof ( bark_energy ) + if bark_energy < 20 then + error("*whine*") + end + return (bark_energy * (bark_power / 4)) + end + + function woofers ( bark_energy ) + if bark_energy < 10 then + error("*whine*") + end + return (bark_energy * (bark_power / 4)) + end + )"; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.script(code); + + sol::protected_function problematic_woof = lua["woof"]; + problematic_woof.error_handler = lua["got_problems"]; + + auto firstwoof = problematic_woof(20); + if ( firstwoof.valid() ) { + // Can work with contents + double numwoof = firstwoof; + std::cout << "Got value: " << numwoof << std::endl; + } + else{ + // An error has occured + sol::error err = firstwoof; + std::string what = err.what(); + std::cout << what << std::endl; + } + + // errors, calls handler and then returns a string error from Lua at the top of the stack + auto secondwoof = problematic_woof(19); + if (secondwoof.valid()) { + // Call succeeded + double numwoof = secondwoof; + std::cout << "Got value: " << numwoof << std::endl; + } + else { + // Call failed + // Note that if the handler was successfully called, this will include + // the additional appended error message information of + // "got_problems handler: " ... + sol::error err = secondwoof; + std::string what = err.what(); + std::cout << what << std::endl; + } + + // can also use optional to tell things + sol::optional maybevalue = problematic_woof(19); + if (maybevalue) { + // Have a value, use it + double numwoof = maybevalue.value(); + std::cout << "Got value: " << numwoof << std::endl; + } + else { + std::cout << "No value!" << std::endl; + } + + std::cout << std::endl; + + return 0; +} diff --git a/examples/table_proxy.cpp b/examples/table_proxy.cpp new file mode 100644 index 00000000..61316801 --- /dev/null +++ b/examples/table_proxy.cpp @@ -0,0 +1,55 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include "assert.hpp" + +#include + +int main () { + + const auto& code = R"( + bark = { + woof = { + [2] = "arf!" + } + } + )"; + + sol::state lua; + lua.open_libraries(sol::lib::base); + lua.script(code); + + // produces proxy, implicitly converts to std::string, quietly destroys proxy + std::string arf_string = lua["bark"]["woof"][2]; + + // lazy-evaluation of tables + auto x = lua["bark"]; + auto y = x["woof"]; + auto z = y[2]; + + // retrivies value inside of lua table above + std::string value = z; + c_assert(value == "arf!"); + + // Can change the value later... + z = 20; + + // Yay, lazy-evaluation! + int changed_value = z; // now it's 20! + c_assert(changed_value == 20); + lua.script("assert(bark.woof[2] == 20)"); + + lua["a_new_value"] = 24; + lua["chase_tail"] = [](int chasing) { + int r = 2; + for (int i = 0; i < chasing; ++i) { + r *= r; + } + return r; + }; + + lua.script("assert(a_new_value == 24)"); + lua.script("assert(chase_tail(2) == 16)"); + + return 0; +} diff --git a/examples/tables.cpp b/examples/tables.cpp index 6e551b98..bcfc57df 100644 --- a/examples/tables.cpp +++ b/examples/tables.cpp @@ -9,53 +9,57 @@ int main() { std::cout << "=== tables ===" << std::endl; - sol::state lua; - // table used as an array - lua.script("table1 = {\"hello\", \"table\"}"); - // table with a nested table and the key value syntax - lua.script("table2 = {" - "[\"nestedTable\"] = {" - "[\"key1\"] = \"value1\"," - "[\"key2\"]= \"value2\"" - "}," - "[\"name\"]= \"table2\"" - "}"); + sol::state lua; + // table used as an array + lua.script(R"(table1 = {"hello", "table"})"); + // table with a nested table and the key value syntax + lua.script(R"( + table2 = { + ["nestedTable"] = { + ["key1"] = "value1", + ["key2"]= "value2", + }, + ["name"] = "table2", + } + )"); - /* Shorter Syntax: */ - // using the values stored in table1 - /*std::cout << (std::string)lua["table1"][1] << " " - << (std::string)lua["table1"][2] << '\n'; + /* Shorter Syntax: */ + // using the values stored in table1 + /*std::cout << (std::string)lua["table1"][1] << " " + << (std::string)lua["table1"][2] << '\n'; */ - // 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'; - std::string t2name = t2["name"]; - std::cout << "name of t2: " << t2name << '\n'; + // 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'; + std::string t2name = t2["name"]; + std::cout << "name of t2: " << t2name << '\n'; - /* Longer Syntax: */ - // using the values stored in table1 - std::cout << lua.get("table1").get(1) << " " - << lua.get("table1").get(2) << '\n'; + /* Longer Syntax: */ + // using the values stored in table1 + std::cout << lua.get("table1").get(1) << " " + << lua.get("table1").get(2) << '\n'; - // some retrieval of values from the nested table - // the cleaner way of doing things - std::cout << "nested table: key1 : " << nestedTable.get("key1") << ", key2: " - // yes you can chain the get<>() results - << lua.get("table2").get("nestedTable").get("key2") - << '\n'; - std::cout << "name of t2: " << t2.get("name") << '\n'; + // some retrieval of values from the nested table + // the cleaner way of doing things + std::cout << "nested table: key1 : " << nestedTable.get("key1") << ", key2: " + // yes you can chain the get<>() results + << lua.get("table2").get("nestedTable").get("key2") + << '\n'; + std::cout << "name of t2: " << t2.get("name") << '\n'; std::cout << std::endl; + + return 0; } diff --git a/examples/this_state.cpp b/examples/this_state.cpp new file mode 100644 index 00000000..78b6c3ad --- /dev/null +++ b/examples/this_state.cpp @@ -0,0 +1,29 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include "assert.hpp" + +int main () { + sol::state lua; + + lua.set_function("bark", []( sol::this_state s, int a, int b ){ + lua_State* L = s; // current state + return a + b + lua_gettop(L); + }); + + lua.script("first = bark(2, 2)"); // only takes 2 arguments, NOT 3 + + // Can be at the end, too, or in the middle: doesn't matter + lua.set_function("bark", []( int a, int b, sol::this_state s ){ + lua_State* L = s; // current state + return a + b + lua_gettop(L); + }); + + lua.script("second = bark(2, 2)"); // only takes 2 arguments + int first = lua["first"]; + c_assert(first == 6); + int second = lua["second"]; + c_assert(second == 6); + + return 0; +} \ No newline at end of file diff --git a/examples/usertype_basics.cpp b/examples/usertype_basics.cpp new file mode 100644 index 00000000..54d25f8c --- /dev/null +++ b/examples/usertype_basics.cpp @@ -0,0 +1,84 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include + +struct ship { + int bullets = 20; + int life = 100; + + bool shoot () { + if (bullets > 0) { + --bullets; + // successfully shot + return true; + } + // cannot shoot + return false; + } + + bool hurt (int by) { + life -= by; + // have we died? + return life < 1; + } +}; + + +int main () { + + std::cout << "=== usertype basics ===" << std::endl; + + static const bool way_1 = true; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + if (way_1) { + lua.new_usertype( "ship", // the name of the class, as you want it to be used in lua + // List the member functions you wish to bind: + // "name_of_item", &class_name::function_or_variable + "shoot", &ship::shoot, + "hurt", &ship::hurt, + // bind variable types, too + "life", &ship::life, + // names in lua don't have to be the same as C++, + // but it probably helps if they're kept the same, + // here we change it just to show its possible + "bullet_count", &ship::bullets + ); + } + else { + // an alternative way: + // use the constructor directly + sol::usertype shiptype( + "shoot", &ship::shoot, + "hurt", &ship::hurt, + "life", &ship::life, + "bullet_count", &ship::bullets + ); + + // set usertype explicitly, with the given name + lua.set_usertype( "ship", shiptype ); + // the shiptype variable is now a useless skeleton type, just let it destruct naturally and don't use it again. + } + + const auto& code = R"( + fwoosh = ship.new() + -- note the ":" that is there: this is mandatory for member function calls + -- ":" means "pass self" in Lua + local success = fwoosh:shoot() + local is_dead = fwoosh:hurt(20) + -- check if it works + print(is_dead) -- the ship is not dead at this point + print(fwoosh.life .. "life left") -- 80 life left + print(fwoosh.bullet_count) -- 19 + )"; + + + lua.script(code); + + std::cout << std::endl; + + return 0; +} diff --git a/examples/variadic_args.cpp b/examples/variadic_args.cpp index 2305849b..15e19cc4 100644 --- a/examples/variadic_args.cpp +++ b/examples/variadic_args.cpp @@ -38,5 +38,8 @@ int main() { lua.script("print(x)"); // 50 lua.script("print(x2)"); // 600 lua.script("print(x3)"); // 21 + std::cout << std::endl; + + return 0; } \ No newline at end of file diff --git a/examples/variadic_args_shifted.cpp b/examples/variadic_args_shifted.cpp new file mode 100644 index 00000000..7e47c3fd --- /dev/null +++ b/examples/variadic_args_shifted.cpp @@ -0,0 +1,34 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include + +int main () { + + std::cout << "=== variadic_args shifting constructor ===" << std::endl; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.set_function("f", [](sol::variadic_args va) { + int r = 0; + sol::variadic_args shifted_va(va.lua_state(), 3); + for (auto v : shifted_va) { + int value = v; + r += value; + } + return r; + }); + + lua.script("x = f(1, 2, 3, 4)"); + lua.script("x2 = f(8, 200, 3, 4)"); + lua.script("x3 = f(1, 2, 3, 4, 5, 6)"); + + lua.script("print(x)"); // 7 + lua.script("print(x2)"); // 7 + lua.script("print(x3)"); // 18 + + std::cout << std::endl; + + return 0; +} diff --git a/examples/variadic_args_storage.cpp b/examples/variadic_args_storage.cpp new file mode 100644 index 00000000..dc6fa31d --- /dev/null +++ b/examples/variadic_args_storage.cpp @@ -0,0 +1,43 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include +#include + +int main() { + + std::cout << "=== variadic_args serialization/storage ===" << std::endl; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + std::function function_storage; + + auto store_routine = [&function_storage] (sol::function f, sol::variadic_args va) { + function_storage = [f, args = std::vector(va.begin(), va.end())]() { + f(sol::as_args(args)); + }; + }; + + lua.set_function("store_routine", store_routine); + + lua.script(R"( +function a(name) + print(name) +end +store_routine(a, "some name") +)"); + function_storage(); + + lua.script(R"( +function b(number, text) + print(number, "of", text) +end +store_routine(b, 20, "these apples") +)"); + function_storage(); + + std::cout << std::endl; + + return 0; +} diff --git a/sol/traits.hpp b/sol/traits.hpp index 72da9e9f..dcc7ad9b 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -602,7 +602,7 @@ namespace sol { namespace meta_detail { template , std::tuple>> = meta::enabler> decltype(auto) force_tuple(T&& x) { - return std::forward_as_tuple(std::forward(x)); + return std::tuple>(std::forward(x)); } template , std::tuple>> = meta::enabler>