1

How do I access a variable from one class in Lua Script. Below is an example:

// C++
struct HObject{
    float x, y, z;
    float sx, sy, sz;

    void funcTest(void);
}

// Binding OBject
static bool checkFunctionArgs(lua_State* ls, const char* fname, unsigned int nargs)
{
   // etc
}

HObject* HObject_check(lua_State* ls, int index)
{
    // etc
}

static int HObject_newHObject(lua_State* ls)
{
   // etc
}

static int HObject_destructor(lua_State* ls)
{
   // etc
}

void HTest_register(lua_State* ls)
{
   // etc
}

-- Lua script
local obj = HObject:new() -- Create instance
obj:funcTest() -- OK
obj.x = 10 -- How to bind?
io.write(obj.x) -- How to bind?

I already linked the functions of the class, missing variables.

Sorry for english...

3
  • What have you tried? A good trick for this sort of problem is to use a binding generator (like SWIG, from swig.org) and see what code it generates for whatever you are trying to do. Or just save yourself a lot of trouble and using a binding library (SWIG, luabind, etc) directly :) Commented Mar 29, 2014 at 20:52
  • @Schollii I need libraries that offer speed. Luabind and others have a slightly lower performance. I'm currently using Luajit. I've tested it with Luabind is easier. However speed is not the same. Commented Mar 30, 2014 at 0:24
  • That's for an optimized release build? With the same error checking? What is the difference in execution time? Commented Mar 30, 2014 at 2:06

2 Answers 2

2

What you want to do can be accomplished with the userdata mechanisms, described in the PIL, starting at http://www.lua.org/pil/28.html. Did you already know about this? You wrote "Okay" next to obj:FuncTest(), as if you got that part to work already.

I will give some nice examples from that page. They describe how one can create a C structure like

typedef struct NumArray {
  int size;
  double values[1];  /* variable part */
} NumArray;

Then by registering methods in a library

static const struct luaL_reg arraylib [] = {
  {"new", newarray},
  {"set", setarray},
  {"get", getarray},
  {"size", getsize},
  {NULL, NULL}
};

int luaopen_array (lua_State *L) {
  luaL_openlib(L, "array", arraylib, 0);
  return 1;
}

one can add data and methods to the userdatum, and access them from Lua. Below is using the array operator [], which requires a little bit more work, but they show how to do it.

a = array.new(1000)
a[10] = 3.4         -- setarray
print(a[10])        -- getarray   --> 3.4

Now I'm not positive, but I suppose that since the userdata is a C structure, it couldn't have functions, but only function pointers. Thus in the C you might have to pass in the appropriate members of 'a' to the function.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the answer. So I know how to bind functions. The problem is that I do not want to use the methods MyClass: MyClass and setMyVariable: getMyRariable. I want to use MyClass.myVariable or = 10 print (MyClass.myVariable).
I don't think this will support s = a.size: if you print(type(s)) it will say function, won't it?
Yes you are right, the code they show won't let you access it like s = a.size and get a number.
1

I found an example from our project that does what you want.

typedef int (*getSetFunction) (lua_State*);

typedef struct luaMyValReg {
  const char *name;
  getSetFunction getter;
  getSetFunction setter;
} luaMyValReg;

#define luaL_reg luaL_Reg

typedef struct luaMyTable {
luaL_reg    *functions;
luaL_reg    *methods;
luaMyValReg *values;
luaMyValReg *arrays;
luaL_reg    *array_methods;
} luaMyTable;

static const struct luaMyValReg lib_val[] = {
   { "key1", MyClass::l_getKey1, MyClass::l_setKey1},
 ...
    {NULL, NULL, NULL}
 }

These are set into a structure and passed to a function that will set up the userdata.

table.functions = (luaL_reg *) &lib_f;
table.methods = (luaL_reg *) &lib_m;
table.values = (luaMyValReg *) &lib_val;
MyClass::initTable(&table, REGNAME, REGID, ARRAY_REGID);

In that function, there is a bit that creates the metatable, and adds each of the fields in the lib_val array. LGlobalState is the lua_State* pointer.

// Register the functions for the Table
luaL_register(LGlobalState, regname, table->functions);

// Stk: Table
// Create the metatable
luaL_newmetatable(LGlobalState, regid);

// Stk: Table metatable
// Register its methods, leaves it on top of the stack
luaL_register(LGlobalState, NULL, table->methods);

// Stk: Table metatable
// Set the metatable
lua_setmetatable(LGlobalState,-2);

// Stk: Table
// Push metatable
lua_getmetatable(LGlobalState, -1);
// Stk: Table metatable

// Add fields to the metatable
int i = 0;
while (table->values[i].name != NULL)
{
    addMetaField(LGlobalState, table->values[i].name, i);
    i++;
}

// Stk: Table, metatable
lua_pop(LGlobalState, 2);
// Stk: empty

if (lua_gettop(LGlobalState) > 0)
    tngL_error(LGlobalState, "%s inconsistant stack size\n", regname);

Here is the function to add the values.

////////////////////////////////////////////////////////////////////////////////
int LUATask::addMetaField(lua_State *L, const char *pKey, int nIndex)
////////////////////////////////////////////////////////////////////////////////
//  Add a field to the metatable.  It must already be on the top
//  of the stack
{
// Stk: metatable
lua_pushstring(L, pKey);
lua_pushnumber(L, nIndex);
// Stk: metatable, string, number
// Use lua_rawset() instead of lua_settable() to avoid
// the __newindex call
lua_rawset(L, -3);
// Stk: metatable
return 1;
}

2 Comments

Thank you for answer. I can not resolve this error. error: invalid use of non-static member function 'int HObject::getId()'.
This is probably something to do with your class being static or not. I will check tomorrow. stackoverflow.com/questions/17391853/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.