Giter Site home page Giter Site logo

sol's Introduction

Sol

Build Status

Sol is a C++ library binding to Lua. It currently supports Lua 5.2. Sol aims to be easy to use and easy to add to a project. At this time, the library is header-only for easy integration with projects.

Sneak Peek

#include <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.hpp>
#include <cassert>

struct vars {
    int boop = 0;
};

int main() {
    sol::state lua;
    lua.new_userdata<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.

Features

  • Supports retrieval and setting of multiple types including std::string.
  • 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.
  • operator[]-style manipulation of tables is provided.
  • Support for tables.

Supported Compilers

Sol makes use of C++11 features. GCC 4.7 and Clang 3.3 or higher should be able to compile without problems. However, the officially supported compilers are:

  • GCC 4.8.0
  • GCC 4.9.0
  • Clang 3.4

Visual Studio 2013 with the November CTP could possibly compile it, despite not being explicitly supported. The last version that Visual Studio 2013 was supported was on tag v1.1.0. Anything after that is wishful thinking. In order to retrieve that tagged version, just do git checkout v1.1.0.

Caveats

Due to how this library is used compared to the C API, the Lua Stack is completely abstracted away. Not only that, but all Lua errors are thrown as exceptions instead. This allows you to handle the errors gracefully without being forced to exit.

It should be noted that the library itself depends on lua.hpp to be found by your compiler. It uses angle brackets, e.g. #include <lua.hpp>.

License

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

sol's People

Contributors

mp4 avatar notlion avatar peterhajdu avatar princesstrash avatar rapptz avatar thephd 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

sol's Issues

visual studio 2015 build failed

Hello, I creating benchmark (https://github.com/bagobor/cpp2lua-buindings-battle) for lua binding libraries and found that Sol failed to build with modern Visual Studio 2015

template<class F>
struct check_deducible_signature {
    template<class G>
    static auto test(int) -> decltype(&G::operator(), void());
    template<class>
    static auto test(...) -> struct nat;

    using type = std::is_void<decltype(test<F>(0))>;
};

template static auto test(...) -> struct nat; leads to compile error. :(
May be you have an idea how to fix it. I'm not so proficient with modern 'meta' magic.

sol::table:size()

Hi

I am very new to github so please forgive my noobness: I started using Sol and managed to integrate it (it's very easy, no problem here) in my test program. I tried the following: load a lua file which has a generateDungeon function which returns a 4096 elements table. Then in C++ I do the following:

sol::function dungeonFunc = luaVM.get<sol::function>("generateDungeon");
sol::table dungeon = dungeonFunc.call<sol::table>();

Everything works flawlessly but when I want to read all the values from table:

for(std::size_t i = 1; i <= dungeon.size(); ++ i)
{
    const auto value = dungeon.get<int>(i);

    // etc...
}

loop finishes but I have seg fault errors in random places. I tested commenting here and there and my conclusion points to sol::table::size(). I took dungeon.size() call out from for loop:

auto dungeonSize = dungeon.size();
for(std::size_t i = 1; i <= dungeonSize; ++ i)

With this change everything works. I checked sol::table:size() and we have the following:

size_t size() const {
    push();
    return lua_rawlen(state(), -1);
}

With my total lack of knowledge of how sol and lua work, I would say that push() makes some stack get bigger in each call to size() and finally makes my app crash. Is it possible this to be a bug?

Thanks for your library by the way ;)

Regards

Setting functions in tables doesn't work.

Can't set a function inside a table, user made or otherwise. Doing it through sol::state::script works just fine though.

Simple test case:

#include <sol.hpp>
#include <iostream>
#include <iomanip>

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base, sol::lib::os);
    lua.get<sol::table>("os").set_function("fun", []() {
        return "test";
    });
    lua.get<sol::table>("os").set("name", "windows");
    lua.script("assert(os.fun() == \"test\")\n" // fails
               "assert(os.name == \"windows\")");
}

Qualifiers in function parameters fails to compile

Having const, volatile, or reference qualifiers in function parameters causes (many) compiler errors.

Minimal test case:

#include <sol.hpp>
#include <iostream>

struct test {
    void g(const std::string& str) {
        std::cout << str << '\n';
    }
};

int main() {
    sol::state lua;
    lua.new_userdata<test>("test", "g", &test::g);
    lua.script("x = test.new()\n"
               "x:g('hello')");
}

error handling without exceptions

Hi, I found this library do not use lua_pcall. I prefer to call a lua function with a message handler to offer a stack trace in error. so a function like lua.where() and lua.error([msg before where]) is good. have some plans to support this?

new get method

Please add std::function in get method:

inline std::function<void()> get(typesstd::function<void()>, lua_State* L, int index = -1)
{
if(!lua_isfunction(L, index))
{
return {}; // maybe error?
};

lua_pushvalue(L, index);
int func = luaL_ref(L, LUA_REGISTRYINDEX);

return [func, L]()
{
    lua_rawgeti(L, LUA_REGISTRYINDEX, func);

    if(lua_isfunction(L, -1))
    {
        if(lua_pcall(L, 0, 0, 0))
        {} // maybe error?
}

    luaL_unref(L, LUA_REGISTRYINDEX, func);
};

}

example:
void testFunc(std::function<void()> f)
{
f();
}

A:testFunc(function() print("hello std::function") end)

set_function or new_userdata error on Windows/Code::Blocks (newbie question)

Hi,
I'm totally new to sol, so maybe my compiling error is stupid.
I'm working on Windows 64 bits (compiling in 32 bits) with Code::Blocks 13.12.
I recompiled lua 5.2.3 like 10 minutes ago.

This simple code won't compile:

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

struct vars {
    int boop = 0;
};

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

When i use a simple examples (basic.cpp or variables.cpp), the code compile and works as expected but when i use the set_function or new_userdata functions like in the code above, i get the following error:

||=== Build: Debug in lua-test (compiler: GNU GCC Compiler) ===|
C:\...\sol-master\sol\traits.hpp||In instantiation of 'struct sol::detail::check_deducible_signature<void (vars::*)()>':|
...\sol-master\sol\traits.hpp|159|required from 'struct sol::has_deducible_signature<void (vars::*)()>'|
...\sol-master\sol\traits.hpp|239|required from 'struct sol::function_traits<void (vars::*)()>'|
...\sol-master\sol\traits.hpp|252|required from 'struct sol::detail::member_traits<void (vars::*)(), false>'|
...\sol-master\sol\function_types.hpp|37|required from 'struct sol::detail::functor<vars, void (vars::*)(), void>'|
...\sol-master\sol\function_types.hpp|377|required from 'struct sol::userdata_function_core<void (vars::*)(), vars>'|
...\sol-master\sol\function_types.hpp|500|required from 'struct sol::userdata_indexing_function<void (vars::*)(), vars>'|
...\lua\sol-master\sol\userdata.hpp|165|required from 'void sol::userdata<T>::build_function_tables(sol::userdata<T>::function_map_t*&, sol::userdata<T>::function_map_t*&) [with unsigned int N = 0u; T = vars; sol::userdata<T>::function_map_t = std::unordered_map<std::basic_string<char>, std::pair<std::unique_ptr<sol::base_function>, bool> >]'|
...\lua\sol-master\sol\userdata.hpp|301|required from 'void sol::userdata<T>::build_function_tables(sol::userdata<T>::function_map_t*&, sol::userdata<T>::function_map_t*&, std::string, Fx&&, Args&& ...) [with unsigned int N = 0u; Fx = int vars::*; Args = {}; T = vars; sol::userdata<T>::function_map_t = std::unordered_map<std::basic_string<char>, std::pair<std::unique_ptr<sol::base_function>, bool> >; std::string = std::basic_string<char>]'|
...\sol\userdata.hpp|330|required from 'sol::userdata<T>::userdata(std::string, sol::constructors<CArgs ...>, Args&& ...) [with Args = {const char (&)[5], int vars::*}; CArgs = {sol::types<>}; T = vars; std::string = std::basic_string<char>]'|
...\sol-master\sol\state.hpp|169|required from 'sol::state& sol::state::new_userdata(const string&, sol::constructors<CArgs ...>, Args&& ...) [with Class = vars; CArgs = {sol::types<>}; Args = {const char (&)[5], int vars::*}; sol::state = sol::state; std::string = std::basic_string<char>]'|
...\sol-master\sol\state.hpp|164|required from 'sol::state& sol::state::new_userdata(const string&, Args&& ...) [with Class = vars; CTor = {}; Args = {const char (&)[5], int vars::*}; sol::state = sol::state; std::string = std::basic_string<char>]'|
...\lua-test\main.cpp|10|required from here|
...\sol-master\sol\traits.hpp|154|error: invalid use of incomplete type 'struct sol::detail::nat'|
...\sol-master\sol\traits.hpp|152|error: forward declaration of 'struct sol::detail::nat'|
...\sol-master\sol\traits.hpp||In instantiation of 'struct sol::function_traits<void (vars::*)()>':|
...\sol-master\sol\traits.hpp|252|required from 'struct sol::detail::member_traits<void (vars::*)(), false>'|
...\sol-master\sol\function_types.hpp|37|required from 'struct sol::detail::functor<vars, void (vars::*)(), void>'|
...\lua\sol-master\sol\function_types.hpp|377|required from 'struct sol::userdata_function_core<void (vars::*)(), vars>'|
...\lua\sol-master\sol\function_types.hpp|500|required from 'struct sol::userdata_indexing_function<void (vars::*)(), vars>'|
...\lua\sol-master\sol\userdata.hpp|165|required from 'void sol::userdata<T>::build_function_tables(sol::userdata<T>::function_map_t*&, sol::userdata<T>::function_map_t*&) [with unsigned int N = 0u; T = vars; sol::userdata<T>::function_map_t = std::unordered_map<std::basic_string<char>, std::pair<std::unique_ptr<sol::base_function>, bool> >]'|
...\lua\sol-master\sol\userdata.hpp|301|required from 'void sol::userdata<T>::build_function_tables(sol::userdata<T>::function_map_t*&, sol::userdata<T>::function_map_t*&, std::string, Fx&&, Args&& ...) [with unsigned int N = 0u; Fx = int vars::*; Args = {}; T = vars; sol::userdata<T>::function_map_t = std::unordered_map<std::basic_string<char>, std::pair<std::unique_ptr<sol::base_function>, bool> >; std::string = std::basic_string<char>]'|
...\lua\sol-master\sol\userdata.hpp|330|required from 'sol::userdata<T>::userdata(std::string, sol::constructors<CArgs ...>, Args&& ...) [with Args = {const char (&)[5], int vars::*}; CArgs = {sol::types<>}; T = vars; std::string = std::basic_string<char>]'|
...\lua\sol-master\sol\state.hpp|169|required from 'sol::state& sol::state::new_userdata(const string&, sol::constructors<CArgs ...>, Args&& ...) [with Class = vars; CArgs = {sol::types<>}; Args = {const char (&)[5], int vars::*}; sol::state = sol::state; std::string = std::basic_string<char>]'|
...\lua\sol-master\sol\state.hpp|164|required from 'sol::state& sol::state::new_userdata(const string&, Args&& ...) [with Class = vars; CTor = {}; Args = {const char (&)[5], int vars::*}; sol::state = sol::state; std::string = std::basic_string<char>]'|
...\lua-test\main.cpp|10|required from here|
...\sol-master\sol\traits.hpp|239|error: 'value' is not a member of 'sol::has_deducible_signature<void (vars::*)()>'|
...\sol-master\sol\function_types.hpp||In instantiation of 'struct sol::detail::functor<vars, void (vars::*)(), void>':|
...\sol-master\sol\function_types.hpp|377|required from 'struct sol::userdata_function_core<void (vars::*)(), vars>'|
...\sol-master\sol\function_types.hpp|500|required from 'struct sol::userdata_indexing_function<void (vars::*)(), vars>'|
...\sol-master\sol\userdata.hpp|165|required from 'void sol::userdata<T>::build_function_tables(sol::userdata<T>::function_map_t*&, sol::userdata<T>::function_map_t*&) [with unsigned int N = 0u; T = vars; sol::userdata<T>::function_map_t = std::unordered_map<std::basic_string<char>, std::pair<std::unique_ptr<sol::base_function>, bool> >]'|
...\sol-master\sol\userdata.hpp|301|required from 'void sol::userdata<T>::build_function_tables(sol::userdata<T>::function_map_t*&, sol::userdata<T>::function_map_t*&, std::string, Fx&&, Args&& ...) [with unsigned int N = 0u; Fx = int vars::*; Args = {}; T = vars; sol::userdata<T>::function_map_t = std::unordered_map<std::basic_string<char>, std::pair<std::unique_ptr<sol::base_function>, bool> >; std::string = std::basic_string<char>]'|
...\sol-master\sol\userdata.hpp|330|required from 'sol::userdata<T>::userdata(std::string, sol::constructors<CArgs ...>, Args&& ...) [with Args = {const char (&)[5], int vars::*}; CArgs = {sol::types<>}; T = vars; std::string = std::basic_string<char>]'|
...\sol-master\sol\state.hpp|169|required from 'sol::state& sol::state::new_userdata(const string&, sol::constructors<CArgs ...>, Args&& ...) [with Class = vars; CArgs = {sol::types<>}; Args = {const char (&)[5], int vars::*}; sol::state = sol::state; std::string = std::basic_string<char>]'|
...\sol-master\sol\state.hpp|164|required from 'sol::state& sol::state::new_userdata(const string&, Args&& ...) [with Class = vars; CTor = {}; Args = {const char (&)[5], int vars::*}; sol::state = sol::state; std::string = std::basic_string<char>]'|
...\lua-test\main.cpp|10|required from here|
...\sol-master\sol\function_types.hpp|37|error: no type named 'args_type' in 'struct sol::detail::member_traits<void (vars::*)(), false>'|
...\sol-master\sol\function_types.hpp|38|error: no type named 'return_type' in 'struct sol::detail::member_traits<void (vars::*)(), false>'|
...\sol-master\sol\function_types.hpp|59|error: no type named 'return_type' in 'struct sol::detail::member_traits<void (vars::*)(), false>'|
...\sol-master\sol\function_types.hpp||In member function 'int sol::userdata_indexing_function<Function, Tp>::fx_call(lua_State*) [with Tx = vars*; Function = void (vars::*)(); Tp = vars; lua_State = lua_State]':|
...\sol-master\sol\function_types.hpp|540|warning: control reaches end of non-void function [-Wreturn-type]|
...\sol-master\sol\function_types.hpp||In member function 'int sol::userdata_indexing_function<Function, Tp>::fx_call(lua_State*) [with Tx = vars; Function = void (vars::*)(); Tp = vars; lua_State = lua_State]':|
...\sol-master\sol\function_types.hpp|540|warning: control reaches end of non-void function [-Wreturn-type]|
||=== Build failed: 6 error(s), 35 warning(s) (0 minute(s), 0 second(s)) ===|

Can someone tell me what i did wrong?
Thanks a lot in advance :)

Template member

Is it possible to bind a template member function?

I'm trying to bind a varient class.

I've tried

  m_lua.new_usertype<Test::Param>(
    "Param",
    "get_bool", &Test::Param::get<bool>
  );

That produces error, expecting 3 arguments

and (although I didn't have hope in this one.)

  m_lua.new_usertype<Test::Param>(
    "Param",
    "get_bool", static_cast<bool (Test::Param::*) ()>( &Test::Param::get<bool> )
  );

Allow arbitrary creation of tables from C++ functions.

At the moment the only way to create a table from C++ and returning it from a binded function is to use sol::table as the return type like so:

sol::table stuff() {
}

However, the only way to actually create a sol::table is through sol::state::create_table which is very awkward to use with free functions. So you typically have to use a lambda or something like so:

int main() {
    sol::state lua;
    lua.set_function("stuff", [&lua](int x) {
        auto&& t = lua.create_table();
        // do stuff with table
    });

It's very annoying and not very intuitive with current C++ code.

Instead, it would be nice if C++ containers returned tables as well.

Example:

std::vector<int> stuff() {
    return { 1, 2, 3, 4, 5 };
}

int main() {
    sol::state lua;
    lua.set_function("stuff", stuff);
}

And then from the lua side:

local t = stuff()
for i = 1, #t do
    print(t[i])
end

Would print 1 2 3 4 5

LuaJIT support?

LuaJIT (a lot of uses) is Lua 5.1 syntax and API interface compatible, could sol support it ?

Dependent template error when compiling with clang

I'm not exactly sure what's going on here, but clang gives me this fixit error when compiling proxy.hpp:

In file included from ../deps/sol/sol.hpp:25:
In file included from ../deps/sol/sol/state.hpp:26:
In file included from ../deps/sol/sol/table.hpp:25:
../deps/sol/sol/proxy.hpp:45:20: error: use 'template' keyword to treat 'get' as a dependent template name
        return tbl.get<T>(key);
                   ^
                   template 
../deps/sol/sol/proxy.hpp:108:20: error: use 'template' keyword to treat 'get' as a dependent template name
        return tbl.get<function>(key)(types<Ret...>(), std::forward<Args>(args)...);
                   ^
                   template

Changing the those lines like so resolves the error:
return tbl.get<T>(key);return tbl.template get<T>(key);

Is this a proper fix?

My clang --version just in case:
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)

Registering a function inside a table

Hi

Is there a way to register a function from C++ so it is contained in a table? So I can call from Lua this way:

local v = MyStuff.doSomething(...)

Thanks

warning while compiling: demange.h

54: const static std::array<std::string, 2> removals = { "struct ", "class " };
55: const static std::array<std::string, 2> replacements = { "::", "_" };

missing braces around initializer for 'std::arraystd::basic_string<char, 2u>::value_type [2] {aka std::basic_string [2]}' [-Wmissing-braces] demangle.hpp

missing braces around initializer for 'std::arraystd::basic_string<char, 2u>::value_type [2] {aka std::basic_string [2]}' [-Wmissing-braces] demangle.hpp


here is fix:
const static std::array<std::string, 2> removals = {{ "struct ", "class " }};
const static std::array<std::string, 2> replacements = {{ "::", "_" }};

Seems to be a bug/ stack.hpp line 217 getter function

template
struct getter<T&> {
static T& get(lua_State* L, int index = -1) {
void* udata = lua_touserdata(L, index);
T** obj = static_cast<T**>(udata);
return **obj;
}
};

after:

template
struct getter<T&> {
static T& get(lua_State* L, int index = -1) {
void* udata = lua_touserdata(L, index);
T* obj = static_cast<T*>(udata); // here change
return *obj; // here change
}
};

Sandbox

Sandboxing is very usefull while you want to load more than one file (ex. for handlers, callbacks).
This code is not working under 5.2, function lua_setfenv is missing.

        lua_State* l = L.get();
        if(luaL_loadfile(state, filename.c_str())) {
            lua_error(state);
            return;
        }

    // create env table
    lua_newtable( state );
    int envTable = lua_gettop( state );
    lua_newtable( state );

    // set the env
    lua_setfenv( state, -2 );

    // copy _G
    lua_newtable( state );
    int __index = lua_gettop( state );
    lua_pushstring( state, "__index" );
    lua_getfield( state, LUA_GLOBALSINDEX, "_G" );
    lua_settable( state, __index );

    // set the metatable for the env table
    lua_setmetatable( state, envTable );

    // set the env
    lua_pushvalue(state, -1);
    lua_setfield(state, LUA_GLOBALSINDEX, name.c_str());

    lua_setfenv( state, -2 );

    lua_pcall(state, 0, -1, 0);

Overloaded Userdata Functions

Is there a way to select which version of a overloaded function to use when creating userdata? This is a class similar to the one I'm trying to bind:

struct vector {
  float x = 0;
  float y = 0;
  vector() = default;
  void set(float x_, float y_) { x = x_; y = y_; }
  void set(const vector& v) { x = v.x; y = v.y; }
};

So given that there are two versions of set, how do I choose which one to bind?

sol::userdata<vector>("vector", ctor, "set", &vector::set); // Doesn't work

Operator overloading

Operator overloading has been mentioned a couple times in the issues, but I can't find an example. Is it possible to add an operator overload to a userdata? I have tried something like this, without luck:

sol::userdata<Vec2f> udata("Vec2", ctor, "__add", &Vec2f::operator+);

I'd be happy to add this to the userdata example if it's possible and someone can show me how 😄

Implement C++ class bindings to Lua.

It's one thing I've put off for a while but I guess it's time to do it eventually. Currently there's no way to bind a C++ class to Lua. This would be a pretty neat feature to have. I'm using this issue for notes on how I'd implement it and/or design it.

One of the difficult things to do is generalising the constructor of a class or what happens when there are multiple constructors. I think for the best case it's better if I pass the constructor types in a variadic template along with the class type. It's probably also for the best to only support a single constructor rather than multiple, since Lua doesn't even have function overloading and overloaded functions don't work with sol anyway so there's no expectation of it working.

At the end of the day, in Lua classes are just tables with the __index meta table pointing to itself. So that shouldn't be too difficult. There's also support for member function pointers already, which I suppose is admittedly a much harder part than constructors.

Open ended questions I'll deal with later:

  • Operator overloading? Will it be easy to provide 1 to 1 translations from operators in C++ to lua meta tables? C++ already allows access of operator overloads through T::operator.
  • Should a new class be made to handle this stuff or is the current table class enough?
  • How should one deal with template classes? Should all classes be non-templated by default? The difficulty of template classes is surely something I don't want to deal with.
  • How would we receive the class name through the template alone? Should the class name be passed as a parameter or should effort be made to automatically detect it using typeid and demangling?

Userdata static methods and free functions

This is sort of two requests. I'm wondering what to do about statics. For example, the Vec2 class that I'm using as a test case has static methods like Vec2f::zero() and Vec2f::xAxis() which can be useful as alternate constructors. It'd be nice to be able to call these from Lua like Vec2.xAxis(). Is there currently a way to do this?

It would also be great to allow free functions for adding functionality that the underlying class does not support:

"__tostring", [](const Vec2<T>& v) {
  return "[" + std::to_string(v.x) + ", " + std::to_string(v.y) + "]";
}

Although, this could probably be added in a Lua script after the userdata is created.. But doing it from C++ might be cleaner.

Bad access when calling a function on returned userdata

Hi! I'm trying to bind a class that returns instances of it's own type. Here's a simplified example:

struct Vec {
  float x, y, z;
  Vec(float x, float y, float z) : x{x}, y{y}, z{z} {}
  float length() {
    return sqrtf(x*x + y*y + z*z);
  }
  Vec normalized() {
    float invS = 1 / length();
    return {x * invS, y * invS, z * invS};
  }
};

sol::state lua;
lua.open_libraries(sol::lib::base);

sol::constructors<sol::types<float, float, float>> ctor;
sol::userdata<Vec> udata("Vec", ctor,
  "normalized", &Vec::normalized,
  "length",     &Vec::length);

lua.set_userdata(udata);

This script works:

lua.script("v = Vec.new(1, 2, 3)\n"
           "print(v:length())");
// --> 3.7416574954987

But this one fails:

lua.script("v = Vec.new(1, 2, 3)\n"
           "print(v:normalized():length())");
// --> EXC_BAD_ACCESS

Is it possible to do this with sol, or am I missing something?

Documentation

There's no documentation for sol. Or well, any other lua binding library really. Should probably fix that.

It's an on going progress and they'll be under the docs branch. They'll be published on a github page.

`sol::table`: Checking for existance of key

Is there a means for checking for an existence of a key within a sol::table?

Additionally, when using sol::table::operator[], it returns a sol::proxy. However, this type has no means of checking the type of the underlying value.

Something like this might be neat:

sol::table tbl; // assume it's initialized
if (auto prox = tbl["my_key"])
{
  // use prox
}
else
{
  // prox doesn't actually exist
}

A method such as exists() would be useful, too. I took this syntax suggestion from boost's optional type.

sol::table::iterator & friends

libjansson offers a c-style "any" iterator where you can fix values from the type like so. A similar API (that's less wonky since we're in C++) could probably be created and allowed for with table's begin() and end() syntax, using sol::object for values and perhaps a new sol::key type (since keys can only be integers or strings in lua).

I'd be interested in doing this for version 2.0 later on!

Nullptr when passing one userdata to another

Userdata is becoming null for some reason when passed to a method of another userdata class. When used by the same class there's no problem. Simple test case:

struct Vec2 {
  float x = 0;
  float y = 0;
  Vec2(float x_, float y_) : x{x_}, y{y_} {}
};

struct Incr {
  Vec2 incr(const Vec2& v) {
    return Vec2(v.x + 1, v.y + 1); // Eek! v is nullptr
  }
};

lua.new_userdata<Vec2, float, float>("Vec2");
lua.new_userdata<Incr>("Incr", "incr", &Incr::incr);

lua.script("a = Vec2.new(10, 20)\n"
           "i = Incr.new()\n"
           "b = i:incr(v)\n"
           "print(b.x, b.y)");

Registering a Inherited method

As of now, I couldn't figure out a better way to access a Derived's class method without overriding the Base's method. Example:

class Base {
public:
Base( int a_num ) : m_num(a_num) {}
int get_num() {
return m_num;
}
protected:
int m_num;
};

class Derived : public Base {
public:
Derived( int a_num ) : Base(a_num) {}
int get_num_10() {
return 10 * m_num;
}
int get_num() {
return Base::get_num();
}
};

//-------------------------------------------------------------//

sol::constructors<sol::types<int>> l_ctor_base;
sol::userdata<Base> l_userdata_base( "Base", l_ctor_base, "get_num", &Base::get_num );

l_lua.set_userdata( l_userdata_base );

l_lua.script( "base = Base.new( 5 )" );
l_lua.script( "print( base:get_num() )" );

sol::constructors<sol::types<int>> l_ctor_derived;
sol::userdata<Derived> l_userdata_derived( "Derived", l_ctor_derived, "get_num", &Derived::get_num, "get_num_10", &Derived::get_num_10 );

l_lua.set_userdata( l_userdata_derived );

l_lua.script( "derived = Derived.new( 7 )" );
l_lua.script( "print( derived:get_num_10() )" );
l_lua.script( "print( derived:get_num() )" );

//------------------------------------------//

If I don't override get_num in Derived, I get the following error when registering get_num:

no matching function for call to ‘sol::userdata::build_function_tables(const char [8], int (Base::)(), const char [11], int (Derived::)())’

It would be interesting to support inheritance, but if not, at least to come up with an workaround to this, since overriding all of the methods is usually not desired.

Other than that, great project! Keep up the good work :D

Passing a `sol::table` fails as a parameter for `usertype` ctor

Currently, sol fails to pass a sol::table as a parameter to a usertype.

Minimum example:

class Foo {

public:
    Foo(sol::table /*table*/) { }
};

int main() {
    sol::state lua; 
    lua.new_usertype<Foo, sol::table>("Foo");
    lua.script("a = Foo.new { a = \"wat\" }");
}

The error message is: lua: error: No matching constructor for the arguments provided

Performance question

Hi

I am currently programming a small home brew game and I plan to use Lua along with Sol. My idea is to somewhat use the model exposed by Unity and other game developing packages: the game entities (for example a zombie enemy) will be formed by different components (sprite or graphical representation, collider, etc). These components will be managed by the C++ part, while Lua will be "the client": it just asks for a collider, a sprite, etc. and uses them in some coherent way (for example collider determines the world position of the sprite). This is somewhat analog to how javascript deals with DOM objects provided by the browser.

So to implement that I thought I could create, to expose to Lua, a bunch of functions like the following:

std::size_t newSprite(const std::string& fileName);
void setSpritePosition(std::size_t spriteId, const Vector2D& position);
void removeSprite(std::size_t spriteId);

These functions would be implemented in order to call SpriteController, which with the spriteId would look up in its sprite list and modify the corresponding sprite object.

But on the other hand I can also expose C++ classes to Lua, for example:

class SpriteLua
{
public:
    Sprite(const std::string& fileName)
    {
        mSprite = spriteController.load(fileName);
    }

    void setPosition(const Vector2D& position)
    {
        mSprite->setPosition(position);
    }
    ...
    ...
private:
    Sprite* mSprite;
};

The class approach seems faster and also more convenient to write in the Lua side (just manage Sprite instance instead of spriteSomething + spriteId + parameters, but I don't know the overhead, if it exists at all, of this second approach.

I know this can be a premature optimization case but I think I need to know both approach relative cost, it can decide how to do a substantial part of C++ <--> Lua communication of the game. Also I welcome any other suggestion about this or related issue.

Thanks

Use of undeclared identifier 'lua_tounsigned'

I'm creating a tower defense game that uses Lua as a scripting engine.

When compiling with both g++ and clang++ I get the following error.

include/sol/sol/stack.hpp:100:31: error: use of undeclared identifier "lua_tounsigned"
    return static_cast<U>(lua_tounsigned(L, index));

I am using the following command to compile:

g++ -Wall -Wno-format -Wno-unused-variable -c -g -O0 -fbuiltin -fpermissive -std=c++11 -I include -I src/include <FILES> -Llib <*snip*> -llua -o ./bin/Tower

I believe there error crops up when I'm defining my classes to use inside Lua. I created a class called LuaScript. Here are the .h and .cpp files

LuaScript.h

#ifndef _LUA_SCRIPT_H
#define _LUA_SCRIPT_H

#include <string>
#include "lua/selene.h"
#include "sol/sol.hpp"

class LuaScript {
public:
    LuaScript(bool loadedClasses = true);

    bool isLoaded() { return _loaded; }
    void setLoaded(bool b) { _loaded = b; }

    void loadScript(const std::string& name);

    sol::state lua;
protected:
    bool _loaded;

    void defineEnemy();
    void defineTower();
    void defineObject();
    void defineTarget();
    void defineMap();
    void defineStats();
};

#endif

LuaScript.cpp

#include "LuaScript.h"

<*Includes have been snipped*>

LuaScript::LuaScript(bool defineClasses) {
    _loaded = false;
    lua.open_libraries(sol::lib::base, sol::lib::math, sol::lib::table,
        sol::lib::package, sol::lib::math, sol::lib::debug);

    if (defineClasses) {
        defineTarget();
        defineObject();
        defineTower();
        defineEnemy();
        defineMap();
        defineStats();
    }
}

void LuaScript::loadScript(const std::string& name) {
    lua.open_file(name);
    setLoaded(true);
}

void LuaScript::defineTower() {
    sol::constructors<sol::types<Map*, float, float, Stats>> towerCon;
    sol::userdata<Tower> towerUserData (
        "Tower", towerCon,
        // Target methods
        "getX", &Tower::getX,
        "getY", &Tower::getY,
        "setPosition", &Tower::setPosition,
        "isSimpleTarget", &Tower::isSimpleTarget,
        // Object methods
        "contains", &Tower::contains,
        "applyStat", &Tower::applyStat,
        "setStats", &Tower::setStats,
        "getSpeed", &Tower::getSpeed,
        "getRange", &Tower::getRange,
        "getFireRate", &Tower::getFireRate,
        "getDamage", &Tower::getDamage,
        "getAccel", &Tower::getAccel,
        "getProjSpeed", &Tower::getProjSpeed,
        //"setRange", &Tower::setRange, // ERROR
        // Tower methods
        "getProjectile", &Tower::getProjectile,
        "setProjectile", &Tower::setProjectile
    );
    lua.set_userdata(towerUserData);
}

void LuaScript::defineObject() {
    <*snip*>
}

void LuaScript::defineTarget() {
    <*snip*>
}

void LuaScript::defineMap() {
    <*snip*>
}

void LuaScript::defineStats() {
    <*snip*>
}

void LuaScript::defineEnemy() {
    <*snip*>
}

All my Tower methods have been defined in Tower.cpp and Tower.h. Here are the relevant parts.

Tower.h

#ifndef _TOWER_H
#define _TOWER_H

#include "Target.h"
#include "Object.h"
#include "Stats.h"

class Tower : public Object {
public:
    <*I've removed all irrelevant code*>
    Tower(Map* map, float x, float y, Stats s);
    ~Tower();

    void loadLua();

    void setPosition(float x, float y);

    Object* getProjectile() { return _projectile; }
    void setProjectile(Object& o);

protected:
    <*snip*>
};
#endif

If I uncomment "setRange", &Tower::setRange I get the undeclared error, but commenting it out works fine.

Tower::setRange is set inside Object.h, the parent class of Tower.

Object.h

#ifndef _OBJECT_H
#define _OBJECT_H

<*Includes have been snipped*>

class Object : public Target, public sf::Drawable, public sf::Transformable {
public:
    Object();
    Object(Map* map, float x, float y, int collRadius, Stats s);
    virtual ~Object();

    <*snip*>

    int getSpeed() const { return _stats.speed + _baseStats.speed; }
    int getRange() const { return _stats.range + _baseStats.range; }
    float getFireRate() const { return _stats.fireRate + _baseStats.fireRate; }
    float getDamage() const { return _stats.damage + _baseStats.damage; }
    float getAccel() const { return _stats.accel + _baseStats.accel; }
    float getProjSpeed() const { return _stats.projSpeed + _baseStats.projSpeed; }
    // Stats setters
    void setRange(int r) { _stats.range = r; } // ERROR method
    <*snip*>
};
#endif

I don't understand why that specific method would cause issues with Sol. All the other methods I've declared work with Sol, and compile fine, but that method throws the error.

If I'm doing something wrong or I need to provide some more information let me so I can get this figured out.

Problem with userdata and metatable

    ClassA* popClass()
    {
        return this;
    }

local A = ClassA:new()
local B = A:popClass()
B:test() -- here is crash

error code:
terminate called after throwing an instance of 'sol::error'
what(): lua: error: script.lua:4: attempt to index local 'B' (a userdata value)

Programmatically ignore warnings.

There are some warnings that cause issues w.r.t. compilation (mainly Clang). Through the use of #pragma and _Pragma you could programmatically disable some warnings that just make things a headache.

Example:

#define STRINGIZE_PRAGMA(x) _Pragma(#x)

#if defined(__clang__)
#define PRAGMA(x) STRINGIZE_PRAGMA (clang x)
#elif defined (__GNUC__)
#define PRAGMA(x) STRINGIZE_PRAGMA (GCC x)
#endif

PRAGMA(diagnostic push)
PRAGMA(diagnostic ignored "-Wwhatever")
// some code here
PRAGMA(diagnostic pop)

Some candidates for programmatic removal include:

  • '-Wno-unused-value'
  • '-Wno-constexpr-not-const'

Probably others as time goes on.

Example of catching exception?

I wrote some purposefully bad Lua code. I tried catching a sol::error after calling "open_file" but the C++ just SEGFAULTs.

Build Problems

Hello. I'm having problems building sol on Ubuntu

Platform: Ubuntu trusty

Software installed:

  • liblua5.1-0:amd64 install
  • liblua5.1-0-dev:amd64 install
  • liblua5.2-0:amd64 install
  • liblua50 install
  • liblua50-dev install
  • libluajit-5.1-common install
  • liblualib50 install
  • lua-bitop:amd64 install
  • lua-cosmo install
  • lua-curl:amd64 install
  • lua-curl-dev:amd64 install
  • lua-event:amd64 install
  • lua-event-dev:amd64 install
  • lua-expat:amd64 install
  • lua-expat-dev:amd64 install
  • lua-filesystem:amd64 install
  • lua-filesystem-dev:amd64 install
  • lua-json install
  • lua-leg install
  • lua-lgi:amd64 install
  • lua-logging install
  • lua-lpeg:amd64 install
  • lua-posix:amd64 install
  • lua-socket:amd64 install
  • lua-socket-dev:amd64 install
  • lua-sql-sqlite3:amd64 install
  • lua5.1 install
  • lua5.2 install
  • lua50 install
  • luajit install

G++ Version

rgb@woland:~/git/sol$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.2-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

Actions:

git clone Catch and sol
copy Catch/single_include/catch.hpp to sol/Catch/include/catch.hpp
python bootstrap.py
ninja

rgb@woland:~/git/sol$ ninja
[1/3] Compiling tests.cpp to obj/tests.o
FAILED: g++ -MMD -MF obj/tests.o.d -c -Wall -Wextra -pedantic -pedantic-errors -std=c++11 -DNDEBUG -O3 -I"." -I"Catch/include" -Werror tests.cpp -o obj/tests.o
In file included from ./sol/reference.hpp:25:0,
from ./sol/object.hpp:25,
from ./sol/proxy.hpp:26,
from ./sol/table.hpp:25,
from ./sol/state.hpp:26,
from ./sol.hpp:25,
from tests.cpp:3:
./sol/types.hpp:25:19: fatal error: lua.hpp: No such file or directory
#include <lua.hpp>
^
compilation terminated.
ninja: build stopped: subcommand failed.

Action: add /usr/include/lua5.1 to build.ninja

Output:

[1/3] Compiling tests.cpp to obj/tests.o
FAILED: g++ -MMD -MF obj/tests.o.d -c -Wall -Wextra -pedantic -pedantic-errors -std=c++11 -DNDEBUG -O3 -I"." -I"Catch/include" -I"/usr/include/lua5.1" -Werror tests.cpp -o obj/tests.o
In file included from ./sol/object.hpp:26:0,
from ./sol/proxy.hpp:26,
from ./sol/table.hpp:25,
from ./sol/state.hpp:26,
from ./sol.hpp:25,
from tests.cpp:3:
./sol/stack.hpp: In static member function ‘static U sol::stack::getter<T, X>::get(lua_State_, int)’:
./sol/stack.hpp:73:39: error: there are no arguments to ‘lua_tounsigned’ that depend on a template parameter, so a declaration of *‘lua_tounsigned’_ must be available [-fpermissive]
return lua_tounsigned(L, index);^M
^
./sol/stack.hpp:73:39: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
In file included from ./sol/state.hpp:26:0,
from ./sol.hpp:25,
from tests.cpp:3:
./sol/table.hpp: In member function ‘size_t sol::table::size() const’:
./sol/table.hpp:108:38: error: ‘lua_rawlen’ was not declared in this scope
return lua_rawlen(state(), -1);^M
^
./sol/table.hpp: In member function ‘sol::table& sol::table::set_fx(std::true_type, T&&, TFx&&, TObj&&)’:
./sol/table.hpp:187:53: error: there are no arguments to ‘luaL_setfuncs’ that depend on a template parameter, so a declaration of ‘luaL_setfuncs’ must be available [-fpermissive]
luaL_setfuncs(state(), funcreg, upvalues + 1);^M
^
./sol/table.hpp: In member function ‘sol::table& sol::table::set_fx(std::false_type, T&&, TFx&&)’:
./sol/table.hpp:206:49: error: there are no arguments to ‘luaL_setfuncs’ that depend on a template parameter, so a declaration of ‘luaL_setfuncs’ must be available [-fpermissive]
luaL_setfuncs(state(), funcreg, upvalues);^M
^
./sol/table.hpp: In member function ‘sol::table& sol::table::set_fx(T&&, std::unique_ptrsol::base_function)’:
./sol/table.hpp:236:42: error: there are no arguments to ‘luaL_setfuncs’ that depend on a template parameter, so a declaration of ‘luaL_setfuncs’ must be available [-fpermissive]
luaL_setfuncs(state(), funcreg, 1);^M

I'd be grateful for your advice.
^

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.