[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.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10177 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Mark Gossage 2007-12-04 09:25:58 +00:00
parent 575efcdd53
commit 89c3acea19
14 changed files with 373 additions and 16 deletions

View File

@ -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

View File

@ -1,6 +1,8 @@
# see top-level Makefile.in
class
constants
dual
embed
funcptr3
functest
functor

View File

@ -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

109
Examples/lua/dual/dual.cpp Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
#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;
}

View File

@ -0,0 +1,10 @@
/* File : example.i */
%module example
%inline %{
struct Foo{
int i;
};
%}

View File

@ -0,0 +1,10 @@
/* File : example2.i */
%module example2
%inline %{
struct Bar{
int i;
};
%}

View File

@ -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

View File

@ -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 <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
/* 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;
}

View File

@ -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");
}

View File

@ -0,0 +1,8 @@
/* File : example.i */
%module example
%inline %{
extern int gcd(int x, int y);
extern double Foo;
extern void greeting();
%}

View File

@ -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

View File

@ -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)

View File

@ -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) */

View File

@ -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));