diff --git a/CHANGES.current b/CHANGES.current index bd468adc8..f27e8e7c4 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,11 @@ Version 1.3.34 (in progress) ============================ +12/04/2007: mgossage + [lua] Fix a bug in the class hierachy code, where the methods were not propagated, + if the name ordering was in a certain order. + Added new example programs (dual, embed) and runtime tests for test-suite. + 11/30/2007: wsfulton Fix using statements using a base class method where the methods were overloaded. Depending on the order of the using statements and method declarations, these diff --git a/Examples/lua/check.list b/Examples/lua/check.list index b5343ce16..f61e2544f 100644 --- a/Examples/lua/check.list +++ b/Examples/lua/check.list @@ -1,6 +1,8 @@ # see top-level Makefile.in class constants +dual +embed funcptr3 functest functor diff --git a/Examples/lua/dual/Makefile b/Examples/lua/dual/Makefile new file mode 100644 index 000000000..ceae37936 --- /dev/null +++ b/Examples/lua/dual/Makefile @@ -0,0 +1,20 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +TARGET = dual +CXXSRCS = example2_wrap.cxx +INTERFACE = dual.i +LUA_INTERP = dual.cpp + +# this is a little different ot normal as we need to static link two modules and a custom intepreter +# we need the external runtime, then swig examples2, and build the module as normal +all:: + $(SWIG) -lua -external-runtime + $(SWIG) -c++ -lua $(SWIGOPT) example2.i + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='example.i' LUA_INTERP='$(LUA_INTERP)' lua_static_cpp + +clean:: + $(MAKE) -f $(TOP)/Makefile lua_clean + +check: all + diff --git a/Examples/lua/dual/dual.cpp b/Examples/lua/dual/dual.cpp new file mode 100644 index 000000000..055ea03af --- /dev/null +++ b/Examples/lua/dual/dual.cpp @@ -0,0 +1,109 @@ +/* +dual.cpp a test for multiple modules and multiple intrepreters staticly linked together. + +Earlier version of lua bindings for SWIG would fail if staticly linked. + +What is happening is as follows: +example.i declares a type Foo +examples2.i declares Bar + +The first lua state will load example.i +and check to see if types Foo and Bar are registered with it +(Foo should be & Bar should not) + +The second lua state will load example2.i +and check to see if types Foo and Bar are registered with it +(Bar should be & Foo should not) + +Note: Though both the modules exist and are loaded, they are not linked together, +as they are connected to seperate lua interpreters. + +When the third lua state loads both example.i and example2.i, +the two modules are now linked together, and all can now find +both Foo and Bar. +*/ + +#include +#include + +#include "swigluarun.h" // the swig runtimes + +// the 2 libraries which are wrappered via SWIG +extern "C" int luaopen_example(lua_State*L); +extern "C" int luaopen_example2(lua_State*L); + +#define DEBUG(X) {printf(X);fflush(stdout);} +#define DEBUG2(X,Y) {printf(X,Y);fflush(stdout);} +#define DEBUG3(X,Y,Z) {printf(X,Y,Z);fflush(stdout);} + +void testModule(lua_State *L) +{ + swig_type_info *pTypeInfo=0,*pTypeInfo2=0; + swig_module_info *pModule=0; + pModule=SWIG_GetModule(L); + DEBUG2(" SWIG_GetModule() returns %p\n",pModule) + if(pModule==0) return; + pTypeInfo = SWIG_TypeQuery(L,"Foo *"); + DEBUG2(" Type (Foo*) is %s\n",pTypeInfo==0?"unknown":"known"); + DEBUG3(" Module %p typeinfo(Foo*) %p\n",pModule,pTypeInfo); + pTypeInfo2 = SWIG_TypeQuery(L,"Bar *"); + DEBUG2(" Type (Bar*) is %s\n",pTypeInfo2==0?"unknown":"known"); + DEBUG3(" Module %p typeinfo(Bar*) %p\n",pModule,pTypeInfo2); +} + +int main(int argc,char* argv[]) +{ + lua_State *L1=0,*L2=0,*L3=0; + + printf("This is a test of having two SWIG'ed modules and three lua states\n" + "statically linked together.\n" + "Its mainly to check that all the types are correctly managed\n\n"); + + DEBUG("creating lua states(L1,L2,L3)"); + L1=lua_open(); + L2=lua_open(); + L3=lua_open(); + DEBUG("ok\n\n"); + + DEBUG("luaopen_example(L1).."); + luaopen_example(L1); + DEBUG("ok\n"); + + DEBUG("Testing Module L1\n"); + DEBUG("This module should know about Foo* but not Bar*\n"); + testModule(L1); + DEBUG("End Testing Module L1\n\n"); + + DEBUG("luaopen_example2(L2).."); + luaopen_example2(L2); + DEBUG("ok\n"); + + DEBUG("Testing Module L2\n"); + DEBUG("This module should know about Bar* but not Foo*\n"); + testModule(L2); + DEBUG("End Testing Module L2\n\n"); + + DEBUG("luaopen_example(L3).."); + luaopen_example(L3); + DEBUG("ok\n"); + DEBUG("luaopen_example2(L3).."); + luaopen_example2(L3); + DEBUG("ok\n"); + + DEBUG("Testing Module L3\n"); + DEBUG("This module should know about Foo* and Bar*\n"); + testModule(L3); + DEBUG("End Testing Module L3\n\n"); + + DEBUG("Testing Module L1 again\n"); + DEBUG("It now should know about Foo* and Bar*\n"); + testModule(L1); + DEBUG("End Testing Module L1 again\n\n"); + + DEBUG("close all.."); + lua_close(L1); + lua_close(L2); + lua_close(L3); + DEBUG("ok, exiting\n"); + return 0; +} diff --git a/Examples/lua/dual/example.i b/Examples/lua/dual/example.i new file mode 100644 index 000000000..5e573ddb3 --- /dev/null +++ b/Examples/lua/dual/example.i @@ -0,0 +1,10 @@ +/* File : example.i */ +%module example + +%inline %{ + +struct Foo{ + int i; +}; + +%} diff --git a/Examples/lua/dual/example2.i b/Examples/lua/dual/example2.i new file mode 100644 index 000000000..94496647f --- /dev/null +++ b/Examples/lua/dual/example2.i @@ -0,0 +1,10 @@ +/* File : example2.i */ +%module example2 + +%inline %{ + +struct Bar{ + int i; +}; + +%} diff --git a/Examples/lua/embed/Makefile b/Examples/lua/embed/Makefile new file mode 100644 index 000000000..51d0e6180 --- /dev/null +++ b/Examples/lua/embed/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +TARGET = embed +SRCS = example.c +INTERFACE = example.i +LUA_INTERP = embed.c + +# this is a little different to normal as we have our own special interpreter +# which we want to static link +all:: + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) SRCS='$(SRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='example.i' LUA_INTERP='$(LUA_INTERP)' lua_static + +clean:: + $(MAKE) -f $(TOP)/Makefile lua_clean + +check: all + diff --git a/Examples/lua/embed/embed.c b/Examples/lua/embed/embed.c new file mode 100644 index 000000000..ec304c5c4 --- /dev/null +++ b/Examples/lua/embed/embed.c @@ -0,0 +1,84 @@ +/* embed.c a simple test for an embeded interpreter + +The idea is that we wrapper a few simple function (example.c) +and write our own app to call it. + +What it will do is load the wrappered lib, load runme.lua and then call some functions. +To make life easier, all the printf's have either [C] or [Lua] at the start +so you can see where they are coming from. + +We will be using the luaL_dostring()/lua_dostring() function to call into lua + +*/ + +#include + +#include +#include +#include + +/* the SWIG wrappered library */ +extern int luaopen_example(lua_State*L); + +/* a really simple way of calling lua from C + just give it a lua state & a string to execute +Unfortunately lua keeps changing its API's. +In lua 5.0.X its lua_dostring() +In lua 5.1.X its luaL_dostring() +so we have a few extra compiles +*/ +int dostring(lua_State *L, char* str) +{ + int ok; +#if (defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM>=501)) + ok=luaL_dostring(L,str); /* looks like this is lua 5.1.X or later, good */ +#else + ok=lua_dostring(L,str); /* might be lua 5.0.x, using lua_dostring */ +#endif + if (ok!=0) + printf("[C] ERROR in dostring: %s\n",lua_tostring(L,-1)); + return ok; +} + + +int main(int argc,char* argv[]) +{ + lua_State *L; + int ok; + printf("[C] Welcome to the simple embedded lua example\n"); + printf("[C] We are in C\n"); + printf("[C] opening a lua state & loading the libraries\n"); + L=lua_open(); + luaopen_base(L); + luaopen_string(L); + luaopen_math(L); + printf("[C] now loading the SWIG wrappered library\n"); + luaopen_example(L); + printf("[C] all looks ok\n"); + printf("\n"); + printf("[C] lets load the file 'runme.lua'\n"); + printf("[C] any lua code in this file will be executed\n"); + if (luaL_loadfile(L, "runme.lua") || lua_pcall(L, 0, 0, 0)) + { + printf("[C] ERROR: cannot run lua file: %s",lua_tostring(L, -1)); + exit(3); + } + printf("[C] We are now back in C, all looks ok\n"); + printf("\n"); + printf("[C] lets call the function 'do_tests()'\n"); + ok=dostring(L,"do_tests()"); + printf("[C] We are back in C, the dostring() function returned %d\n",ok); + printf("\n"); + printf("[C] Lets call lua again, but create an error\n"); + ok=dostring(L,"no_such_function()"); + printf("[C] We are back in C, the dostring() function returned %d\n",ok); + printf("[C] it should also have returned 1 and printed an error message\n"); + printf("\n"); + printf("[C] Lets call lua again, calling the greeting function\n"); + ok=dostring(L,"call_greeting()"); + printf("[C] This was C=>Lua=>C (getting a bit complex)\n"); + printf("\n"); + printf("[C] all finished, closing the lua state\n"); + lua_close(L); + return 0; +} diff --git a/Examples/lua/embed/example.c b/Examples/lua/embed/example.c new file mode 100644 index 000000000..d359f6c1e --- /dev/null +++ b/Examples/lua/embed/example.c @@ -0,0 +1,21 @@ +/* File : example.c */ + +/* A global variable */ +double Foo = 3.0; + +/* Compute the greatest common divisor of positive integers */ +int gcd(int x, int y) { + int g; + g = y; + while (x > 0) { + g = x; + x = y % x; + y = g; + } + return g; +} + +void greeting() +{ + printf("Hello from the C function 'greeting'\n"); +} diff --git a/Examples/lua/embed/example.i b/Examples/lua/embed/example.i new file mode 100644 index 000000000..7784b8e3c --- /dev/null +++ b/Examples/lua/embed/example.i @@ -0,0 +1,8 @@ +/* File : example.i */ +%module example + +%inline %{ +extern int gcd(int x, int y); +extern double Foo; +extern void greeting(); +%} \ No newline at end of file diff --git a/Examples/lua/embed/runme.lua b/Examples/lua/embed/runme.lua new file mode 100644 index 000000000..e02fd1d55 --- /dev/null +++ b/Examples/lua/embed/runme.lua @@ -0,0 +1,40 @@ +print "[lua] This is runme.lua" +-- test program for embeded lua +-- we do not need to load the library, as it was already in the intrepreter +-- but lets check anyway +assert(type(example)=='table',"Don't appear to have loaded the example module") + +-- a test function to run the tests +function do_tests() + print("[lua] We are now in Lua, inside the do_tests() function") + print("[lua] We will be calling example.gcd() and changing example.Foo") + -- Call our gcd() function + x = 42 + y = 105 + g = example.gcd(x,y) + print("[lua] The gcd of",x,"and",y,"is",g) + + -- Manipulate the Foo global variable + + -- Output its current value + print("[lua] Foo = ", example.Foo) + + -- Change its value + example.Foo = 3.1415926 + + -- See if the change took effect + print("[lua] Foo = ", example.Foo) + print("[lua] ending the do_tests() function") +end + +function call_greeting() + print("[lua] We are now in Lua, inside the call_greeting() function") + example.greeting() + print("[lua] ending the call_greeting() function") +end + + + + + + diff --git a/Examples/test-suite/lua/multi_import_runme.lua b/Examples/test-suite/lua/multi_import_runme.lua new file mode 100644 index 000000000..5d4c1360c --- /dev/null +++ b/Examples/test-suite/lua/multi_import_runme.lua @@ -0,0 +1,16 @@ +require("import") -- the import fn +-- note: need to import the base class module before the derived class +-- this is because if the derived class is imported first it doesn't get the base class methods +import("multi_import_b") -- import code +import("multi_import_a") -- import code + +x = multi_import_b.XXX() +assert(x:testx() == 0) + +y = multi_import_b.YYY() +assert(y:testx() == 0) +assert(y:testy() == 1) + +z = multi_import_a.ZZZ() +assert(z:testx() == 0) +assert(z:testz() == 2) diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg index 0eda3e6b9..f9b4d4959 100644 --- a/Lib/lua/luarun.swg +++ b/Lib/lua/luarun.swg @@ -327,7 +327,7 @@ SWIGINTERN int SWIG_Lua_class_get(lua_State* L) lua_pushvalue(L,2); /* key */ lua_rawget(L,-2); /* look for the fn */ lua_remove(L,-2); /* stack tidy, remove .fn table */ - if (lua_iscfunction(L,-1)) + if (lua_isfunction(L,-1)) /* note: if its a C function or lua function */ { /* found it so return the fn & let lua call it */ lua_remove(L,-2); /* stack tidy, remove metatable */ return 1; @@ -490,6 +490,28 @@ SWIGINTERN void SWIG_Lua_add_class_details(lua_State* L,swig_lua_class* clss) } } +/* set up the base classes pointers. +Each class structure has a list of pointers to the base class structures. +This function fills them. +It cannot be done at compile time, as this will not work with hireachies +spread over more than one swig file. +Therefore it must be done at runtime, querying the SWIG type system. +*/ +SWIGINTERN void SWIG_Lua_init_base_class(lua_State* L,swig_lua_class* clss) +{ + int i=0; + swig_module_info* module=SWIG_GetModule(L); + for(i=0;clss->base_names[i];i++) + { + if (clss->bases[i]==0) /* not found yet */ + { + /* lookup and cache the base class */ + swig_type_info *info = SWIG_TypeQueryModule(module,module,clss->base_names[i]); + if (info) clss->bases[i] = (swig_lua_class *) info->clientdata; + } + } +} + /* performs the entire class registration process */ SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) { @@ -528,20 +550,6 @@ SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) lua_rawset(L,-3); /* metatable into registry */ lua_pop(L,1); /* tidy stack (remove registry) */ - /* set up the class base classes - we need to check the names of the classes to see if the base class exists - if so, we need to set up the pointer to it */ - swig_module_info* module=SWIG_GetModule(L); - for(i=0;clss->base_names[i];i++) - { - if (clss->bases[i]==0) /* not found yet */ - { - /* lookup and cache the base class */ - swig_type_info *info = SWIG_TypeQueryModule(module,module,clss->base_names[i]); - if (info) clss->bases[i] = (swig_lua_class *) info->clientdata; - } - } - SWIG_Lua_get_class_metatable(L,clss->name); SWIG_Lua_add_class_details(L,clss); /* recursive adding of details (atts & ops) */ lua_pop(L,1); /* tidy stack (remove class metatable) */ diff --git a/Lib/lua/luaruntime.swg b/Lib/lua/luaruntime.swg index afb516a89..04f1adf89 100644 --- a/Lib/lua/luaruntime.swg +++ b/Lib/lua/luaruntime.swg @@ -45,7 +45,13 @@ SWIGEXPORT int SWIG_init(lua_State* L) for (i = 0; swig_variables[i].name; i++){ SWIG_Lua_module_add_variable(L,swig_variables[i].name,swig_variables[i].get,swig_variables[i].set); } - /* additional registration structs & classes in lua: */ + /* set up base class pointers (the hierachy) */ + for (i = 0; swig_types[i]; i++){ + if (swig_types[i]->clientdata){ + SWIG_Lua_init_base_class(L,(swig_lua_class*)(swig_types[i]->clientdata)); + } + } + /* additional registration structs & classes in lua */ for (i = 0; swig_types[i]; i++){ if (swig_types[i]->clientdata){ SWIG_Lua_class_register(L,(swig_lua_class*)(swig_types[i]->clientdata));