I want users of my C++ application to be able to provide anonymous functions to perform small chunks of work.
Small fragments like this would be ideal.
function(arg) return arg*5 end
Now I'd like to be able to write something as simple as this for my C code,
// Push the function onto the lua stack
lua_xxx(L, "function(arg) return arg*5 end" )
// Store it away for later
int reg_index = luaL_ref(L, LUA_REGISTRY_INDEX);
However I dont think lua_loadstring will do "the right thing".
Am I left with what feels to me like a horrible hack?
void push_lua_function_from_string( lua_State * L, std::string code )
{
// Wrap our string so that we can get something useful for luaL_loadstring
std::string wrapped_code = "return "+code;
luaL_loadstring(L, wrapped_code.c_str());
lua_pcall( L, 0, 1, 0 );
}
push_lua_function_from_string(L, "function(arg) return arg*5 end" );
int reg_index = luaL_ref(L, LUA_REGISTRY_INDEX);
Is there a better solution?
If you need access to parameters, the way you have written is correct. lua_loadstring returns a function that represents the chunk/code you are compiling. If you want to actually get a function back from the code, you have to return it. I also do this (in Lua) for little "expression evaluators", and I don't consider it a "horrible hack" :)
If you only need some callbacks, without any parameters, you can directly write the code and use the function returned by lua_tostring. You can even pass parameters to this chunk, it will be accessible as the ... expression. Then you can get the parameters as:
local arg1, arg2 = ...
-- rest of code
You decide what is better for you - "ugly code" inside your library codebase, or "ugly code" in your Lua functions.
Have a look at my ae. It caches functions from expressions so you can simply say ae_eval("a*x^2+b*x+c") and it'll only compile it once.
Related
Use case: I am converting data from a very old program of mine to a database friendly format. There are parts where I have to do multiple passes over the old data, because in particular the keys have to first exist before I can reference them in relationships. So I thought why not put the incomplete parts in a vector of references during the first pass and return it from the working function, so I can easily use that vector to make the second pass over whatever is still incomplete. I like to avoid pointers when possible so I looked into std::reference_wrapper<T> which seemes like exactly what I need .. except I don't understand it's behavior at all.
I have both vector<OldData> old_data and vector<NewData> new_data as member of my conversion class. The converting member function essentially does:
//...
vector<reference_wrapper<NewData>> incomplete;
for(const auto& old_elem : old_data) {
auto& new_ref = *new_data.insert(new_data.end(), convert(old_elem));
if(is_incomplete(new_ref)) incomplete.push_back(ref(new_ref));
}
return incomplete;
However, incomplete is already broken immediately after the for loop. The program compiles, but crashes and produces gibberish. Now I don't know if I placed ref correctly, but this is only one of many tries where I tried to put it somewhere else, use push_back or emplace_back instead, etc. ..
Something seems to be going out of scope, but what? both new_data and old_data are class members, incomplete also lives outside the loop, and according to the documentation, reference_wrapper is copyable.
Here's a simplified MWE that compiles, crashes, and produces gibberish:
// includes ..
using namespace std;
int main() {
int N = 2; // works correctly for N = 1 without any other changes ... ???
vector<string> strs;
vector<reference_wrapper<string>> refs;
for(int i = 0; i < N; ++i) {
string& sref = ref(strs.emplace_back("a"));
refs.push_back(sref);
}
for (const auto& r : refs) cout << r.get(); // crash & gibberish
}
This is g++ 10.2.0 with -std=c++17 if it means anything. Now I will probably just use pointers and be done, but I would like to understand what is going on here, documentation / search does not seem to help..
The problem here is that you are using vector data structure which might re-allocate memory for the entire vector any time that you add an element, so all previous references on that vector most probably get invalidated, you can resolve your problem by using list instead of vector.
Consider the following line of code that doesn't compile in Dart -- lack of comma operator, but comparable things are totally fine in JavaScript or C++:
final foo = (ArgumentError.checkNotNull(value), value) * 2;
The closest I could get with an ugly workaround is
final foo = last(ArgumentError.checkNotNull(value), value) * 2;
with function
T last<T>(void op, T ret) => ret;
Is there a better solution?
Dart does not have a comma operator similar to the one in JavaScript.
There is no obviously better solution than what you already have.
The work-around operation you introduced is how I would solve it. I usually call it seq for "sequence" if I write it.
There is sadly no good way to use an extension operator because you need to be generic on the second operand and operators cannot be generic. You could use an extension method like:
extension Seq on void {
T seq<T>(T next) => next;
}
Then you can write ArgumentError.checkNotNull(value).seq(value).
(For what it's worth, the ArgumentError.checkNotNull function has been changed to return its value, but that change was made after releasing Dart 2.7, so it will only be available in the next release after that).
If the overhead doesn't matter, you can use closures without arguments for a similar effect (and also more complex operations than just a sequence of expressions).
final foo = () {
ArgumentError.checkNotNull(value);
return value;
} ();
This is not great for hot paths due to the overhead incurred by creating and calling a closure, but can work reasonably well outside those.
If you need this kind of test-plus-initialization pattern more than once, the cleanest way would arguably be to put it in a function of its own, anyway.
T ensureNotNull<T>(T value) {
ArgumentError.checkNotNull(value);
return value;
}
final foo = ensureNotNull(value);
Here is the function
calc.lua:
function foo(n)
return n*2
end
Here is my LuaJavaCall
L.getGlobal("foo");
L.pushJavaObject(8);
int retCode=L.pcall(1,1,0); // nResults)//L.pcall(1, 1,-2);
String errstr = L.toString(-1); // Attempt to perform arithmetic on local variable 'n'
Update: as indicated below I needed to use L.pushNumber(8.0) instead of L.pushJavaObject()
Try using L.pushNumber instead of L.pushJavaObject like this:
L.getGlobal("foo");
L.pushNumber(8.0);
int retCode = L.pcall(1,1,0);
String errstr = L.toString(-1);
Lua probably sees JavaObject as a type of 'userdata' in which case there are no predefined operations for it; Lua won't know what to do with a JavaObject * 2 since you didn't define how to handle it.
OTOH, Lua does know how to handle a number since that's a builtin primitive type. For the code snippet you presented, pushing a number would be the least painful way to get it working instead of writing extra code that tells Lua how to work with numbers wrapped inside a JavaObject.
I'm trying to call a user-defined Lua function from C. I've seen some discussion on this, and the solution seems clear. I need to grab the index of the function with luaL_ref(), and save the returned index for use later.
In my case, I've saved the value with luaL_ref, and I'm at a point where my C code needs to invoke the Lua function saved with luaL_ref. For that, I'm using lua_rawgeti as follows:
lua_rawgeti(l, LUA_REGISTRYINDEX, fIndex);
This causes a crash in lua_rawgeti.
The fIndex I'm using is the value I received from luaL_ref, so I'm not sure what's going on here.
EDIT:
I'm running a Lua script as follows:
function errorFunc()
print("Error")
end
function savedFunc()
print("Saved")
end
mylib.save(savedFunc, errorFunc)
I've defined my own Lua library 'mylib', with a C function:
static int save(lua_State *L)
{
int cIdx = myCIndex = luaL_ref(L, LUA_REGISTRYINDEX);
int eIdx = luaL_ref(L, LUA_REGISTRYINDEX);
I save cIdx and eIdx away until a later point in time when I receive some external event at which point I would like to invoke one of the functions set as parameters in my Lua script. Here, (on the same thread, using the same lua_State*), I call:
lua_rawgeti(L, LUA_REGISTRYINDEX, myCIndex);
Which is causing the crash.
My first suggestion is to get it working without storing the function in C at all. Just assign your function to a global in Lua, then in C use the Lua state (L) to get the global, push the args, call the function, and use the results. Once that's working, you've got the basics and know your function is working, you can change the way you get at the function to use the registry. Good luck!
As #Schollii mentioned, I was making this call after doing a lua_close(L).
I don't really want to go down the metatables etc. route as it seems rather complicated.
To crudely access 'C' structs in Lua I do:
void execute_lua_script(char *name)
{
lua_pushstring (L,name);
lua_gettable (L, LUA_GLOBALSINDEX);
lua_pushstring(L,"junk");
lua_pushinteger(L,7);
lua_pushlightuserdata(L, avatar_obj);
lua_pcall (L, 3, 2, 0);
}
The registered C func is:
int get_obj_struct(lua_State *L)
{
const char *str;
OBJECT_DEF *obj;
int stack;
obj=(OBJECT_DEF *)lua_touserdata(L,1);
str=lua_tostring(L,2);
//printf("\nIN OBJ:%d %s",obj,str);
if (!strcmp(str,"body->p.x"))
lua_pushnumber(L,obj->body->p.x);
if (!strcmp(str,"collided_with"))
lua_pushlightuserdata(L, obj->collided_with);
if (!strcmp(str,"type"))
lua_pushnumber(L,obj->type);
stack=lua_gettop(L);
//printf("\n%d",stack);
if (stack<3)
report_error("Unknown structure request ",(char *)str);
return 1;
}
Although crude; it works! :-)
The problem is when I request "collided_with" (a pointer); I need to return that back to my script; but for reasons I don't understand 'obj' ends up as nil.
My lua script:
function test(a,b,obj)
--print("\nLUA! test:",a,b);
b=b+1;
c=get_obj_struct(obj,"body->p.x");
--print("x:",c);
collided_with=get_obj_struct(obj,"collided_with");
type=get_obj_struct(collided_with,"type");
print("type:",type);
return a,b;
end
I am expecting 'collided_with' to be a pointer that I can then pass back into get_obj_struct and look for type.
I know it's something to do with me mis-using pushlightuserdata and also reading for the obj.
So an explanation would be great!. Also if someone wishes to give a version that uses 'tables' (as I assume that would be much more efficient) then I would be grateful for the help.
The online "Programming In Lua" book provides a good description of how to implement Lua types in C. In my opinion, your best bet would be to follow the examples provided in Chapter 28 to "do it right" and create a complete Lua wrapper for your object. In addition to being easier to maintain, it will almost certainly be more faster than a strcmp based implementation.