diff --git a/CHANGES.current b/CHANGES.current index 6ea618ecc..abee8c9eb 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,12 @@ Version 1.3.36 (in progress) ============================= +04/30/2008: mgossage + [Lua] Removed generation of _wrap_delete_XXXXX (wrappered destructor) + which was unused and causing warning with g++ -Wall. + Removed other unused warning in typemaps.i and other places. + Added Examples/lua/embed3, and run tests a few test cases. + 04/24/2008: olly [Python] Fix generated code for IBM's C++ compiler on AIX (patch from Goeran Uddeborg in SF#1928048). diff --git a/Examples/lua/check.list b/Examples/lua/check.list index 587318e25..6862e4478 100644 --- a/Examples/lua/check.list +++ b/Examples/lua/check.list @@ -5,6 +5,7 @@ constants dual embed embed2 +embed3 exception funcptr3 functest diff --git a/Examples/lua/embed3/Makefile b/Examples/lua/embed3/Makefile new file mode 100644 index 000000000..def3528a5 --- /dev/null +++ b/Examples/lua/embed3/Makefile @@ -0,0 +1,20 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +TARGET = embed3 +SRCS = example.cpp +INTERFACE = example.i +LUA_INTERP = embed3.cpp + +# this is a little different to normal as we have our own special interpreter +# which we want to static link +# we also need the external runtime, so we can get access to certain internals of SWIG +all:: + $(SWIG) -c++ -lua $(SWIGOPT) -external-runtime swigluarun.h + $(MAKE) -f $(TOP)/Makefile $(SWIGLIB) SRCS='$(SRCS)' 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/embed3/embed3.cpp b/Examples/lua/embed3/embed3.cpp new file mode 100644 index 000000000..e42401cda --- /dev/null +++ b/Examples/lua/embed3/embed3.cpp @@ -0,0 +1,133 @@ +/* embed3.cpp A C++ embeded interpreter + +This will register a C++ class with Lua, and then call a Lua function +passing C++ objects to this function. + +*/ + +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +} + +#include "swigluarun.h" // the SWIG external runtime + +/* the SWIG wrappered library */ +extern "C" int luaopen_example(lua_State*L); + +// the code itself +#include "example.h" + +// this code pushes a C++ pointer as well as the SWIG type onto the Lua stack +bool push_pointer(lua_State*L, void* ptr, const char* type_name, int owned = 0) { + // task 1: get the object 'type' which is registered with SWIG + // you need to call SWIG_TypeQuery() with the class name + // (normally, just look in the wrapper file to get this) + swig_type_info * pTypeInfo = SWIG_TypeQuery(L, type_name); + if (pTypeInfo == 0) + return false; // error + // task 2: push the pointer to the Lua stack + // this requires a pointer & the type + // the last param specifies if Lua is responsible for deleting the object + SWIG_NewPointerObj(L, ptr, pTypeInfo, owned); + return true; +} + +/* This is an example of how to call the Lua function + void onEvent(Event e) + its very tedious, but gives you an idea of the issues involed. +*/ +int call_onEvent(lua_State *L, Event e) { + int top; + /* ok, here we go: + push a, push b, call 'add' check & return res + */ + top = lua_gettop(L); /* for later */ + lua_pushstring(L, "onEvent"); /* function name */ + lua_gettable(L, LUA_GLOBALSINDEX); /* function to be called */ + if (!lua_isfunction(L, -1)) { + printf("[C++] error: cannot find function 'OnEvent'\n"); + lua_settop(L, top); // reset + return 0; + } + // push the event object + push_pointer(L, &e, "Event *", 0); + if (lua_pcall(L, 1, 0, 0) != 0) /* call function with 1 arguments and no result */ + { + printf("[C++] error running function `OnEvent': %s\n", lua_tostring(L, -1)); + lua_settop(L, top); // reset + return 0; + } + lua_settop(L, top); /* reset stack */ + return 1; // ok +} + + +int main(int argc, char* argv[]) { + int ok; + int res; + char str[80]; + printf("[C++] Welcome to the simple embedded Lua example v3\n"); + printf("[C++] We are in C++\n"); + printf("[C++] opening a Lua state & loading the libraries\n"); + lua_State *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 create an Engine and pass a pointer to Lua\n"); + Engine engine; + /* this code will pass a pointer into lua, but C++ still owns the object + this is a little tedious, to do, but lets do it + we need to pass the pointer (obviously), the type name + and a flag which states if Lua should delete the pointer once its finished with it + The type name is a class name string which is registered with SWIG + (normally, just look in the wrapper file to get this) + in this case we don't want Lua to delete the pointer so the ownership flag is 0 + */ + push_pointer(L,&engine,"Engine *",0); + lua_setglobal(L, "pEngine"); // set as global variable + + printf("[C++] now 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 Lua function onEvent(e)\n"); + printf("[C++] We will give it different events, as we wish\n"); + printf("[C++] Starting with STARTUP\n"); + Event ev; + ev.mType = Event::STARTUP; + call_onEvent(L, ev); + printf("[C++] ok\n"); + printf("[C++] now we will try MOUSEPRESS,KEYPRESS,MOUSEPRESS\n"); + ev.mType = Event::MOUSEPRESS; + call_onEvent(L, ev); + ev.mType = Event::KEYPRESS; + call_onEvent(L, ev); + ev.mType = Event::MOUSEPRESS; + call_onEvent(L, ev); + printf("[C++] ok\n"); + printf("[C++] Finally we will SHUTDOWN\n"); + ev.mType = Event::SHUTDOWN; + call_onEvent(L, ev); + printf("[C++] ok\n"); + + printf("\n"); + printf("[C++] all finished, closing the lua state\n"); + lua_close(L); + return 0; +} diff --git a/Examples/lua/embed3/example.cpp b/Examples/lua/embed3/example.cpp new file mode 100644 index 000000000..a8264f370 --- /dev/null +++ b/Examples/lua/embed3/example.cpp @@ -0,0 +1,25 @@ +/* File : example.cpp */ + +#include +#include "example.h" + +void Engine::start() +{ + printf("[C++] Engine::start()\n"); +} + +void Engine::stop() +{ + printf("[C++] Engine::stop()\n"); +} + +void Engine::accelerate(float f) +{ + printf("[C++] Engine::accelerate(%f)\n",f); +} + +void Engine::decelerate(float f) +{ + printf("[C++] Engine::decelerate(%f)\n",f); +} + diff --git a/Examples/lua/embed3/example.h b/Examples/lua/embed3/example.h new file mode 100644 index 000000000..41c13e9c1 --- /dev/null +++ b/Examples/lua/embed3/example.h @@ -0,0 +1,24 @@ +/* File : example.h */ + +/* This is some kind of engine of some kind +we will give it some dummy methods for Lua to call*/ + +class Engine +{ +public: + void start(); + void stop(); + void accelerate(float f); + void decelerate(float f); +}; + + +/* We also want to pass some events to Lua, so lets have a few classes +to do this. +*/ +class Event +{ +public: + enum {STARTUP,KEYPRESS,MOUSEPRESS,SHUTDOWN} mType; + // etc +}; diff --git a/Examples/lua/embed3/example.i b/Examples/lua/embed3/example.i new file mode 100644 index 000000000..032805c0e --- /dev/null +++ b/Examples/lua/embed3/example.i @@ -0,0 +1,8 @@ +/* File : example.i */ +%module example + +%{ +#include "example.h" +%} + +%include "example.h" diff --git a/Examples/lua/embed3/runme.lua b/Examples/lua/embed3/runme.lua new file mode 100644 index 000000000..3a44bd2fc --- /dev/null +++ b/Examples/lua/embed3/runme.lua @@ -0,0 +1,35 @@ +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. Do not run this file directly, run the embed3 executable") + +print "[lua] looking to see if we have a pointer to the engine" +if type(pEngine)=="userdata" then + print "[lua] looks good" +else + print "[lua] nope, no signs of it" +end + + +-- the embed program expects a function void onEvent(Event) +-- this is it + +function onEvent(e) + print("[Lua] onEvent with event",e.mType) + -- lets do something with the Engine + -- nothing clever, but ... + if e.mType==example.Event_STARTUP then + pEngine:start() + elseif e.mType==example.Event_KEYPRESS then + pEngine:accelerate(0.4) + elseif e.mType==example.Event_MOUSEPRESS then + pEngine:decelerate(0.4) + elseif e.mType==example.Event_SHUTDOWN then + pEngine:stop() + else + error("unknown event type") + end + print("[Lua] ending onEvent") +end \ No newline at end of file diff --git a/Examples/lua/owner/example.i b/Examples/lua/owner/example.i index 0be5bccc3..4e7c331bc 100644 --- a/Examples/lua/owner/example.i +++ b/Examples/lua/owner/example.i @@ -27,9 +27,6 @@ void add_Shape(Shape* s,ShapeOwner* own){own->add(s);} // or a better solution is a typemap %apply SWIGTYPE *DISOWN {Shape* ptr}; - -//%ignore ShapeOwner::add; - // now we can grab the header file %include "example.h" diff --git a/Examples/test-suite/lua/disown_runme.lua b/Examples/test-suite/lua/disown_runme.lua new file mode 100644 index 000000000..270758990 --- /dev/null +++ b/Examples/test-suite/lua/disown_runme.lua @@ -0,0 +1,12 @@ +require("import") -- the import fn +import("disown") -- import code + +-- catch "undefined" global variables +setmetatable(getfenv(),{__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) + +for x=0,100 do + a=disown.A() + b=disown.B() + b:acquire(a) +end +collectgarbage() -- this will double delete unless the memory is managed properly diff --git a/Examples/test-suite/lua/import_nomodule_runme.lua b/Examples/test-suite/lua/import_nomodule_runme.lua new file mode 100644 index 000000000..947acebf5 --- /dev/null +++ b/Examples/test-suite/lua/import_nomodule_runme.lua @@ -0,0 +1,14 @@ +require("import") -- the import fn +import("import_nomodule") -- import code + +-- catch "undefined" global variables +setmetatable(getfenv(),{__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) + +f = import_nomodule.create_Foo() +import_nomodule.test1(f,42) +import_nomodule.delete_Foo(f) + +b = import_nomodule.Bar() +import_nomodule.test1(b,37) + +collectgarbage() \ No newline at end of file diff --git a/Lib/lua/typemaps.i b/Lib/lua/typemaps.i index bccfbe120..e0adcf192 100644 --- a/Lib/lua/typemaps.i +++ b/Lib/lua/typemaps.i @@ -192,7 +192,7 @@ There probably is some compiler that its not true for, so the code is left here #define SWIG_FREE_ARRAY(PTR) free(PTR); #endif /* counting the size of arrays:*/ -int SWIG_itable_size(lua_State* L, int index) +SWIGINTERN int SWIG_itable_size(lua_State* L, int index) { int n=0; while(1){ @@ -205,7 +205,7 @@ int SWIG_itable_size(lua_State* L, int index) return n; } -int SWIG_table_size(lua_State* L, int index) +SWIGINTERN int SWIG_table_size(lua_State* L, int index) { int n=0; lua_pushnil(L); /* first key*/ @@ -218,7 +218,7 @@ int SWIG_table_size(lua_State* L, int index) /* super macro to declare array typemap helper fns */ #define SWIG_DECLARE_TYPEMAP_ARR_FN(NAME,TYPE)\ - int SWIG_read_##NAME##_num_array(lua_State* L,int index,TYPE *array,int size){\ + SWIGINTERN int SWIG_read_##NAME##_num_array(lua_State* L,int index,TYPE *array,int size){\ int i;\ for (i = 0; i < size; i++) {\ lua_rawgeti(L,index,i+1);\ @@ -232,7 +232,7 @@ int SWIG_table_size(lua_State* L, int index) }\ return 1;\ }\ - static TYPE* SWIG_get_##NAME##_num_array_fixed(lua_State* L, int index, int size){\ + SWIGINTERN TYPE* SWIG_get_##NAME##_num_array_fixed(lua_State* L, int index, int size){\ TYPE *array;\ if (!lua_istable(L,index) || SWIG_itable_size(L,index) != size) {\ lua_pushfstring(L,"expected a table of size %d",size);\ @@ -246,7 +246,7 @@ int SWIG_table_size(lua_State* L, int index) }\ return array;\ }\ - static TYPE* SWIG_get_##NAME##_num_array_var(lua_State* L, int index, int* size)\ + SWIGINTERN TYPE* SWIG_get_##NAME##_num_array_var(lua_State* L, int index, int* size)\ {\ TYPE *array;\ if (!lua_istable(L,index)) {\ @@ -266,7 +266,7 @@ int SWIG_table_size(lua_State* L, int index) }\ return array;\ }\ - void SWIG_write_##NAME##_num_array(lua_State* L,TYPE *array,int size){\ + SWIGINTERN void SWIG_write_##NAME##_num_array(lua_State* L,TYPE *array,int size){\ int i;\ lua_newtable(L);\ for (i = 0; i < size; i++){\ @@ -414,7 +414,7 @@ so if the C/C++ frees then Lua is not aware */ %{ -int SWIG_read_ptr_array(lua_State* L,int index,void **array,int size,swig_type_info *type){ +SWIGINTERN int SWIG_read_ptr_array(lua_State* L,int index,void **array,int size,swig_type_info *type){ int i; for (i = 0; i < size; i++) { lua_rawgeti(L,index,i+1); @@ -426,7 +426,7 @@ int SWIG_read_ptr_array(lua_State* L,int index,void **array,int size,swig_type_i } return 1; } -static void** SWIG_get_ptr_array_fixed(lua_State* L, int index, int size,swig_type_info *type){ +SWIGINTERN void** SWIG_get_ptr_array_fixed(lua_State* L, int index, int size,swig_type_info *type){ void **array; if (!lua_istable(L,index) || SWIG_itable_size(L,index) != size) { lua_pushfstring(L,"expected a table of size %d",size); @@ -440,7 +440,7 @@ static void** SWIG_get_ptr_array_fixed(lua_State* L, int index, int size,swig_ty } return array; } -static void** SWIG_get_ptr_array_var(lua_State* L, int index, int* size,swig_type_info *type){ +SWIGINTERN void** SWIG_get_ptr_array_var(lua_State* L, int index, int* size,swig_type_info *type){ void **array; if (!lua_istable(L,index)) { lua_pushstring(L,"expected a table"); @@ -459,7 +459,7 @@ static void** SWIG_get_ptr_array_var(lua_State* L, int index, int* size,swig_typ } return array; } -void SWIG_write_ptr_array(lua_State* L,void **array,int size,swig_type_info *type,int own){ +SWIGINTERN void SWIG_write_ptr_array(lua_State* L,void **array,int size,swig_type_info *type,int own){ int i; lua_newtable(L); for (i = 0; i < size; i++){ diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx index d2e419ba2..f807a7f87 100644 --- a/Source/Modules/lua.cxx +++ b/Source/Modules/lua.cxx @@ -51,6 +51,7 @@ char cvsroot_lua_cxx[] = "$Id$"; */ #define REPORT(T,D) // no info: //#define REPORT(T,D) {Printf(stdout,T"\n");} // only title +//#define REPORT(T,D) {Printf(stdout,T" %p\n",n);} // title & pointer //#define REPORT(T,D) {Printf(stdout,T"\n");display_mapping(D);} // the works //#define REPORT(T,D) {Printf(stdout,T"\n");if(D)Swig_print_node(D);} // the works @@ -333,7 +334,7 @@ public: * --------------------------------------------------------------------- */ virtual int functionWrapper(Node *n) { - // REPORT("functionWrapper",n); + REPORT("functionWrapper",n); String *name = Getattr(n, "name"); String *iname = Getattr(n, "sym:name"); @@ -620,8 +621,17 @@ public: Replaceall(f->code, "$result", "result"); /* Dump the function out */ - Wrapper_print(f, f_wrappers); - + /* in Lua we will not emit the destructor as a wrappered function, + Lua will automatically call the destructor when the object is free'd + However: you cannot just skip this function as it will not emit + any custom destructor (using %extend), as you need to call emit_action() + Therefore we go though the whole function, + but do not write the code into the wrapper + */ + if(current!=DESTRUCTOR) { + Wrapper_print(f, f_wrappers); + } + /* NEW LANGUAGE NOTE:*********************************************** register the function in SWIG different language mappings seem to use different ideas @@ -689,7 +699,18 @@ public: Replaceall(dispatch, "$args", "self,args"); Printv(f->code, dispatch, "\n", NIL); - Printf(f->code, "lua_pushstring(L,\"No matching function for overloaded '%s'\");\n", symname); + + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + Printf(protoTypes, "\n\" %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms"))); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(f->code, "lua_pushstring(L,\"Wrong arguments for overloaded function '%s'\\n\"\n" + "\" Possible C/C++ prototypes are:\\n\"%s);\n",symname,protoTypes); + Delete(protoTypes); + Printf(f->code, "lua_error(L);return 0;\n"); Printv(f->code, "}\n", NIL); Wrapper_print(f, f_wrappers); @@ -840,7 +861,7 @@ public: * ------------------------------------------------------------ */ virtual int classHandler(Node *n) { - REPORT("classHandler", n); + //REPORT("classHandler", n); String *mangled_classname = 0; String *real_classname = 0; @@ -892,6 +913,8 @@ public: // Register the class structure with the type checker // Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_classname); + + // emit a function to be called to delete the object if (have_destructor) { Printv(f_wrappers, "static void swig_delete_", class_name, "(void *obj) {\n", NIL); if (destructor_action) { @@ -1061,7 +1084,7 @@ public: * ------------------------------------------------------------ */ virtual int destructorHandler(Node *n) { - //REPORT("destructorHandler", n); + REPORT("destructorHandler", n); current = DESTRUCTOR; Language::destructorHandler(n); current = NO_CPP;