Giter Site home page Giter Site logo

lua-intf's Introduction

lua-intf

lua-intf is a binding between C++11 and Lua language, it provides three different set of API in one package:

  • LuaBinding, Export C++ class or function to Lua script
  • LuaRef, High level API to access Lua object
  • LuaState, Low level API as simple wrapper for Lua C API

lua-intf has no dependencies other than Lua and C++11. And by default it is headers-only library, so there is no makefile or other install instruction, just copy the source, include LuaIntf.h, and you are ready to go.

lua-intf is inspired by vinniefalco's LuaBridge work, but has been rewritten to take advantage of C++11 features.

Lua and C++ error handling

By default LuaIntf expect the Lua library to build under C++, this will allow Lua library to throw exception upon error, and make sure C++ objects on stack to be destructed correctly. For more info about error handling issues, please see:

http://lua-users.org/wiki/ErrorHandlingBetweenLuaAndCplusplus

If you really want to use Lua library compiled under C and want to live with longjmp issues, you can define LUAINTF_LINK_LUA_COMPILED_IN_CXX to 0 before including lua-intf headers:

#define LUAINTF_LINK_LUA_COMPILED_IN_CXX 0
#include "LuaIntf/LuaIntf.h"

Compile Lua library in C++

Most distributions of precompiled Lua library are compiled under C, if you need Lua library compiled under C++, you probably need to compile it by yourself. It is actually very easy to build Lua library under C++, first get a copy of source code of the Lua library:

curl http://www.lua.org/ftp/lua-5.3.0.tar.gz -o lua-5.3.0.tar.gz
tar xf lua-5.3.0.tar.gz
cd lua-5.3.0

To compile on Linux:

make linux MYCFLAGS="-x c++" CC="g++"

To compile on Mac OSX:

make macosx MYCFLAGS="-x c++" MYLDFLAGS="-lc++"

To compile on Windows with MINGW and MSYS:

make mingw MYCFLAGS="-x c++" CC="g++"

And then install to your chosen directory in <path>:

make install INSTALL_TOP=<path>

Export C++ class or function to Lua script

You can easily export C++ class or function for Lua script, consider the following C++ class:

    class Web
    {
    public:
        // base_url is optional
        Web(const std::string& base_url);
        ~Web();

        static void go_home();

        static std::string home_url();
        static void set_home_url(const std::string& url);

        std::string url() const;
        void set_url(const std::string& url);
        std::string resolve_url(const std::string& uri);

        // doing reload if uri is empty
        std::string load(const std::string& uri);
    };

You can export the Web class by the following code:

    LuaBinding(L).beginClass<Web>("Web")
        .addConstructor(LUA_ARGS(_opt<std::string>))
        .addStaticProperty("home_url", &Web::home_url, &Web::set_home_url)
        .addStaticFunction("go_home", &Web::go_home)
        .addProperty("url", &Web::url, &Web::set_url)
        .addFunction("resolve_url", &Web::resolve_url)
        .addFunction("load", &Web::load, LUA_ARGS(_opt<std::string>))
        .addStaticFunction("lambda", [] {
            // you can use C++11 lambda expression here too
            return "yes";
        })
    .endClass();

To access the exported Web class in Lua:

    local w = Web()								-- auto w = Web("");
    w.url = "http://www.yahoo.com"				-- w.set_url("http://www.yahoo.com");
    local page = w:load()						-- auto page = w.load("");
    page = w:load("http://www.google.com")		-- page = w.load("http://www.google.com");
    local url = w.url							-- auto url = w.url();

Module and class

C++ class or functions exported are organized by module and class. The general layout of binding looks like:

    LuaBinding(L)
        .beginModule(string module_name)
            .addFactory(function* func)

            .addConstant(string constant_name, VALUE_TYPE value)

            .addVariable(string property_name, VARIABLE_TYPE* var, bool writable = true)
            .addVariableRef(string property_name, VARIABLE_TYPE* var, bool writable = true)

            .addProperty(string property_name, FUNCTION_TYPE getter, FUNCTION_TYPE setter)
            .addProperty(string property_name, FUNCTION_TYPE getter)

            .addFunction(string function_name, FUNCTION_TYPE func)

            .beginModule(string sub_module_name)
                ...
            .endModule()

            .beginClass<CXX_TYPE>(string class_name)
                ...
            .endClass()

            .beginExtendClass<CXX_TYPE, SUPER_CXX_TYPE>(string sub_class_name)
                ...
            .endClass()
        .endModule()

        .beginClass<CXX_TYPE>(string class_name)
            .addFactory(FUNCTION_TYPE func)		// you can only have one addFactory or addConstructor
            .addConstructor(LUA_ARGS(...))

            .addConstant(string constant_name, VALUE_TYPE value)

            .addStaticVariable(string property_name, VARIABLE_TYPE* var, bool writable = true)
            .addStaticVariableRef(string property_name, VARIABLE_TYPE* var, bool writable = true)

            .addStaticProperty(string property_name, FUNCTION_TYPE getter, FUNCTION_TYPE setter)
            .addStaticProperty(string property_name, FUNCTION_TYPE getter)

            .addStaticFunction(string function_name, FUNCTION_TYPE func)

            .addVariable(string property_name, CXX_TYPE::FIELD_TYPE* var, bool writable = true)
            .addVariableRef(string property_name, CXX_TYPE::FIELD_TYPE* var, bool writable = true)

            .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE setter)
            .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE getter_const, CXX_TYPE::FUNCTION_TYPE setter)
            .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter)

            .addPropertyReadOnly(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE getter_const)
            .addPropertyReadOnly(string property_name, CXX_TYPE::FUNCTION_TYPE getter)

            .addFunction(string function_name, CXX_TYPE::FUNCTION_TYPE func)
        .endClass()

        .beginExtendClass<CXX_TYPE, SUPER_CXX_TYPE>(string sub_class_name)
            ...
        .endClass()

A module binding is like a package or namespace, it can also contain other sub-module or class. A module can have the following bindings:

  • factory function - bind to global or static C++ functions, or forward to sub-class constructor or sub-module factory
  • constant - bind to constant value
  • variable - bind to global or static variable, the valued pushed to lua is by-value, can be read-only
  • variable reference - bind to global or static variable, the valued pushed to lua is by-reference, can be read-only
  • property - bind to getter and setter functions, can be read-only
  • function - bind to global or static function

A class binding is modeled after C++ class, it models the const-ness correctly, so const object can not access non-const functions. It can have the following bindings:

  • constructor - bind to class constructor
  • factory function - bind to global or static function that return the newly created object
  • constant - bind to constant value, constant is static
  • static variable - bind to global or static variable, the valued pushed to lua is by-value, can be read-only
  • static variable reference - bind to global or static variable, the valued pushed to lua is by-reference, can be read-only
  • static property - bind to global or static getter and setter functions, can be read-only
  • static function - bind to global or static function
  • member variable - bind to member fields, the valued pushed to lua is by-value, can be read-only
  • member variable reference - bind to member fields, the valued pushed to lua is by-reference, can be read-only
  • member property - bind to member getter and setter functions, you can bind const and non-const version of getters, can be read-only
  • member function - bind to member functions

For module and class, you can have only one constructor or factory function. To access the factory or constructor in Lua script, you call the module or class name like a function, for example the above Web class:

    local w = Web("http://www.google.com")

The static or module variable, property and constant is accessible by module/class name, it is just like table field:

    local url = Web.home_url
    Web.home_url = "http://www.google.com"

The static function can be called by the following, note the '.' syntax and class name:

    Web.go_home()

The member variable and property is associated with object, so it is accessible by variable:

    local session = Web("http://www.google.com")
    local url = session.url
    session.url = "http://www.google.com"

The member function can be called by the following, note the ':' syntax and object name:

    session:load("http://www.yahoo.com")

Integrate with Lua module system

The lua module system don't register modules in global variables. So you'll need to pass a local reference to LuaBinding. For example:

    extern "C" int luaopen_modname(lua_State* L)
    {
        LuaRef mod = LuaRef::createTable(L);
        LuaBinding(mod)
            ...;
        mod.pushToStack();
        return 1;
    }

C++ object life-cycle

lua-intf store C++ object via Lua userdata, and it stores the object in the following ways:

  • By value, the C++ object is stored inside userdata. So when Lua need to gc the userdata, the memory is automatically released. lua-intf will make sure the C++ destructor is called when that happened. C++ constructor or function returns object struct will create this kind of Lua object.

  • By pointer, only the pointer is stored inside userdata. So when Lua need to gc the userdata, the object is still alive. The object is owned by C++ code, it is important the registered function does not return pointer to newly allocated object that need to be deleted explicitly, otherwise there will be memory leak. C++ function returns pointer or reference to object will create this kind of Lua object.

  • By shared pointer, the shared pointer is stored inside userdata. So when Lua need to gc the userdata, the shared pointer is destructed, that usually means Lua is done with the object. If the object is still referenced by other shared pointer, it will keep alive, otherwise it will be deleted as expected. C++ function returns shared pointer will create this kind of Lua object. A special version of addConstructor will also create shared pointer automatically.

Using shared pointer

If both C++ and Lua code need to access the same object, it is usually better to use shared pointer in both side, thus avoiding memory leak. You can use any kind of shared pointer class, as long as it provides:

  • operator ->
  • operator *
  • operator bool
  • default constructor
  • copy constructor

Before you can use it, you need to register it with lua-intf, take std::shared_ptr for example:

    namespace LuaIntf
    {
        LUA_USING_SHARED_PTR_TYPE(std::shared_ptr)
    }

For constructing shared pointer inside Lua userdata, you can register the constructor by adding LUA_SP macro and the actual shared pointer type, for example:

    LuaBinding(L).beginClass<Web>("web")
        .addConstructor(LUA_SP(std::shared_ptr<Web>), LUA_ARGS(_opt<std::string>))
        ...
    .endClass();

Using custom deleter

If custom deleter is needed instead of the destructor, you can register the constructor with deleter by adding LUA_DEL macro, for example:

     class MyClass
     {
     public:
          MyClass(int, int);
          void release();
     };

     struct MyClassDeleter
     {
         void operator () (MyClass* p)
         {
             p->release();
         }
     };

    LuaBinding(L).beginClass<MyClass>("MyClass")
        .addConstructor(LUA_DEL(MyClassDeleter), LUA_ARGS(int, int))
        ...
    .endClass();

Using STL-style container

By default lua-intf does not add conversion for container types, however, you can enable support for container type with the following:

    namespace LuaIntf
    {
        LUA_USING_LIST_TYPE(std::vector)
        LUA_USING_MAP_TYPE(std::map)
    }

For non-template or non-default template container type, you can use:

    class non_template_int_list
    { ... };

    template <typename T, typename A, typename S>
    class custom_template_list<T, A, S>
    { ... };

    namespace LuaIntf
    {
        LUA_USING_LIST_TYPE_X(non_template_int_list)

        // you need to use LUA_COMMA for , to workaround macro limitation
        LUA_USING_LIST_TYPE_X(custom_template_list<T LUA_COMMA A LUA_COMMA S>,
            typename T, typename A, typename S)
    }

Function calling convention

C++ function exported to Lua can follow one of the two calling conventions:

  • Normal function, the return value will be the value seen on the Lua side.

  • Lua lua_CFunction convention, that the first argument is lua_State* and the return type is int. And just like lua_CFunction you need to manually push the result onto Lua stack, and return the number of results pushed.

lua-intf extends lua_CFunction convention by allowing more arguments besides lua_State*, the following functions will all follow the lua_CFunction convention:

    // regular lua_CFunction convention
    int func_1(lua_state* L);

    // lua_CFunction convention, but allow arg1, arg2 to map to arguments
    int func_2(lua_state* L, const std::string& arg1, int arg2);

    // this is *NOT* lua_CFunction
    // the L can be placed anywhere, and it is stub to capture lua_State*,
    // and do not contribute to actual Lua arguments
    int func_3(const std::string& arg1, lua_state* L);

    class Object
    {
    public:
        // class method can follow lua_CFunction convention too
        int func_1(lua_state* L);

        // class lua_CFunction convention, but allow arg1, arg2 to map to arguments
        int func_2(lua_state* L, const std::string& arg1, int arg2);
    };

    // the following can also be lua_CFunction convention if it is added as class functions
    // note the first argument must be the pointer type of the registered class
    int obj_func_1(Object* obj, lua_state* L);
    int obj_func_2(Object* obj, lua_state* L, const std::string& arg1, int arg2);

For every function registration, lua-intf also support C++11 std::function type, so you can use std::bind or lambda expression if needed. You can use lambda expression freely without giving full std::function declaration; std::bind on the other hand, must be declared:

    LuaBinding(L).beginClass<Web>("Web")
        .addStaticFunction("lambda", [] {
            // you can use C++11 lambda expression here too
            return "yes";
        })
        .addStaticFunction<std::function<std::string()>>("bind",
            std::bind(&Web::url, other_web_object))
    .endClass();

If your C++ function is overloaded, pass &function is not enough, you have to explicitly cast it to proper type:

    static int test(string, int);
    static string test(string);

    LuaBinding(L).beginModule("utils")

        // this will bind int test(string, int)
        .addFunction("test_1", static_cast<int(*)(string, int)>(&test))

        // this will bind string test(string), by using our LUA_FN macro
        // LUA_FN(RETURN_TYPE, FUNC_NAME, ARG_TYPES...)
        .addFunction("test_2", LUA_FN(string, test, string))

    .endModule();

Function argument modifiers

By default the exported functions expect every argument to be mandatory, if the argument is missing or not compatible with the expected type, the Lua error will be raised. You can change the function passing requirement by adding argument passing modifiers in LUA_ARGS, lua-intf supports the following modifiers:

  • _opt<TYPE>, specify the argument is optional; if the argument is missing, the value is created with default constructor

  • _def<TYPE, DEF_NUM, DEF_DEN = 1>, specify the argument is optional; if the argument is missing, the default value is used as DEF_NUM / DEF_DEN

  • _out<TYPE&>, specify the argument is for output only; the output value will be pushed after the normal function return value, and in argument order if there is multiple output

  • _ref<TYPE&>, specify the argument is mandatory and for input/output; the output value will be pushed after the normal function return value, and in argument order if there is multiple output

  • _ref_opt<TYPE&>, combine _ref<TYPE&> and _opt<TYPE>

  • _ref_def<TYPE&, DEF_NUM, DEF_DEN = 1>, combine _ref<TYPE&> and _def<TYPE, DEF_NUM, DEF_DEN = 1>

  • If none of the above modifiers are used, the argument is mandatory and for input only

All output modifiers require the argument to be reference type, using pointer type for output is not supported. The reason _def<TYPE, DEF_NUM, DEF_DEN = 1> requires DEF_NUM and DEF_DEN is to workaround C++ limitation. The C++ template does not allow floating point number as non-type argument, in order specify default value for float, you have to specify numerator and denominator pair (the denominator is 1 by default). For example:

    struct MyString
    {
        std::string indexOf(const std::string& str, int pos);
        std::string desc(float number);
        ...
    };

    #define _def_float(f) _def<float, long((f) * 1000000), 1000000>

    LuaBinding(L).beginClass<MyString>("mystring")

        // this will make pos = 1 if it is not specified in Lua side
        .addFunction("indexOf", &MyString::indexOf, LUA_ARGS(std::string, _def<int, 1>))

        // this will make number = 1.333 = (4 / 3) if it is not specified in Lua side
        // because C++ does not allow float as non-type template parameter
        // you have to use ratio to specify floating numbers 1.333 = (4 / 3)
        // LUA_ARGS(_def<float, 1.33333f>) will result in error
        .addFunction("indexOf", &MyString::desc, LUA_ARGS(_def<float, 4, 3>))

        // you can define your own macro to make it easier to specify float
        // please see _def_float for example
        .addFunction("indexOf2", &MyString::desc, LUA_ARGS(_def_float(1.3333f)))
    .endClass();

Return multiple results for Lua

It is possible to return multiple results by telling which argument is for output, for example:

    static std::string match(const std::string& src, const std::string& pat, int pos, int& found_pos);

    LuaBinding(L).beginModule("utils")

        // this will return (string) (found_pos)
        .addFunction("match", &match, LUA_ARGS(std::string, std::string, _def<int, 1>, _out<int&>))

    .endModule();

Yet another way to return multiple results is to use std::tuple:

    static std::tuple<std::string, int> match(const std::string& src, const std::string& pat, int pos);

    LuaBinding(L).beginModule("utils")

        // this will return (string) (found_pos)
        .addFunction("match", &match)

    .endModule();

And you can always use lua_CFunction to manually push multiple results by yourself.

Lua for-loop iteration function

lua-intf provides a helper class CppFunctor to make it easier to implement for-loop iteration function for Lua. To use it, user need to inherit CppFunctor, and override run method and optional destructor. Then call pushToStack to create the functor object on Lua stack.

    class MyIterator : public CppFunctor
    {
        MyIterator(...)
        {
            ...
        }

        virtual ~MyIterator()
        {
            ...
        }

        // the for-loop will call this function for each step until it return 0
        virtual int run(lua_State* L) override
        {
            ...
            // return the number of variables for each step of for-loop
            // or return 0 to end the for-loop
            return 2;
        }
    }

    int xpairs(lua_State* L)
    {
        return CppFunctor::make<MyIterator>(L, ...); // ... is constructor auguments
    }

To register the for-loop iteration function:

    LuaBinding(L).beginModule("utils")

        .addFunction("xpairs", &xpairs)

    .endModule();

To use the iteration function in Lua code:

    for x, y in utils.xpairs(...) do
        ...
    end

Custom type mapping

It is possible to add primitive type mapping to the lua-intf, all you need to do is to add template specialization to LuaTypeMapping<Type>. You need to:

  • provide void push(lua_State* L, const Type& v)
  • provide Type get(lua_State* L, int index)
  • provide Type opt(lua_State* L, int index, const Type& def)

For example, to add std::wstring mapping to Lua string:

    namespace LuaIntf
    {

    template <>
    struct LuaTypeMapping <std::wstring>
    {
        static void push(lua_State* L, const std::wstring& str)
        {
            if (str.empty()) {
                lua_pushliteral(L, "");
            } else {
                std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
                std::string buf = conv.to_bytes(str);
                lua_pushlstring(L, buf.data(), buf.length());
            }
        }

        static std::wstring get(lua_State* L, int index)
        {
            size_t len;
            const char* p = luaL_checklstring(L, index, &len);
            std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
            return conv.from_bytes(p, p + len);
        }

        static std::wstring opt(lua_State* L, int index, const std::wstring& def)
        {
            return lua_isnoneornil(L, index) ? def : get(L, index);
        }
    };

    } // namespace LuaIntf

After that, you are able to push std::wstring onto or get std::wstring from Lua stack directly:

    std::wstring s = ...;
    Lua::push(L, s);

    ...

    s = Lua::pop<std::wstring>(L);

High level API to access Lua object

LuaRef is designed to provide easy access to Lua object, and in most case you don't have to deal with Lua stack like the low level API. For example:

    lua_State* L = ...;
    lua_getglobal(L, "module");
    lua_getfield(L, -1, "method");
    lua_pushintteger(L, 1);
    lua_pushstring(L, "yes");
    lua_pushboolean(L, true);
    lua_call(L, 3, 0);

The above code can be rewritten as:

    LuaRef func(L, "module.method");
    func(1, "yes", true);

Table access is as simple:

    LuaRef table(L, "my_table");
    table["value"] = 15;
    int value = table.get<int>("value");

    for (auto& e : table) {
        std::string key = e.key<std::string>();
        LuaRef value = e.value<LuaRef>();
        ...
    }

And you can mix it with the low level API:

    lua_State* L = ...;
    LuaRef v = ...;
    lua_getglobal(L, "my_method");
    Lua::push(L, 1);					// the same as lua_pushinteger
    Lua::push(L, v);					// push v to lua stack
    Lua::push(L, true);					// the same as lua_pushboolean
    lua_call(L, 3, 2);
    LuaRef r(L, -2); 					// map r to lua stack index -2

You can use the std::tuple for multiple return values:

    LuaRef func(L, "utils.match");
    std::string found;
    int found_pos;
    std::tie(found, found_pos) = func.call<std::tuple<std::string, int>>("this is test", "test");

Low level API as simple wrapper for Lua C API

LuaState is a simple wrapper of one-to-one mapping for Lua C API, consider the following code:

    lua_State* L = ...;
    lua_getglobal(L, "module");
    lua_getfield(L, -1, "method");
    lua_pushintteger(L, 1);
    lua_pushstring(L, "yes");
    lua_pushboolean(L, true);
    lua_call(L, 3, 0);

It can be effectively rewritten as:

    LuaState lua = L;
    lua.getGlobal("module");
    lua.getField(-1, "method");
    lua.push(1);
    lua.push("yes");
    lua.push(true);
    lua.call(3, 0);

This low level API is completely optional, and you can still use the C API, or mix the usage. LuaState is designed to be a lightweight wrapper, and has very little overhead (if not as fast as the C API), and mostly can be auto-casting to or from lua_State*. In the lua-intf, LuaState and lua_State* are inter-changeable, you can pick the coding style you like most.

LuaState does not manage lua_State* life-cycle, you may take a look at LuaContext class for that purpose.

lua-intf's People

Contributors

0xc0dec avatar bastiendurel avatar krisr avatar louisbrunner avatar luzpaz avatar n-01 avatar stevekchiu 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

lua-intf's Issues

addVariable results in copy on read

It appears addVariable always results in a copy of the variable being created before it is pushed on the stack. This is problematic for class types for two reasons: it results in extra work and memory, and it does not support class types which are missing copy constructors.

I'll take a stab at changing the behavior for class types, but I wanted to call it to your attention first in case I am potentially misreading the code or misusing the API.

Premature SharedPtr dereference

Hey Steve,

I'm using LUA_USING_SHARED_PTR_TYPE to expose my own shared ptr class, however, I was surprised to find that the default SharedPtr wrapper type dereferences the shared_ptr on construction. I can see why this wouldn't be a big deal for standard shared ptrs, but it doesn't play well with custom shared ptrs that do work to dereference the ptr for the first time.

For example, there is a common pattern in Game engines to define a SharedPtr like interface for Resource Handles. The Resource Handle interface will typically only load the resource when it is first dereferenced. By dereferencing the handle early you may be forcing resources to be loaded that are never actually used. Furthermore, in my case, resources can be reloaded, and their pointers change in the process so the current LuaIntf SharedPtr impl is a no go - though I'm not opposed to trying to change my own code to reuse the same pointer if possible.

I can see three ways of fixing this:

  1. Update CppObjectSharedPtr so that it does not dereference the shared ptr until it is actually needed. Update my Resource Handle impl so it reuses the same pointer. This will probably also require some tweaks to the SharedPtr base class, but it should not effect performance at all.
  2. Update CppObjectSharedPtr so that it always dereferences the shared ptr on demand when it is needed, and never stores the ptr. This will be compatible with the most shared ptr classes but may come with a slight perf cost.
  3. Don't bother touching LuaIntf at avoid LUA_USING_SHARED_PTR_TYPE in favor of my own LuaType implementation for Handles.

My preference is to do 1 or 2, but only if you agree. Otherwise, it makes more sense to do 3 so I don't have to maintain my own fork ;).

Thanks,
Kris

Can't get it compiled.

||=== Build: Debug CLANG x86_64 in login-server_sql (compiler: LLVM Clang Compiler) ===|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|92|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|98|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|98|error: use of undeclared identifier 'lua_pushunsigned'; did you mean 'lua_pushinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lua.h|162|note: 'lua_pushinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|103|error: use of undeclared identifier 'luaL_checkunsigned'; did you mean 'luaL_checkinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|44|note: 'luaL_checkinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|108|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|108|error: use of undeclared identifier 'luaL_optunsigned'; did you mean 'luaL_optinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|45|note: 'luaL_optinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|92|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|98|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|98|error: use of undeclared identifier 'lua_pushunsigned'; did you mean 'lua_pushinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lua.h|162|note: 'lua_pushinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|103|error: use of undeclared identifier 'luaL_checkunsigned'; did you mean 'luaL_checkinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|44|note: 'luaL_checkinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|108|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|108|error: use of undeclared identifier 'luaL_optunsigned'; did you mean 'luaL_optinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|45|note: 'luaL_optinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|347|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|348|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|349|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|347|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|348|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|349|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|190|error: use of undeclared identifier 'luaL_len'; did you mean 'luaL_ref'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|61|note: 'luaL_ref' declared here|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|471|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|474|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|477|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|477|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|541|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|360|error: use of undeclared identifier 'lua_version'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|347|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|348|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|349|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|347|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|348|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|349|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|190|error: use of undeclared identifier 'luaL_len'; did you mean 'luaL_ref'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|61|note: 'luaL_ref' declared here|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|471|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|474|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|477|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|477|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|541|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/LuaState.h|360|error: use of undeclared identifier 'lua_version'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|92|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|98|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|98|error: use of undeclared identifier 'lua_pushunsigned'; did you mean 'lua_pushinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lua.h|162|note: 'lua_pushinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|103|error: use of undeclared identifier 'luaL_checkunsigned'; did you mean 'luaL_checkinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|44|note: 'luaL_checkinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|108|error: unknown type name 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|108|error: use of undeclared identifier 'luaL_optunsigned'; did you mean 'luaL_optinteger'?|
../src/3rdparty/LuaJIT-2.0.3/src/lauxlib.h|45|note: 'luaL_optinteger' declared here|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|347|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|348|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|360|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|349|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|347|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|348|note: expanded from macro 'LUA_USING_VALUE_TYPE_EXT'|
../src/3rdparty/lua-intf/LuaIntf/impl/LuaType.h|362|error: use of undeclared identifier 'lua_Unsigned'; did you mean 'unsigned'?|
||More errors follow but not being shown.|
||Edit the max errors limit in compiler options...|
||=== Build finished: 50 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Support for user aligned types

I would like to patch LuaIntf to support user aligned types. At the moment, the alignment of types is ignored as a result of the way placement new works. User aligned types are common in games where SIMD instructions are useful. I worked around this for a while by patching LuaIntf to allocate user aligned types directly via new, and just store their pointers in the user data. However, I think it would probably be better to use something like alignof to dynamically allocate extra memory and offset it so as to avoid the additional memory allocation.

LuaContext typecast to lua_State*

Hello SteveKChiu,

I really enjoy Your work and I have got a small enhancement.
It would be nice if You add cast mentioned in title, like this: operator lua_State* () const { return L; } in LuaContext class. Doing it this way integrates LuaContext with for example LuaRef.

Keep it up ๐Ÿ‘

Inherit native C++ class in script

Is it possible to create a class in Lua that inherits a native class that has been bound to Lua via Lua-intf?

If it's possible, it would be helpful if you could provide a small Lua module (e.g. luaintf.lua) along with the library which people could use to create classes derived from the bound classes in Lua. Something like this (inspired by middleclass):

local luaintf = require('luaintf') -- The module

local DerivedClass = class('DerivedClass', BaseClass) -- BaseClass is native C++ class bound via lua-intf

-- Implement the constructor
function DerivedClass:construct(foo)
   BaseClass.construct(self, foo)
   -- Do stuff
end

-- Add methods
function DerivedClass:hello()
   print("Hello, world!")
end

-- Override methods
function DerivedClass:foo(bar)
   BaseClass.foo(self, bar)
   -- Do stuff
end

return DerivedClass
local DerivedClass = require('DerivedClass')

local test = DerivedClass("blah")
test:hello() -- Prints "Hello, world"
test:foo()

Compiler error when registering function with return type std::shared_ptr<const Class>

Hello again,

I'm getting a compiler error when registering function with return type std::shared_ptr<const Class>. Here's the test code:

#include "../lua-intf/LuaIntf/LuaIntf.h"
#include <cstdio>
#include <memory>

extern "C" {
    #include "lua.h"
    #include "lauxlib.h"
    #include "lualib.h"
}

using namespace LuaIntf;

namespace LuaIntf
{
    LUA_USING_SHARED_PTR_TYPE(std::shared_ptr)
}

//------

class A {
public:
};

//------

std::shared_ptr<A> returnA() {
    return std::shared_ptr<A>(new A);
}

std::shared_ptr<const A> returnConstA() {
    return std::shared_ptr<const A>(new A);
}

//------

int main(int argc, char **argv) {
    LuaState L = LuaState::newState();

    LuaBinding(L).beginClass<A>("A")
    .endClass();

    LuaBinding(L).beginModule("utils")
        .addFunction("returnA", &returnA)
        .addFunction("returnConstA", &returnConstA)
    .endModule();

    printf("Hello world!\n");
    return 0;
}

Here's the compiler error which I received:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -std=c++11 -I../lua-5.2.3/src -L../lua-5.2.3/src -llua -o test1 test1.cpp
In file included from test1.cpp:1:
In file included from ./../lua-intf/LuaIntf/LuaIntf.h:41:
./../lua-intf/LuaIntf/impl/CppObject.h:284:11: error: no matching constructor for initialization of 'LuaIntf::CppObject'
        : CppObject(&*sp)
          ^         ~~~~
./../lua-intf/LuaIntf/impl/CppObject.h:319:19: note: in instantiation of member function 'LuaIntf::CppObjectSharedPtr<std::__1::shared_ptr<const A>,
      A>::CppObjectSharedPtr' requested here
        new (mem) CppObjectSharedPtr<SP, T>(sp);
                  ^
./../lua-intf/LuaIntf/impl/CppObject.h:422:40: note: in instantiation of member function 'LuaIntf::CppObjectSharedPtr<std::__1::shared_ptr<const A>, A>::pushToStack'
      requested here
            CppObjectSharedPtr<SP, T>::pushToStack(L, sp, is_const);
                                       ^
./../lua-intf/LuaIntf/impl/CppObject.h:454:62: note: in instantiation of member function 'LuaIntf::LuaCppObjectFactory<std::__1::shared_ptr<const A>, A, true,
      true>::push' requested here
        LuaCppObjectFactory<T, ObjectType, IsShared, IsRef>::push(L, t, IsConst);
                                                             ^
./../lua-intf/LuaIntf/impl/CppInvoke.h:62:21: note: in instantiation of member function 'LuaIntf::LuaCppObject<std::__1::shared_ptr<const A>, false, false>::push'
      requested here
        LuaType<R>::push(L, call(func, args));
                    ^
./../lua-intf/LuaIntf/impl/CppBindModule.h:102:79: note: in instantiation of member function 'LuaIntf::CppInvokeMethod<std::__1::shared_ptr<const A> (*)(),
      std::__1::shared_ptr<const A>>::push' requested here
            int n = CppInvokeMethod<FN, R, typename CppArg<P>::ValueType...>::push(L, fn, args);
                                                                              ^
./../lua-intf/LuaIntf/impl/CppBindModule.h:333:71: note: in instantiation of member function 'LuaIntf::CppBindMethodBase<0, std::__1::shared_ptr<const A> (*)(), 1,
      std::__1::shared_ptr<const A>>::call' requested here
        m_meta.rawset(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc)));
                                                                      ^
test1.cpp:44:4: note: in instantiation of function template specialization 'LuaIntf::CppBindModule::addFunction<std::__1::shared_ptr<const A> (*)()>' requested here
                .addFunction("returnConstA", &returnConstA)
                 ^
./../lua-intf/LuaIntf/impl/CppObject.h:117:14: note: candidate constructor not viable: no known conversion from 'const A *' to 'void *' for 1st argument
    explicit CppObject(void* ptr)
             ^
./../lua-intf/LuaIntf/impl/CppObject.h:142:5: note: candidate constructor not viable: no known conversion from 'const A *' to 'const LuaIntf::CppObject' for 1st
      argument
    CppObject(const CppObject&) = delete;
    ^
1 error generated.

My compiler is clang++:

$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ --version
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix

Unable to bind functions with non-cost non-input reference type arguments

Hey Steve,

This was the other issue that I mentioned. Since merging your tweaks to my original CppArgHolder change, I can no longer compile code uses addFunction to expose a method with non-const reference arguments.

Here is an example of some code that now fails to compile:

.addFunction("addRenderable", &wv::BaseSceneRenderer::addRenderable, LUA_ARGS(wv::Renderable &))

The error message I get is:

Binding of reference to type 'wv::Renderable' to a value of type 'const wv::Renderable' drops qualifiers.

It's not clear to me where exactly the code is trying to cast to a non-const type since CppArgOutput<traits, false> takes a const typename Traits::ValueType& v. It's also not clear to me what you changed that could have possibly broke this.

In any case, I created this change set to fix (workaround?) the issue:
krisr@1dd8683

Curious if you have any thoughts and have experienced the same issue?

Thanks,
Kris

Integrate into game engine with component system

Hi,
First of all, very great library and lot of neat features, i would like to use into my game engine which has scene graph with component based system, i would like to know how would i be able to has scripting components using lua and attach to node, would be possible to extend c++ class and call lua function for methods, ie => initialize, update, draw etc.

any advice?

I found something similar with LuaBridge (http://www.executionunit.com/blog/2014/03/09/integrating-lua-and-my-c-game-engine/)

Thanks

use std::bind error

use std::bind error with the auto return type on VS14 or Clang.
gcc not tested.

bool f(int i, std::string file) {return true;}
int ii=1;
....
std::function<bool (std::string)> f1 = std::bind(f, ii);
.addFunction("f1", f1) //ok
.addFunction("f11", std::bind(f, ii)) //error!!
.addFunction("f2", [ii](std::string s) {
return f(ii,s);
}) //ok

error occured here: decltype(&FN::operator())

I don't know how to fix it.

Problem with CppBindClass::addConstant

I'm stuck with a problem with CppBindClass::setConstant but after several hours I haven't solved it yet.

CPP:

.beginModule("myModule")
    .addConstant("myConst", 10) 
.endModule()

.beginClass<myClass>("myClass")
    .addConstant("myConst", 10) 
.endClass()

Lua:

print(myModule.myConst)  -- prints 10 correctly
print(myClass.myConst) -- Problem here: prints 'nil' value
print(myClass.___getters.myConst) -- prints 10 correctly

TDM GCC 4.9.2 64 bit under WIndows 7 with LuaJIT 2.0.3

Unfortunately it seems that I'm unable to solve this myself... any advice?
Thank you again very much

LUAINTF_BUILD_LUA_CXX and extern "C"

In file LuaCompat.h

if !LUAINTF_BUILD_LUA_CXX

extern "C"
{

endif

include "lualib.h"

include "lauxlib.h"

if !LUAINTF_BUILD_LUA_CXX

}

this should be

if LUAINTF_BUILD_LUA_CXX

extern "C"
..

maybe your test project include lua.hpp before include LuaInf.h

Please allow VS 2013 support.

Most of developers out uses VS 2013 or even VS 2012, lua-intf is great library but I cannot use it as it does not have
VS 2013 support, some stuff can be tweaked using the _MSC_VER definition.

Thanks

Parse issue with LuaTypeID::Nil when compiled for iOS/OSX due to macro expansion

I discovered this issue a few weeks ago. I think it should be mentioned here. I'm using lua-intf for an iOS application (it should be the same for OSX too), and initially the project failed to compile due to a parse issue:

.../lua-intf/LuaIntf/impl/LuaType.h:30:5: error: expected '}'
    Nil = LUA_TNIL,
    ^

.
.
.

.../usr/include/objc/objc.h:80:16: note: expanded from macro 'Nil'
#   define Nil nullptr

.
.
.

.../lua-intf/LuaIntf/impl/LuaType.h:28:1: note: to match this '{'
{
^

This is because there is a macro Nil defined in usr/include/objc/objc.h:

#ifndef Nil
# if __has_feature(cxx_nullptr)
#   define Nil nullptr
# else
#   define Nil __DARWIN_NULL
# endif
#endif

I fixed it by renaming LuaTypeID::Nil to LuaTypeID::Null.

Lua MultiThreaded

I have idea.
Can you add threads to Lua?
1 file - 1 thread or something other with multithread support..

This is only proposal. ;)

Cannot bind to enum methods.

I have a class

enum HorizontalAlignment
    {
        HorizontalAlignment_Left,
        HorizontalAlignment_Center,
        HorizontalAlignment_Right,
        HorizontalAlignment_Stretch
    };

HorizontalAlignment GetHorizontalAlignment() const { return _horizontalAlignment; }
void SetHorizontalAlignment(HorizontalAlignment value) { _horizontalAlignment = value; }

When I do

.addProperty("horizontalAlignment",
            &UIElement::GetHorizontalAlignment,
            &UIElement::SetHorizontalAlignment)

Does not work.

Problem with construction of LuaRef object from LuaTableRef

Lua compiled with LUA_USE_APICHECK.
Code belows:

LuaIntf::LuaState state = LuaIntf::LuaState::newState();

state.doString("AA = {1,2,3, sub= function () return 0 end}"));

LuaIntf::LuaRef tableAA(script::g_engine->state,"AA");

while (true)
{
    LuaIntf::LuaRef sub = tableAA["sub"]; // Crashes in just serveral loop iterations
    //LuaIntf::LuaRef sub = tableAA.get<LuaIntf::LuaRef>("sub"); // Works well
}

causes overflow of lua stack.

Visual Studio "14" support

I know the "C++11" means that this project do not support Visual Studio.
But Visual Studio "14" (current CTP4) is much better now.
It's only need a little change to work with VS14 .
Will you accept It?^_^
I'll post the linux/gcc,mac/clang compatibility of this chane later. :)

patch:
CppArg.h
-typedef typename Traits::Type Type;
-typedef typename Traits::ValueType ValueType;
-typedef typename Traits::HolderType HolderType;
+typedef Traits::Type Type;
+typedef Traits::ValueType ValueType;
+typedef Traits::HolderType HolderType;

Add possibility for function wrapping

Hi,
I would like to bind to instance function with wrapper method:

void MyWrapper_Method(ClassInstance* instance, int test)
{
}

.addWrapperFunction("test", &MyWrapper_Method)

I have done this into CppBindClass.h

template <typename FN>
    CppBindClass<T>& addWrapperFunction(const char* name, const FN& proc)
    {
        static_assert(!std::is_function<FN>::value,
            "function pointer is needed, please prepend & to function name");
        using CppProc = CppBindMethod<FN>;
        setMemberFunction(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc)), true);
        return *this;
    }

Thanks

Visual Studio 2013 Support?

Hi Steve,

Was just wondering if there was at some point a VS2013 compatible version of this library? The current version makes use of VS2014+ features and it breaks my build.

Thanks

-Matt

const variables?

Hey Steve,

Any plans to support const variables? For example, I would like to export const globals with addVariable if possible, but I'm also happy writing a addProperty + lambda. However, I'm less clear how I would expose a const field on a class, since I haven't checked if you have access to the instance in the lambda.

Thanks again,
Kris

How to add my own C++ function to an existing table

I'm using the "os" Lua table, it has functions like "getenv". I want to add a "setenv" function to it but I'm having trouble getting the syntax correct.

I tried
LuaBinding(lua_context.state()).beginModule("os")
.addFunction("setenv", &lua_setenv)
.endModule();
which results in error: bad argument #-1 (table expected, got nil)

I poked around in LuaRef.h, guessing that there would be something there along the lines of the example

LuaRef(L, "os").addFunction("setenv", &lua_setenv);

but I didn't see anything like that- there were some createFunction methods, but those didn't seem to be the right thing.

I did try just qualifying the function name, like

LuaIntf::LuaBinding(lua_context.state()).addFunction("os.setenv", &lua_setenv);

but that results in

[string "..."]:7: attempt to call field 'setenv' (a nil value)

when I try to use it in a lua script

Any assistance would be appreciated.

Thanks for a really cool framework!

Problem with pass by value on reference arguments

It appears that lua-intf attempts to copy reference argument types which results in compilation errors when passing types that do not have copy constructors, and inefficiencies otherwise:

template <typename Traits, bool IsDefault>
struct CppArgTraitsInput <Traits, true, false, IsDefault>
{
    static int get(lua_State* L, int index, typename Traits::ValueType& r)
    {
        r = LuaType<typename Traits::Type>::get(L, index);
        return 1;
    }
};

I'm going to dig into this further and see how difficult it would be to handle reference types without copying them. Let me know if you have any suggestions!

LUA_ARGS() now causing wrong return type?

UPDATE:
Actually, this may have just been a compiler bug (apple llvm). I cannot reproduce it after moving back to the original code. It could just be that the compiler had cached a bad version and was not rebuilding it properly. It's not the first time I've seen xcode do that. I'll let you know if I see it again.

Hey Steve,

After upgrading to the latest version, I'm having a couple issues. The most serious of which is that one of my functions is returning the wrong value when I explicitly state the parameters via LUA_ARGS() macro.

For example, when exposing this function:

Pass& Material::createPass(const ShaderProgramHandle& shader_program)

This correctly returns a Lua object with __type=class<wv::Pass>

.addFunction(
  "createPass", &wv::Material::createPass)

But, this incorrectly returns a Lua object with __type=class<wv::ShaderProgram>

.addFunction(
  "createPass", &wv::Material::createPass, LUA_ARGS(const ShaderProgramHandle& shader))

Even stranger, wv::ShaderProgram is the type contained in the "Smart Pointer" that is wv::ShaderProgramHandle.

I can work around this by not using LUA_ARGS in functions where they are unnecessary, but I still need to add them in other places like the constructors. Perhaps the argument is being misinterpreted as a output argument due to some of your recent changes?

The other issue I am having may be related. After your updates to my introduction of PasserType (which is now named HolderType), I can no longer pass non-const reference types around due to a type error. I had to work around this by modifying HolderType such that value is always const qualified and the actual held value is mutable. I was hoping to find a better way but didn't have time yet.

Kris

Compile error on .addConstructor(LUA_ARGS(_opt<std::string>))

Hey,

I am getting the below compile error.
What could be the cause of it?
I did add the lib as headers only, but also tried compiling as cpp.

Ries

In file included from ./lua-intf/LuaIntf.h:27:
In file included from ./lua-intf/LuaIntf/LuaIntf.h:32:
In file included from ./lua-intf/LuaIntf/LuaContext.h:32:
./lua-intf/LuaIntf/LuaRef.h:1098:36: warning: unused parameter 'L' [-Wunused-parameter]
    static void pushArg(lua_State* L)
                                   ^
In file included from cad/lualibrecadbridge.cpp:6:
In file included from ./lua-intf/LuaIntf.h:27:
In file included from ./lua-intf/LuaIntf/LuaIntf.h:40:

..
..
./lua-intf/LuaIntf/impl/CppInvoke.h:236:32: warning: unused parameter 'L' [-Wunused-parameter]
    static int push(lua_State* L, T* t, const FN& func, std::tuple& args)
                               ^
cad/lualibrecadbridge.cpp:26:25: error: type name requires a specifier or qualifier
        .addConstructor(LUA_ARGS(_opt))
                        ^
./lua-intf/LuaIntf/impl/CppArg.h:49:35: note: expanded from macro 'LUA_ARGS'
#define LUA_ARGS(...) static_cast(nullptr)
                                  ^
./lua-intf/LuaIntf/impl/CppArg.h:48:28: note: expanded from macro 'LUA_ARGS_TYPE'
#define LUA_ARGS_TYPE(...) _arg(*)(__VA_ARGS__)
                           ^
cad/lualibrecadbridge.cpp:26:25: error: expected '>'
./lua-intf/LuaIntf/impl/CppArg.h:49:35: note: expanded from macro 'LUA_ARGS'
#define LUA_ARGS(...) static_cast(nullptr)
                                  ^
./lua-intf/LuaIntf/impl/CppArg.h:48:28: note: expanded from macro 'LUA_ARGS_TYPE'
#define LUA_ARGS_TYPE(...) _arg(*)(__VA_ARGS__)
                           ^
cad/lualibrecadbridge.cpp:26:25: note: to match this '<'
./lua-intf/LuaIntf/impl/CppArg.h:49:34: note: expanded from macro 'LUA_ARGS'
#define LUA_ARGS(...) static_cast(nullptr)
                                 ^
7 warnings and 2 errors generated.
make: *** [generated/obj/lualibrecadbridge.o] Error 1

Binding class with default constructor ?

Hello Steve, I was testing today your library. I like it, but what I don't understand is, is it possible to bind C++ classes with empty default constructors ?

I tried doing this:

    LuaIntf::LuaBinding(L).beginClass<Block>("Block")
        .addConstructor(LUA_ARGS(void))
        .addConstructor(LUA_ARGS(std::string))
        .addFunction("printName", &Block::printName)
    .endClass();

Where I have this very simple class definition for testing:

class Block {
    public:
        Block() { 
            printf("DEFAULT CONSTRUCTOR!\n");
            _name = "Jantteri";
        };

        Block(std::string name) : _name(name) {};

        ~Block() = default;

        void printName() {
            printf("BLOCK HERE, My name is %s\n", _name.c_str());
            printf("Check it yo! Before you wreck it yo!\n");
        }

    private:
        std::string _name;
};

And I call this in the Lua side:

function callBlokk()
    print("CALLBLOKK");
    b = Block("PETTERI");
    b:printName();

    c = Block();
    c:printName();
end

When the object 'c' gets constructed, the default constructor is not called for some reason. Does it set the parameter to "" ? How should I define or bind this ? Can't see any empty constructors in the documentation. It doesn't even create the 'c' object. 'b' works perfectly fine.

Also, what about using default values in the constructor ? Doesn't seem to work. Like this:

Block(std::string name = "BLOCK") : _name(name) {};

This just gives this template error:

clang++ -Os -Wall -stdlib=libc++ -std=c++11 -I/usr/local/include  -I/opt/local/include   -c -o testgame.o testgame.cpp
In file included from testgame.cpp:11:
In file included from ./LuaIntf/LuaIntf.h:40:
./LuaIntf/impl/CppInvoke.h:172:28: error: call to constructor of 'Block' is ambiguous
        return ::new (mem) T(std::get<INDEX>(args).value()...);
                           ^
./LuaIntf/impl/CppInvoke.h:186:80: note: in instantiation of member function
      'LuaIntf::CppDispatchClassConstructor<Block, std::__1::tuple<>, 0>::call' requested here
        return CppDispatchClassConstructor<T, std::tuple<P...>, sizeof...(P)>::call(mem, args);
                                                                               ^
./LuaIntf/impl/CppObject.h:181:45: note: in instantiation of member function
      'LuaIntf::CppInvokeClassConstructor<Block>::call' requested here
        CppInvokeClassConstructor<T, P...>::call(v->objectPtr(), args);
                                            ^
./LuaIntf/impl/CppBindClass.h:41:32: note: in instantiation of function template specialization
      'LuaIntf::CppObjectValue<Block>::pushToStack<>' requested here
            CppObjectValue<T>::pushToStack(L, args, false);
                               ^
./LuaIntf/impl/CppBindClass.h:647:71: note: in instantiation of member function 'LuaIntf::CppBindClassConstructor<Block,
      Block, LuaIntf::_arg (*)()>::call' requested here
        m_meta.rawset("__call", &CppBindClassConstructor<T, T, ARGS>::call);
                                                                      ^
testgame.cpp:256:4: note: in instantiation of function template specialization 'LuaIntf::CppBindClass<Block,
      LuaIntf::CppBindModule>::addConstructor<LuaIntf::_arg (*)()>' requested here
                .addConstructor(LUA_ARGS(void))
                 ^
testgame.cpp:133:3: note: candidate constructor
                Block(std::string name = "BLOCK") : _name(name) {};
                ^
testgame.cpp:134:3: note: candidate constructor
                Block() { 
                ^
1 error generated.

Can you help me ? Bit of a Lua newbie here! Thank you!

better support for nil

1.When need to know whether a LuaRef instance is have meaningful data,we should use
if(inst.isValid() && inst.type() != LuaTypeID::NIL) xxx(inst);
maybe
if(inst) xxx(inst);
is more useful.

code change:
class LuaRef
{
...
operator bool() const {
return isValid() && type() != LuaTypeID::NIL;
}
...
}

2.When pass a LuaRef instance using default constructor as param,the function call will crash.
LuaRef fun(L,"test");
LuaRef a;
fun(a); //crash because there's no lua_State* in a

template <>
struct LuaValueType {
...
static void push(lua_State* L, const LuaRef& r)
{
if (r) //!!need operator bool()
r.pushToStack();
else
Lua::push(L, nullptr);
}
...
}

This will also fix the return of default constructor.
LuaIntf::LuaRef TTT() {
return LuaIntf::LuaRef();
}
Export this function to lua,and call it in lua will cause crash.

A constructor to create a nil will also helps.sothing like
LuaRef inst(L); //this return a nil

But considered using LuaRef as a member of Class
class A{
public:
LuaRef a;
}
but we do not want to pass luaState* in A's constructor(or the luaState* are not available until some function called),we just want "a" to keep nil.
The solution as the code above is better.

The usage is from my project use luabind before. luabind::object() means nil,do not need lua_State*.
If there's something already considered in LuaInf and already have a normal way to achieve my goal,please let me know,thanks.

Lua 5.2 linking problem

CMakeFiles/TiC.dir/src/main.cpp.o: In function `LuaState::newState()':
/home/theaifam5/Documents/CLion Projects/TiC/src/ScriptEngine/Lua/LuaState.h: undefined reference to `luaL_newstate()'
CMakeFiles/TiC.dir/src/main.cpp.o: In function `LuaState::version() const':
/home/theaifam5/Documents/CLion Projects/TiC/src/ScriptEngine/Lua/LuaState.h: undefined reference to `lua_version(lua_State*)'
CMakeFiles/TiC.dir/src/main.cpp.o: In function `LuaState::openLibs() const':
/home/theaifam5/Documents/CLion Projects/TiC/src/ScriptEngine/Lua/LuaState.h: undefined reference to `luaL_openlibs(lua_State*)'

if i use a extern, work normally.

I have arch linux and Lua 5.2.

problem with precompiled Lua from repository?

Fails to include the stl memory header

Compiling with GCC 4.9.1, I get loads of errors because CppBindClass.h needs the memory header, but if it is directly included in the offending file it seems to be setting the included objects/methods in the LuaIntf namespace.

(It works if the memory header is included in the LuaIntf.h file, but that's a bit ugly.)

Access derived class' methods from a base class object

Sample classes:

class Base {};

class Derived : public Base {
public:
   void foo();
};

// Their binding code

LuaIntf::LuaBinding(L).beginClass<Base>("Base")
.endClass();

LuaIntf::LuaBinding(L).beginExtendClass<Derived, Base>("Derived")
    .addFunction("foo", &Derived::foo)
.endClass();

Let's say I have an object of class Derived, but the pointer that keeps track of it is of type Base:

Derived *a = new Derived();
// ...
Base *b = a;

I notice that if I push b to lua, I will not be able to call foo inside the script:

Lua::setGlobal(L, "b", b);
b:foo() -- This fails

Is it possible to get it to work? (I think it's duck typing)
Thank you very much. :)

Should this work?

LuaIntf::LuaContext lua_context;
lua_context.doString("my_variable=25");
LuaIntf::LuaRef globals(lua_context.state(), "_G");
for(auto& e : globals) {
std::string key = e.keystd::string();
}

I get a core dump on the for() line. It dumps in LuaTableIterator::next()

I"m using Lua 5.2.3 on Windows 7 and a slightly older (six months?) version of lua-intf that I hacked a little to work with VS2013. It's entirely possible that I broke lua-intf, but I have been using it successfully.

Thanks

returning shared_ptr<const ...> ?

hey Steve,

first of all I would like to say that lua-intf compiles fine without modification, I must have been doing something dumb, this was something I reported 2 weeks ago.

Getting more familiar with it, I was wondering about this issue:

I can do this:

    shared_ptr<lc::Layer> getLayer() const {
        return shared_ptr<lc::Layer>();
    }

but I cannot do this:

    shared_ptr<const lc::Layer> getLayer() const {
        return shared_ptr<lc::Layer>();
    }

I work with a lot of immutable so I would like to have these const correct.
Again, i wish I could propose a patch, but my knowledge on template classes in c++ is rather limited.

type "signed char" is not related to lua_Integer

When export function with the type "signed char",it'll trigger static_assert(std::is_class::value,
"type is not class, need template specialization");
example:void f(signed char i) {}

typeid(char).name() and typeid(signed char).name() are not the same.

patch:
luaType.h
LUA_USING_VALUE_TYPE(char)
+LUA_USING_VALUE_TYPE_EXT(signed char, lua_Integer)
LUA_USING_VALUE_TYPE_EXT(unsigned char, lua_Integer)

Can you add some usefull modules?

Hi,

  1. Function return all members of script (locals, globals and functions name, class names and class members and parameters) for AutoComplete system
  2. Add support for lint code (checking errors etc)

Allow custom destructor?

Hi,
Some code has ref pointer support therefore addRef and release method are used for reference tracing, in this case class destructor is private.

Cannot use _def for float or double type.

I have a bound function:

.addStaticFunction("createPerspective", 
                &Camera::CreatePerspective, 
                LUA_ARGS(_def<float, 3.14f>, _def<float, 1.33333333333333f>, _def<float, 0.2f>, _def<float, 100000.0f>))
            .endClass().

What I get is:

Error   1   error C2993: 'float' : illegal type for non-type template parameter 'DEF'.

override operator new cause error when export Constructor

If a class override the operator new(this is normal when using some kind of memory pool),when export the Constructor, it'll triggeran error:
'operator new' : function does not take 2 arguments

To be sure to use the global allocation function,the placement new should explicit use ::new.

patch:
CppInvoke.h
static T* call(void* mem, TUPLE& args)
{
-return new (mem) T(std::get(args).value()...);
+return ::new (mem) T(std::get(args).value()...);
}

Problems with std::shared_ptr

Hi, when I try to compile even this simple code:

namespace LuaIntf
{
    LUA_USING_SHARED_PTR_TYPE(std::shared_ptr)
}

class A {
};

std::shared_ptr<A> returnA() {
    return std::shared_ptr<A>(new A);
}
std::shared_ptr<const A> returnConstA() {
    return std::shared_ptr<const A>(new A);
}

void do_the_bind(lua_State* L) {

     LuaBinding(L).beginClass<A>("A")
        .endClass();
        LuaBinding(L).beginModule("utils")
            .addFunction("returnA", &returnA)
            .addFunction("returnConstA", &returnConstA)
        .endModule();
}

The compiler give me this error:

../../Dependencies/Include/lua-intf/impl/LuaType.h: In instantiation of 'struct LuaIntf::LuaTypeMappingExistsstd::shared_ptr':
../../Dependencies/Include/lua-intf/impl/LuaType.h:68:16: required from 'struct LuaIntf::LuaTypestd::shared_ptr'
../../Dependencies/Include/lua-intf/impl/CppInvoke.h:80:45: required from 'static int LuaIntf::CppInvokeMethod<FN, R, P>::push(lua_State_, const FN&, std::tuple<Args2 ...>&) [with FN = std::shared_ptr ()(); R = std::shared_ptr; P = {}; lua_State = lua_State]'
../../Dependencies/Include/lua-intf/impl/CppBindModule.h:124:96: required from 'static int LuaIntf::CppBindMethodBase<CHK, FN, IARG, R, P>::call(lua_State_) [with int CHK = 0; FN = std::shared_ptr ()(); int IARG = 1; R = std::shared_ptr; P = {}; lua_State = lua_State]'
../../Dependencies/Include/lua-intf/impl/CppBindModule.h:447:61: required from 'LuaIntf::CppBindModule& LuaIntf::CppBindModule::addFunction(const char
, const FN&) [with FN = std::shared_ptr (_)()]'
..\Source\Core../Lua/aeLuaIO.hpp:62:42: required from here
../../Dependencies/Include/lua-intf/impl/LuaType.h:62:63: error: invalid use of incomplete type 'struct LuaIntf::LuaTypeMappingstd::shared_ptr<A, void>'
: decltype(LuaTypeExists(std::declval<LuaTypeMapping>())) {};
^
../../Dependencies/Include/lua-intf/impl/LuaType.h:42:8: error: declaration of 'struct LuaIntf::LuaTypeMappingstd::shared_ptr<A, void>'
struct LuaTypeMapping;
^

../../Dependencies/Include/lua-intf/impl/LuaType.h: In instantiation of 'struct LuaIntf::LuaTypeMappingExists<std::shared_ptr >':
../../Dependencies/Include/lua-intf/impl/LuaType.h:68:16: required from 'struct LuaIntf::LuaType<std::shared_ptr >'
../../Dependencies/Include/lua-intf/impl/CppInvoke.h:80:45: required from 'static int LuaIntf::CppInvokeMethod<FN, R, P>::push(lua_State_, const FN&, std::tuple<Args2 ...>&) [with FN = std::shared_ptr ()(); R = std::shared_ptr; P = {}; lua_State = lua_State]'
../../Dependencies/Include/lua-intf/impl/CppBindModule.h:124:96: required from 'static int LuaIntf::CppBindMethodBase<CHK, FN, IARG, R, P>::call(lua_State_) [with int CHK = 0; FN = std::shared_ptr ()(); int IARG = 1; R = std::shared_ptr; P = {}; lua_State = lua_State]'
../../Dependencies/Include/lua-intf/impl/CppBindModule.h:447:61: required from 'LuaIntf::CppBindModule& LuaIntf::CppBindModule::addFunction(const char
, const FN&) [with FN = std::shared_ptr (_)()]'
..\Source\Core../Lua/aeLuaIO.hpp:63:52: required from here
../../Dependencies/Include/lua-intf/impl/LuaType.h:62:63: error: invalid use of incomplete type 'struct LuaIntf::LuaTypeMapping<std::shared_ptr, void>'
: decltype(LuaTypeExists(std::declval<LuaTypeMapping>())) {};
^
../../Dependencies/Include/lua-intf/impl/LuaType.h:42:8: error: declaration of 'struct LuaIntf::LuaTypeMapping<std::shared_ptr, void>'
struct LuaTypeMapping;

I'm using TDM-GCC 4.9.2 64 bit under Windows 7.

Thank you for help and for the amazing work you are doing!

Cannot call function with pointer types using LuaRef

I have my script:

MyComponent = class()

function MyComponent:initialize(gameObject)
    self.parent = gameObject
end

Then from code

LuaRef typeTable(_lua, "MyComponent");
            if (!typeTable.isTable())
            {
                ALIMER_ERROR("Could not find lua table %s", "MyComponent");
            }

            auto factory = Lua::eval<LuaRef>(_lua, "MyComponent");
                        SceneNode* parent = GetParent();
            LuaRef instance = factory.call<LuaRef>(parent ); // This cannot be done

This can be done in luabridge.

operators and overloaded functions support?

Hey Steve,

This library is coming along really nicely. I especially like the clean use of C++ 11 features. I was curious if you have any plans to support operators and/or function overloads?

Kris

Question: Passing "lightuserdata" from c++ to lua

Hi

and thanks for a great library!

What is the easiest way to pass a pointer to an object from c++ to lua? The low level method seems to be by using lua_pushlightuserdata() but I'm guessing lua-intf has a nicer solution? Could you give a practical example?

Thanks,

Mikko

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.