LuaPlus: How to force a function to return a table?

I am wondering how I can create and register a function from the C ++ side that returns a table when called from the Lua side.
I tried a lot of things, but nothing really worked.: /

(sorry for the long code) This, for example, will not work, because Register () expects the function "luaCFunction" -styled:

LuaPlus::LuaObject Test( LuaPlus::LuaState* state ) { int top = state->GetTop(); std::string var( state->ToString(1) ); LuaPlus::LuaObject tableObj(state); tableObj.AssignNewTable(state); if (var == "aaa") tableObj.SetString("x", "ABC"); else if (var == "bbb") tableObj.SetString("x", "DEF"); tableObj.SetString("y", "XYZ"); return tableObj; } int main() { LuaPlus::LuaState* L = LuaPlus::LuaState::Create(true); //without true I can't access the standard libraries like "math.","string."... //with true, GetLastError returns 2 though (ERROR_FILE_NOT_FOUND) //no side effects noticed though LuaPlus::LuaObject globals = L->GetGlobals(); globals.Register("Test",Test); char pPath[MAX_PATH]; GetCurrentDirectory(MAX_PATH,pPath); strcat_s(pPath,MAX_PATH,"\\test.lua"); if(L->DoFile(pPath)) { if( L->GetTop() == 1 ) // An error occured std::cout << "An error occured: " << L->CheckString(1) << std::endl; } } 

When I try to configure it as a luaCFunction function, it just crashes (0x3) and says:
Approval failed: 0, file C: \ ...... \ luafunction.h , line 41

 int Test( LuaPlus::LuaState* state ) { int top = state->GetTop(); std::string var( state->ToString(1) ); LuaPlus::LuaObject tableObj(state); tableObj.AssignNewTable(state); if (var == "aaa") tableObj.SetString("x", "ABC"); else if (var == "bbb") tableObj.SetString("x", "DEF"); tableObj.SetString("y", "XYZ"); tableObj.Push(); return state->GetTop() - top; } 

To clarify: on the Lua side, I wanted this to be invoked as follows:

 myVar = Test("aaa") Print(myVar) -- output: ABC 

EDIT: The print function comes from here . And basically the reason for this did not work. Printing can only print rows without tables ... The C ++ code above works fine if you just come back.

This is the documentation that came with my version of LuaPlus: http://luaplus.funpic.de/

I really hope that you can help me .. I'm already starting to think that this is impossible .: '(

edit I completely forgot to say that using PushStack () results in an error because "member does not exist" ...

+6
source share
2 answers

After some painstaking research from a long discussion of comments, I am posting this answer to help summarize the situation and hopefully offer some useful tips.

The main problem OP was facing was that the wrong print function was called in the lua script test. Unlike the source code, the actual code that the OP tested was calling Print(myVar) , which is a custom lua_CFunction function, not a built-in print function.

Somehow along the way, this led to the creation of some instance of template <typename RT> class LuaFunction and the call to the overloaded operator()() . From the luafunction.h check from luaPlus, any lua errors that occur inside this call will be swallowed without any logging (not a very good design solution for the luaPlus part):

  if (lua_pcall(L, 0, 1, 0)) { const char* errorString = lua_tostring(L, -1); (void)errorString; luaplus_assert(0); } 

To help catch future errors like this, I suggest adding a new luaplus_assertlog macro. In particular, this macro will include errorString so that the context is not completely lost and hopefully helps with debugging. This change, hopefully, will not violate existing uses of luaplua_assert from other parts of the API. Ultimately, it is probably best to modify luaplus_assert so that it really includes something meaningful.

In any case, there have been changes:

LuaPlusInternal.h

 @@ -81,5 +81,6 @@ } // namespace LuaPlus #if !LUAPLUS_EXCEPTIONS +#include <stdio.h> #include <assert.h> #define luaplus_assert(e) if (!(e)) assert(0) @@ -84,5 +85,6 @@ #include <assert.h> #define luaplus_assert(e) if (!(e)) assert(0) +#define luaplus_assertlog(e, msg) if (!(e)) { fprintf(stderr, msg); assert(0); } //(void)0 #define luaplus_throw(e) assert(0) //(void)0 

LuaFunction.h

 @@ -21,7 +21,7 @@ class LuaFunction { public: - LuaFunction(LuaObject& _functionObj) + LuaFunction(const LuaObject& _functionObj) : functionObj(_functionObj) { } @@ -36,7 +36,7 @@ if (lua_pcall(L, 0, 1, 0)) { const char* errorString = lua_tostring(L, -1); (void)errorString; - luaplus_assert(0); + luaplus_assertlog(0, errorString); } return LPCD::Type<RT>::Get(L, -1); } 

In the change above, I decided not to use std::cerr simply because C ++ streams tend to be heavier than simple C-style idio functions. This is especially true if you use mingw as a toolchain - the ld linker cannot remove unused C ++ stream characters, even if your program never uses it.

With this in place, here is an example where an unprotected call is made using the lua function so that you can see the errorString printout before failure:

 // snip... int main(int argc, const char *argv[]) { LuaStateAuto L ( LuaState::Create(true) ); LuaObject globals = L->GetGlobals(); globals.Register("Test", Test); globals.Register("Print", Print); if(argc > 1) { /* if (L->DoFile(argv[argc - 1])) std::cout << L->CheckString(1) << '\n'; /*/ L->LoadFile( argv[argc - 1] ); LuaFunction<int> f ( LuaObject (L, -1) ); f(); //*/ } } 

Doing the above will crash, but will include a semi-official error message:

 g++ -Wall -pedantic -O0 -g -I ./Src -I ./Src/LuaPlus/lua51-luaplus/src plustest.cpp -o plustest.exe lua51-luaplus.dll plustest.exe plustest.lua plustest.lua:2: bad argument #1 to 'Print' (string expected, got table)Assertion failed! Program: G:\OSS\luaplus51-all\plustest.exe File: ./Src/LuaPlus/LuaFunction.h, Line 39 Expression: 0 This application has requested the Runtime to terminate it in an unusual way. Please contact the application support team for more information. 
+1
source

first you can try registering the function with RegisterDirect (), this can avoid the lua_CFunction problem, check the luaplus manual.

 LuaPlus::LuaObject globals = L->GetGlobals(); globals.RegisterDirect("Test",Test); 

second, if I remember to create a table, there are two solutions, for example

 //first LuaObject globalsObj = state->GetGlobals(); LuaObject myArrayOfStuffTableObj = globalsObj.CreateTable("MyArrayOfStuff"); //second LuaObject aStandaloneTableObj; aStandaloneTableObj.AssignNewTable(state); 

check if you are using the correct function.

Thirdly, I remember that the lua stack object is not a luaobject object, it has a transform, maybe you can try this

 LuaStackObject stack1Obj(state, 1); LuaObject nonStack1Obj = stack1Obj; 

forward, like the Test () function you specified above, the tableObj table that you push on the lua stack, you must remember to clear the object.

+1
source

Source: https://habr.com/ru/post/957555/


All Articles