diff options
Diffstat (limited to 'src/lua/tolua_tm.c')
-rw-r--r-- | src/lua/tolua_tm.c | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/src/lua/tolua_tm.c b/src/lua/tolua_tm.c new file mode 100644 index 00000000..8fd7b28d --- /dev/null +++ b/src/lua/tolua_tm.c @@ -0,0 +1,585 @@ +/* tolua: tag methods +** Support code for Lua bindings. +** Written by Waldemar Celes +** TeCGraf/PUC-Rio +** Jul 1998 +** $Id: tolua_tm.c,v 1.2 2001/11/26 23:00:27 darkgod Exp $ +*/ + +/* This code is free software; you can redistribute it and/or modify it. +** The software provided hereunder is on an "as is" basis, and +** the author has no obligation to provide maintenance, support, updates, +** enhancements, or modifications. +*/ + +#include "tolua.h" +#include "tolua_tm.h" +#include "tolua_tt.h" +#include "tolua_rg.h" + +#include <string.h> + + + +/* Global tables created in Lua registry: + tolua_tbl_class: indexed by instance tags, stores the class tables. + tolua_tbl_clone: indexed by memory address, stores the tag indicanting + it is a clone. + tolua_tbl_mate: indexed by memory address, stores the associate instance + table. + + General tags stored in Lua registry: + tolua_tag_global; + tolua_tag_module; + tolua_tag_class; + tolua_tag_instance; + tolua_tag_linstance; + tolua_tag_indirect; +*/ + +/* internal function prototype */ +static void setmethods (lua_State* L); + +static void settag (lua_State* L, int lo, char* tag_registry_field) +{ + toluaI_getregistry(L,tag_registry_field); + lua_pushvalue(L,lo); + lua_settag(L,(int)lua_tonumber(L,-2)); + lua_pop(L,2); +} + +void toluaI_tm_global (lua_State* L, int lo) +{ + settag(L,lo,"tolua_tag_global"); +} + +void toluaI_tm_module (lua_State* L, int lo) +{ + settag(L,lo,"tolua_tag_module"); +} + +void toluaI_tm_setclass (lua_State* L, int lo) +{ + settag(L,lo,"tolua_tag_class"); +} + +void toluaI_tm_class (lua_State* L, int lo, char* name) +{ + int tag_class; + int tag = lua_newtag(L); + char* type = toluaI_tt_concat("class ",name); + toluaI_getregistry(L,"tolua_tag_class"); + tag_class = (int)lua_tonumber(L,-1); + lua_copytagmethods(L,tag,tag_class); + toluaI_tt_register(L,tag,type); + toluaI_tt_sethierarchy(L,tag,tag_class); + lua_pushvalue(L,lo); + lua_settag(L,tag); + lua_pop(L,2); /* tag_class and lo */ +} + +void toluaI_tm_instance (lua_State* L, int tag, int lo) +{ + toluaI_getregistry(L,"tolua_tbl_class"); + lua_pushnumber(L,tag); + lua_pushvalue(L,lo); + lua_settable(L,-3); + toluaI_getregistry(L,"tolua_tag_instance"); + lua_copytagmethods(L,tag,(int)lua_tonumber(L,-1)); + lua_pop(L,2); /* tbl_class and tag_instance */ +} + +void toluaI_tm_linstance (lua_State* L, int tag, int lo) +{ + toluaI_getregistry(L,"tolua_tbl_class"); + lua_pushnumber(L,tag); + lua_pushvalue(L,lo); + lua_settable(L,-3); + toluaI_getregistry(L,"tolua_tag_linstance"); + lua_copytagmethods(L,tag,(int)lua_tonumber(L,-1)); + lua_pop(L,2); /* tbl_class and tag_linstance */ +} + +void* tolua_doclone (lua_State* L, void* value, int tag) +{ + toluaI_getregistry(L,"tolua_tbl_clone"); + lua_pushuserdata(L,value); + lua_pushnumber(L,tag); + lua_settable(L,-3); + lua_pop(L,1); + return value; +} + +void* tolua_copy (lua_State* L, void* value, unsigned int size) +{ + void* clone = (void*)malloc(size); + if (clone) + memcpy(clone,value,size); + else + tolua_error(L,"insuficient memory"); + return clone; +} + +static void toluaI_tm_undoclone (lua_State* L, int tag, void* clone) +{ + toluaI_getregistry(L,"tolua_tbl_clone"); + lua_pushuserdata(L,clone); + lua_gettable(L,-2); + if (lua_isnumber(L,-1) && lua_tonumber(L,-1)==tag) + { + lua_pushuserdata(L,clone); + lua_pushnil(L); + lua_settable(L,-4); + + /* get base class */ + toluaI_getregistry(L,"tolua_tbl_class"); + lua_pushnumber(L,tag); + lua_rawget(L,-2); + + /* look for destructor */ + lua_pushstring(L,"delete"); + lua_gettable(L,-2); + if (lua_iscfunction(L,-1)) + { + lua_pushusertag(L,clone,tag); + lua_call(L,1,0); + } + else + { + free(clone); /* no destructor: use raw free */ + lua_pop(L,1); /* the nil function value */ + } + lua_pop(L,2); /* tbl_class and class method table */ + } + lua_pop(L,2); /* table and value */ +} + +void toluaI_tm_pushmate (lua_State* L, int lo) +{ + toluaI_getregistry(L,"tolua_tbl_mate"); + lua_pushvalue(L,lo); + lua_rawget(L,-2); + lua_insert(L,-2); + lua_pop(L,1); +} + +void toluaI_tm_pushclass (lua_State* L, int lo) +{ + toluaI_getregistry(L,"tolua_tbl_class"); + lua_pushnumber(L,lua_tag(L,lo)); + lua_rawget(L,-2); + lua_insert(L,-2); + lua_pop(L,1); +} + +int toluaI_gettag (lua_State* L, char* tagname) +{ + int tag; + toluaI_getregistry(L,tagname); + tag = (int)lua_tonumber(L,-1); + lua_pop(L,1); + return tag; +} + +void toluaI_tm_init (lua_State* L) +{ + lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_class"); + lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_clone"); + lua_newtable(L); toluaI_setregistry(L,"tolua_tbl_mate"); + + lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_global"); + lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_module"); + lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_class"); + lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_instance"); + lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_linstance"); + lua_pushnumber(L,lua_newtag(L)); toluaI_setregistry(L,"tolua_tag_indirect"); + + toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_global"),"generic variable"); + toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_module"),"generic module"); + toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_class"),"generic class"); + toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_indirect"),"generic indirect"); + toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_instance"),"generic instance"); + toluaI_tt_register(L,toluaI_gettag(L,"tolua_tag_linstance"),"generic lua instance"); + + /* allows modules and classes to be used as ordinary tables */ + toluaI_tt_sethierarchy(L,toluaI_gettag(L,"tolua_tag_module"),tolua_tag_table); + toluaI_tt_sethierarchy(L,toluaI_gettag(L,"tolua_tag_class"),tolua_tag_table); + + setmethods(L); +} + +static int map (lua_State* L) +{ + int m = lua_gettop(L); + /* do not pass string fields starting with a dot */ + if (!lua_isstring(L,1) || *lua_tostring(L,1)!='.') + { + lua_getglobals(L); + lua_pushvalue(L,1); + lua_pushvalue(L,m); + lua_rawset(L,-3); + lua_pop(L,1); + } + return 0; +} + +void toluaI_tm_using (lua_State* L, int module) +{ + lua_newtable(L); + lua_settag(L,toluaI_gettag(L,"tolua_tag_indirect")); + lua_pushstring(L,".module"); + lua_pushvalue(L,module); + lua_settable(L,-3); + + lua_getglobal(L,"foreach"); + lua_pushvalue(L,module); + lua_pushvalue(L,-3); + lua_pushcclosure(L,map,1); + lua_call(L,2,0); + + lua_getglobal(L,"foreach"); + lua_pushvalue(L,module); + lua_pushstring(L,".get"); + lua_gettable(L,-2); + lua_insert(L,-2); + lua_pop(L,1); /* module table */ + lua_pushvalue(L,-3); + lua_pushcclosure(L,map,1); + lua_call(L,2,0); + lua_pop(L,1); /* indirect table */ +} + +/********************************************************** tag methods */ + +/* tag methods coded in C */ + +/* generic gettable */ +static void oo_gettable (lua_State* L, int table, int base, int index) +{ + while (lua_istable(L,base)) + { + lua_pushvalue(L,index); + lua_rawget(L,base); + if (!lua_isnil(L,-1)) + return; /* returned value already on the top */ + else if (lua_isnumber(L,index)) + { + lua_pushstring(L,"operator_get"); + lua_rawget(L,base); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,table); + lua_pushvalue(L,index); + lua_call(L,2,1); + return; + } + } + else + { + lua_pushstring(L,".get"); + lua_rawget(L,base); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,index); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,table); + lua_pushvalue(L,index); /* need to access array field (?) */ + lua_call(L,2,1); + return; + } + } + } + lua_pushstring(L,".base"); lua_rawget(L,base); + base = lua_gettop(L); + } + lua_pushnil(L); +} + +/* generic settable */ +static int oo_settable (lua_State* L, int table, int base, int index, int value) +{ + while (lua_istable(L,base)) + { + lua_pushstring(L,".set"); + lua_rawget(L,base); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,index); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,table); + lua_pushvalue(L,value); + lua_call(L,2,0); + return 1; + } + } + lua_pushstring(L,".base"); lua_rawget(L,base); + base = lua_gettop(L); + } + return 0; +} + +/* class tag methods */ +static int class_index (lua_State* L) +{ + int table = 1; + int index = 2; + oo_gettable(L,table,table,index); + return 1; +} +static int class_settable (lua_State* L) +{ + int table = 1; + int index = 2; + int value = 3; + if (oo_settable(L,table,table,index,value) == 0) + { + lua_pushvalue(L,table); + lua_pushvalue(L,index); + lua_pushvalue(L,value); + lua_rawset(L,-3); + } + return 0; +} + +/* instance tags */ +static int instance_gettable (lua_State* L) +{ + int table = 1; + int index = 2; + toluaI_tm_pushmate(L,table); /* pushes mate */ + if (!lua_isnil(L,-1)) /* if there's a mate table */ + { + lua_pushvalue(L,index); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) /* if field in mate table exists */ + return 1; + } + toluaI_tm_pushclass(L,table); /* pushes base */ + oo_gettable(L,table,lua_gettop(L),index); + return 1; +} +static int instance_settable (lua_State* L) +{ + int table = 1; + int index = 2; + int value = 3; + toluaI_tm_pushclass(L,table); /* pushes base */ + if (lua_isnumber(L,index)) + { + lua_pushstring(L,"operator_set"); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) + {/* the stack here is: table,index,value,base,operator */ + /* call operator passing table, index, and value */ + lua_insert(L,1); + lua_pop(L,1); /* base */ + lua_call(L,3,0); + return 0; + } + } + if (oo_settable(L,table,4,index,value) == 0) + { + toluaI_tm_pushmate(L,table); /* pushes mate */ + if (lua_isnil(L,-1)) + { + /* creates mate table */ + lua_newtable(L); + toluaI_getregistry(L,"tolua_tbl_mate"); + lua_pushvalue(L,table); /* that is the userdata */ + lua_pushvalue(L,-3); + lua_rawset(L,-3); + lua_pop(L,1); /* tbl_mate */ + } + /* the mate table is on the top */ + lua_pushvalue(L,index); + lua_pushvalue(L,value); + lua_rawset(L,-3); + } + return 0; +} +static int instance_gc (lua_State* L) +{ + toluaI_tm_undoclone(L,lua_tag(L,1),lua_touserdata(L,1)); + return 0; +} +static int gen_operator (lua_State* L) +{ + int op1 = 1; + int op2 = 2; + int event = 3; + char* name = toluaI_tt_concat("operator_",lua_tostring(L,event)); + lua_pushstring(L,name); + lua_gettable(L,op1); + lua_pushvalue(L,op1); + lua_pushvalue(L,op2); + lua_call(L,2,1); + return 1; +} +static int instance_operator (lua_State* L) +{ + return gen_operator(L); +} +static int instance_relational (lua_State* L) +{ + gen_operator(L); + if ((int)lua_tonumber(L,-1)==0) lua_pushnil(L); + return 1; +} + +/* lua instance tags */ +static int linstance_index (lua_State* L) +{ + toluaI_tm_pushclass(L,1); + oo_gettable(L,1,3,2); /* table,base,index */ + return 1; +} + + +/* module tag methods */ +static int module_index (lua_State* L) +{ + int table = 1; + int index = 2; + lua_pushstring(L,".get"); + lua_rawget(L,table); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,index); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) + { + lua_call(L,0,1); + return 1; + } + } + lua_pushnil(L); + return 1; +} +static int module_settable (lua_State* L) +{ + int table = 1; + int index = 2; + int value = 3; + lua_pushstring(L,".set"); + lua_rawget(L,table); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,index); + lua_rawget(L,-2); + if (!lua_isnil(L,-1)) + { + lua_pushvalue(L,value); + lua_call(L,1,0); + return 0; + } + } + lua_pushvalue(L,index); + lua_pushvalue(L,value); + lua_rawset(L,table); + return 0; +} + +/* global variable tag methods */ +static int global_getglobal (lua_State* L) +{ + int value = 2; + lua_pushstring(L,".get"); + lua_rawget(L,value); + lua_call(L,0,1); + return 1; +} +static int global_setglobal (lua_State* L) +{ + int value = 2; + int newvalue = 3; + lua_pushstring(L,".set"); + lua_rawget(L,value); + if (lua_isnil(L,-1)) + lua_error(L,"value of const variable cannot be changed"); + else + { + lua_pushvalue(L,newvalue); + lua_call(L,1,0); + } + return 0; +} + +/* indirect tag methods */ +static int indirect_getglobal (lua_State* L) +{ + int varname = 1; + int value = 2; + lua_pushstring(L,".module"); + lua_gettable(L,value); + lua_pushvalue(L,varname); + lua_gettable(L,-2); + return 1; +} +static int indirect_setglobal (lua_State* L) +{ + int varname = 1; + int value = 2; + int newvalue = 3; + lua_pushstring(L,".module"); + lua_gettable(L,value); + lua_pushvalue(L,varname); + lua_pushvalue(L,newvalue); + lua_settable(L,-3); + return 0; +} + +static void setmethods (lua_State* L) +{ + /* global variable */ + lua_pushcfunction(L,global_getglobal); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_global"),"getglobal"); + lua_pushcfunction(L,global_setglobal); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_global"),"setglobal"); + + /* module */ + lua_pushcfunction(L,module_index); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_module"),"index"); + lua_pushcfunction(L,module_settable); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_module"),"settable"); + + /* class */ + lua_pushcfunction(L,class_index); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_class"),"index"); + lua_pushcfunction(L,class_settable); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_class"),"settable"); + + /* instance */ + lua_pushcfunction(L,instance_gettable); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"gettable"); + lua_pushcfunction(L,instance_settable); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"settable"); + lua_pushcfunction(L,instance_operator); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"add"); + lua_pushcfunction(L,instance_operator); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"sub"); + lua_pushcfunction(L,instance_operator); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"mul"); + lua_pushcfunction(L,instance_operator); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"div"); + lua_pushcfunction(L,instance_relational); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"lt"); + lua_pushcfunction(L,instance_gc); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_instance"),"gc"); + + /* lua instance */ + lua_pushcfunction(L,linstance_index); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_linstance"),"index"); + + /* indirect */ + lua_pushcfunction(L,indirect_getglobal); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_indirect"),"getglobal"); + lua_pushcfunction(L,indirect_setglobal); + lua_settagmethod(L,toluaI_gettag(L,"tolua_tag_indirect"),"setglobal"); +} + + + |