summaryrefslogtreecommitdiff
path: root/src/lua/tolua_tm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua/tolua_tm.c')
-rw-r--r--src/lua/tolua_tm.c585
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");
+}
+
+
+