Calling a Lua function from C is fairly straight forward but is there a way to store a Lua function somewhere for later use? I want to store user defined Lua functions passed to my C function for use on events, similar to how the Connect function works in wxLua.
check the registry (luaL_ref()). it manages a simple table that lets you store any Lua value (like the function), and refer to it from C by a simple integer.
Building on Javier's answer, Lua has a special universally-accessible table called the registry, accessible through the C API using the pseudo-index LUA_REGISTRYINDEX. You can use the luaL_ref function to store any Lua value you like in the registry (including Lua functions) and receive back an integer that can be used to refer to it from C:
// Assumes that the function you want to store is on the top of stack L
int function_index = luaL_ref(L, LUA_REGISTRYINDEX);
The easiest way to do this is for your function to take a "name" and the lua function text. Then you create a table in the interpreter (if it doesn't exist) and then store the function in the table using the named parameter.
In your app just keep hold of a list of function names tied to each event. When the event fires just call all the functions from your table whose key matches the names in the list.
Related
From an in-app server, I receive a table and inside this table there's a key marked as userdata. I red this type is there to allow arbitrary C data to be stored inside Lua variables. Is it possible to read/access its content from Lua?
Lua can't read data from userdata, unless you write native functions that will read and return bytes from userdata in some way you will find convenient - as array of numbers, as string, or maybe just returning single byte at specified index.Maybe your host app/framework already has these functions, but Lua itself definitely can't do that.
Corona SDK's page for userdata only quotes Lua's doc, telling basically the same - there's no operations on userdata in Lua, except assignment and identity test.
C functions that are passed to Lua to so that Lua can call native functions are static functions and thus not related to an object instance.
In my application, I have multiple sessions. Each session runs on its own thread, has its own data and its own scripts, and a script of the session N must be able to access the data of that session N.
The problem is that when you register a native C function to be callable from Lua, I can't pass the instance of the session object to make it available in the static Lua function.
One possibility could to be store the instance of the session into a static variable that can be called from the static C function (called from Lua), but this looks dirty and would require synchronization that could cause some scripts to hang.
A second possibility might be to create an Lua object that represents the session and call member methods on it so that, in my C function, I would have a way to access the Lua object representing the session ("this") and retreive the actual native session instance represented by this object. But I have no idea how to do that.
Is there a way to create Lua objects representing native object instances in Lua so that native Lua functions would have access to that native object instance ?
When you register a C function with Lua, you can store additional values as so-called "upvalues". The C function can then retrieve those values when it's called:
// ...
// push session instance pointer
lua_pushlightuserdata( L, (void*)get_current_session() );
// create a closure with one upvalue
lua_pushcclosure( L, my_static_C_function, 1 );
// ... (the resulting Lua function is at the stack top now)
In your static C function you access the instance data like this:
static int my_static_C_function( lua_State* L ) {
session_t* instance = (session_t*)lua_touserdata( L, lua_upvalueindex( 1 ) );
instance->do_something();
return 0;
}
Since each session has its own thread, why don't you link them together?
Whenever your function is called, get the session from the current thread.
You might want to take a look at the manuals about userdata.
Since "Each session runs on its own thread" you could simply save session data as static thread-local.
Better would be to transport session data by userdata, with a metatable bound for associated functions, and don't rely on static stuff.
As last alternative, let's combine: save session data as userdata/pointer Lua-state-local.
In all cases you have to care about class instances destruction because userdata are freed in C-style, same as thread data.
I have several global integer variables, like A0, A1, A2 in Lua script. They are declared on C side. Each of them contains unique numeric value.
In a script user manipulates device pins using this aliases:
set_pin_bool(A0, 1)
And this calls corresponding C function. I think it is too C-like and not very handy. The better is to call methods like A0.hi(), A0.low(), A0.set(1) etc.
So I tried to declare A0 and others as tables in C(this is just a struct):
lua_newtable(this->luactx);
lua_pushstring(this->luactx, "val");
lua_pushinteger(this->luactx, value);
lua_rawset(this->luactx, -3);
lua_setglobal ( this->luactx, "A0" );
I can create a filed like hi and using lua_pushcfunction register it. But when I call A0.hi(), on C side I won't be able to access a table it was called from to get another fields. And as I googled there is no way to get something like self from C. Is there any way to accomplish it? I don't want to pass table itself as argument, like A0.hi(A0)
There may be a lot of aliases and they can be named differently.
Or may be there are different approaches to the same goal?
Call your hi function like this:
A0:hi()
This is equivalent to:
A0.hi(A0)
I am working on a project written in C++ which uses Lua as a scripting language.
In order to facilitate debugging we implemented a network debugger which receives Lua code, runs it, encodes the return values in Json and sends that string back.
I managed to implement that for tables, but now I am stuck with variables stored in userdata.
E.g. I have this Lua code:
Elements.Avatar.testVar = 5
Elements.testVar = 15
return Elements
// result
{
"result0": "{Application:userdata; Avatar:userdata; Physics:userdata; testVar:15; }"
}
Application, Avatar and Physics are objects that have been created in C++. The two testVars however have been created in the script above.
Elements is a table, so I can list all elements, but Avatar.testVar seems to be hidden because Avatar is a LUA_TUSERDATA.
Does anyone have an idea how I can detect variables that have been added to userdata in Lua?
There is no such thing as a "variable stored in userdata", At least, not as far as Lua is concerned. From Lua's perspective, userdata is a giant black box. All Avatar.testVar = 5 does is call the metamethod __newindex in Avatar with the string testVar and the new value 15. How your C++ metamethod (because only C++ code can put metamethods on userdata) interprets this is entirely up to your code.
So it can't be done from Lua. Your code will need to provide debugging hooks. Lua 5.2 allows you to implement the __pairs and __ipairs metamethods, which the pairs and ipairs functions can use to iterate over your values. Outside of that, you're on your own for querying what does and doesn't exist in a userdata.
This is a sort of followup to my previous question about nested registered C functions found here:
Trying to call a function in Lua with nested tables
The previous question gave me the answer to adding a nested function like this:
dog.beagle.fetch()
I also would like to have variables at that level like:
dog.beagle.name
dog.beagle.microchipID
I want this string and number to be allocated in C and accessible by Lua. So, in C code, the variables might be defined as:
int microchipIDNumber;
char dogname[500];
The C variables need to be updated by assignments in Lua and its value needs to be retrieved by Lua when it is on the right of the equal sign. I have tried the __index and __newindex metamethod concept but everything I try seems to break down when I have 2 dots in the Lua path to the variable. I know I am probably making it more complicated with the 2 dots, but it makes the organization much easier to read in the Lua code. I also need to get an event for the assignment because I need to spin up some hardware when the microchipIDNumber value changes. I assume I can do this through the __newindex while I am setting the value.
Any ideas on how you would code the metatables and methods to accomplish the nesting? Could it be because my previous function declarations are confusing Lua?
The colon operator (:) in Lua is used only for functions. Consider the following example:
meta = {}
meta["__index"] = function(n,m) print(n) print(m) return m end
object = {}
setmetatable(object,meta)
print(object.foo)
The index function will simply print the two arguments it is passed and return the second one (which we will also print, because just doing object.foo is a syntax error). The output is going to be table: 0x153e6d0 foo foo with new lines. So __index gets the object in which we're looking up the variable and it's name. Now, if we replace object.foo with object:foo we get this:
input:5: function arguments expected near ')'
This is the because : in object:foo is syntactic sugar for object.foo(object), so Lua expects that you will provide arguments for a function call. If we did provide arguments (object:foo("bar")) we get this:
table: 0x222b3b0
foo
input:5: attempt to call method 'foo' (a string value)
So our __index function still gets called, but it is not passed the argument - Lua simply attemps to call the return value. So don't use : for members.
With that out of the way, let's look at how you can sync variables between Lua and C. This is actually quite involved and there are different ways to do it. One solution would be to use a combination of __index and __newindex. If you have a beagle structure in C, I'd recommend making these C functions and pushing them into the metatable of a Lua table as C-closures with a pointer to your C struct as an upvalue. Look at this for some info on lua_pushcclosure and this on closures in Lua in general.
If you don't have a single structure you can reference, it gets a lot more complicated, since you'll have to somehow store pairs variableName-variableLocation on the C side and know what type each is. You could maintain such a list in the actual Lua table, so dog.beagle would be a map of variable name to one or two something's. There a couple of options for this 'something'. First - one light user data (ie - a C pointer), but then you'll have the issue of figuring out what that is pointing to, so that you know what Lua type to push in for __index and what to pop out for __newindex . The other option is to push two functions/closures. You can make a C function for each type you'll have to handle (number, string, table, etc) and push the appropriate one for each variable, or make a uber-closure that takes a parameter what type it's being given and then just vary the up-values you push it with. In this case the __index and __newindex functions will simply lookup the appropriate function for a given variable name and call it, so it would be probably easiest to implement it in Lua.
In the case of two functions your dog.beagle might look something like this (not actual Lua syntax):
dog.beagle = {
__metatable = {
__index = function(table,key)
local getFunc = rawget(table,key).get
return getFunc(table,key)
end
__newindex = function(table,key,value)
local setFunc = rawget(table,key).set
setFunc(table,key,value)
end
}
"color" = {
"set" = *C function for setting color or closure with an upvalue to tell it's given a color*,
"get" = *C function for getting color or closure with an upvalue to tell it to return a color*
}
}
Notes about the above: 1.Don't set an object's __metatable field directly - it's used to hide the real metatable. Use setmetatable(object,metatable). 2. Notice the usage of rawget. We need it because otherwise trying to get a field of the object from within __index would be an infinite recursion. 3. You'll have to do a bit more error checking in the event rawget(table,key) returns nil, or if what it returns does not have get/set members.