2015-09-19 3 views
3

У меня есть Actor, что я хочу дать Script.Как создать модуль Lua внутри модуля Lua в C?

Вместо того, чтобы иметь несколько общих объектов, я хотел бы иметь один модуль верхнего уровня, который включает в себя его собственные зависимости.

Другими словами, я хочу быть в состоянии сделать это:

Actor = require 'Actor' 
Script = require 'Actor.Script' 

script = Script("To be, or not to be ..."); 
actor = Actor(); 

Оба эти просто возвращают функции, которые создают userdata обоих Actor и Actor.Script типов. Моя проблема в том, что, хотя я могу загрузить этот код, он работает не так, как ожидалось. Кажется, что Script просто возвращает Actoruserdata.

print(script) => Actor 0x7fb7a240e998 
print(actor) => Actor 0x7fb7a240a478 

я ожидал:

print(script) => Actor.Script 0x7fb7a240e998 
print(actor) => Actor 0x7fb7a240a478 

Если я «бюст из» код в двух различных модулей, я получаю ожидаемых результатов, но мне очень хотелось бы, чтобы это в одном модуле ,

Я компиляции на OSX и Clang с:

clang -Wall -I./ -I/usr/local/include/ -bundle -undefined dynamic_lookup actor.c script.c -o Actor.so -L./ -L/usr/local/lib 

Вот код, я использую:

actor.c:

#include "common.h" 

#define ACTOR_LIB "Actor" 

typedef struct Actor { 
    struct Script *script; 
} Actor; 

/* 
* Allocate, initialize, and push a new Actor onto the stack. 
* Returns a pointer to that Actor. 
*/ 
Actor* 
lua_newactor (lua_State *L) 
{ 
    Actor *actor = lua_malloc(L, sizeof(Actor)); 
    actor->script = NULL; 
    return actor; 
} 

/* 
* Make sure the argument at index N is a actor and return it if it is. 
*/ 
Actor* 
lua_checkactor (lua_State *L, int index) 
{ 
    return (Actor *) luaL_checkudata(L, index, ACTOR_LIB); 
} 

static int 
actor_new (lua_State* L) 
{ 
    Actor *actor = lua_newactor(L); 
    lua_pushobject(L, actor, ACTOR_LIB); 
    return 1; 
} 

static int 
actor_print (lua_State* L) 
{ 
    Actor *actor = lua_checkactor(L, 1); 
    lua_pushfstring(L, "%s %p", ACTOR_LIB, actor); 
    return 1; 
} 

static const luaL_Reg actor_methods[] = { 
    {"__tostring", actor_print}, 
    { NULL, NULL } 
}; 

int 
luaopen_Actor (lua_State * L) 
{ 
    /* create metatable */ 
    luaL_newmetatable(L, ACTOR_LIB); 

    /* metatable.__index = metatable */ 
    lua_pushvalue(L, -1); 
    lua_setfield(L, -1, "__index"); 

    /* register methods */ 
    luaL_setfuncs(L, actor_methods, 0); 

    /* Actor() => new Actor */ 
    lua_pushcfunction(L, actor_new); 

    return 1; 
} 

script.c:

#include "common.h" 

#define SCRIPT_LIB "Actor.Script" 

typedef struct Script { 
    const char *string; 
} Script; 

/* 
* Allocate a new Script to be passed around. 
*/ 
Script * 
lua_newscript (lua_State *L, const char *string) 
{ 
    if (string == NULL) 
     luaL_error(L, "`string` cannot be empty!"); 

    Script *script = (Script*) lua_malloc(L, sizeof(Script)); 
    script->string = string; 
    return script; 
} 

/* 
* Make sure the argument at index N is a Script and return it if it is. 
*/ 
Script * 
lua_checkscript (lua_State *L, int index) 
{ 
    return (Script *) luaL_checkudata(L, index, SCRIPT_LIB); 
} 

static int 
script_new (lua_State *L) 
{ 
    const char *filename = luaL_checkstring(L, 1); 
    Script *script = lua_newscript(L, filename); 
    lua_pushobject (L, script, SCRIPT_LIB); 
    return 1; 
} 

static int 
script_print (lua_State* L) 
{ 
    Script *script = lua_checkscript(L, 1); 
    lua_pushfstring(L, "%s %p", SCRIPT_LIB, script); 
    return 1; 
} 

static const luaL_Reg script_methods[] = { 
    {"__tostring", script_print}, 
    { NULL, NULL } 
}; 

int 
luaopen_Actor_Script (lua_State *L) 
{ 
    /* create metatable */ 
    luaL_newmetatable(L, SCRIPT_LIB); 

    /* metatable.__index = metatable */ 
    lua_pushvalue(L, -1); 
    lua_setfield(L, -1, "__index"); 

    /* register methods */ 
    luaL_setfuncs(L, script_methods, 0); 

    /* Push a function: Script(...) => new script */ 
    lua_pushcfunction(L, script_new); 

    return 1; 
} 

common.h:

#ifndef COMMON 
#define COMMON 

#include <lua.h> 
#include <lauxlib.h> 
#include <lualib.h> 

/* 
* Allocates size_t memory on the given Lua state. 
* lua_newuserdata automatically pushes it, so we pop it. 
*/ 
static 
void * 
lua_malloc (lua_State *L, size_t size) 
{ 
    void *p = lua_newuserdata(L, size); 
    lua_pop(L, 1); 
    return p; 
} 

/* 
* Associate an object pointer with given name and push that onto the stack. 
*/ 
static 
void 
lua_pushobject (lua_State *L, void *object_pointer, const char *metatable_name) 
{ 
    lua_pushlightuserdata(L, object_pointer); 
    luaL_getmetatable(L, metatable_name); 
    lua_setmetatable(L, -2); 
} 

#endif 
+3

Не добавляйте значение, созданное 'lua_newuserdata()' немедленно, это единственное, что предотвращает сбор ваших данных пользователя. Кроме того, все светлые userdatas имеют общую метатебель, поэтому все ваши оборванные указатели^W^W «объекты» имеют один и тот же тип. – siffiejoe

+0

@siffiejoe вы можете указать мне в правильном направлении для создания нескольких объектов для Lua на C и как работают метаданные? – Leroy

+1

Просто избавьтесь от 'lua_pop' и' lua_pushlightuserdata' в 'common.h', и ваш код должен работать. Ваша единственная проблема заключается в том, что вы используете lightuserdata, когда вы должны использовать полные пользовательские данные. – siffiejoe

ответ

1

В этом случае функции модулей и подмодуль были правильными в C. Отсюда следует форму luaopen_Parent_Child_..._Descendant в качестве имени функции в C и Parent.Child.Descendant в Lua.

Проблема была в том, что я вводил в заблуждение lua_pushlightuserdata с lua_newuserdata с точки зрения того, что попадает в стек. lua_pushlightuserdata все имеют одинаковый метатет, поэтому я не мог иметь отдельные объекты.

Смежные вопросы