satoren / kaguya

C++ binding to Lua
Boost Software License 1.0
345 stars 70 forks source link

How does newLib work ? #39

Closed Memorix101 closed 8 years ago

Memorix101 commented 8 years ago

Hey, I'm currently trying to understand "newLib". I want to register a lua script from inside my C++ code for my main lua script I load with dofile. :)

An example would be great :)

Thank you :D

satoren commented 8 years ago

You need make lua module. This is shared-object(UNIX) or DLL(Windows).

I'm wrote an example for module. https://github.com/satoren/kaguya/blob/ba1611a4d277825bccda0fdfbb8b0f9161cb6048/examples/hello_lua_module.cpp https://github.com/satoren/kaguya/blob/ba1611a4d277825bccda0fdfbb8b0f9161cb6048/examples/hello_lua_module_exec.lua

Memorix101 commented 8 years ago

Thank you for the examples :)

Memorix101 commented 8 years ago

Oh, what I meant was.

I have a main.lua file and I want to pass a module (example.lua) to it from inside my C++ code. Instead of writing require in my file. the reason why i want that is. I'm using a virtual file system and so I need to write an include function to do that. the default script linking from lua doesnt work, becasue it cant read the filesystem. So I wrote a function called include that first seeks if the lua file I want to include is existing and then I wanted to say the kaguya lib, hey mount that script and pass it to my main lua.

ffff

Here we are inside my virtual filesystem. There is my main lua script that gets mounted first. Next to it is another lua script with another functions and stuff in it. I need to link both, but cant use 'require' or packages to do, because my filesystem is an encrypted file only my c++ code can read and write to.

C++ Code exmaple

int include_module(const char* t)
{
    if (PHYSFS_exists(t))
    {
        std::cout << t << " LUA FOUND" << std::endl;

        std::stringstream sstream;
        PhysFS::ifstream  m(t);
        std::string mtemp((std::istreambuf_iterator<char>(m)), std::istreambuf_iterator<char>());

        //Kaguya needs to link the found script here to my main script

    }
    else
    {
        std::cout << "INCLUDE " << t << " NOT FOUND" << std::endl;
    }

    return 0;
}
satoren commented 8 years ago
int include_module(lua_State* L)
{
  kaguya::State state(L);
  const char* t = lua_tostring(L,1);//get first arguments
 //load data.

 state.dostream(stream); or  state.dostring(luacode);
}

or

kaguya::LuaCodeChunkResult include_module(const char* t)
{
//load data

return kaguya::LuaCodeChunkResult(luacode)://Execute lua code, and return value from that.
}
Memorix101 commented 8 years ago

Well, that's still not linking the other lua file with my main file.

Another try to explain:

int include { //include external lua file to extend main file }

int main() { //loads vfs //loads main.lua as stream //loads included lua files catched by include module function before }

my code looks like that:

int include_module(const char* t)
{
    //load data
    if (PHYSFS_exists(t))
    {
        std::cout << t << " LUA FOUND" << std::endl;

        std::stringstream sstream;
        PhysFS::ifstream  m(t); //mounts the declared "t" file as stream within the vfs
        std::string mtemp((std::istreambuf_iterator<char>(m)), std::istreambuf_iterator<char>());

        //includede lua file
        state.dostream(sstream); // i think this is still wrong :P
    }
    else
    {
        std::cout << "INCLUDE " << t << " LUA NOT FOUND" << std::endl;
    }

    return 0;
}

int main(int argc, char* argv[])
{
    ...

        PHYSFS_mount(mountFile, NULL, 1);  // ROM file //For details on(arg, NULL, 1) read

        int hasMain = PHYSFS_exists("main.lua");

        if (hasMain != 1)
            mounted = false;

        if (mounted)
        {

            kaguya::LoadLibs();

            //register modules
            luaopen_graphics(state);
            luaopen_audio(state);
            luaopen_system(state);
            luaopen_input(state);

            state.setErrorHandler(HandleError);

            std::stringstream sstream;
            PhysFS::ifstream  m("main.lua"); mounts the main.lua file as stream within the vfs
            std::string mtemp((std::istreambuf_iterator<char>(m)), std::istreambuf_iterator<char>());

            sstream << mtemp;
            mstream = mtemp; // Debug stuff for console

            state.loadstream(sstream); // That loads main.lua first

            state["include"] = &include_module; //here gets all other files included to extend my main lua
        ...
    return 0;
}

In lua code :

require "stuff.lua"  --this will pull an error because of the vfs
include_module("stuff.lua") --this is our c++ function declared above to include the required lua file from within the vfs

lua bla bla bla
satoren commented 8 years ago

Where do you define for state? and Where do you execute the main.lua?

This is totally off the topic, but kaguya::LoadLibs(); is do nothing.

Memorix101 commented 8 years ago

State is defined in main.h and dofile is defined some later after checking some more stuff, but I think this is not case related.

Memorix101 commented 8 years ago

That's what I want to do in Kaguya http://stackoverflow.com/questions/4525757/embedded-lua-loading-modules-programatically-c

Memorix101 commented 8 years ago

Ok found out how I can do it.

main.cpp


  kaguya::State state;

int include_module(const char* t)
{
    //load data
    if (PHYSFS_exists(t))
    {
        std::cout << t << "FOUND" << std::endl;

        std::stringstream some_stream;
        PhysFS::ifstream  some_input(t);
        std::string this_mtemp((std::istreambuf_iterator<char>(some_input)), std::istreambuf_iterator<char>());

         some_stream << this_mtemp;

        state.dostream(some_stream);
    }
    else
    {
        std::cout <<  t << " NOT FOUND" << std::endl;
    }

    return 0;
}

int main()
{

  std::stringstream sstream;

  PhysFS::ifstream  m("main.lua");
  std::string mtemp((std::istreambuf_iterator<char>(m)), std::istreambuf_iterator<char>());

  state["include"] = &include_module;  

  sstream << mtemp;

  state.dostream(sstream )  

  while(true)
  {

   // SDL DRAW STUFF OR WHATEVER 

  }

   retrun 0;

}

main.lua

include("test.lua")

print("meep meep")

stuffinstuff()

test.lua

function stuffinstuff()

print("this is stuff")

end

Done, wow. I thought I need to register it as a Lua Lib or Lua Table.

satoren commented 8 years ago

Did you know instance or scope?

int main()
{
kaguya::State state;
{
  kaguya::State state;
  state["value"] = 1;
  state.dostring("assert(value == 1)"); //pass
}
  state.dostring("assert(value == nil)"); //pass
}
satoren commented 8 years ago
//in C
lua_getfield (L, LUA_GLOBALSINDEX, "require"); // function
lua_pushstring (L, "funky");     // arg 0: module name
err = lua_pcall (L, 1, 1, 0);
lua_setfield (L, LUA_GLOBALSINDEX, "funky");

equal to

-- in lua
funky = require ("funky")

equal to

//in C++ with Kaguya
state["funky"] = state["require"]("funky");
satoren commented 8 years ago

I'm wrote example.

int include_module(lua_State* L)
{
  kaguya::State state(L);
  const char* t = lua_tostring(L,1);//get first arguments`

but you write

int include_module(const char* t)
{

Why?

Memorix101 commented 8 years ago

I told you that my lua scripts are inside a virtual filesystem. Lua itself can't find other scripts inside that (because of encryption, it shows a nil error), so I need the vfs to check if the needed file is existing. If existing the vfs needs to save it to memory and stream it.

satoren commented 8 years ago
using namespace kaguya;
State state;
void bad_function(const char* t)
{
  state["value"] = t;//assigned to line:2 state
}
void good_function(lua_State* L)
{
  State state(L);
  const char* t = lua_tostring(L,1);
  state["value"] = t;
}

int main()
{
   State state;
   state["bad_function"] = &bad_function;
   state["good_function"] = &good_function;
  state.dostring("bad_function('test')");
  state.dostring("assert(value == nil)");//not assigned

  state.dostring("good_function('test')");
  state.dostring("assert(value == 'test')");//pass
}

Your implement is bad_function.

Memorix101 commented 8 years ago

Are you sure ?

123

1234

Memorix101 commented 8 years ago

Why can I call this only once ? (I'd like to replace my current implementation with this one)

int include_module_L(lua_State* L)
{
        kaguya::State state(L);
        const char* t = lua_tostring(L, 1);
        //state["value"] = t;
        state["require"](t);
              //or
state[t] = state["require"](t);

    return 0;
}

require ("stuff") --one require call works

require ("stuff") --two doesn't
require ("another") --this is nil somehow
satoren commented 8 years ago

I'm sorry for my miss.

int good_function(lua_State* L)
{
  State state(L);
  const char* t = lua_tostring(L,1);
  state["value"] = t;
return 0;
}

Please read lua document for require. http://www.lua.org/manual/5.3/manual.html

Memorix101 commented 8 years ago

Ah, ok.

For my case this works:

local Aname = require "stuff"
local Bname = require "another"

but normally this works, too

require "stuff"
require "another"

print("meep meep")

stuffinstuff()
moarstuff()
Memorix101 commented 8 years ago

wtf .. this implementation works inside the vfs without mounting the lua files first :o

int include_module_L(lua_State* L)
{
        kaguya::State state(L);
        const char* t = lua_tostring(L, 1);
        state[t] = state["require"](t);

    return 0;
}

It works for

local Aname = require "stuff"
local Bname = require "another"

and

require "stuff"
require "another"

Totally unexpected :o

Flamefire commented 8 years ago

@satoren So the working example would be:

using namespace kaguya;
int good_function(lua_State* L)
{
  State state(L);
  const char* t = lua_tostring(L,1);
  state["value"] = t;
  return 0;
}

int main()
{
   State state;
   state["good_function"] = &good_function;

  state.dostring("good_function('test')");
  state.dostring("assert(value == 'test')");//pass
}

Is this correct? Why is the return value required here? Is there any documentation on using functions taking a lua_state* with kaguya? From the current readme I would have expected the void-function to work.

satoren commented 8 years ago

I'm sorry, it is not documented.

typedef int (*lua_CFunction) (lua_State *L); defined in plain Lua. And it is specialized in kaguya, it mean direct call from Lua VM.

Flamefire commented 8 years ago

Ah ok. Could you add that explanation somewhere? Also: How come the function got matched, although the return value was wrong? Shouldn't that be an error? If not, could you make it one so no one else falls into this trap?

satoren commented 8 years ago

use static_cast? state["f"] = static_cast<lua_CFunction>(&f);

Flamefire commented 8 years ago

No, I mean, Why does this work?:

void wrongSig(lua_State* L){}
state["wrongSig"] = &wrongSig;

I think this should throw a compile time error because it is NOT a lua_CFunction or be wrapped in kaguya so you don't need the return value.

satoren commented 8 years ago

Why does this work?:

lua_State* is same type of coroutine.

void coroutine_receive_fn(lua_State* co){
  lua_resume(co,0,0);
}
state["coroutine_receive_fn"] = &coroutine_receive_fn;
coroutine_receive_fn( coroutine.create(function () return 1 end) )

Do you think how should divide?

satoren commented 8 years ago

OK. lua_CFunction specialization is removed.

state["f"] = kaguya::luacfunction(&plain_lua_cfunction);//directcall by lua
state["corfn"] = kaguya::function(&plain_lua_cfunction);//int (coroutine)  function(wrapped by kaguya)
state["corfn2"] = &plain_lua_cfunction;//int (coroutine)  function(wrapped by kaguya)