Giter Site home page Giter Site logo

thephd / sol2 Goto Github PK

View Code? Open in Web Editor NEW
4.0K 126.0 463.0 25.66 MB

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:

Home Page: http://sol2.rtfd.io/

License: MIT License

C++ 90.06% Python 0.61% C 2.07% Shell 0.90% CMake 6.11% Meson 0.09% Dockerfile 0.15%
sol lua lua-bindings lua-binding lua-scripting simple modern-cpp gcc clang visual-studio

sol2's Introduction

sol2

Documentation Status

sol2 is a C++ library binding to Lua. It currently supports all Lua versions 5.1+ (LuaJIT 2.0+ and MoonJIT included). sol2 aims to be easy to use and easy to add to a project. The library is header-only for easy integration with projects, and a single header can be used for drag-and-drop start up.

Sneak Peek

#include <sol/sol.hpp>
#include <cassert>

int main() {
    sol::state lua;
    int x = 0;
    lua.set_function("beep", [&x]{ ++x; });
    lua.script("beep()");
    assert(x == 1);
}
#include <sol/sol.hpp>
#include <cassert>

struct vars {
    int boop = 0;
};

int main() {
    sol::state lua;
    lua.new_usertype<vars>("vars", "boop", &vars::boop);
    lua.script("beep = vars.new()\n"
               "beep.boop = 1");
    assert(lua.get<vars>("beep").boop == 1);
}

More examples are given in the examples directory here.

Documentation

Find it here. A run-through kind of tutorial is here! The API documentation goes over most cases (particularly, the "api/usertype" and "api/table_proxy" and "api/function" sections) that should still get you off your feet and going, and there's an examples directory here as well.

"I need X Feature or Fix, Right Now™"

Find the support option that's right for you, here! If you're happy to wait, you can just file a boring issue and we'll get to it Whenever There Is Time™.

I want to donate to help!

You can find donation and sponorship options here and from the little heart button near the top of this repository that will take you to a bevy of links in which you can donate and show support for this project and others!

Features

  • Fastest in the land (see: sol2 bar in graph).
  • Supports retrieval and setting of multiple types including:
    • std::string, std::wstring, std::u16string and std::u32string support (and for views).
    • understands and works with containers such as std::map/unordered_map, c-style arrays, vectors, non-standard custom containers and more.
    • user-defined types, with or without registering that type
    • std::unique_ptr, std::shared_ptr, and optional support of other pointer types like boost::shared_ptr.
    • custom optional<T> that works with references, and support for the inferior std::optional.
    • C++17 support for variants and similar new types.
  • Lambda, function, and member function bindings are supported.
  • Intermediate type for checking if a variable exists.
  • Simple API that completely abstracts away the C stack API, including protected_function with the ability to use an error-handling function.
  • operator[]-style manipulation of tables
  • C++ type representations in Lua userdata as usertypes with guaranteed cleanup.
  • Customization points to allow your C++ objects to be pushed and retrieved from Lua as multiple consecutive objects, or anything else you desire!
  • Overloaded function calls: my_function(1); my_function("Hello") in the same Lua script route to different function calls based on parameters
  • Support for tables, nested tables, table iteration with table.for_each / begin() and end() iterators.
  • Zero string overhead for usertype function lookup.

Supported Compilers

sol2 makes use of C++17 features. GCC 7.x.x and Clang 3.9.x (with -std=c++1z and appropriate standard library) or higher should be able to compile without problems. However, the officially supported and CI-tested compilers are:

  • GCC 7.x.x+ (MinGW 7.x.x+)
  • Clang 3.9.x+
  • Visual Studio 2017 Community (Visual C++ 15.0)+

Please make sure you use the -std=c++2a, -std=c++1z, -std=c++17 or better standard flags (some of these flags are the defaults in later versions of GCC, such as 7+ and better).

If you would like support for an older compiler (at the cost of some features), use the latest tagged sol2 branch. If you would like support for an even older compiler, feel free to contact me for a Custom Solution.

sol2 is checked by-hand for other platforms as well, including Android-based builds with GCC and iOS-based builds out of XCode with Apple-clang. It should work on both of these platforms, so long as you have the proper standards flags. If something doesn't work or you need special options, you may need to look into the different ways to support the project to have it done for you!

Creating a single header

You can grab a single header (and the single forward header) out of the library here. For stable version, check the releases tab on GitHub for a provided single header file for maximum ease of use. A script called single.py is provided in the repository if there's some bleeding edge change that hasn't been published on the releases page. You can run this script to create a single file version of the library so you can only include that part of it. Check single.py --help for more info.

If you use CMake, you can also configure and generate a project that will generate the sol2_single_header for you. You can also include the project using CMake. Run CMake for more details. Thanks @Nava2, @alkino, @mrgreywater and others for help with making the CMake build a reality.

Testing

Testing turns on certain CI-only variables in the CMake to test a myriad of configuration options. You can generate the tests by running CMake and configuring SOL2_TESTS, SOL2_TESTS_SINGLE, SOL2_TESTS_EXAMPLES, and SOL2_EXAMPLES to be on. Make sure SOL2_SINGLE is also on.

You will need any flavor of python3 and an available compiler. The testing suite will build its own version of Lua and LuaJIT, so you do not have to provide one (you may provide one with the LUA_LOCAL_DIR variable).

Presentations

"A Sun For the Moon - A Zero-Overhead Lua Abstraction using C++"
ThePhD Lua Workshop 2016 - Mashape, San Francisco, CA
Deck

"Wrapping Lua C in C++ - Efficiently, Nicely, and with a Touch of Magic"
ThePhD Boston C++ Meetup November 2017 - CiC (Milk Street), Boston, MA
Deck

"Biting the CMake Bullet"
ThePhD Boston C++ Meetup February 2018 - CiC (Main Street), Cambridge, MA
Deck

"Compile Fast, Run Faster, Scale Forever: A look into the sol2 Library"
ThePhD C++Now 2018 - Hudson Commons, Aspen Physics Center, Aspen, Colorado
Deck

"Scripting at the Speed of Thought: Using Lua in C++ with sol2"
ThePhD CppCon 2018 - 404 Keystone, Meydenbauer Center, Aspen, Colorado
Deck

"The Plan for Tomorrow: Compile-Time Extension Points in C++" ThePhD C++Now 2019 - Flug Auditorium, Aspen Physics Center, Aspen, Colorado Deck

License

sol2 is distributed with an MIT License. You can see LICENSE.txt for more info.

If you need a custom solution, feel free to reach out.

sol2's People

Contributors

agjohnson avatar alkino avatar atom0s avatar btdavis avatar chebee7i avatar cloudops-wstevens avatar danieloaks avatar dimitrisudell avatar ehough avatar eliasdaler avatar ericholscher avatar geneotech avatar gl3n avatar ivoz avatar jodal avatar kami avatar milerius avatar nava2 avatar orfeasz avatar princesstrash avatar rapptz avatar reworks avatar shepherdsoasis avatar smertig avatar snide avatar the-fyp avatar thephd avatar titilambert avatar tony avatar ubpa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sol2's Issues

Build problems on Clang

I saw the listed support for Clang 3.6, however, the current state does not compile against it.

Here is my build log.

I'm happy to help, but if I'm honest, I'm not that well versed in the level of templates used here.

$ clang++ --version
Ubuntu clang version 3.6.2-1 (tags/RELEASE_362/final) (based on LLVM 3.6.2)
Target: x86_64-pc-linux-gnu
Thread model: posix

I haven't tried this against MSVC, but as of late, they're pretty good with C++11 things and lacking a bit on C++14.

The build badge for travis is misleading, the project doesn't build on Travis at the moment, that should probably be adjusted.

Callbacks?

I don't know where to ask this, please point me to a better location if you are offended having it here.

I have been trying to introduce myself to binding my own functions into lua. I have a (from what I can tell) very complicated end-goal read on StackOverflow if interested.

I need to be able to take a callback from lua so I can do asynchronous things before passing back into lua with a result.

// works great
lua.set_function("print", [](const char *  y){ std::cout << y << std::endl; });

// what I need and don't know how to do...
lua.set_function("getUser", [](int id, luaFncPointer cb)
{
/* ... */
// async operation on database, io, etc.
/* ... */
 });
-- user written lua script
getUser(1, function(err, user)
   if err then
      print('Error', err)
   else
      print('Found user with id', user.id)
   end
end)

Do you have some examples I could look at or suggestions on what to do?

Feature table update

Improve the feature table. Currently frameworks like Kaguya and one other do support overloading, so the feature table should be updated to show that.

std::unique_ptr and std::shared_ptr

We should have support for these two in that we shouldn't be calling the regular T __gc method, but calling whatever destructor the special types give us.

Additional sol::state arguments

Support to pass one's own allocator function and the accompanying ud to lua_newstate that's invoked by sol::state would be nice?

A small warning with -Wall

Hi,

There's a small warning with sol 2.3 (not the case with 2.1) when building my project :

protected_function.hpp:86:14: warning: unused variable ‘handlerpushed’ [-Wunused-variable]
         bool handlerpushed = error_handler.valid();

It seems that this boolean is never used again. Don't know if this line can be removed or not (that's why I did make a PR).

Issues with examples/usertype.cpp on linux

I just started looking at sol. I worked through the examples, everything works fine but usertype.

  1. It compiles but it terminates when run:
terminate called after throwing an instance of 'sol::error'
  what():  lua: error: [string "v = vector.new()..."]:1: attempt to call a nil value (field 'new')

The solution:

diff --git a/examples/usertype.cpp b/examples/usertype.cpp
index b34309b..7a4f1b6 100644
--- a/examples/usertype.cpp
+++ b/examples/usertype.cpp
@@ -75,7 +75,7 @@ int main() {
         // the first argument of construction is the name
         // second is the constructor types
         // then the rest are function name and member function pointer pairs
-        sol::usertype<vector> udata("vector", ctor, "is_unit", &vector::is_unit);
+        sol::usertype<vector> udata(ctor, "is_unit", &vector::is_unit);^M

         // then you must register it
         lua.set_usertype("vector", udata);

Note the issue with the line ending. Seems examples are encoded differently than the sol sources.
Furthermore the example talks about "userdata" in the comments but the functions are names "*usertype" which confused me ;)

  1. Compilation with lua5.1 does not work (this happens with every example)
In file included from examples/usertype.cpp:1:
In file included from ./sol.hpp:25:
In file included from ./sol/state.hpp:25:
In file included from ./sol/state_view.hpp:26:
In file included from ./sol/table.hpp:25:
In file included from ./sol/table_core.hpp:25:
In file included from ./sol/proxy.hpp:26:
In file included from ./sol/object.hpp:25:
In file included from ./sol/reference.hpp:25:
In file included from ./sol/types.hpp:25:
In file included from ./sol/compatibility.hpp:36:
./sol/compatibility/5.x.x.inl:311:9: error: use of undeclared identifier 'strerror_s'; did you mean 'strerror_r'?
        strerror_s(buf, 1024, en);
        ^~~~~~~~~~
        strerror_r
/usr/include/string.h:433:14: note: 'strerror_r' declared here
extern char *strerror_r (int __errnum, char *__buf, size_t __buflen)
             ^
In file included from examples/usertype.cpp:1:
In file included from ./sol.hpp:25:
In file included from ./sol/state.hpp:25:
In file included from ./sol/state_view.hpp:26:
In file included from ./sol/table.hpp:25:
In file included from ./sol/table_core.hpp:25:
In file included from ./sol/proxy.hpp:26:
In file included from ./sol/object.hpp:25:
In file included from ./sol/reference.hpp:25:
In file included from ./sol/types.hpp:25:
In file included from ./sol/compatibility.hpp:36:
./sol/compatibility/5.x.x.inl:311:20: error: cannot initialize a parameter of type 'int' with an lvalue of type 'char [1024]'
        strerror_s(buf, 1024, en);
                   ^~~
/usr/include/string.h:433:30: note: passing argument to parameter '__errnum' here
extern char *strerror_r (int __errnum, char *__buf, size_t __buflen)
                             ^
In file included from examples/usertype.cpp:1:
In file included from ./sol.hpp:25:
In file included from ./sol/state.hpp:25:
./sol/state_view.hpp:85:20: warning: enumeration value 'coroutine' not handled in switch [-Wswitch]
            switch(library) {
                   ^

I am on glibc-2.23.
the solution here:

diff --git a/sol/compatibility/5.x.x.inl b/sol/compatibility/5.x.x.inl
index 377cba2..e2ebf49 100644
--- a/sol/compatibility/5.x.x.inl
+++ b/sol/compatibility/5.x.x.inl
@@ -308,7 +308,7 @@ inline int luaL_fileresult(lua_State *L, int stat, const char *fname) {
     }
     else {
         char buf[1024];
-        strerror_s(buf, 1024, en);
+        strerror_r(en, buf, 1024);
         lua_pushnil(L);
         if (fname)
             lua_pushfstring(L, "%s: %s", fname, buf);

I did not create a pull request as I really don't know if the fixes are correct. They just made things work for me... (That's also the reason for not tackling the warning ;))

sol::property

Code like lua.set( "a", sol::property( getter_func, setter_func ) ) or sol::property( &my_class::variable, my_class() ) should create a variable that is accessible by a = 24 or local x = a. You can make a variable write-only by only specifying setter_func, and readonly by only specifying getter_func. Still have to figure out if a sol::writeonly wrapper is necessary for member variables as well....

stack::check_get

There should be a variant of stack::get and stack::check that combines both of them into one API, e.g. stack::check_get. get by default should use this if SOL_CHECK_ARGUMENTS is defined, and if not fall back to the regular stack::get. This allows the users to have maximum safety when they want it, but turn it off when they don't (e.g.: debug versus release).

API should look like:

optional<T> o = stack::check_get( L, -1, throw_error ); // base API
optional<T> o = stack::check_get( L ); // defaults -1 index, no_panic handler
optional<T> o = stack::check_get( L, -1 ); // defaults no_panic handler

I have been wary of providing this because std::optional is just getting support and I really don't think rolling our own sol::optional is wise, but if we want this safer API we might have to roll with it regardless. Thankfully, I already have an optional implementation that will handle this for us, and maybe I can hide it behind a #define that checks compiler versions? Bwuh.

Super Duper Overloading

It would be nice to overhaul the overloading system to do overload ranking (for usertypes and only usertypes), so that we don't have a first-come-first-serve implementation for things that match.

Note that the first-come-first-serve implementation is 100% fine for any function set that does not take a userdata (e.g., ones that are overloaded on just arity and on primitive types such as strings, ints, etc.).

Check if a variable exists

Hi

I have updated my code to use sol2 (it was easy, just change very few method names was enough) and everything is working fine, but I have a small question: how can I know if a variable is set or not in the script? I want to do something like this:

config.lua

fullScreen = true

In C++:

sol::state vm;
vm.script_file("config.lua");

bool isFullScreen = true; // Default value

if(vm.exists("fullScreen"))
{
    isFullScreen = vm["fullScreen"]; // Get user configuration
}

Is it possible to do something equivalent to this in sol2? How?

Thank you very much

SegFault using user type the wrong way

I initialize the sol::state object with the following code:

lua.new_usertype<LuaApp>("System", "libContext", &LuaApp::getLibContext,
                                        "import", &LuaApp::loadModule);

lua.set("system", this);

When I run

system:import("LibTest1")

everything works fine. But when I run

system.import("LibTest1")

it crashes with the following stacktrace:

1   sol::stack::getter<RBS::App::LuaApp *, void>::get_no_nil    sol.hpp 3833    0x688f1c    
2   sol::stack::getter<RBS::App::LuaApp&, void>::get    sol.hpp 3896    0x68dd0d    
3   sol::stack::getter<RBS::App::LuaApp, void>::get sol.hpp 3725    0x68db33    
4   _ZN3sol5stack12stack_detail13unchecked_getIN3RBS3App6LuaAppEEEDcP9lua_Statei    sol.hpp 2998    0x68d8b9    
5   _ZN3sol5stack12stack_detail10tagged_getIN3RBS3App6LuaAppEEEDcNS_5typesIJT_EEEP9lua_Statei   sol.hpp 3064    0x68d8db    
6   _ZN3sol5stack3getIN3RBS3App6LuaAppEEEDcP9lua_Statei sol.hpp 3077    0x68d902    
7   sol::function_detail::usertype_function<void (RBS::App::LuaApp:: *)(std::string const&), RBS::App::LuaApp>::prelude sol.hpp 5466    0x68d92e    
8   sol::function_detail::usertype_function<void (RBS::App::LuaApp:: *)(std::string const&), RBS::App::LuaApp>::operator()  sol.hpp 5474    0x68d7dd    
9   sol::detail::trampoline<sol::function_detail::base_function&>   sol.hpp 2519    0x436a20    
10  sol::function_detail::base_call sol.hpp 5100    0x67d79a    
11  sol::function_detail::usertype_call<2ul>    sol.hpp 5147    0x68631f    
12  luaD_precall            0x69c1ba    
13  luaV_execute            0x6a726d    
14  luaD_call           0x69c59f    
15  luaD_callnoyield            0x69c5f1    
16  luaD_rawrunprotected            0x69b9dc    
17  luaD_pcall          0x69c84d    
18  lua_pcallk          0x699ea1    
19  sol::state_view::script sol.hpp 7571    0x67fcbb    

I guess sol should throw an exception here, shouldn't it?

table iterators

Despite InputIterator being the weakest category, we should support it on tables anyways since people want to have it. vOv

Inheritance

[ Bikeshed ] We can support inheritance if a person has exceptions enabled. The problem is, we'll have to start figuring out "best match" functions for overloading, which gets hairy. We could simply say "first one to match wins", which means if you have two functions registered that take

fooA( A* );
fooB( B* );

And B inherits from A, then fooA will always get matched first in the "first come first serve" model. This will result in people doing zany things to differentiate, unless we implement "and we looked at all the functions and found this one matches the bestest."

Buh.

Write a tutorial

The current README is pretty terse, and reading API reference is a not pleasant way to learn any library. I propose to kidnap manual from any competing library (kagaya, selene, lua-intf to name a few), made a few edits to identifiers (and list of supported compilers) and put it into README. You may even combine parts kidnapeed here and there. Later Sol-specific features may be added, but it will be a good start.

I believe that now, when you are released a major stable version, lack of step-by-step tutorial is main barrier to wider Sol2 acceptance.

Table Iterators fail on empty tables

I am making a table printer and was using the table iterators, when passed an empty table, it either segfaults, or throws a luarror stating that
states, invalid key to 'next' if the iterator is not used.

Example:

std::ostream& operator<<(std::ostream &os, const sol::object& obj);

std::ostream& operator<<(std::ostream &os, const sol::table& tbl)
{
    std::ostringstream oss;
    oss << "{ ";
    for(auto& kvp : tbl)
    {
        sol::object key = kvp.first;
        sol::object value = kvp.second;
        oss << key << ": " << value << ", ";
    }
    oss << " }";
    return os << oss.str();
}

std::ostream& operator<<(std::ostream &os, const sol::object& obj)
{
    // remove this for segfault
    if(!obj)
        return os;
    //

    sol::type type = obj.get_type();
    switch(type)
    {
        case sol::type::string:
            return os << obj.as<std::string>();
            break;
        case sol::type::number:
            return os << obj.as<double>();
            break;
        case sol::type::boolean:
            return os << obj.as<bool>();
            break;
        case sol::type::table:
            return os << obj.as<sol::table>();
            break;
        case sol::type::nil:
            return os << "nil";
            break;
        default:
            return os << "NA";
            break;
    }
}

I was also able to create this bug by modifying the test case for the tables/iterator test case.

sol::environment

std::string code = "function f (i) return 1, 2, 3 end";

sol::state lua;
lua_State* L = lua.lua_state();

// environment sandboxed / isolated, but with access to things in the state?
sol::environment env(L);
sol::script s(env, code);

sol::optional<sol::function> x = lua["f"]; // if ( x ) is false
sol::optional<sol::function> y = env["f"]; // if ( y ) is true

Is this what "sandboxing" and "environments" are all about?

Testing on OSX

I'll investigate this one, just want a record of it.

Known failures:

  • xcode7 appleclang, lua53
  • gcc-5, luajit51

Build 1

get<T>()-chaining doesn't work

In this example code
https://github.com/ThePhD/sol2/blob/develop/examples/tables.cpp
at the very bottom there is get-chaining as an example.

lua.get<sol::table>("table2").get<sol::table>("nestedTable").get<std::string>("key2")

However if i try to copy that code snippet to my Visual Studio 2015 only the first get<sol::table>() gets accepted. The second get<sol::table>() and the get<std::string>() get red marks, with the note "Error : type name not allowed"

If i type in the first

lua.get<sol::table>("table2")

and add a dot (".") after the ")" usually Visual studio then shows me possible member functions/variables that can follow, however nothing is displayed.
If chaining were allowed and working properly, then typing a dot would usually reveal a list, showing all the possible member functions and variables that could follow.

Feature request : optional std::cout << error instead of throw(error)

EDIT: Just found out that you commented on this in the readme -.- damn i'm dumb/blind... need moar sleep. XD I'm so sorry.

I've noticed with Sol2 when a Lua error is detected (syntax error, trying to index nil values, etc) the program throws an error and the program gets aborted/stopped.
In the state_view.hpp:

namespace sol {
namespace detail {
inline int atpanic(lua_State* L) {
#ifdef SOL_NO_EXCEPTIONS
    (void)L;
    return -1;
#else
    const char* message = lua_tostring(L, -1);
    std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic";
    throw error(err);
#endif
}
} // detail

Would it be possible to add an "error handling"-option for the sol::state where the user can choose to
-throw() the error message (abort/disrupt the C++ program), like it is now or
-std::cout the error message to console (don't destroy lua-state and don't abort/disrupt the C++ progam, instead abort the currently active lua-activity, return to C++, let the C++ program continue and show Lua error message in console).

Many use Lua in combination with C++ so they have a part of the program (Lua) that does not neccessarily crash the entire program if an error occurs in that part.
In many cases and for many users, the only reason where an error in the Lua part should crash/disrupt the entire program if C++ expects a return value from Lua but Lua has an error (resulting in C++ not getting any return or getting wrong returns), but in that case it's the C++s side to handle that situation.
That's why i think adding an option to std::cout the error to the console, return to C++ and let the C++ program continue would be a really nice feature (so people have the choice of either throwing each time an error occurs or letting the program continue with a displayed error message in the console).

Another good reason for an error console output would be because, at least in Visual Studio 2015, the compiler optimizes the throw()-error away when compiling the release version:

err Error reading register value.   
L   Variable is optimized away and not available.   
message Variable is optimized away and not available.   

So in the release version there is no indication what actually went wrong in the Lua files, which is bad when you want your users to be able to modify/add lua files to your program. If i try to catch the std::runtime_error thrown by Sol2, like this

        try { 
            this->lua["updateGame"](dt); 
        }
        catch (const sol::error& e) { 
            std::cout << e.what() << std::endl; 
        }

in debug-mode it works, the error message gets displayed in the console and the program continues. In release mode however the error message from the Sol2-function atpanic gets optimized away, making the try-catch not working anymore. So again, a "print-to-console-and-continue-in-C++ instead of throw()"-option would be useful.

An console-printed error message would also allow users who later use the released software to edit/add lua files to the program and see error message without the program getting closed due to the throw().

Tunneling syntax

We need a function name for tunneling deeply into types:
lua.what_is_this_called("a", "b", "c");
Xeo mentioned using a delimeter in the string
lua.get("a:b:c");
But that requires a bit of runtime processing, and we'd rather let the user pick their own delimeter (since any string can technically be a key for get/set, and we don't want to tie anyone's hands to a specific kind) (Xeo did recommend a second argument to pick the delimeter, but still meh-ish?)

Nevertheless, a single function call with a good name would be useful, and would also help with efficiency purposes (avoiding mutiple push/pop calls when we can push all at once, pop all at once).

Member function calls are slow

Member function calls on usertypes are slow. There should be a way to call the function directly without going through the index metamethod to get the right function, but doing that may require explicitly setting the functions on each and every userdata when the :new() function is run. This may be problematic...

Document SOL_CHECK_ARGUMENTS and other build params

I propose to add section into API reference documenting SOL_CHECK_ARGUMENTS and any other build params if they are exist.

One particular thing that makes me cautious about Sol2 is your concentration on the speed, while reliability of applications using Sol is under question. In particular, it seems that without SOL_CHECK_ARGUMENTS, i.e. by default, i can export C++ function accepting string, call it from Lua with number and make a crash.

In another place you mention "Do NOT save the return type of a function_result with auto". It will be great to protect from such errors with some type machinery. Aa well as combine all the remaining warnings in the single documentation section.

SOL_CHECK_ARGUMENTS - everywhere

Currently, when someone gets a sol::table and such from the stack, we don't assert that it's actually a table on construction, even when SOL_CHECK_ARGUMENTS is specified. That should be fixed for all the sol::reference types, such as:

  • sol::table
  • sol::userdata
  • sol::light_userdata
  • sol::function
  • sol::protected_function
  • sol::thread
  • sol::coroutine (is just a function)

Stack overflow

I'm writing benchmark.

    sol::state state;
    state.script("lua_function=function(i)return i;end");
    sol::function f = state["lua_function"];
    std::string teststring = "testtext";
    for (int i = 0; i < 1000000; ++i)
    {
        std::string result = f(teststring);
        if (result != teststring) { throw std::logic_error(""); }
    }

this code crashed at gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2) with '-O3 -DNDEBUG -std=c++14'

error message:

terminate called after throwing an instance of 'sol::error'
  what():  lua: error: stack overflow

Do you know what's bad?

need to detect missing keys in tables. could we have a "getOpt" function for sol tables or references?

I've had a previous issue on the original sol library regarding detecting when a key was missing from a table.
With sol2 and sol::optional, I was able to work around this problem, but I had to write a convenient wrapper to make it being actually useful. This is named getOpt and it is shown below:

template<typename T, typename K>
T getOpt(sol::table tb, K && key, T def = T{})
{
    auto res = tb.get<sol::optional<T>>(std::forward<K>(key));
    return res.value_or(def);
}

usage example snippet:

auto animSpec = tbAnim.get<sol::table>(k); // k is an int index
MaskedImage img = images.loadMasked(
    animSpec["image"], 
    getOpt<bool>(animSpec,"flipX"),
    getOpt<bool>(animSpec,"flipY"));

example lua script:

  local basedir = "res/sprites/"
  local defDuration = 200
    animations = {
      left = {
        {image = basedir.."walkerLeft0.png", duration = defDuration},
        {image = basedir.."walkerLeft1.png", duration = defDuration},
      },
      right = {
        {image = basedir.."walkerLeft0.png", flipX = true, duration = defDuration},
        {image = basedir.."walkerLeft1.png", flipX = true, duration = defDuration},
      }
    }

do you think tables or references could benefit from having a getOpt() like function? (this will save client code from dealing directly with sol::optional objects)

thanks!

Registering C++ class instance object and nonstatic functions

Note : Solved, solution is further down

I've noticed registering C++ functions, at least the ways described in the API documentation and in the examples, only works if the function is either global or a static class member function.
I've tried it in many different ways Sol2 offers function registration, but so far nothing works. Here is an example:

class Object {
  Object() :lua() {
    //trying to register nonstatic functions
    this->lua.set_function("nonStaticFunction", &Object::nonStaticFunction); // doesn't work either

    //trying to register static functions
    this->lua.set_function("staticFunction", &Object::staticFunction); // works
  }
    void nonStaticMethod() {};
    static void staticMethod() {};
    sol::state lua;
}

I know in the other topic
#36
you told me how to register class instances by just saving a reference value to a lua table (thank you for that! :) ), and it's working fine, now i'd like to know if and how one can register nonstatic class functions.

In your example files you
-register global C++ functions in Lua,
-register static C++ class functions in Lua
-or functions of objects that you initialize in Lua, like here
https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp
however there is no example of calling nonstatic class functions so when Lua calls a nonstatic C++ function the C++ function can access thisand nonstatic instance member variables.

EDIT: Solution below. i'll leave this here for people who might have the same problem/issue/question:
I think there is a solution:
I've noticed on your site
http://sol2.readthedocs.org/en/latest/api/table.html
you mention futher down on that site

template<typename Key, typename Fx>
state_view& set_function(Key&& key, Fx&& fx, [...]);

you mentioned that the this allows passing an object instance pointer and "a member function".
Not sure what you mean by additionally passing an additional member function, but by testing myself i found out that instead of

    this->lua.set_function("nonStatic", &Object::nonStaticFunction); // throws error

using this

    this->lua.set_function("nonStaticFunction", &Object::nonStaticFunction, this); // ok

allows the use of nonstatic functions, thanks to the additional this.
In addition to that you can use lambdas, apparently this way:

    this->lua.set_function("nonStaticfunction", [this]() {this->nonStaticFunction();});

If you register class functions from outside that class i guess you can just replace this in the lambda/the set_function()-arguments with a pointer or reference to that class instance.

This was quite confusing as none of the example codes showed this (nonstatic functions and access to this) in any way. You may use this for your soon-Tutorial. :)

Curious : is there any performance difference between the ""function", &Object::function, this"-solution and the lambda-solution?

Build issue with clang++ and g++

I'm using Lua 5.3.2

clang++ --version outputs:

clang version 3.7.1 (tags/RELEASE_371/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
g++ --version outputs: 
g++ (GCC) 5.3.0

I'm getting the following errors when building with g++: http://termbin.com/c4e7
With clang++: http://termbin.com/dqoz

I don't know where to begin deciphering those error messages so I was hoping I could have some help in fixing this issue. If I should provide more information let me know and I'll get that to you as soon as I can.

stack_{x} types

As it stands, sol::reference and all its derived types are instantiated from elements on the stack but are forcefully backed by being referenced into the lua registry and kept there. This is good in the general sense, but for performance reasons it would be beneficial to simply reference objects that already exist on the stack, without copying them into the registry first and enforcing an unreferencing from the registry upon destruction. These would be called stack_whatever, and would probably include:

  • struct stack_reference
  • struct stack_object : stack_reference
  • struct stack_table : stack_reference
  • struct stack_userdata : stack_reference
  • struct stack_lightuserdata : stack_reference
  • struct stack_function : stack_reference
  • struct stack_protected_function : stack_reference

sol::thread is too permanent to warrant this, as is sol::corountine, and so they won't be part of this API.

The code between the stack version and the originals we already have would be identical except for whether or not its copied into the registry, so folding these implementations with their counterparts (e.g. sol::table and the analogous) (just have different base classes that handle its behavior when it gets the value from the stack).

Namespace cleanup

The toplevel namespace has many functions and traits in it that probably won't ever be used. Shift all non-user-frendly entities into detail namespace or meta namespace.

Compatibility - How much?

How much of the sol/compatibility folder is truly required? Most of the code was yoinked from elsewhere with bits and pieces rewritten for sol: it would be prudent to try rewriting parts of it and scraping everything else that isn't explicitly required to make sol work.

LuaJIT 5.1: Exceptions are not rethrown through sol::error

In my code, I'm trying to force some sandboxing, one part of this is setting the require function to nil.

To test this, I create an "library script":

local M = {}
function M.foo()
    return "foo"
end
return M

I store this into a file in the test dir, m.lua, and then load it via:

local M= require('m')
assert(M.foo() == "foo");

On Lua 5.2, this throws a sol::error claiming the require function is nil. This is the expected behaviour, however, luajit exceptions are never caught and it throws an error unrecognized.

Stack Guard

Much like lock_guard, stack_guard should get the number of elements on the stack on construction and then get the number on exist and throw / error if the number is wrong if there's a violation in the destructor. It can be used as a check invariants and expectations.

There could be two types: one used internally in the framework that only errors / throws on if SOL_CHECK_ARGUMENTS is specified (but these invariants aren't something the framework is ever supposed to break, so... redundant / overkill in addition to unit tests?). The other should error all the time (this one will be stack_guard).

global table: integer keys

Write tests to make sure sol::state lua; lua[1] = 25.2; double p = lua[1]; top-level kind of code works properly with the new optimization.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.