From a774bfc860471ac880a9b33bbe68761ec9187caf Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 14 May 2015 08:08:32 +0800 Subject: init --- .gitignore | 3 + .gitmodules | 3 + Makefile | 18 + install.sh | 5 + luaT/README.md | 239 ++++++++++++ luaT/luaT.c | 1079 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ luaT/luaT.h | 111 ++++++ luajit-2.0 | 1 + nerv | 2 + nerv.c | 13 + oop_example.c | 89 +++++ oop_example.lua | 7 + 12 files changed, 1570 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 100755 install.sh create mode 100644 luaT/README.md create mode 100644 luaT/luaT.c create mode 100644 luaT/luaT.h create mode 160000 luajit-2.0 create mode 100755 nerv create mode 100644 nerv.c create mode 100644 oop_example.c create mode 100644 oop_example.lua 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 @@ + +# 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. + + +## Memory functions ## + +Classical memory allocation functions which generate a Lua error in case of +problem. + + +### 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. + + +### 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. + + +### 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. + + +## 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. + + +### 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. + + +### 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). + + +### 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. + + +### 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. + + +### 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. + + +### 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). + + +### 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. + + +### 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. + + +### 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. + + +## 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. + + +## 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. + + +## 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. + + +## 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. + + +## 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. + + +## 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. + + +### 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. + + +### 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. + + +### 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. + + +### 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. + + +### 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. + + +### 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`. + + +### 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 +#include + +#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 +#include +#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 index 0000000..11106aa --- /dev/null +++ b/luajit-2.0 @@ -0,0 +1 @@ +Subproject commit 11106aa83374c95f88679452e997229ecedefdcc 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 +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#include "luaT/luaT.h" +#include +#include + +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]) -- cgit v1.2.3-70-g09d2