lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I am implementing a library in iOS to provided Lua (5.2) bindings for game programming.  I have managed to successfully create several datatypes (if that is the correct word) using userdata, metatables, and uservalues.  A typical constructor function is given below:




///////////// lines ///////////////////////////
static int newLine(lua_State *L){
    NSLog(@"Creating new line...");
    lineSetup(L);
    NSLog(@"New line created.");

    

    return 1;
}


lineSetup() is a C function created by factoring out common setup code:

void lineSetup(lua_State *L){
    GeminiLine *line = [[GeminiLine allocinitWithLuaState:L];
    GeminiLine **lLine = (GeminiLine **)lua_newuserdata(L, sizeof(GeminiLine *)); 
    *lLine = line;
    
    luaL_getmetatable(L, GEMINI_LINE_LUA_KEY);
    lua_setmetatable(L, -2);
    
    lua_pushvalue(L, -1);
    line.selfRef = luaL_ref(L, LUA_REGISTRYINDEX);
    
    // append a lua table to this user data to allow the user to store values in it
    lua_newtable(L);
    lua_pushvalue(L, -1); // make a copy of the table becaue the next line pops the top value
    // store a reference to this table so we can access it later
    line.propertyTableRef = luaL_ref(L, LUA_REGISTRYINDEX);
    // set the table as the user value for the Lua object
    lua_setuservalue(L, -2);

}

Here GeminiLine is one of the Objective C types in my library.  initWithLuaState: is an initializer that simply stores the pointer to the lua_State to be used later.  It does not alter the state.  GeminiLine objects store a reference to their user data obtained with the call to luaL_ref().

In addition to assigning a metatable to the new object I am attaching a Lua table as a uservalue to allow users to store attribute information for the object.  A reference to this table is also stored with the GeminiLine object.  The metatable is created when the library is opened and bound in the registry to a constant string key, GEMINI_LINE_LUA_KEY, defined in the header.  The function to open the library is given here:

int luaopen_display_lib (lua_State *L){
    // create meta tables for our various types /////////

    

    // lines
    luaL_newmetatable(L, GEMINI_LINE_LUA_KEY);
    lua_pushvalue(L, -1);
    luaL_setfuncs(L, line_m, 0);

    

    

    /////// finished with metatables ///////////

    

    // create the table for this library and popuplate it with pointers to our functions
    luaL_newlib(L, displayLib_f);

    

    return 1;
}

The call to luaL_newmetatable() is where the metatable is created and associated in the registry with my key, GEMINI_LINE_LUA_KEY.  Note:  this is a call to luaL_newmetatable, NOT a call to lua_newmetatable.  The pointers to the object methods and metamethods and their string keys are given in the array line_m, not shown here.  Similarly, the pointers to the functions for the library (the factory methods) and their keys are stored in the array displayLib_f, also not shown here.

For the most part this works great.  I am able to create new objects in Lua scripts and access there methods/attributes, e.g.,

1    display = require('display')
2
3    line = display.newLine()
4    line.width = 3

etc. (line numbers shown)

When I try to create one of these objects directly in Objective C and bind it to a global variable, however, I run into problems. The following (admittedly contrived) example should work, but does not.

Creating an object in Objective C code after initializing Lua but before loading my script like this

-(void)createGlobal {
    lineSetup(L);

    

    // create an entry in the global table
    lua_setglobal(L, "Runtime");
    // clear the stack
    lua_pop(L, lua_gettop(L));
}

should create a global called "Runtime", if I understand lua_setglobal() correctly.  But running the following script afterwards

1    display = require('display')
2
3    line = display.newLine()
4    line.width = 3
5
6    x = Runtime
7    x.width = 4

generates the following error:

test.lua:7: attempt to index global 'x' (a userdata value)

My question is, why does line 4 work correctly, while line 7 complains about the global being userdata?  What is the difference between the = assignment on line 3 and the lua_setglobal in my Objective C code?

Thanks in advance for any suggestions.

-James