Modules now reside in Lua and are treated (almost) like normal objects.

Also added a way of getting a pointer to abstract module instances internally.
This commit is contained in:
rude
2009-09-02 21:18:13 +02:00
parent bea504af2b
commit 623e701549
22 changed files with 247 additions and 176 deletions
+2 -3
View File
@@ -24,15 +24,14 @@
// LOVE
#include "runtime.h"
#include "Exception.h"
#include "Object.h"
namespace love
{
/**
* Abstract superclass for all modules.
*
* @author Anders Ruud
**/
class Module
class Module : public Object
{
public:
+30 -39
View File
@@ -37,23 +37,12 @@ namespace love
**/
static int w__gc(lua_State * L)
{
UserData * u = (UserData *)lua_touserdata(L, 1);
Proxy * u = (Proxy *)lua_touserdata(L, 1);
Object * t = (Object *)u->data;
t->release();
return 0;
}
/**
* Special garbage collector for Modules.
**/
static int w__Module_gc(lua_State * L)
{
UserData * u = (UserData *)lua_touserdata(L, 1);
Module * t = (Module *)u->data;
delete t;
return 0;
}
Reference * luax_refif(lua_State * L, int type)
{
Reference * r = 0;
@@ -115,38 +104,36 @@ namespace love
return 0;
}
int luax_register_gc(lua_State * L, Module * m)
int luax_register_module(lua_State * L, const WrappedModule & m)
{
luax_getregistry(L, REGISTRY_GC);
// Put a reference to the C++ module in Lua.
luax_getregistry(L, REGISTRY_MODULES);
UserData * u = (UserData *)lua_newuserdata(L, sizeof(UserData));
u->own = true;
u->data = m;
Proxy * p = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
p->own = true;
p->data = m.module;
p->flags = m.flags;
luaL_newmetatable(L, m->getName());
lua_pushcfunction(L, w__Module_gc);
luaL_newmetatable(L, m.module->getName());
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, w__gc);
lua_setfield(L, -2, "__gc");
lua_setmetatable(L, -2);
lua_setfield(L, -2, m.name); // _modules[name] = proxy
lua_pop(L, 1);
lua_setfield(L, -2, m->getName());
lua_pop(L, 1); // Registry
return 0;
}
int luax_register_module(lua_State * L, const luaL_Reg * fn, const lua_CFunction * types, const LuaConstant * constants, const char * name)
{
// Gets the love table.
luax_insistglobal(L, "love");
// Install constants.
if(constants != 0)
if(m.constants != 0)
{
for(int i = 0; constants[i].name != 0; i++)
for(int i = 0; m.constants[i].name != 0; i++)
{
lua_pushinteger(L, constants[i].value);
lua_setfield(L, -2, constants[i].name);
lua_pushinteger(L, m.constants[i].value);
lua_setfield(L, -2, m.constants[i].name);
}
}
@@ -154,14 +141,14 @@ namespace love
lua_newtable(L);
// Register all the functions.
luaL_register(L, 0, fn);
luaL_register(L, 0, m.functions);
// Register types.
if(types != 0)
for(const lua_CFunction * t = types; *t != 0; t++)
if(m.types != 0)
for(const lua_CFunction * t = m.types; *t != 0; t++)
(*t)(L);
lua_setfield(L, -2, name); // love.graphics = table
lua_setfield(L, -2, m.name); // love.graphics = table
lua_pop(L, 1); // love
return 0;
@@ -189,7 +176,9 @@ namespace love
lua_pushcfunction(L, w__gc);
lua_setfield(L, -2, "__gc");
luaL_register(L, 0, f);
if(f != 0)
luaL_register(L, 0, f);
lua_pop(L, 1); // Pops metatable.
return 0;
}
@@ -217,7 +206,7 @@ namespace love
void luax_newtype(lua_State * L, const char * name, bits flags, void * data, bool own)
{
UserData * u = (UserData *)lua_newuserdata(L, sizeof(UserData));
Proxy * u = (Proxy *)lua_newuserdata(L, sizeof(Proxy));
u->data = data;
u->flags = flags;
@@ -232,7 +221,7 @@ namespace love
if(lua_isuserdata(L, idx) == 0)
return false;
return ((((UserData *)lua_touserdata(L, idx))->flags & type) == type);
return ((((Proxy *)lua_touserdata(L, idx))->flags & type) == type);
}
int luax_getfunction(lua_State * L, const char * mod, const char * fn)
@@ -318,6 +307,8 @@ namespace love
{
case REGISTRY_GC:
return luax_insistlove(L, "_gc");
case REGISTRY_MODULES:
return luax_insistlove(L, "_modules");
default:
return luaL_error(L, "Attempted to use invalid registry.");
}
+62 -25
View File
@@ -44,31 +44,61 @@ namespace love
enum Registry
{
REGISTRY_GC = 1,
REGISTRY_MODULES,
};
/**
* This structure wraps all Lua-exposed objects. It exists in the
* Lua state as a full UserData (so we can catch __gc "events"),
* though the Object it refers to is light UserData in the sense
* Lua state as a full userdata (so we can catch __gc "events"),
* though the Object it refers to is light userdata in the sense
* that it is not allocated by the Lua VM.
**/
struct UserData
struct Proxy
{
bits flags; // Holds type information (see types.h).
// Holds type information (see types.h).
bits flags;
// The light userdata.
void * data;
bool own; // True if Lua should delete on GC.
// True if Lua should delete on GC.
bool own;
};
/**
* Used to store constants in arrays.
**/
struct LuaConstant
struct Constant
{
const char * name;
int value;
};
/**
* A Module with Lua wrapper functions and other data.
**/
struct WrappedModule
{
// The module containing the functions.
Module * module;
// The name for the table to put the functions in, without the 'love'-prefix.
const char * name;
// The type flags of this module.
love::bits flags;
// The functions of the module (last element {0,0}).
const luaL_Reg * functions;
// A list of functions which expose the types of the modules (last element 0).
const lua_CFunction * types;
// A list of constants (last element 0).
const Constant * constants;
};
/**
* Returns a reference to the top stack element (-1) if the value
* is of the specified type. If the value is incorrect, zero is returned.
@@ -134,22 +164,10 @@ namespace love
int luax_assert_function(lua_State * L, int idx);
/**
* Register a dummy UserData (full) for a module. This enables us to catch the
* call to __gc, and properly call the destructor on the Module in question.
* Register a module in the love table. The love table will be created if it does not exist.
* @param L The Lua state.
* @param module The Module to register the dummy UserData for.
**/
int luax_register_gc(lua_State * L, Module * module);
/**
* Register a module in the love table. The love table will created if it does not exist.
* @param L The Lua state.
* @param f The functions of the module (last element {0,0}).
* @param t A list of functions which expose the types of the modules (last element 0).
* @param c A list of constants (last element 0).
* @param name The name for the table to put the functions in, without the 'love'-prefix.
**/
int luax_register_module(lua_State * L, const luaL_Reg * f, const lua_CFunction * t, const LuaConstant * c, const char * name);
int luax_register_module(lua_State * L, const WrappedModule & m);
/**
* Inserts a module with 'name' into the package.preloaded table.
@@ -164,7 +182,7 @@ namespace love
* even from other modules.
* @param f The list of member functions for the type.
**/
int luax_register_type(lua_State * L, const char * tname, const luaL_Reg * f);
int luax_register_type(lua_State * L, const char * tname, const luaL_Reg * f = 0);
/**
* Register a new searcher function for package.loaders. This can for instance enable
@@ -189,7 +207,7 @@ namespace love
* @param L The Lua state.
* @param idx The index on the stack.
* @param type The type to check for.
* @return True if the value is UserData of the specified type, false otherwise.
* @return True if the value is Proxy of the specified type, false otherwise.
**/
bool luax_istype(lua_State * L, int idx, love::bits type);
@@ -258,11 +276,11 @@ namespace love
template <typename T>
T * luax_totype(lua_State * L, int idx, const char * name, love::bits type)
{
return (T*)(((UserData *)lua_touserdata(L, idx))->data);
return (T*)(((Proxy *)lua_touserdata(L, idx))->data);
}
/**
* Like luax_totype, but causes an error if the value at idx is not UserData,
* Like luax_totype, but causes an error if the value at idx is not Proxy,
* or is not the specified type.
* @param L The Lua state.
* @param idx The index on the stack.
@@ -275,7 +293,7 @@ namespace love
if(lua_isuserdata(L, idx) == 0)
luaL_error(L, "Incorrect parameter type: expected userdata.");
UserData * u = (UserData *)lua_touserdata(L, idx);
Proxy * u = (Proxy *)lua_touserdata(L, idx);
if((u->flags & type) != type)
luaL_error(L, "Incorrect parameter type: expected %s", name);
@@ -283,6 +301,25 @@ namespace love
return (T *)u->data;
}
template <typename T>
T * luax_getmodule(lua_State * L, const char * k, love::bits type)
{
luax_getregistry(L, REGISTRY_MODULES);
lua_getfield(L, -1, k);
if(!lua_isuserdata(L, -1))
luaL_error(L, "Tried to get nonexisting module %s.", k);
Proxy * u = (Proxy *)lua_touserdata(L, -1);
if((u->flags & type) != type)
luaL_error(L, "Incorrect module %s", k);
lua_pop(L, 2);
return (T*)u->data;
}
} // love
#endif // LOVE_RUNTIME_H
+13 -1
View File
@@ -26,11 +26,12 @@
namespace love
{
enum
enum Type
{
// Cross-module types.
OBJECT_ID = 0,
DATA_ID,
MODULE_ID,
// Filesystem.
FILESYSTEM_FILE_ID,
@@ -79,6 +80,11 @@ namespace love
PHYSICS_REVOLUTE_JOINT_ID,
PHYSICS_PULLEY_JOINT_ID,
PHYSICS_GEAR_JOINT_ID,
// The modules themselves. Only add abstracted modules here.
MODULE_FILESYSTEM_ID,
MODULE_IMAGE_ID,
MODULE_SOUND_ID,
// Count the number of bits needed.
BIT_SIZE
@@ -88,6 +94,7 @@ namespace love
const bits OBJECT_T = bits(1) << OBJECT_ID;
const bits DATA_T = (bits(1) << DATA_ID) | OBJECT_T;
const bits MODULE_T = (bits(1) << MODULE_ID) | OBJECT_T;
// Filesystem.
const bits FILESYSTEM_FILE_T = (bits(1) << FILESYSTEM_FILE_ID) | OBJECT_T;
@@ -136,6 +143,11 @@ namespace love
const bits PHYSICS_PULLEY_JOINT_T = (bits(1) << PHYSICS_PULLEY_JOINT_ID) | PHYSICS_JOINT_T;
const bits PHYSICS_GEAR_JOINT_T = (bits(1) << PHYSICS_GEAR_JOINT_ID) | PHYSICS_JOINT_T;
// Modules.
const bits MODULE_FILESYSTEM_T = (bits(1) << MODULE_FILESYSTEM_ID) | MODULE_T;
const bits MODULE_IMAGE_T = (bits(1) << MODULE_IMAGE_ID) | MODULE_T;
const bits MODULE_SOUND_T = (bits(1) << MODULE_SOUND_ID) | MODULE_T;
} // love
#endif // LOVE_TYPES_H