Reputation: 111
%module test
class Foo{
public:
Foo();
}
I want to have something like this:
%extend Foo{
%native(Bar) int Bar(lua_State * L);
}
Upvotes: 1
Views: 509
Reputation: 705
In the .i file for your bindings, at the end include this code:
%wrapper %{
// This is code to add a new function to the object's metatable
void script_addNativeMethod(lua_State *L, const char *className, const char *methodName, lua_CFunction fn)
{
SWIG_Lua_get_class_registry(L); /* get the registry */
lua_pushstring(L, className); /* get the name */
lua_rawget(L,-2); /* get the metatable itself */
lua_remove(L,-2); /* tidy up (remove registry) */
// If the metatable is not null, add the method to the ".fn" table
if(lua_isnil(L, -1) != 1)
{
SWIG_Lua_get_table(L, ".fn");
SWIG_Lua_add_function(L, methodName, fn);
lua_pop(L, 2); /* tidy up (remove metatable and ".fn" table) */
}
else
{
printf("[script_addNativeMethod(..)] - \"%s\" metatable is not found. Method \"%s\" will not be added\n", className, methodName);
return;
}
}
%}
What this does is adds a new function to the wrapper CPP file called "script_addNativeMethod". You can call this function in the "init" binding code like so:
// Wrapper to add native Lua methods to existing C++ classes
%init %{
script_addNativeMethod(L, "MetatableName", "methodName", /*int function(lua_State *L)*/function);
%}
Above all this, in the binding file you need to have the actual native lua function that you want to use as a method of your userdata:
%{
int function(lua_State *L)
{
printf("Method called!\n");
return 0;
}
%}
I practically just figured this out, and I wanted to post it here because this page ranks high in google and this is a pretty decent solution to get the job done. This needs to be done in every wrapper binding (*.i) file that you write with SWIG.
Good luck!
Upvotes: 1
Reputation: 29543
Lua does not have any true concept of method, just of tables of functions with some syntactic sugar so you can write Lua code that looks quite OO'ish:
foo = test.Foo() # will call the C++ Foo constructor and return a wrapped (Lua) Foo
myInt = foo:Bar()
When you write
myInt = foo:Bar()
Lua is actually executing
myInt = foo.Bar(foo)
which will cause Lua to look in the foo metatable for a function called Bar and will give it the foo instance as first parameter. Therefore what you would have to do is more along the lines of the following pseudocode (not tested, there are likely syntax errors, wrong order of parameters etc but hopefully you get the idea):
%native(Bar) int Bar(lua_State * L);
%{
int Bar(lua_State*L) {
// there should be one arg on the stack: the Foo instance
Foo* foo = (Foo*)<get void* from L stack>
int answer = foo.Bar();
// push answer onto L stack
lua_pushnumber(L, answer);
return 1;
}
%}
%luacode {
test.Foo.Bar = test.Bar
}
...
%}
The %luacode makes Bar available as part of Foo "class", although I'm a little rusty in that area, you might have to add Bar the the Foo metatable instead, or do it from C (see section 5.6 of the SWIG user guide for sections of .i file where you could try to do this).
Curious to know if that works.
Upvotes: 0