tags:

views:

453

answers:

3

Hello there. I have a C++ project, where 1 method of a 1 class changes very often. So I want to take that code from C++ to Lua. Note, I'm novice to Lua.

The whole task:

  1. Bind some class methods to Lua state machine;
  2. Pass reference to class object to a function, written in Lua;
  3. Operate with passed C++ object in Lua function.

I've found how to make first step with Lunar, and can't cope with second and third.

I can't use SWIG and boost.

+1  A: 

Have you taken a look at luabind? It makes it fairly easy to expose C++ objects and functions to LUA.

John Ledbetter
Yes, I have. As mentioned on http://www.rasterbar.com/products/luabind/docs.html it uses boost
A: 

Like John, I've used luabind and recommend it. However, since using boost isn't an option for you, you may find the list of libraries on this page helpful. You may also want to check out the DoItYourselfCppBinding page on the lua-users wiki.

On library mentioned on the page is oolua, which has no dependencies (so it says).

Zack Mulgrew
I just can't believe, that I need some library for such an easy operation.
Keep in mind that you can always use the Lua C API and do the binding yourself. The libraries are there to make it "easier" to bind C++ classes to Lua.
Zack Mulgrew
Zack the statement is correct, OOLua only requires on Lua.
+2  A: 
//This has a large number of steps, but I'm gonna post them all. This is all using native Lua 5 and the lua CAPI.
int CreateInstanceOfT(lua_State* L) {
    new (lua_newuserdata(L, sizeof(T));) T(constructor args);
    return 1;
}
int CallSomeFuncOnT(lua_State* L) {
    if (lua_istable(L, 1)) { // If we're passed a table, get CData
        lua_getfield(L, 1, "CData");
        lua_replace(L, 1);
    }
    if (!lua_touserdata(L, 1))
        lua_error(L); // longjmp out.
    T& ref = *(T*)lua_touserdata(L, 1);
    ref.SomeFunc(); // If you want args, I'll assume that you can pass them yourself
    return 0;
}
int main() {
    lua_State* L = luaL_newstate();
    lua_pushcfunction(L, CreateInstanceOfT);
    lua_setglobal(L, "CreateInstanceOfT");
    lua_pushcfunction(L, CallSomeFuncOnT);
    lua_setglobal(L, "CallSomeFuncOnT");
    luaL_dofile(L, "something.lua");
    lua_close(L);
}
-- Accompanying Lua code: semicolons are optional but I do out of habit. In something.lua
function CreateCInstance()
    local Instance = {
        CData = CreateInstanceOfT();
        SomeFunc = CallSomeFuncOnT;
    }
    return Instance;
end

local object = CreateCInstance();
object:SomeFunc(); // Calls somefunc.

I could post a great quantity of detail about how to make exposure easier, and how to make inheritance, and suchlike - and it'll need altering if you want to expose more than one T (I think the most common solution is a simple struct { std::auto_ptr<void>, int type } deal). But, it should be a starting point if you don't understand anything about this process.

Bascally, first, we ask Lua to allocate some space (the userdata), then put T in it. When CallSomeFuncOnT comes up, first we ask it if we have a table (many Lua classes are based around tables, as they support object orientation, metatables, and such), and get the userdata out, which we then convert into a pointer to our object, and then convert into a reference. Remember that lua_touserdata gives you a void*, so you'd better be damn sure about what's on the other end. Then we call somefunc and return. In Main, we just register the functions as globals.

Now, in Lua, when you call CreateInstanceOfT, it effectively just calls the T constructor, transparently to the Lua user. Then we ditch it in a table, which is simpler for Lua novices, and call SomeFunc by passing it this table.

DeadMG