I want to link a Lua table function to a C++ variable using LUAPlus. So far using what information I can find on the web, I've managed to call a table function using DoString("tableName:functionName"), but I want to be able to call the function through a variable. I know its possible but I cant figure out what I'm doing wrong.
In the code I've added, pLuaState->DoString("table1:prints()") works fine and prints everything as needed.
When I try to get the function and call it using the func variable, my program crashes with
error message
Assertion failed: 0, file .../luafunciton.h, line 41
If I remove all the prints in the prints() function in Lua except "print("in prints")", everything works fine. Based on this I assume that GetByName("functionName") returns a function that doesn't contain a reference to its parent table. And this is where I get stuck.
main.cpp
pLuaState = LuaPlus::LuaState::Create(true);
pLuaState->DoFile("test.lua");
LuaObject globals = pLuaState->GetGlobals();
LuaObject metaTableObj = pLuaState->GetGlobals().Lookup("RandomMove");
if (metaTableObj.IsNil())
{
metaTableObj = pLuaState->GetGlobals().CreateTable("RandomMove");
}
metaTableObj.SetObject("__index", metaTableObj);
metaTableObj.RegisterObjectDirect("GetX", (TestLua*)0, &TestLua::GetX);
metaTableObj.RegisterObjectDirect("SetX", (TestLua*)0, &TestLua::SetX);
TestLua obj1(6);
LuaObject table1Obj = pLuaState->GetGlobals().CreateTable("table1");
table1Obj.SetLightUserData("__object", &obj1);
table1Obj.SetObject("__index", metaTableObj);
table1Obj.SetMetaTable(metaTableObj);
pLuaState->DoString("table1:prints()");
auto prints = table1Obj.GetByName("prints");
if (!prints.IsFunction())
cout << "nil function" << endl;
else
{
LuaPlus::LuaFunction<void> func(prints);
func();
}
test.lua
print("test.lua")
RandomMove =
{
_thing = 1
}
function RandomMove:SetThing()
print("I am "..tostring(self.__object))
end
function RandomMove:prints()
print("in prints")
print("__object is: " .. tostring(self.__object))
print("_thing is: ".. tostring(self._thing))
print(self:GetX())
end
Any help would be appreciated.
You are correct. Functions do not know anything about their "parents" or their "objects" or anything. That's why the : calling syntax exists. The call table1:prints() is identical to table1.prints(table1) (only lua ensures that table1 is evaluated only once.
So if you grab the function from the table/etc. directly when you call it directly you need to ensure that you pass the correct table/etc. as the first argument (before any other arguments the function expects).
Related
I'm trying to use the SWI-PL engine in C++ using SWI-cpp.h.
I don't have any tutorial, I'm only using this reference and I'm looking in GitHub repos for some examples.
My code works fine, except for one thing; calling this definition:
foo([bar]).
As you can see, the definition requires a list.
Since I can't put a PlTermv in a PlTermv, I have no idea how to construct a list. I could use a PlTail, but I only know a way in which I have to add an empty head.
This is my CPP code so far:
PlTermv av(1);
// Load external pl file that contaions the foo definition.
PlCall("consult", PlTerm("foobar.pl"));
PlAtom bar = PlAtom("hello");
// I want Prolog to return a list with this compound.
av[0] = PlCompound("foo", PlTermv(bar));
PlCall("call", av); // So that this statement returns 'true' instead of 'false'.
How could I change this code in a way that PlCall("call",av); returnstrue?
Creating lists in Prolog can be done using the atomic_list_concat/3 predicate.
This means PlCall has to be called one more time in the code and it's result has to be stored in a PlTerm:
PlTermv av(1);
// Load external pl file that contaions the foo definition.
PlCall("consult", PlTerm("foobar.pl"));
PlTerm list;
// Use space as separator. Sets the value of 'list' to '[bar]'.
PlCall("atomic_list_concat", PlTermv(list, " ", "bar"));
av[0] = PlCompound("foo", PlTermv(list));
PlCall("call", av); // returns 'true'
I've been to the end of Google and back trying to solve this problem.
I have a few userdata objects that I push from C++ to Lua.
I have a function that should get the X value of either a 2D or 3D object.
When I try to get the userdata object, taking into consideration that it could be either a 2D element or 3D object, I need to be able to get the X for whichever the user chooses.
Here is what I tried:
int getX(lua_State* L)
{
Object3D* a = static_cast<Object3D*>(luaL_checkudata(L, 1, "Object3D"));
if (!a)
{
Object2D* b = static_cast<Object2D*>(luaL_checkudata(L, 1, "Object2D"));
if (b)
{
lua_pushnumber(L, b:getX());
}
else
{
lua_pushnil(L);
}
}
else
{
lua_pushnumber(L, a:getX());
}
return 1;
}
Unfortunately if the userdata type is not Object3D, it fails and exits on an lua error without continuing to try Object2D.
Therefore, it will only work in the above code if the object being passed is of type Object3D.
luaL_testudata
void *luaL_testudata (lua_State *L, int arg, const char *tname);
This function works like luaL_checkudata, except that, when the test fails, it returns NULL instead of raising an error.
The lua(L)_check* functions throw Lua errors on failure, the lua(L)_to* functions return NULL. For whatever reason, this one deviates from the naming convention and is named lua(L)_test* instead, which makes it a bit harder to find.
Your code is incomplete and doesn't compile as-is so I can't be bothered to check, but if I'm not mistaken, just replacing luaL_checkudata with luaL_testudata should make it work as intended.
Solved by using rawequal to see which class the registry matches.
Good afternoon,
I am working on a LUA/C++ application, from which i need lua to be able to call other lua code recursively, e.g: C++ calls lua function, lua function calls another lua function from another string that is loaded using a registered C function that runs at the start of the first lua function;
here are the steps i am following:
lua_State* state = luaL_newstate();
luaL_openlibs(state);
lua_register(state, "secondLua", secondLua);
lua_getfield( _luaState, LUA_GLOBALSINDEX, "init" );
lua_pcall( _luaState, 0, 0, 0 );
int secondLua(lua_State* state){
char* myString[128] = "function init2()\n io.write(\"hello\")\n end";
luaL_loadstring(pLuaState, myString);
lua_getfield(pLuaState,LUA_GLOBALSINDEX, "init2"); // function init2 declared on myString
lua_pcall(pLuaState, 0, LUA_MULTRET, 0);
//getting "attempt to call a nil value" here
return 0;
}
Any help is appreciated, and second, i would like to know if there is a way i can name the second function "init" as well as the first one;
PS: I am using C++14 and lua 5.1 on LUAJIT, and i cant use lua's dofile;
lua_loadstring() compiles supplied source and puts Lua chunk on stack. It won't execute it though, so init2() still not defined when you expect that.
Replace lua_loadstring() with luaL_dostring() to actually run that chunk and define new lua functions. Or call lua_pcall() right after lua_loadstring(). Actually, luaL_dostring() does exactly that - lua_loadstring() followed by lua_pcall().
I know the basics of interacting with lua and C, and I am currently trying to perform the following line of lua in c++
Func1():Func2().Table1.value1
I am trying to get the value of "value2" and use it in my C program. The following is the code I wrote to attempt to get this value in C.
int GetNumber()
{
int retn = 0;
g_clientlua.lua_getfield(LUA_REGISTRYINDEX, "Player");
g_clientlua.lua_getfield(-1, "Func2");
g_clientlua.lua_getfield(LUA_GLOBALSINDEX, "Func1");
g_clientlua.lua_call(0, 1);
g_clientlua.lua_call(1, 1);
if (g_clientlua.lua_isnil(-1))
return retn;
g_clientlua.lua_getfield(-1, "Table1");
if (g_clientlua.lua_isnil(-1))
return retn;
g_clientlua.lua_getfield(-1, "value1");
if (g_clientlua.lua_isnil(-1))
return retn;
retn = (int)g_clientlua.lua_tointeger(-1);
}
The clientlua thing is an object that basically just allows me to call a method which calls it's lua_* function equivalent and fills the lua_state pointer parameter with a member variable that is a pointer to the lua state.
Every time I call this, it complains about me causing a lua stack leak. To solve this, I tried adding a lua_pop(3) to the end, but then it just crashes my program without reporting an error, so I assume I am doing something wrong.
Anyone have any words of wisdom for me? Kinda lost here. I doubt the above code is even written properly, how would I write the above lua call in C?
You need to call Func1 before you try to get Func2 as Func2 comes from the table that Func1 returns (and not from the global table).
Then you need to call Func2 and look up Table1 in that returned value, etc.
What "stack leak" complaint are you getting? If you are calling this function from C directly then yes, you need to be sure that anything you put on the lua stack (that isn't for consumption by the caller, etc.) is popped from the lua stack before you return.
The GetNumber function isn't doing exactly the same as the lua snippet you're going for. Specifically GetNumber is getting the value of "Func2" from the registry while your lua snippet is getting the value of "Func2" from the table returned by Func1(). Unless you're certain that registry.Player.Func2 == Func1().Func2 is always true, your C++ version will not have the same behavior.
Let's break down Func1():Func2().Table1.value1 into more explicit steps to help with the C translation:
Get function associated with _G.Func1
Call that function and get a table back
Get function associated with "Func2" from the returned table in step 2
Call that function and pass as argument the table from step 2. Get another table back as result
I found it helpful to track what the stack contains as a side-comment as the operations are performed:
int GetNumber()
{
// Func1()
gclientlua.lua_getfield(LUA_GLOBALSINDEX, "Func1"); // Func1
g_clientlua.lua_call(0, 1); // {}
// Func2( {} )
g_clientlua.lua_getfield(-1, "Func2"); // {}, Func2
g_clientlua.lua_insert(-2); // Func2, {}
g_clientlua.lua_call(1, 1); // {}
if( g_clientlua.lua_type(-1) != LUA_TTABLE )
{
g_clientlua.lua_pop(1);
return 0;
}
// {}.Table1
g_clientlua.lua_getfield(-1, "Table1"); // {}, {}(Table1)
if( g_clientlua.lua_type(-1) != LUA_TTABLE )
{
g_clientlua.lua_pop(2);
return 0;
}
// tonumber( Table1.value1 )
g_clientlua.lua_getfield(-1, "value1"); // {}, {}(Table1), value1
int retn = g_clientlua.lua_tointeger(-1);
g_clientlua.lua_pop(3);
return retn;
}
Notice that GetNumber pops off all the arguments it places on the stack before returning. This ensures that GetNumber leaves the lua stack the way it was found. This can probably be automated with RAII if you're using C++.
I'm attempting to call a function inside of a lua file called test2.lua
This is the contents of test2.lua:
function abc(path)
t = {}
table.insert(t, "a")
return t
end
As you can see it takes a single input and returns a string.
Here is my C code. It's pretty simple. However my call getglobal in order to call that function does not work... lua_getglobal says it isn't a function when I test it... Any reason why this is? Shouldn't abc be a global function returnable inside of the source file? Why then does it only find nil for this global?
L = lua_open();
luaL_openlibs(L);
luaL_loadfile(L, "src/test2.lua");
lua_getglobal(L, "abc");
lua_pushstring(L, "coollll");
int error = 0;
if ((error = lua_pcall(L, 1, 1, 0)) == 0)
{
std::cout << "cool";
}
EDIT:
calling lua_getglobal is causing my program to break control regardless of using loadfile or dofile... any idea why?
lua_getglobal crashing program
The function luaL_loadfile() reads, parses, and compiles the named Lua file. It does not execute any of its content. This is important in your case because the statement function abc(path)...end has no visible effect until it is executed. The function keyword as you've used it is equivalent to writing
abc = function(path)
t = {}
table.insert(t, "a")
return t
end
In this form, it is clearer that the variable named abc is not actually assigned a value until the code executes.
When luaL_loadfile() returns, it has pushed an anonymous function on the top of the Lua stack that is the result of compiling your file. You need to call it, and lua_pcall() will do the trick. Replace your reference to luaL_loadfile() with this:
if (luaL_loadfile(L, "src/test2.lua") || lua_pcall(L, 0, LUA_MULTRET, 0)) {
// do something with the error
}
At this point, test2.lua has been executed and any functions it defined or other global variables it modified are available.
This is a common enough idiom, that the function luaL_dofile() is provided to load and call a file by name.
There is a second, more subtle issue in your code as presented. The function abc() uses a variable named t, but you should be aware that t as used is a global variable. You probably meant to write local t = {} at the top of abc().
It's not enough to call luaL_loadfile: this puts a chunk onto the stack. Either follow up with luaL_[p]call to execute the chunk (thus making the function available), or use luaL_dofile.