summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2015-05-14 08:08:32 +0800
committerDeterminant <[email protected]>2015-05-14 08:08:32 +0800
commita774bfc860471ac880a9b33bbe68761ec9187caf (patch)
tree67be5f7a04719750441845698ab7426ce9fd8a63
init
-rw-r--r--.gitignore3
-rw-r--r--.gitmodules3
-rw-r--r--Makefile18
-rwxr-xr-xinstall.sh5
-rw-r--r--luaT/README.md239
-rw-r--r--luaT/luaT.c1079
-rw-r--r--luaT/luaT.h111
m---------luajit-2.00
-rwxr-xr-xnerv2
-rw-r--r--nerv.c13
-rw-r--r--oop_example.c89
-rw-r--r--oop_example.lua7
12 files changed, 1569 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d1c2910
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+libnerv.so
+build/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..0202a2a
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "luajit-2.0"]
+ path = luajit-2.0
+ url = http://luajit.org/git/luajit-2.0.git
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..659774c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+.PHONY: all clean
+OBJS := oop_example.o nerv.o luaT.o
+INCLUDE := -I luajit-2.0/build/include/luajit-2.0/ -DLUA_USE_APICHECK
+LDFLAGS := -L luajit-2.0/build/lib/ -llua -lm
+OBJ_DIR := build/objs
+OBJS := $(addprefix $(OBJ_DIR)/,$(OBJS))
+all: libnerv.so
+$(OBJS): $(OBJ_DIR)
+$(OBJ_DIR):
+ -mkdir -p $(OBJ_DIR)
+$(OBJ_DIR)/%.o: %.c
+ gcc -c -o $@ $< $(INCLUDE) -fPIC
+$(OBJ_DIR)/luaT.o:
+ gcc -c -o $@ luaT/luaT.c $(INCLUDE) -fPIC
+libnerv.so: $(OBJS)
+ gcc -shared -o $(OBJ_DIR)/$@ $(OBJS)
+clean:
+ -rm -rf $(OBJ_DIR)
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..3b0f423
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+PREFIX="${PWD}/build"
+LUAJIT_SRC='luajit-2.0/'
+LUAJIT_PREFIX="${PREFIX}/luaJIT"
+(cd "$LUAJIT_SRC"; make && make PREFIX="$LUAJIT_PREFIX" install)
diff --git a/luaT/README.md b/luaT/README.md
new file mode 100644
index 0000000..6e9cf0d
--- /dev/null
+++ b/luaT/README.md
@@ -0,0 +1,239 @@
+<a name="luat.dok"/>
+# Lua Torch C API #
+
+luaT provides an API to interface Lua and C in Torch packages. It defines a
+concept of _classes_ to Lua for Torch, and provides a mechanism to easily
+handle these Lua classes from C.
+
+It additionally provides few functions that `luaL` should have defined, and
+defines several functions similar to `luaL` ones for better type error printing when using
+`luaT` classes.
+
+<a name="luat.memory.dok"/>
+## Memory functions ##
+
+Classical memory allocation functions which generate a Lua error in case of
+problem.
+
+<a name="luaT_alloc"/>
+### void* luaT_alloc(lua_State *L, long size) ###
+
+Allocates `size` bytes, and return a pointer on the allocated
+memory. A Lua error will be generated if running out of memory.
+
+<a name="luaT_realloc"/>
+### void* luaT_realloc(lua_State *L, void *ptr, long size) ###
+
+Realloc `ptr` to `size` bytes. `ptr` must have been previously
+allocated with [luaT_alloc](#luaT_alloc) or
+[luaT_realloc](#luaT_realloc), or the C `malloc` or `realloc`
+functions. A Lua error will be generated if running out of memory.
+
+<a name="luaT_free"/>
+### void luaT_free(lua_State *L, void *ptr) ###
+
+Free memory allocated at address `ptr`. The memory must have been
+previously allocated with [luaT_alloc](#luaT_alloc) or
+[luaT_realloc](#luaT_realloc), or the C `malloc` or `realloc`
+functions.
+
+<a name="luat.classcreate"/>
+## Class creation and basic handling ##
+
+A `luaT` class is basically either a Lua _table_ or _userdata_ with
+an appropriate _metatable_. This appropriate metatable is created with
+[luaT_newmetatable](#luaT_newmetatable). Contrary to luaL userdata
+functions, luaT mechanism handles inheritance. If the class inherit from
+another class, then the metatable will itself have a metatable
+corresponding to the _parent metatable_: the metatables are cascaded
+according to the class inheritance. Multiple inheritance is not supported.
+
+<a name="luat.operatoroverloading"/>
+### Operator overloading ###
+
+The metatable of a `luaT` object contains `Lua` operators like
+`__index`, `__newindex`, `__tostring`, `__add`
+(etc...). These operators will respectively look for `__index__`,
+`__newindex__`, `__tostring__`, `__add__` (etc...) in the
+metatable. If found, the corresponding function or value will be returned,
+else a Lua error will be raised.
+
+If one wants to provide `__index__` or `__newindex__` in the
+metaclass, these operators must follow a particular scheme:
+
+ * `__index__` must either return a value _and_ `true` or return `false` only. In the first case, it means `__index__` was able to handle the given argument (for e.g., the type was correct). The second case means it was not able to do anything, so `__index` in the root metatable can then try to see if the metaclass contains the required value.
+
+ * `__newindex__` must either return `true` or `false`. As for `__index__`, `true` means it could handle the argument and `false` not. If not, the root metatable `__newindex` will then raise an error if the object was a userdata, or apply a rawset if the object was a Lua table.
+
+Other metaclass operators like `__tostring__`, `__add__`, etc... do not have any particular constraint.
+
+<a name="luat_newmetatable"/>
+### const char* luaT_newmetatable(lua_State *L, const char *tname, const char *parenttname, lua_CFunction constructor, lua_CFunction destructor, lua_CFunction factory) ###
+
+This function creates a new metatable, which is the Lua way to define a new
+object class. As for `luaL_newmetatable`, the metatable is registered in
+the Lua registry table, with the key `tname`. In addition, `tname` is
+also registered in the Lua registry, with the metatable as key (the
+typename of a given object can be thus easily retrieved).
+
+The class name `tname` must be of the form `modulename.classname`. The module name
+If not NULL, `parenttname` must be a valid typename corresponding to the
+parent class of the new class.
+
+If not NULL, `constructor`, a function `new` will be added to the metatable, pointing to this given function. The constructor might also
+be called through `modulename.classname()`, which is an alias setup by `luaT_metatable`.
+
+If not NULL, `destructor` will be called when garbage collecting the object.
+
+If not NULL, `factory` must be a Lua C function creating an empty object
+instance of the class. This functions are used in Torch for serialization.
+
+Note that classes can be partly defined in C and partly defined in Lua:
+once the metatable is created in C, it can be filled up with additional
+methods in Lua.
+
+The return value is the value returned by [luaT_typenameid](#luat_typenameid).
+
+<a name="luat_pushmetatable"/>
+### int luaT_pushmetatable(lua_State *L, const name *tname) ###
+
+Push the metatable with type name `tname` on the stack, it `tname` is a
+valid Torch class name (previously registered with luaT_newmetatable).
+
+On success, returns 1. If `tname` is invalid, nothing is pushed and it
+returns 0.
+
+<a name="luat_typenameid"/>
+### const char* luaT_typenameid(lua_State *L, const char *tname) ###
+
+If `tname` is a valid Torch class name, then returns a unique string (the
+contents will be the same than `tname`) pointing on the string registered
+in the Lua registry. This string is thus valid as long as Lua is
+running. The returned string shall not be freed.
+
+If `tname` is an invalid class name, returns NULL.
+
+<a name="luat_typename"/>
+### const char* luaT_typename(lua_State *L, int ud) ###
+
+Returns the typename of the object at index `ud` on the stack. If it is
+not a valid Torch object, returns NULL.
+
+<a name="luat_pushudata"/>
+### void luaT_pushudata(lua_State *L, void *udata, const char *tname) ###
+
+Given a C structure `udata`, push a userdata object on the stack with
+metatable corresponding to `tname`. Obviously, `tname` must be a valid
+Torch name registered with [luaT_newmetatable](#luat_newmetatable).
+
+<a name="luat_toudata"/>
+### void *luaT_toudata(lua_State *L, int ud, const char *tname) ###
+
+Returns a pointer to the original C structure previously pushed on the
+stack with [luaT_pushudata](#luat_pushudata), if the object at index
+`ud` is a valid Torch class name. Returns NULL otherwise.
+
+<a name="luat_isudata"/>
+### int luaT_isudata(lua_State *L, int ud, const char *tname) ###
+
+Returns 1 if the object at index `ud` on the stack is a valid Torch class name `tname`.
+Returns 0 otherwise.
+
+<a name="luat_getfield"/>
+### Checking fields of a table ###
+
+This functions check that the table at the given index `ud` on the Lua
+stack has a field named `field`, and that it is of the specified type.
+These function raises a Lua error on failure.
+
+<a name="luat_getfieldcheckudata"/>
+## void *luaT_getfieldcheckudata(lua_State *L, int ud, const char *field, const char *tname) ##
+
+Checks that the field named `field` of the table at index `ud` is a
+Torch class name `tname`. Returns the pointer of the C structure
+previously pushed on the stack with [luaT_pushudata](#luat_pushudata) on
+success. The function raises a Lua error on failure.
+
+<a name="luat_getfieldchecklightudata"/>
+## void *luaT_getfieldchecklightudata(lua_State *L, int ud, const char *field) ##
+
+Checks that the field named `field` of the table at index `ud` is a
+lightuserdata. Returns the lightuserdata pointer on success. The function
+raises a Lua error on failure.
+
+<a name="luat_getfieldcheckint"/>
+## int luaT_getfieldcheckint(lua_State *L, int ud, const char *field) ##
+
+Checks that the field named `field` of the table at index `ud` is an
+int. Returns the int value pointer on success. The function raises a Lua
+error on failure.
+
+<a name="luat_getfieldcheckstring"/>
+## const char* luaT_getfieldcheckstring(lua_State *L, int ud, const char *field) ##
+
+Checks that the field named `field` of the table at index `ud` is a
+string. Returns a pointer to the string on success. The function raises a
+Lua error on failure.
+
+<a name="luat_getfieldcheckboolean"/>
+## int luaT_getfieldcheckboolean(lua_State *L, int ud, const char *field) ##
+
+Checks that the field named `field` of the table at index `ud` is a
+boolean. On success, returns 1 if the boolean is `true`, 0 if it is
+`false`. The function raises a Lua error on failure.
+
+<a name="luat_getfieldchecktable"/>
+## void luaT_getfieldchecktable(lua_State *L, int ud, const char *field) ##
+
+Checks that the field named `field` of the table at index `ud` is a
+table. On success, push the table on the stack. The function raises a Lua
+error on failure.
+
+<a name="luat_typerror"/>
+### int luaT_typerror(lua_State *L, int ud, const char *tname) ###
+
+Raises a `luaL_argerror` (and returns its value), claiming that the
+object at index `ud` on the stack is not of type `tname`. Note that
+this function does not check the type, it only raises an error.
+
+<a name="luat_checkboolean"/>
+### int luaT_checkboolean(lua_State *L, int ud) ###
+
+Checks that the value at index `ud` is a boolean. On success, returns 1
+if the boolean is `true`, 0 if it is `false`. The function raises a Lua
+error on failure.
+
+<a name="luat_optboolean"/>
+### int luaT_optboolean(lua_State *L, int ud, int def) ###
+
+Checks that the value at index `ud` is a boolean. On success, returns 1
+if the boolean is `true`, 0 if it is `false`. If there is no value at
+index `ud`, returns `def`. In any other cases, raises an error.
+
+<a name="luat_registeratname"/>
+### void luaT_registeratname(lua_State *L, const struct luaL_Reg *methods, const char *name) ###
+
+This function assume a table is on the stack. It creates a table field
+`name` in the table (if this field does not exist yet), and fill up
+`methods` in this table field.
+
+<a name="luat_classrootname"/>
+### const char *luaT_classrootname(const char *tname) ###
+
+Assuming `tname` is of the form `modulename.classname`, returns
+`classname`. The returned value shall not be freed. It is a pointer
+inside `tname` string.
+
+<a name="luat_classmodulename"/>
+### const char *luaT_classmodulename(const char *tname) ###
+
+Assuming `tname` is of the form `modulename.classname`, returns
+`modulename`. The returned value shall not be freed. It is valid until the
+next call to `luaT_classrootname`.
+
+<a name="luat_stackdump"/>
+### void luaT_stackdump(lua_State *L) ###
+
+This function print outs the state of the Lua stack. It is useful for debug
+purposes.
+
diff --git a/luaT/luaT.c b/luaT/luaT.c
new file mode 100644
index 0000000..7b85ce3
--- /dev/null
+++ b/luaT/luaT.c
@@ -0,0 +1,1079 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "luaT.h"
+
+void* luaT_alloc(lua_State *L, long size)
+{
+ void *ptr;
+
+ if(size == 0)
+ return NULL;
+
+ if(size < 0)
+ luaL_error(L, "$ Torch: invalid memory size -- maybe an overflow?");
+
+ ptr = malloc(size);
+ if(!ptr)
+ luaL_error(L, "$ Torch: not enough memory: you tried to allocate %dGB. Buy new RAM!", size/1073741824);
+
+ return ptr;
+}
+
+void* luaT_realloc(lua_State *L, void *ptr, long size)
+{
+ if(!ptr)
+ return(luaT_alloc(L, size));
+
+ if(size == 0)
+ {
+ luaT_free(L, ptr);
+ return NULL;
+ }
+
+ if(size < 0)
+ luaL_error(L, "$ Torch: invalid memory size -- maybe an overflow?");
+
+ ptr = realloc(ptr, size);
+ if(!ptr)
+ luaL_error(L, "$ Torch: not enough memory: you tried to reallocate %dGB. Buy new RAM!", size/1073741824);
+ return ptr;
+}
+
+void luaT_free(lua_State *L, void *ptr)
+{
+ free(ptr);
+}
+
+void luaT_stackdump(lua_State *L)
+{
+ int i;
+ const char *tname = NULL;
+ int top = lua_gettop(L);
+ for(i = 1; i <= top; i++)
+ {
+ int t = lua_type(L, i);
+ printf("%3d. ", i);
+ switch(t)
+ {
+ case LUA_TSTRING:
+ printf("'%s'", lua_tostring(L,i));
+ break;
+ case LUA_TBOOLEAN:
+ printf(lua_toboolean(L, i) ? "true" : "false");
+ break;
+ case LUA_TNUMBER:
+ printf("%g", lua_tonumber(L,i));
+ break;
+ case LUA_TUSERDATA:
+ tname = luaT_typename(L, i);
+ printf("userdata %lx [%s]", (long)lua_topointer(L, i), (tname ? tname : "not a Torch object"));
+ break;
+ case 10:
+ tname = luaT_typename(L, i);
+ printf("cdata %lx [%s]", (long)lua_topointer(L, i), (tname ? tname : "not a Torch object"));
+ break;
+ case LUA_TTABLE:
+ lua_pushvalue(L, i);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if(lua_isstring(L, -1))
+ tname = lua_tostring(L, -1); /*luaT_typenameid(L, lua_tostring(L, -1)); */
+ else
+ tname = NULL;
+ lua_pop(L, 1);
+ if(tname)
+ printf("metatable [%s]", tname);
+ else
+ {
+ tname = luaT_typename(L, i);
+ printf("table %lx [%s]", (long)lua_topointer(L, i), (tname ? tname : "not a Torch object"));
+ }
+ break;
+ default:
+ printf("Lua object type: %s", lua_typename(L,t));
+ break;
+ }
+ printf("\n");
+ }
+ printf("---------------------------------------------\n");
+}
+
+/* metatable operator methods */
+static int luaT_mt__index(lua_State *L);
+static int luaT_mt__newindex(lua_State *L);
+static int luaT_mt__tostring(lua_State *L);
+static int luaT_mt__add(lua_State *L);
+static int luaT_mt__sub(lua_State *L);
+static int luaT_mt__mul(lua_State *L);
+static int luaT_mt__div(lua_State *L);
+static int luaT_mt__mod(lua_State *L);
+static int luaT_mt__pow(lua_State *L);
+static int luaT_mt__unm(lua_State *L);
+static int luaT_mt__concat(lua_State *L);
+static int luaT_mt__len(lua_State *L);
+static int luaT_mt__eq(lua_State *L);
+static int luaT_mt__lt(lua_State *L);
+static int luaT_mt__le(lua_State *L);
+static int luaT_mt__call(lua_State *L);
+
+/* Constructor-metatable methods */
+static int luaT_cmt__call(lua_State *L);
+static int luaT_cmt__newindex(lua_State *L);
+
+const char* luaT_newmetatable(lua_State *L, const char *tname, const char *parenttname,
+ lua_CFunction constructor, lua_CFunction destructor, lua_CFunction factory)
+{
+ lua_pushcfunction(L, luaT_lua_newmetatable);
+ lua_pushstring(L, tname);
+ (parenttname ? lua_pushstring(L, parenttname) : lua_pushnil(L));
+ (constructor ? lua_pushcfunction(L, constructor) : lua_pushnil(L));
+ (destructor ? lua_pushcfunction(L, destructor) : lua_pushnil(L));
+ (factory ? lua_pushcfunction(L, factory) : lua_pushnil(L));
+ lua_call(L, 5, 1);
+ return luaT_typenameid(L, tname);
+}
+
+int luaT_pushmetatable(lua_State *L, const char *tname)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, tname);
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ return 0;
+ }
+ return 1;
+}
+
+const char *luaT_typenameid(lua_State *L, const char *tname)
+{
+ if(luaT_pushmetatable(L, tname))
+ {
+ const char *tnameid = NULL;
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if(lua_isstring(L, -1))
+ tnameid = lua_tostring(L, -1);
+ lua_pop(L, 1); /* the string/nil */
+ return tnameid;
+ }
+ return NULL;
+}
+
+static const char cdataname[] = ""
+ "local _, ffi = pcall(require, 'ffi')\n"
+ "if ffi then\n"
+ " local id2name = {}\n"
+ " return function(cdata, name)\n"
+ " local id = tonumber(ffi.typeof(cdata))\n"
+ " if id then\n"
+ " if name then\n"
+ " id2name[id] = name\n"
+ " return name\n"
+ " else\n"
+ " return rawget(id2name, id)\n"
+ " end\n"
+ " end\n"
+ " return nil\n"
+ " end\n"
+ "else\n"
+ " return function() end\n"
+ "end\n";
+
+static const char* luaT_cdataname(lua_State *L, int ud, const char *tname)
+{
+ lua_pushstring(L, "__cdataname");
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if(lua_isnil(L,-1))
+ {
+ lua_pop(L, 1);
+
+ if(luaL_dostring(L, cdataname)) /* did something go wrong? */
+ luaL_error(L, "internal error (could not load cdataname): %s", lua_tostring(L, -1));
+
+ lua_pushstring(L, "__cdataname");
+ lua_pushvalue(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ if(!lua_isfunction(L, -1)) /* should not happen */
+ luaL_error(L, "internal error (cdataname is not a function)");
+
+ lua_pushvalue(L, ud);
+ if(tname)
+ lua_pushstring(L, tname);
+ if(lua_pcall(L, (tname ? 2 : 1), 1, 0))
+ luaL_error(L, "internal error (cdataname): %s", lua_tostring(L, -1));
+
+ tname = lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ return tname;
+}
+
+const char* luaT_typename(lua_State *L, int ud)
+{
+ if(lua_type(L, ud) == 10)
+ return luaT_cdataname(L, ud, NULL);
+ else if(lua_getmetatable(L, ud))
+ {
+ const char *tname = NULL;
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if(lua_isstring(L, -1))
+ tname = lua_tostring(L, -1);
+ lua_pop(L, 1); /* the string/nil */
+ return tname;
+ }
+ return NULL;
+}
+
+void luaT_pushudata(lua_State *L, void *udata, const char *tname)
+{
+ if(udata)
+ {
+ void **udata_p = lua_newuserdata(L, sizeof(void*));
+ *udata_p = udata;
+ if(!luaT_pushmetatable(L, tname))
+ luaL_error(L, "Torch internal problem: cannot find metatable for type <%s>", tname);
+ lua_setmetatable(L, -2);
+ }
+ else
+ lua_pushnil(L);
+}
+
+void *luaT_toudata(lua_State *L, int ud, const char *tname)
+{
+ void **p = lua_touserdata(L, ud);
+ if(p != NULL) /* value is a userdata? */
+ {
+ if(!luaT_pushmetatable(L, tname))
+ luaL_error(L, "Torch internal problem: cannot find metatable for type <%s>", tname);
+
+ /* initialize the table we want to get the metatable on */
+ /* note that we have to be careful with indices, as we just inserted stuff */
+ lua_pushvalue(L, (ud < 0 ? ud - 1 : ud));
+ while(lua_getmetatable(L, -1)) /* get the next metatable */
+ {
+ lua_remove(L, -2); /* remove the previous metatable [or object, if first time] */
+ if(lua_rawequal(L, -1, -2))
+ {
+ lua_pop(L, 2); /* remove the two metatables */
+ return *p;
+ }
+ }
+ lua_pop(L, 2); /* remove the two metatables */
+ }
+ return NULL;
+}
+
+int luaT_isudata(lua_State *L, int ud, const char *tname)
+{
+ if(luaT_toudata(L, ud, tname))
+ return 1;
+ else
+ return 0;
+}
+
+void *luaT_checkudata(lua_State *L, int ud, const char *tname)
+{
+ void *p = luaT_toudata(L, ud, tname);
+ if(!p)
+ luaT_typerror(L, ud, tname);
+ return p;
+}
+
+void *luaT_getfieldcheckudata(lua_State *L, int ud, const char *field, const char *tname)
+{
+ void *p;
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+ p = luaT_toudata(L, -1, tname);
+ if(!p)
+ luaL_error(L, "bad argument #%d (field %s is not a %s)", ud, field, tname);
+ return p;
+}
+
+void *luaT_getfieldchecklightudata(lua_State *L, int ud, const char *field)
+{
+ void *p;
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+
+ if(!lua_islightuserdata(L, -1))
+ luaL_error(L, "bad argument #%d (field %s is not a light userdata)", ud, field);
+
+ p = lua_touserdata(L, -1);
+
+ return p;
+}
+
+double luaT_getfieldchecknumber(lua_State *L, int ud, const char *field)
+{
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+ if(!lua_isnumber(L, -1))
+ luaL_error(L, "bad argument #%d (field %s is not a number)", ud, field);
+ return lua_tonumber(L, -1);
+}
+
+int luaT_getfieldcheckint(lua_State *L, int ud, const char *field)
+{
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+ if(!lua_isnumber(L, -1))
+ luaL_error(L, "bad argument #%d (field %s is not a number)", ud, field);
+ return (int)lua_tonumber(L, -1);
+}
+
+const char* luaT_getfieldcheckstring(lua_State *L, int ud, const char *field)
+{
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+ if(!lua_isstring(L, -1))
+ luaL_error(L, "bad argument #%d (field %s is not a string)", ud, field);
+ return lua_tostring(L, -1);
+}
+
+int luaT_getfieldcheckboolean(lua_State *L, int ud, const char *field)
+{
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+ if(!lua_isboolean(L, -1))
+ luaL_error(L, "bad argument #%d (field %s is not a boolean)", ud, field);
+ return lua_toboolean(L, -1);
+}
+
+void luaT_getfieldchecktable(lua_State *L, int ud, const char *field)
+{
+ lua_getfield(L, ud, field);
+ if(lua_isnil(L, -1))
+ luaL_error(L, "bad argument #%d (field %s does not exist)", ud, field);
+ if(!lua_istable(L, -1))
+ luaL_error(L, "bad argument #%d (field %s is not a table)", ud, field);
+}
+
+/**** type checks as in luaL ****/
+int luaT_typerror(lua_State *L, int ud, const char *tname)
+{
+ const char *msg;
+ const char *tnameud = luaT_typename(L, ud);
+
+ if(!tnameud)
+ tnameud = lua_typename(L, ud);
+
+ msg = lua_pushfstring(L, "%s expected, got %s",
+ tname,
+ (tnameud ? tnameud : "unknown object"));
+
+ return luaL_argerror(L, ud, msg);
+}
+
+int luaT_checkboolean(lua_State *L, int ud)
+{
+ if(!lua_isboolean(L, ud))
+ luaT_typerror(L, ud, lua_typename(L, LUA_TBOOLEAN));
+ return lua_toboolean(L, ud);
+}
+
+int luaT_optboolean(lua_State *L, int ud, int def)
+{
+ if(lua_isnoneornil(L,ud))
+ return def;
+
+ return luaT_checkboolean(L, ud);
+}
+
+void luaT_registeratname(lua_State *L, const struct luaL_Reg *methods, const char *name)
+{
+ int idx = lua_gettop(L);
+
+ luaL_checktype(L, idx, LUA_TTABLE);
+ lua_pushstring(L, name);
+ lua_rawget(L, idx);
+
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+ lua_pushstring(L, name);
+ lua_newtable(L);
+ lua_rawset(L, idx);
+
+ lua_pushstring(L, name);
+ lua_rawget(L, idx);
+ }
+
+ luaL_register(L, NULL, methods);
+ lua_pop(L, 1);
+}
+
+
+/* utility functions */
+const char *luaT_classrootname(const char *tname)
+{
+ int i;
+ int sz = strlen(tname);
+
+ for(i = 0; i < sz; i++)
+ {
+ if(tname[i] == '.')
+ return tname+i+1;
+ }
+ return tname;
+}
+
+/* module_name must be a buffer at least as big as tname
+ * return true if the class is part of a module */
+int luaT_classmodulename(const char *tname, char *module_name)
+{
+ char chars[] = {'.', '\0'};
+ size_t n;
+ n = strcspn(tname, chars);
+ strncpy(module_name, tname, n);
+ module_name[n] = '\0';
+ return tname[n] == '.';
+}
+
+/* Lua only functions */
+int luaT_lua_newmetatable(lua_State *L)
+{
+ const char* tname = luaL_checkstring(L, 1);
+ char module_name[256];
+ int is_in_module = 0;
+ is_in_module = luaT_classmodulename(tname, module_name);
+
+ lua_settop(L, 5);
+ luaL_argcheck(L, lua_isnoneornil(L, 2) || lua_isstring(L, 2), 2, "parent class name or nil expected");
+ luaL_argcheck(L, lua_isnoneornil(L, 3) || lua_isfunction(L, 3), 3, "constructor function or nil expected");
+ luaL_argcheck(L, lua_isnoneornil(L, 4) || lua_isfunction(L, 4), 4, "destructor function or nil expected");
+ luaL_argcheck(L, lua_isnoneornil(L, 5) || lua_isfunction(L, 5), 5, "factory function or nil expected");
+
+ if(is_in_module)
+ lua_getfield(L, LUA_GLOBALSINDEX, module_name);
+ else
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ if(!lua_istable(L, 6))
+ luaL_error(L, "while creating metatable %s: bad argument #1 (%s is an invalid module name)", tname, module_name);
+
+ /* we first create the new metaclass if we have to */
+ if(!luaT_pushmetatable(L, tname))
+ {
+ /* create the metatable */
+ lua_newtable(L);
+
+ /* registry[name] = metatable */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, LUA_REGISTRYINDEX, tname);
+
+ /* registry[metatable] = tname */
+ lua_pushvalue(L, -1);
+ lua_pushstring(L, tname);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ /* __index handling */
+ lua_pushcfunction(L, luaT_mt__index);
+ lua_setfield(L, -2, "__index");
+
+ /* __newindex handling */
+ lua_pushcfunction(L, luaT_mt__newindex);
+ lua_setfield(L, -2, "__newindex");
+
+ /* __typename contains the typename */
+ lua_pushstring(L, tname);
+ lua_setfield(L, -2, "__typename");
+
+ /* __metatable is self */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__metatable");
+
+ /* by default, __version equals 1 */
+ lua_pushnumber(L, 1);
+ lua_setfield(L, -2, "__version");
+
+ /* assign default operator functions */
+ lua_pushcfunction(L, luaT_mt__tostring);
+ lua_setfield(L, -2, "__tostring");
+
+ lua_pushcfunction(L, luaT_mt__add);
+ lua_setfield(L, -2, "__add");
+
+ lua_pushcfunction(L, luaT_mt__sub);
+ lua_setfield(L, -2, "__sub");
+
+ lua_pushcfunction(L, luaT_mt__mul);
+ lua_setfield(L, -2, "__mul");
+
+ lua_pushcfunction(L, luaT_mt__div);
+ lua_setfield(L, -2, "__div");
+
+ lua_pushcfunction(L, luaT_mt__mod);
+ lua_setfield(L, -2, "__mod");
+
+ lua_pushcfunction(L, luaT_mt__pow);
+ lua_setfield(L, -2, "__pow");
+
+ lua_pushcfunction(L, luaT_mt__unm);
+ lua_setfield(L, -2, "__unm");
+
+ lua_pushcfunction(L, luaT_mt__concat);
+ lua_setfield(L, -2, "__concat");
+
+ lua_pushcfunction(L, luaT_mt__len);
+ lua_setfield(L, -2, "__len");
+
+ lua_pushcfunction(L, luaT_mt__eq);
+ lua_setfield(L, -2, "__eq");
+
+ lua_pushcfunction(L, luaT_mt__lt);
+ lua_setfield(L, -2, "__lt");
+
+ lua_pushcfunction(L, luaT_mt__le);
+ lua_setfield(L, -2, "__le");
+
+ lua_pushcfunction(L, luaT_mt__call);
+ lua_setfield(L, -2, "__call");
+ }
+
+ /* we assign the parent class if necessary */
+ if(!lua_isnoneornil(L, 2))
+ {
+ if(lua_getmetatable(L, -1))
+ luaL_error(L, "class %s has been already assigned a parent class\n", tname);
+ else
+ {
+ const char* parenttname = luaL_checkstring(L, 2);
+ if(!luaT_pushmetatable(L, parenttname))
+ luaL_error(L, "bad argument #2 (invalid parent class name %s)", parenttname);
+ lua_setmetatable(L, -2);
+ }
+ }
+
+ /* register the destructor function */
+ if(!lua_isnoneornil(L, 4))
+ {
+ /* does it exists already? */
+ lua_pushstring(L, "__gc");
+ lua_rawget(L, -2);
+
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1); /* pop nil */
+ lua_pushstring(L, "__gc");
+ lua_pushvalue(L, 4);
+ lua_rawset(L, -3);
+ }
+ else
+ luaL_error(L, "%s has been already assigned a destructor", tname);
+ }
+
+ /* register the factory function */
+ if(!lua_isnoneornil(L, 5))
+ {
+ /* does it exists already? */
+ lua_pushstring(L, "__factory");
+ lua_rawget(L, -2);
+
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1); /* pop nil */
+ lua_pushstring(L, "__factory");
+ lua_pushvalue(L, 5);
+ lua_rawset(L, -3);
+ }
+ else
+ luaL_error(L, "%s has been already assigned a factory", tname);
+ }
+
+ /******** Constructor table and metatable ********/
+ lua_pushstring(L, "__constructor");
+ lua_rawget(L, -2);
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1); /* pop nil */
+ lua_newtable(L); /* fancy table */
+ lua_newtable(L); /* fancy metatable */
+
+ lua_pushvalue(L, -3); /* metatable */
+ lua_setfield(L, -2, "__index"); /* so we can get the methods */
+
+ lua_pushcfunction(L, luaT_cmt__newindex);
+ lua_setfield(L, -2, "__newindex"); /* so we add new methods */
+
+ lua_pushcfunction(L, luaT_cmt__call);
+ lua_setfield(L, -2, "__call"); /* so we can create, we are here for only that */
+
+ lua_pushvalue(L, -3);
+ lua_setfield(L, -2, "__metatable"); /* redirect to metatable with methods */
+
+ lua_setmetatable(L, -2); /* constructor metatable is ... this fancy metatable */
+
+ /* set metatable[__constructor] = constructor-metatable */
+ lua_pushstring(L, "__constructor");
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -4);
+ }
+
+ /* register the constructor function */
+ if(!lua_isnoneornil(L, 3))
+ {
+ /* get constructor metatable */
+ lua_getmetatable(L, -1);
+
+ /* does it exists already? */
+ lua_pushstring(L, "__new");
+ lua_rawget(L, -2);
+
+ if(lua_isnil(L, -1))
+ {
+ lua_pop(L, 1); /* pop nil */
+ lua_pushstring(L, "__new");
+ lua_pushvalue(L, 3);
+ lua_rawset(L, -3);
+
+ /* set "new" in the metatable too */
+ lua_pushstring(L, "new");
+ lua_pushvalue(L, 3);
+ lua_rawset(L, -5);
+ }
+ else
+ luaL_error(L, "%s has been already assigned a constructor", tname);
+
+ /* pop constructor metatable */
+ lua_pop(L, 1);
+ }
+
+ /* module.name = constructor metatable */
+ lua_setfield(L, 6, luaT_classrootname(tname));
+
+ return 1; /* returns the metatable */
+}
+
+/* Lua only utility functions */
+
+/* add any custom type, provided the object has a metatable */
+int luaT_lua_metatype(lua_State *L)
+{
+ if( (lua_gettop(L) != 2) && (lua_gettop(L) != 3) )
+ luaL_error(L, "expecting: string table [ctype]");
+
+ luaL_checkstring(L, 1);
+ luaL_checktype(L, 2, LUA_TTABLE);
+
+ if(lua_gettop(L) == 3)
+ {
+ if(!luaT_cdataname(L, 3, lua_tostring(L, 1)))
+ luaL_error(L, "could not register cdata type -- missing ffi library?");
+ }
+
+ /* registry[name] = metatable */
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ /* registry[metatable] = tname */
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, 1);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ return 0;
+}
+
+/* return a userdata from a C pointer */
+/* you are better to know what you are doing */
+int luaT_lua_pushudata(lua_State *L)
+{
+ void *udata = NULL;
+ const char *tname = luaL_checkstring(L, 2);
+
+ if(lua_type(L, 1) == 10)
+ udata = *((void**)lua_topointer(L, 1));
+ else if(lua_isnumber(L, 1))
+ udata = (void*)(long)lua_tonumber(L, 1);
+ else
+ luaL_argerror(L, 1, "expecting number or cdata");
+
+ luaT_pushudata(L, udata, tname);
+
+ return 1;
+}
+
+int luaT_lua_factory(lua_State *L)
+{
+ const char* tname = luaL_checkstring(L, 1);
+ if(luaT_pushmetatable(L, tname) && !lua_isnil(L, -1))
+ {
+ lua_pushstring(L, "__factory");
+ lua_rawget(L, -2);
+ }
+ else
+ {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+int luaT_lua_getconstructortable(lua_State *L)
+{
+ const char* tname = luaL_checkstring(L, 1);
+ if(luaT_pushmetatable(L, tname))
+ {
+ lua_pushstring(L, "__constructor");
+ lua_rawget(L, -2);
+ return 1;
+ }
+ return 0;
+}
+
+
+int luaT_lua_typename(lua_State *L)
+{
+ const char* tname = NULL;
+ luaL_checkany(L, 1);
+ if((tname = luaT_typename(L, 1)))
+ {
+ lua_pushstring(L, tname);
+ return 1;
+ }
+ return 0;
+}
+
+int luaT_lua_isequal(lua_State *L)
+{
+ if(lua_isuserdata(L, 1) && lua_isuserdata(L, 2))
+ {
+ void **u1, **u2;
+ luaL_argcheck(L, luaT_typename(L, 1), 1, "Torch object expected");
+ luaL_argcheck(L, luaT_typename(L, 2), 2, "Torch object expected");
+
+ u1 = lua_touserdata(L, 1);
+ u2 = lua_touserdata(L, 2);
+ if(*u1 == *u2)
+ lua_pushboolean(L, 1);
+ else
+ lua_pushboolean(L, 0);
+ }
+ else if(lua_istable(L, 1) && lua_istable(L, 2))
+ lua_pushboolean(L, lua_rawequal(L, 1, 2));
+ else
+ lua_pushboolean(L, 0);
+ return 1;
+}
+
+int luaT_lua_pointer(lua_State *L)
+{
+ if(lua_isuserdata(L, 1))
+ {
+ void **ptr;
+ luaL_argcheck(L, luaT_typename(L, 1), 1, "Torch object expected");
+ ptr = lua_touserdata(L, 1);
+ lua_pushnumber(L, (long)(*ptr));
+ return 1;
+ }
+ else if(lua_istable(L, 1) || lua_isthread(L, 1) || lua_isfunction(L, 1))
+ {
+ const void* ptr = lua_topointer(L, 1);
+ lua_pushnumber(L, (long)(ptr));
+ return 1;
+ }
+ else if(lua_type(L, 1) == 10) /* cdata */
+ {
+ /* we want the pointer holded by cdata */
+ /* not the pointer on the cdata object */
+ const void* ptr = *((void**)lua_topointer(L, 1));
+ lua_pushnumber(L, (long)(ptr));
+ return 1;
+ }
+ else if(lua_isstring(L, 1))
+ {
+ const char* ptr = lua_tostring(L, 1);
+ lua_pushnumber(L, (long)(ptr));
+ return 1;
+ }
+ else
+ luaL_error(L, "Torch object, table, thread, cdata or function expected");
+
+ return 0;
+}
+
+int luaT_lua_setenv(lua_State *L)
+{
+ if(!lua_isfunction(L, 1) && !lua_isuserdata(L, 1))
+ luaL_typerror(L, 1, "function or userdata");
+ luaL_checktype(L, 2, LUA_TTABLE);
+ lua_setfenv(L, 1);
+ return 0;
+}
+
+int luaT_lua_getenv(lua_State *L)
+{
+ if(!lua_isfunction(L, 1) && !lua_isuserdata(L, 1))
+ luaL_typerror(L, 1, "function or userdata");
+ lua_getfenv(L, 1);
+ return 1;
+}
+
+int luaT_lua_getmetatable(lua_State *L)
+{
+ const char *tname = luaL_checkstring(L, 1);
+ if(luaT_pushmetatable(L, tname))
+ return 1;
+ return 0;
+}
+
+int luaT_lua_version(lua_State *L)
+{
+ luaL_checkany(L, 1);
+
+ if(lua_type(L, 1) == 10)
+ {
+ const char *tname = luaT_cdataname(L, 1, NULL);
+ if(tname)
+ {
+ luaT_pushmetatable(L, tname);
+ lua_pushstring(L, "__version");
+ lua_rawget(L, -2);
+ return 1;
+ }
+ return 0;
+ }
+ else if(lua_getmetatable(L, 1))
+ {
+ lua_pushstring(L, "__version");
+ lua_rawget(L, -2);
+ return 1;
+ }
+ return 0;
+}
+
+int luaT_lua_setmetatable(lua_State *L)
+{
+ const char *tname = luaL_checkstring(L, 2);
+ luaL_checktype(L, 1, LUA_TTABLE);
+
+ if(!luaT_pushmetatable(L, tname))
+ luaL_error(L, "unknown typename %s\n", tname);
+ lua_setmetatable(L, 1);
+
+ return 1;
+}
+
+/* metatable operator methods */
+static int luaT_mt__index(lua_State *L)
+{
+ if(!lua_getmetatable(L, 1))
+ luaL_error(L, "critical internal indexing error: no metatable found");
+
+ if(!lua_istable(L, -1))
+ luaL_error(L, "critical internal indexing error: not a metatable");
+
+ /* test for __index__ method first */
+ lua_getfield(L, -1, "__index__");
+ if(!lua_isnil(L, -1))
+ {
+ int result;
+
+ if(!lua_isfunction(L, -1))
+ luaL_error(L, "critical internal indexing error: __index__ is not a function");
+
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+
+ lua_call(L, 2, LUA_MULTRET); /* DEBUG: risque: faut vraiment retourner 1 ou 2 valeurs... */
+
+ result = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+
+ if(result)
+ return 1;
+
+ /* on the stack: 1. the object 2. the value 3. the metatable */
+ /* apparently, __index wants only one element returned */
+ /* return lua_gettop(L)-3; */
+
+ }
+ else
+ lua_pop(L, 1); /* remove nil __index__ on the stack */
+
+ lua_pushvalue(L, 2);
+ lua_gettable(L, -2);
+
+ return 1;
+}
+
+static int luaT_mt__newindex(lua_State *L)
+{
+ if(!lua_getmetatable(L, 1))
+ luaL_error(L, "critical internal indexing error: no metatable found");
+
+ if(!lua_istable(L, -1))
+ luaL_error(L, "critical internal indexing error: not a metatable");
+
+ /* test for __newindex__ method first */
+ lua_getfield(L, -1, "__newindex__");
+ if(!lua_isnil(L, -1))
+ {
+ int result;
+
+ if(!lua_isfunction(L, -1))
+ luaL_error(L, "critical internal indexing error: __newindex__ is not a function");
+
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, 3);
+
+ lua_call(L, 3, 1); /* DEBUG: risque: faut vraiment retourner qqch */
+
+ result = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+
+ if(result)
+ return 0;
+ }
+ else
+ lua_pop(L, 1); /* remove nil __newindex__ on the stack */
+
+ lua_pop(L, 1); /* pop the metatable */
+ if(lua_istable(L, 1))
+ lua_rawset(L, 1);
+ else
+ luaL_error(L, "the class %s cannot be indexed", luaT_typename(L, 1));
+
+ return 0;
+}
+
+/* note: check dans metatable pour ca, donc necessaire */
+#define MT_DECLARE_OPERATOR(NAME, NIL_BEHAVIOR) \
+ int luaT_mt__##NAME(lua_State *L) \
+ { \
+ if(!lua_getmetatable(L, 1)) \
+ luaL_error(L, "internal error in __" #NAME ": no metatable"); \
+ \
+ lua_getfield(L, -1, "__" #NAME "__"); \
+ if(lua_isnil(L, -1)) \
+ { \
+ NIL_BEHAVIOR; \
+ } \
+ else \
+ { \
+ if(lua_isfunction(L, -1)) \
+ { \
+ lua_insert(L, 1); /* insert function */ \
+ lua_pop(L, 1); /* remove metatable */ \
+ lua_call(L, lua_gettop(L)-1, LUA_MULTRET); /* we return the result of the call */ \
+ return lua_gettop(L); \
+ } \
+ /* we return the thing the user left in __tostring__ */ \
+ } \
+ return 0; \
+ }
+
+MT_DECLARE_OPERATOR(tostring,
+ lua_pushstring(L, luaT_typename(L, 1));
+ return 1;)
+MT_DECLARE_OPERATOR(add, luaL_error(L, "%s has no addition operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(sub, luaL_error(L, "%s has no substraction operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(mul, luaL_error(L, "%s has no multiplication operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(div, luaL_error(L, "%s has no division operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(mod, luaL_error(L, "%s has no modulo operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(pow, luaL_error(L, "%s has no power operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(unm, luaL_error(L, "%s has no negation operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(concat, luaL_error(L, "%s has no concat operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(len, luaL_error(L, "%s has no length operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(eq,
+ lua_settop(L, 2);
+ lua_pushcfunction(L, luaT_lua_isequal);
+ lua_insert(L, 1);
+ lua_call(L, 2, 1);
+ return 1;)
+MT_DECLARE_OPERATOR(lt, luaL_error(L, "%s has no lower than operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(le, luaL_error(L, "%s has no lower or equal than operator", luaT_typename(L, 1)))
+MT_DECLARE_OPERATOR(call, luaL_error(L, "%s has no call operator", luaT_typename(L, 1)))
+
+
+/* constructor metatable methods */
+int luaT_cmt__call(lua_State *L)
+{
+ if(!lua_istable(L, 1))
+ luaL_error(L, "internal error in __call: not a constructor table");
+
+ if(!lua_getmetatable(L, 1))
+ luaL_error(L, "internal error in __call: no metatable available");
+
+ lua_pushstring(L, "__new");
+ lua_rawget(L, -2);
+
+ if(lua_isnil(L, -1))
+ luaL_error(L, "no constructor available");
+
+ lua_remove(L, 1); /* remove constructor atable */
+ lua_insert(L, 1); /* insert constructor */
+ lua_pop(L, 1); /* remove fancy metatable */
+
+ lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+ return lua_gettop(L);
+}
+
+int luaT_cmt__newindex(lua_State *L)
+{
+ if(!lua_istable(L, 1))
+ luaL_error(L, "internal error in __newindex: not a constructor table");
+
+ if(!lua_getmetatable(L, 1))
+ luaL_error(L, "internal error in __newindex: no metatable available");
+
+ lua_pushstring(L, "__metatable");
+ lua_rawget(L, -2);
+
+ if(!lua_istable(L, -1))
+ luaL_error(L, "internal error in __newindex: no metaclass available");
+
+ lua_insert(L, 2);
+ lua_pop(L, 1); /* remove the metatable over the constructor table */
+
+ lua_rawset(L, -3);
+
+ return 0;
+}
+
+/******************** deprecated functions ********************/
+int luaT_pushmetaclass(lua_State *L, const char *tname)
+{
+ return luaT_pushmetatable(L, tname);
+}
+
+const char* luaT_id(lua_State *L, int ud)
+{
+ return luaT_typename(L, ud);
+}
+
+const char* luaT_id2typename(lua_State *L, const char *id)
+{
+ return id;
+}
+
+const char* luaT_typename2id(lua_State *L, const char *tname)
+{
+ return luaT_typenameid(L, tname);
+}
+
+int luaT_getmetaclass(lua_State *L, int index)
+{
+ return lua_getmetatable(L, index);
+}
+
+const char* luaT_checktypename2id(lua_State *L, const char *tname)
+{
+ const char* id = luaT_typenameid(L, tname);
+ if(!id)
+ luaL_error(L, "unknown class <%s>", tname);
+ return id;
+}
+
+void luaT_registeratid(lua_State *L, const struct luaL_Reg *methods, const char *id)
+{
+ luaT_registeratname(L, methods, id);
+}
+
+/**************************************************************/
diff --git a/luaT/luaT.h b/luaT/luaT.h
new file mode 100644
index 0000000..5e8dd2f
--- /dev/null
+++ b/luaT/luaT.h
@@ -0,0 +1,111 @@
+#ifndef LUAT_UTILS_INC
+#define LUAT_UTILS_INC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <lua.h>
+#include <lauxlib.h>
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef LUA_EXTERNC
+# ifdef __cplusplus
+# define LUA_EXTERNC extern "C"
+# else
+# define LUA_EXTERNC extern
+# endif
+#endif
+
+#ifdef _MSC_VER
+# define DLL_EXPORT __declspec(dllexport)
+# define DLL_IMPORT __declspec(dllimport)
+# ifdef luaT_EXPORTS
+# define LUAT_API LUA_EXTERNC DLL_EXPORT
+# else
+# define LUAT_API LUA_EXTERNC DLL_IMPORT
+# endif
+#else
+# define DLL_EXPORT
+# define DLL_IMPORT
+# define LUAT_API LUA_EXTERNC
+#endif
+
+
+/* C functions */
+
+LUAT_API void* luaT_alloc(lua_State *L, long size);
+LUAT_API void* luaT_realloc(lua_State *L, void *ptr, long size);
+LUAT_API void luaT_free(lua_State *L, void *ptr);
+
+LUAT_API const char* luaT_newmetatable(lua_State *L, const char *tname, const char *parenttname,
+ lua_CFunction constructor, lua_CFunction destructor, lua_CFunction factory);
+
+LUAT_API int luaT_pushmetatable(lua_State *L, const char *tname);
+
+LUAT_API const char* luaT_typenameid(lua_State *L, const char *tname);
+LUAT_API const char* luaT_typename(lua_State *L, int ud);
+
+LUAT_API void luaT_pushudata(lua_State *L, void *udata, const char *tname);
+LUAT_API void *luaT_toudata(lua_State *L, int ud, const char *tname);
+LUAT_API int luaT_isudata(lua_State *L, int ud, const char *tname);
+LUAT_API void *luaT_checkudata(lua_State *L, int ud, const char *tname);
+
+LUAT_API void *luaT_getfieldcheckudata(lua_State *L, int ud, const char *field, const char *tname);
+LUAT_API void *luaT_getfieldchecklightudata(lua_State *L, int ud, const char *field);
+LUAT_API double luaT_getfieldchecknumber(lua_State *L, int ud, const char *field);
+LUAT_API int luaT_getfieldcheckint(lua_State *L, int ud, const char *field);
+LUAT_API const char* luaT_getfieldcheckstring(lua_State *L, int ud, const char *field);
+LUAT_API int luaT_getfieldcheckboolean(lua_State *L, int ud, const char *field);
+LUAT_API void luaT_getfieldchecktable(lua_State *L, int ud, const char *field);
+
+LUAT_API int luaT_typerror(lua_State *L, int ud, const char *tname);
+
+LUAT_API int luaT_checkboolean(lua_State *L, int ud);
+LUAT_API int luaT_optboolean(lua_State *L, int ud, int def);
+
+LUAT_API void luaT_registeratname(lua_State *L, const struct luaL_Reg *methods, const char *name);
+
+/* utility functions */
+LUAT_API const char *luaT_classrootname(const char *tname);
+LUAT_API int luaT_classmodulename(const char *tname, char *module_name);
+
+/* debug */
+LUAT_API void luaT_stackdump(lua_State *L);
+
+/* Lua functions */
+LUAT_API int luaT_lua_newmetatable(lua_State *L);
+LUAT_API int luaT_lua_factory(lua_State *L);
+LUAT_API int luaT_lua_getconstructortable(lua_State *L);
+LUAT_API int luaT_lua_typename(lua_State *L);
+LUAT_API int luaT_lua_isequal(lua_State *L);
+LUAT_API int luaT_lua_pointer(lua_State *L);
+LUAT_API int luaT_lua_setenv(lua_State *L);
+LUAT_API int luaT_lua_getenv(lua_State *L);
+LUAT_API int luaT_lua_getmetatable(lua_State *L);
+LUAT_API int luaT_lua_version(lua_State *L);
+LUAT_API int luaT_lua_setmetatable(lua_State *L);
+LUAT_API int luaT_lua_metatype(lua_State *L);
+LUAT_API int luaT_lua_pushudata(lua_State *L);
+
+/* deprecated functions */
+/* ids have been replaced by string names to identify classes */
+/* comments show what function (that you should use) they call now */
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define LUAT_DEPRECATED __attribute__((__deprecated__))
+#elif defined(_MSC_VER)
+#define LUAT_DEPRECATED __declspec(deprecated)
+#else
+#define LUAT_DEPRECATED
+#endif
+
+LUAT_API LUAT_DEPRECATED int luaT_pushmetaclass(lua_State *L, const char *tname); /* same as luaT_pushmetatable */
+LUAT_API LUAT_DEPRECATED const char* luaT_id(lua_State *L, int ud); /* same as luaT_typename */
+LUAT_API LUAT_DEPRECATED const char* luaT_id2typename(lua_State *L, const char *id); /* same as luaT_typenameid */
+LUAT_API LUAT_DEPRECATED const char* luaT_typename2id(lua_State *L, const char*); /* same as luaT_typenameid */
+LUAT_API LUAT_DEPRECATED int luaT_getmetaclass(lua_State *L, int index); /* same as luaT_getmetatable */
+LUAT_API LUAT_DEPRECATED const char* luaT_checktypename2id(lua_State *L, const char *tname); /* same as luaT_typenameid */
+LUAT_API LUAT_DEPRECATED void luaT_registeratid(lua_State *L, const struct luaL_Reg *methods, const char *id); /* same as luaT_registeratname */
+
+#endif
diff --git a/luajit-2.0 b/luajit-2.0
new file mode 160000
+Subproject 11106aa83374c95f88679452e997229ecedefdc
diff --git a/nerv b/nerv
new file mode 100755
index 0000000..d2010ff
--- /dev/null
+++ b/nerv
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec 'build/luaJIT/bin/luajit' -e "package.cpath=\"${PWD}/build/objs/?.so\"" -e "require 'libnerv' " "$@"
diff --git a/nerv.c b/nerv.c
new file mode 100644
index 0000000..2118a3c
--- /dev/null
+++ b/nerv.c
@@ -0,0 +1,13 @@
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+
+extern int nerv_point_init(lua_State *L);
+
+LUALIB_API int luaopen_libnerv(lua_State *L) {
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, LUA_GLOBALSINDEX, "nerv");
+ nerv_point_init(L);
+ return 1;
+}
diff --git a/oop_example.c b/oop_example.c
new file mode 100644
index 0000000..fecac14
--- /dev/null
+++ b/oop_example.c
@@ -0,0 +1,89 @@
+#include <math.h>
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "luaT/luaT.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ double x, y;
+ int arr[100];
+} Point;
+
+static int point_get_sinx (lua_State *L) {
+ Point *p = luaT_checkudata(L, 1, "nerv.point");
+ lua_pushnumber(L, sin(p->x));
+ return 1;
+}
+
+static int point_set_x (lua_State *L) {
+ Point *p = luaT_checkudata(L, 1, "nerv.point");
+ p->x = luaL_checknumber(L, 2);
+ return 0;
+}
+
+
+static int point_get_y(lua_State *L) {
+ Point *p = luaT_checkudata(L, 1, "nerv.point");
+ lua_pushnumber(L, sin(p->x));
+ return 1;
+}
+
+static int point_newindex(lua_State *L) {
+ Point *p = luaT_checkudata(L, 1, "nerv.point");
+ if (lua_isnumber(L, 2))
+ {
+ int d = luaL_checkinteger(L, 2);
+ double v = luaL_checknumber(L, 3);
+ if (0 <= d && d < 100)
+ p->arr[d] = v;
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ else
+ {
+ lua_pushboolean(L, 0);
+ return 1;
+ }
+}
+
+static int point_index(lua_State *L) {
+ Point *p = luaT_checkudata(L, 1, "nerv.point");
+ if (lua_isnumber(L, 2))
+ {
+ int d = luaL_checkinteger(L, 2);
+ if (0 <= d && d < 100)
+ lua_pushnumber(L, p->arr[d]);
+ lua_pushboolean(L, 1);
+ return 2;
+ }
+ else
+ {
+ lua_pushboolean(L, 0);
+ return 1;
+ }
+}
+
+int point_new(lua_State *L) {
+ Point *self = (Point *)malloc(sizeof(Point));
+ self->x = 0;
+ self->y = 0;
+ luaT_pushudata(L, self, "nerv.point");
+ return 1;
+}
+
+static const luaL_Reg point[] = {
+ {"get_sinx", point_get_sinx},
+ {"set_x", point_set_x},
+ {"get_y", point_get_y},
+ {"__index__", point_index},
+ {"__newindex__", point_newindex},
+ {NULL, NULL}
+};
+
+void nerv_point_init(lua_State *L) {
+ luaT_newmetatable(L, "nerv.point", NULL, point_new, NULL, NULL);
+ luaL_register(L, NULL, point);
+ lua_pop(L, 1);
+}
diff --git a/oop_example.lua b/oop_example.lua
new file mode 100644
index 0000000..a4e7009
--- /dev/null
+++ b/oop_example.lua
@@ -0,0 +1,7 @@
+a = nerv.point()
+print(a:get_sinx())
+a:set_x(3.14)
+print(a:get_sinx())
+print(a[2])
+a[2] = 3
+print(a[2])