diff options
21 files changed, 2692 insertions, 953 deletions
diff --git a/Doc/Manual/Lua.html b/Doc/Manual/Lua.html index aab6a2ceb..379fdfc94 100644 --- a/Doc/Manual/Lua.html +++ b/Doc/Manual/Lua.html @@ -77,7 +77,7 @@ eLua stands for Embedded Lua (can be thought of as a flavor of Lua) and offers t <p> -The current SWIG implementation is designed to work with Lua 5.0.x, 5.1.x and 5.2.x. It should work with later versions of Lua, but certainly not with Lua 4.0 due to substantial API changes. It is possible to either static link or dynamic link a Lua module into the interpreter (normally Lua static links its libraries, as dynamic linking is not available on all platforms). SWIG also supports eLua and works with eLua 0.8. SWIG generated code for eLua has been tested on Stellaris ARM Cortex-M3 LM3S and Infineon TriCore. +The current SWIG implementation is designed to work with Lua 5.0.x, 5.1.x and 5.2.x. It should work with later versions of Lua, but certainly not with Lua 4.0 due to substantial API changes. It is possible to either static link or dynamic link a Lua module into the interpreter (normally Lua static links its libraries, as dynamic linking is not available on all platforms). SWIG also has support for eLua starting from eLua 0.8. Due to substantial changes between SWIG 2.x and SWIG 3.0 and unavailability of testing platform, eLua status was downgraded to 'experimental'. </p> <H2><a name="Lua_nn3"></a>26.2 Running SWIG</H2> @@ -159,6 +159,14 @@ swig -lua -help <td>Do not register the module name as a global variable but return the module table from calls to require.</td> </tr> +<tr> + <td>-no-old-metatable-bindings</td> + <td>Disable backward compatibility: old-style binding names generations and a few other things. Explanations are included into appropriate sections.</td> +</tr> +<tr> + <td>-squash-bases</td> + <td>Squashes symbols from all inheritance tree of a given class into itself. Emulates pre-SWIG3.0 inheritance. Insignificantly speeds things up, but increases memory consumption.</td> +</tr> </table> <H3><a name="Lua_nn4"></a>26.2.2 Compiling and Linking and Interpreter</H3> @@ -349,7 +357,8 @@ creates a built-in function <tt>example.fact(n)</tt> that works exactly like you > </pre></div> <p> -To avoid name collisions, SWIG create a Lua table which it keeps all the functions and global variables in. It is possible to copy the functions out of this and into the global environment with the following code. This can easily overwrite existing functions, so this must be used with care. +To avoid name collisions, SWIG create a Lua table which it keeps all the functions, constants, classes and global variables in. It is possible to copy the functions, constants and classes (but not variables) out of this and into the global environment with the following code. This can easily overwrite existing functions, so this must be used with care. +This option is considered deprecated and will be removed in near future. </p> <div class="targetlang"><pre> > for k,v in pairs(example) do _G[k]=v end @@ -490,6 +499,52 @@ If you're using eLua and have used <tt>-elua</tt> or <tt>-eluac</tt> to generate > print(example.const.SCONST) Hello World </pre></div> + +<H4>Constants/enums and classes/structures</H4> +<p> +Unlike previous version of bindings, enums are now exported into class table. For example, given some enums: +</p> +<div class="code"><pre>%module example +enum Days{SUNDAY = 0,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}; +class Test { + enum { TEST1 = 10, TEST2 = 10 } + static const int ICONST = 12; +}; +</pre></div> +<p> +This is 'effectively' converted into the following Lua code: +</p> +<div class="targetlang"><pre> +> print(example.const.SUNDAY) +0 +> print(example.Test.TEST1) +10 +> print(example.Test.ICONST) +12 +</pre></div> +<H4>Backward compatibility</H4> +<p> +If <tt>-no-old-metatable-bindings</tt> option is not given, then in addition to previously described bindings, the old-style ones are generated: +</p> +<div class="targetlang"><pre> +> print(example.Test_TEST1) +10 +> print(example.Test_ICONST) +12 +</pre></div> +<p> +However, in C mode, names of enums are not prefixed with names of structure. This is the due to C Standard. +</p> +<div class="targetlang"><pre> +> print(example.TEST1) +10 +> print(example.ICONST) +12 +</pre></div> +<p> +It worth mentioning, that <tt>example.Test.TEST1</tt> and <tt>example.Test_TEST1</tt> are different entities and changind one wouldn't change another. +Given the fact, that these are constantes and they are not supposed to be changed, it is up to you to avoid such issues. +</p> <H3><a name="Lua_nn12"></a>26.3.5 Pointers</H3> @@ -551,7 +606,7 @@ is used as follows: </pre></div> <p> Similar access is provided for unions and the data members of C++ classes.<br> -C structures are created using a function <tt>new_Point()</tt>, but for C++ classes are created using just the name <tt>Point()</tt>. +C structures can be created using a function <tt>new_Point()</tt>, and both C structures and C++ classes can be created using just the name <tt>Point()</tt>. </p> <p> If you print out the value of p in the above example, you will see something like this: @@ -679,9 +734,9 @@ public: In Lua, the static members can be accessed as follows: </p> <div class="code"><pre> -> example.Spam_foo() -- calling Spam::foo() -> a=example.Spam_bar -- reading Spam::bar -> example.Spam_bar=b -- writing to Spam::bar +> example.Spam.foo() -- calling Spam::foo() +> a=example.Spam.bar -- reading Spam::bar +> example.Spam.bar=b -- writing to Spam::bar </pre></div> <p> It is not (currently) possible to access static members of an instance: @@ -692,6 +747,13 @@ It is not (currently) possible to access static members of an instance: -- does NOT work </pre></div> +<H4>Backward compatibility</H4> +<p> If <tt>-no-old-metatable-bindings</tt> option is not given, then backward compatible names are generated in addition to ordinary ones: </p> +<div class="code"><pre> +> example.Spam_foo() -- calling Spam::foo() +> a=example.Spam_bar -- reading Spam::bar +> example.Spam_bar=b -- writing to Spam::bar +</pre></div> <H3><a name="Lua_nn15"></a>26.3.8 C++ inheritance</H3> @@ -1256,6 +1318,143 @@ and the "<a href="Customization.html#Customization_exception">Exception handling add exception specification to functions or globally (respectively). </p> +<H3><a name ="Lua_nn23_5"></a>26.3.17 Namespaces </H3> +<p> +Since SWIG 3.0 C++ namespaces are supported. You can enabled handling namespaces with %nspace feature. Everything below is valid only after you enabled %nspace. +</p> +<p> Namespaces are mapped into lua tables. Each of those tables contains names that were defined within appropriate namespace. Namespaces structure (a.k.a nested namespaces) is preserved. Consider the following C++ code: +</p> +<div class="code"><pre>%module example +%nspace MyWorld::Nested::Dweller; +%nspace MyWorld::World; +/* and so on */ +int module_function() { return 7;} +int module_variable; // = 9 +namespace MyWorld { + class World { + public: + int create_world() { return 17;} + const int world_max_count = 9; + }; + namespace Nested { + class Dweller { + enum Gender {MALE, FEMALE; + static int populate_cave() { return 19; } + int create_cave() { return 13;} + int food_count; // = 11 + } + } +} +</pre></div> +Now, in Lua it could be used like this: +<div class="targetlang"><pre> +> example.module_function() +7 +> print(example.module_variable) +8 +> print(example.MyWorld.World():create_world()) +17 +> print(example.MyWorld.World.world_max_count) +9 +> print(example.MyWordl.Nested.Dweller.MALE) +0 +> print(example.MyWordl.Nested.Dweller().food_count) +11 +> +</pre></div> +<H4> Backward compatibility </H4> +<p> +If SWIG is running in backward compatible way, i.e. without <tt>-no-old-metatable-bindings</tt> option, then additional old-style names are generated(notice the underscore): +</p> +<div class="targetlang"><pre> +9 +> print(example.MyWorld.Nested.Dweller_MALE) +0 +> print(example.MyWorld.Nested.Dweller_populate_cave()) +11 +> +</pre></div> +<H3> Backward compatibility </H3> +<H4> Names </H4> +<p> If SWIG is launched without <tt>-no-old-metatable-bindings</tt> option, then it enters backward-compatible mode. While in this mode, it tries +to generate additional names for static functions, class static constants and class enums. +Those names are in a form <tt>$classname_$symbolname</tt> and are added to the scope surrounding the class. +If %nspace is enabled, then class namespace is taken as scope. If there is no namespace, or %nspace is disabled, +then module is considered a class namespace.</p> +<p> Consider the following C++ code </p> +<div class="code"><pre>%module example +%nspace MyWorld::Test; +namespace MyWorld { +class Test { + public: + enum { TEST1 = 10, TEST2 } + static const int ICONST = 12; +}; +class Test2 { + public: + enum { TEST3 = 20, TEST4 } + static const int ICONST2 = 23; +} +</pre></div> +<p> When in backward compatible mode, in addition to usual names, the following ones will be generated (notice the underscore):</p> +<div class="targetlang"><pre> +9 +> print(example.MyWorld.Test_TEST1) -- Test has %nspace enabled +10 +> print(example.MyWorld.Test_ICONST) -- Test has %nspace enabled +12 +> print(example.Test2_TEST3) -- Test2 doesn't have %nspace enabled +20 +> print(example.Test2_ICONST2) -- Test2 doesn't have %nspace enabled +23 +> +</pre></div> +<p> There is a slight difference with enums when in C mode. As per C standard, enums from C structures are exported to +surrounding scope without any prefixing. Pretending that Test2 is a struct, not class, that would be:</p> +<div class="targetlang"><pre> +> print(example.TEST3) -- NOT Test2_TEST3 +20 +> +</pre></div> + +<H4> Inheritance </H4> +<p> The internal organization of inheritance has changed. +Consider the following C++ code:</p> +<div class="code"><pre>%module example +class Base { + public: + int base_func() +}; +class Derived : public Base { + public: + int derived_func() +} +</pre></div> +<p>Lets assume for a moment that class member functions are stored in <tt>.fn</tt> table. Previously, when classes +were exported to Lua during module initialization, for every derived class all service tables <tt>ST(i.e. ".fn")</tt> +were squashed and added to corresponding derived class <tt>ST</tt>: Everything from <tt>.fn</tt> table of class Base +was copied to <tt>.fn</tt> table of class Derived and so on. This was a recursive procedure, so in the end the whole +inheritance tree of derived class was squashed into derived class. </p> +<p> That means that any changes done to class Base after module initialization wouldn't affect class Derived:</p> +<div class="targetlang"><pre> +base = example.Base() +der = example.Derived() +> print(base.base_func) +function: 0x1367940 +> getmetatable(base)[".fn"].new_func = function (x) return x -- Adding new function to class Base (to class, not to an instance!) +> print(base.new_func) -- Checking this function +function +> print(der.new_func) -- Wouldn't work. Derived doesn't check Base any more. +nil +> +</pre></div> +<p> This behaviour was changed. Now unless -squash-bases option is provided, Derived store a list of it's bases and if some symbol is not found in it's own service tables +then its bases are searched for it. Option -squash-bases will effectively return old behaviour. +<div class="targetlang"><pre> +> print(der.new_func) -- Now it works +function +> +</pre></div> <H2><a name="Lua_nn24"></a>26.4 Typemaps</H2> diff --git a/Examples/test-suite/director_nspace.i b/Examples/test-suite/director_nspace.i index 512077e8b..fdea75e2f 100644 --- a/Examples/test-suite/director_nspace.i +++ b/Examples/test-suite/director_nspace.i @@ -40,7 +40,7 @@ namespace TopLevel %include <std_string.i> // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGLUA) %nspace TopLevel::Bar::Foo; %nspace TopLevel::Bar::FooBar; #else diff --git a/Examples/test-suite/director_nspace_director_name_collision.i b/Examples/test-suite/director_nspace_director_name_collision.i index c6f13b451..8fd27c968 100644 --- a/Examples/test-suite/director_nspace_director_name_collision.i +++ b/Examples/test-suite/director_nspace_director_name_collision.i @@ -34,7 +34,7 @@ namespace TopLevel %include <std_string.i> // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGLUA) %nspace TopLevel::A::Foo; %nspace TopLevel::B::Foo; #else diff --git a/Examples/test-suite/keyword_rename.i b/Examples/test-suite/keyword_rename.i index 46c3338b3..a9f58ebef 100644 --- a/Examples/test-suite/keyword_rename.i +++ b/Examples/test-suite/keyword_rename.i @@ -32,8 +32,10 @@ KW(go, defer) KW(chan, fallthrough) /* Lua keywords */ +#ifdef SWIGLUA KW(end, function) KW(nil,local) +#endif %} diff --git a/Examples/test-suite/lua/enums_runme.lua b/Examples/test-suite/lua/enums_runme.lua index 6211581fe..998f01cfc 100644 --- a/Examples/test-suite/lua/enums_runme.lua +++ b/Examples/test-suite/lua/enums_runme.lua @@ -19,4 +19,12 @@ assert(enums.globalinstance3==30) assert(enums.AnonEnum1==0) assert(enums.AnonEnum2==100) +-- In C enums from struct are exported without prefixing with struct name +-- In C++ they are prefixed. +-- We are emulating xor :) +assert(enums.BAR1 ~= enums.Foo_BAR1) -- It is either C style, or C++ style, but not both +assert((enums.BAR1 ~= nil ) or (enums.Foo_BAR1 ~= nil)) + +assert(enums.Phoo ~= enums.iFoo_Phoo) +assert((enums.Phoo == 50) or (enums.iFoo_Phoo == 50)) -- no point in checking fns, C will allow any value diff --git a/Examples/test-suite/lua/grouping_runme.lua b/Examples/test-suite/lua/grouping_runme.lua index 7ab08499f..b13409514 100644 --- a/Examples/test-suite/lua/grouping_runme.lua +++ b/Examples/test-suite/lua/grouping_runme.lua @@ -14,4 +14,5 @@ assert(g.test3 == 37) g.test3 = 42 assert(g.test3 == 42) +assert(g.NEGATE ~= nil) assert(g.do_unary(5, g.NEGATE) == -5) diff --git a/Examples/test-suite/lua/li_carrays_runme.lua b/Examples/test-suite/lua/li_carrays_runme.lua index 285d7b32a..d007fae36 100644 --- a/Examples/test-suite/lua/li_carrays_runme.lua +++ b/Examples/test-suite/lua/li_carrays_runme.lua @@ -1,8 +1,6 @@ require("import") -- the import fn import("li_carrays") -- import code - --- moving to global -for k,v in pairs(li_carrays) do _G[k]=v end +lc = li_carrays -- catch "undefined" global variables local env = _ENV -- Lua 5.2 @@ -10,22 +8,22 @@ if not env then env = getfenv () end -- Lua 5.1 setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) -- Testing for %array_functions(int,intArray) -ary = new_intArray(2) -intArray_setitem(ary, 0, 0) -intArray_setitem(ary, 1, 1) -assert(intArray_getitem(ary, 0)==0) -assert(intArray_getitem(ary, 1)==1) -delete_intArray(ary) +ary = lc.new_intArray(2) +lc.intArray_setitem(ary, 0, 0) +lc.intArray_setitem(ary, 1, 1) +assert(lc.intArray_getitem(ary, 0)==0) +assert(lc.intArray_getitem(ary, 1)==1) +lc.delete_intArray(ary) -- Testing for %array_class(double, doubleArray) -d = doubleArray(10) +d = lc.doubleArray(10) d[0] = 7 d[5] = d[0] + 3 assert(d[5] + d[0] == 17) --print(d[5] + d[0]) ptr = d:cast() -- to ptr -d2 = doubleArray_frompointer(ptr) -- and back to array +d2 = lc.doubleArray_frompointer(ptr) -- and back to array assert(d2[5] + d2[0] == 17) --print(d2[5] + d2[0]) diff --git a/Examples/test-suite/lua/member_pointer_runme.lua b/Examples/test-suite/lua/member_pointer_runme.lua index 8dddab295..1240d92a0 100644 --- a/Examples/test-suite/lua/member_pointer_runme.lua +++ b/Examples/test-suite/lua/member_pointer_runme.lua @@ -1,43 +1,46 @@ --Example using pointers to member functions - require("import") -- the import fn import("member_pointer") -- import code +mp = member_pointer -for k,v in pairs(member_pointer) do _G[k]=v end +-- catching undefined variables +local env = _ENV -- Lua 5.2 +if not env then env = getfenv () end -- Lua 5.1 +setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) function check(what, expected, actual) assert(expected == actual,"Failed: "..what.." Expected: "..expected.." Actual: "..actual) end -- Get the pointers -area_pt = areapt() -perim_pt = perimeterpt() +area_pt = mp.areapt() +perim_pt = mp.perimeterpt() -- Create some objects -s = Square(10) +s = mp.Square(10) -- Do some calculations -check ("Square area ", 100.0, do_op(s,area_pt)) -check ("Square perim", 40.0, do_op(s,perim_pt)) +check ("Square area ", 100.0, mp.do_op(s,area_pt)) +check ("Square perim", 40.0, mp.do_op(s,perim_pt)) -- Try the variables -- these have to still be part of the 'member_pointer' table -memberPtr = member_pointer.areavar -memberPtr = member_pointer.perimetervar +memberPtr = mp.areavar +memberPtr = mp.perimetervar -check ("Square area ", 100.0, do_op(s,member_pointer.areavar)) -check ("Square perim", 40.0, do_op(s,member_pointer.perimetervar)) +check ("Square area ", 100.0, mp.do_op(s,mp.areavar)) +check ("Square perim", 40.0, mp.do_op(s,mp.perimetervar)) -- Modify one of the variables -member_pointer.areavar = perim_pt +mp.areavar = perim_pt -check ("Square perimeter", 40.0, do_op(s,member_pointer.areavar)) +check ("Square perimeter", 40.0, mp.do_op(s,mp.areavar)) -- Try the constants -memberPtr = AREAPT -memberPtr = PERIMPT -memberPtr = NULLPT +memberPtr = mp.AREAPT +memberPtr = mp.PERIMPT +memberPtr = mp.NULLPT -check ("Square area ", 100.0, do_op(s,AREAPT)) -check ("Square perim", 40.0, do_op(s,PERIMPT)) +check ("Square area ", 100.0, mp.do_op(s,mp.AREAPT)) +check ("Square perim", 40.0, mp.do_op(s,mp.PERIMPT)) diff --git a/Examples/test-suite/lua/newobject1_runme.lua b/Examples/test-suite/lua/newobject1_runme.lua index 5de8276db..55d04eeb7 100644 --- a/Examples/test-suite/lua/newobject1_runme.lua +++ b/Examples/test-suite/lua/newobject1_runme.lua @@ -1,8 +1,8 @@ require("import") -- the import fn import("newobject1") -- import code -foo1 = newobject1.Foo_makeFoo() -- lua doesnt yet support static fns properly -assert(newobject1.Foo_fooCount() == 1) -- lua doesnt yet support static fns properly +foo1 = newobject1.Foo_makeFoo() +assert(newobject1.Foo_fooCount() == 1) foo2 = foo1:makeMore() assert(newobject1.Foo_fooCount() == 2) diff --git a/Examples/test-suite/lua/nspace_extend_runme.lua b/Examples/test-suite/lua/nspace_extend_runme.lua new file mode 100644 index 000000000..d942b7b9d --- /dev/null +++ b/Examples/test-suite/lua/nspace_extend_runme.lua @@ -0,0 +1,39 @@ +require("import") -- the import fn +import("nspace_extend") -- import lib + +-- catch "undefined" global variables +local env = _ENV -- Lua 5.2 +if not env then env = getfenv () end -- Lua 5.1 +setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) + +ne = nspace_extend + +-- Inner1 + +-- Constructors +in1_clr1 = ne.Outer.Inner1.Color() +in1_clr2 = ne.Outer.Inner1.Color.create() +in1_clr3 = ne.Outer.Inner1.Color(in1_clr2) + +-- methods +in1_clr1:colorInstanceMethod(1.0) +ne.Outer.Inner1.Color.colorStaticMethod(2.0) + +-- Inner2 + +-- Constructors +in2_clr1 = ne.Outer.Inner2.Color() +in2_clr2 = ne.Outer.Inner2.Color.create() +in2_clr3 = ne.Outer.Inner2.Color(in2_clr2) + +assert(pcall(ne.Outer.Inner2.Color, in1_clr1) == false) + +-- methods +in2_clr1:colorInstanceMethod(1.0) +ne.Outer.Inner2.Color.colorStaticMethod(2.0) + +in2_clr3:colors(in1_clr1, in1_clr2, in2_clr2, in2_clr2, in2_clr3) + +assert(pcall(in2_clr3.colors, in2_clr3, + in2_clr1, in2_clr2, in1_clr2, in2_clr2, in2_clr3) == false) + diff --git a/Examples/test-suite/lua/nspace_runme.lua b/Examples/test-suite/lua/nspace_runme.lua new file mode 100644 index 000000000..2ed8a86b7 --- /dev/null +++ b/Examples/test-suite/lua/nspace_runme.lua @@ -0,0 +1,67 @@ +require("import") -- the import fn
+import("nspace") -- import lib
+
+-- catch "undefined" global variables
+local env = _ENV -- Lua 5.2
+if not env then env = getfenv () end -- Lua 5.1
+setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end})
+
+ns = nspace
+
+-- Inheritance
+blue1 = ns.Outer.Inner3.Blue()
+
+-- blue1:blueInstanceMethod()
+blue1:colorInstanceMethod(60.0)
+blue1.instanceMemberVariable = 4
+assert( blue1.instanceMemberVariable == 4 )
+
+-- Constructors
+color1 = ns.Outer.Inner1.Color()
+color2 = ns.Outer.Inner1.Color.create()
+color = ns.Outer.Inner1.Color(color1)
+color3 = ns.Outer.Inner2.Color.create()
+color4 = ns.Outer.Inner2.Color.create()
+color5 = ns.Outer.Inner2.Color.create()
+mwp2 = ns.Outer.MyWorldPart2()
+gc = ns.GlobalClass()
+
+nnsp = ns.NoNSpacePlease()
+
+-- Class methods
+color:colorInstanceMethod(20.0)
+ns.Outer.Inner1.Color.colorStaticMethod(30.0)
+color3:colorInstanceMethod(40.0)
+ns.Outer.Inner2.Color.colorStaticMethod(50.0)
+color3:colors(color1, color2, color3, color4, color5)
+
+gc:gmethod()
+
+-- Class variables
+color.instanceMemberVariable = 5
+color1.instanceMemberVariable = 7
+assert( color.instanceMemberVariable == 5 )
+assert( color1.instanceMemberVariable == 7 )
+assert(ns.Outer.Inner1.Color.staticMemberVariable == 0 )
+assert(ns.Outer.Inner2.Color.staticMemberVariable == 0 )
+ns.Outer.Inner1.Color.staticMemberVariable = 9
+ns.Outer.Inner2.Color.staticMemberVariable = 11
+assert(ns.Outer.Inner1.Color.staticMemberVariable == 9)
+assert(ns.Outer.Inner2.Color.staticMemberVariable == 11)
+
+-- Class constants
+assert( ns.Outer.Inner1.Color.Specular == 0x20 )
+assert( ns.Outer.Inner2.Color.Specular == 0x40 )
+assert( ns.Outer.Inner1.Color.staticConstMemberVariable == 222 )
+assert( ns.Outer.Inner2.Color.staticConstMemberVariable == 333 )
+assert( ns.Outer.Inner1.Color.staticConstEnumMemberVariable ~= ns.Outer.Inner2.Color.staticConstEnumMemberVariable )
+
+
+-- Aggregation
+sc = ns.Outer.SomeClass()
+assert( sc:GetInner1ColorChannel() ~= sc:GetInner2Channel() )
+assert( sc:GetInner1Channel() ~= sc:GetInner2Channel() )
+
+
+
+
diff --git a/Examples/test-suite/lua/template_default_arg_runme.lua b/Examples/test-suite/lua/template_default_arg_runme.lua index ebb22ed63..853f57882 100644 --- a/Examples/test-suite/lua/template_default_arg_runme.lua +++ b/Examples/test-suite/lua/template_default_arg_runme.lua @@ -3,6 +3,7 @@ import("template_default_arg") -- import code --for k,v in pairs(template_default_arg) do _G[k]=v end -- move to global helloInt = template_default_arg.Hello_int() +assert(template_default_arg.Hello_int_hi ~= nil) helloInt:foo(template_default_arg.Hello_int_hi) x = template_default_arg.X_int() diff --git a/Examples/test-suite/lua/valuewrapper_runme.lua b/Examples/test-suite/lua/valuewrapper_runme.lua new file mode 100644 index 000000000..94d49c7cc --- /dev/null +++ b/Examples/test-suite/lua/valuewrapper_runme.lua @@ -0,0 +1,17 @@ +require("import") -- the import fn +import("valuewrapper") -- import code +v=valuewrapper -- renaming import + +-- catch "undefined" global variables +local env = _ENV -- Lua 5.2 +if not env then env = getfenv () end -- Lua 5.1 +setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) + +assert(v.Xi ~= nil) +assert(v.YXi ~= nil) + +x1 = v.Xi(5) + +y1 =v.YXi() +assert(y1:spam(x1) == 0) +assert(y1:spam() == 0) diff --git a/Examples/test-suite/nspace.i b/Examples/test-suite/nspace.i index c60a45df5..58c560412 100644 --- a/Examples/test-suite/nspace.i +++ b/Examples/test-suite/nspace.i @@ -2,7 +2,7 @@ %module nspace // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGLUA) #if defined(SWIGJAVA) SWIG_JAVABODY_PROXY(public, public, SWIGTYPE) diff --git a/Examples/test-suite/nspace_extend.i b/Examples/test-suite/nspace_extend.i index 782ce90ca..e92ff8c1d 100644 --- a/Examples/test-suite/nspace_extend.i +++ b/Examples/test-suite/nspace_extend.i @@ -2,7 +2,7 @@ %module nspace_extend // nspace feature only supported by these languages -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) || defined(SWIGLUA) #if defined(SWIGJAVA) SWIG_JAVABODY_PROXY(public, public, SWIGTYPE) diff --git a/Lib/lua/lua.swg b/Lib/lua/lua.swg index ee83d11b7..40087236b 100644 --- a/Lib/lua/lua.swg +++ b/Lib/lua/lua.swg @@ -41,12 +41,12 @@ %typemap(consttab) long long, unsigned long long {SWIG_LUA_CONSTTAB_STRING("$symname", "$value")} -%typemap(consttab) SWIGTYPE *, SWIGTYPE *const, SWIGTYPE &, SWIGTYPE &&, SWIGTYPE [] - { SWIG_LUA_POINTER, (char *)"$symname", 0, 0, (void *)$value, &$1_descriptor} +%typemap(consttab) SWIGTYPE *, SWIGTYPE *const, SWIGTYPE &, SWIGTYPE [] + { SWIG_LUA_CONSTTAB_POINTER("$symname",$value, $1_descriptor) } // member function pointers %typemap(consttab) SWIGTYPE (CLASS::*) - { SWIG_LUA_BINARY, (char *)"$symname", sizeof($type), 0, (void *)&$value, &$1_descriptor} + { SWIG_LUA_CONSTTAB_BINARY("$symname", sizeof($type),&$value, $1_descriptor) } /* ----------------------------------------------------------------------------- diff --git a/Lib/lua/luarun.swg b/Lib/lua/luarun.swg index 8485ed499..547231815 100644 --- a/Lib/lua/luarun.swg +++ b/Lib/lua/luarun.swg @@ -27,23 +27,110 @@ extern "C" { # error SWIG_LUA_TARGET not defined #endif +#if defined(SWIG_LUA_ELUA_EMULATE) + +struct swig_elua_entry; + +typedef struct swig_elua_key { + int type; + union { + const char* strkey; + lua_Number numkey; + } key; +} swig_elua_key; + +typedef struct swig_elua_val { + int type; + union { + lua_Number number; + const struct swig_elua_entry *table; + const char *string; + lua_CFunction function; + struct { + char member; + long lvalue; + void *pvalue; + swig_type_info **ptype; + } userdata; + } value; +} swig_elua_val; + +typedef struct swig_elua_entry { + swig_elua_key key; + swig_elua_val value; +} swig_elua_entry; + +#define LSTRKEY(x) {LUA_TSTRING, {.strkey = x} } +#define LNUMKEY(x) {LUA_TNUMBER, {.numkey = x} } +#define LNILKEY {LUA_TNIL, {.strkey = 0} } + +#define LNUMVAL(x) {LUA_TNUMBER, {.number = x} } +#define LFUNCVAL(x) {LUA_TFUNCTION, {.function = x} } +#define LROVAL(x) {LUA_TTABLE, {.table = x} } +#define LNILVAL {LUA_TNIL, {.string = 0} } +#define LSTRVAL(x) {LUA_TSTRING, {.string = x} } + +#define LUA_REG_TYPE swig_elua_entry + +#define SWIG_LUA_ELUA_EMUL_METATABLE_KEY "__metatable" + +#define lua_pushrotable(L,p)\ + lua_newtable(L);\ + assert(p);\ + SWIG_Lua_elua_emulate_register(L,(swig_elua_entry*)(p)); + +#define SWIG_LUA_CONSTTAB_POINTER(B,C,D)\ + LSTRKEY(B), {LUA_TUSERDATA, { .userdata={0,0,(void*)(C),&D} } } + +#define SWIG_LUA_CONSTTAB_BINARY(B,S,C,D)\ + LSTRKEY(B), {LUA_TUSERDATA, { .userdata={1,S,(void*)(C),&D} } } +#endif + #if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC) # define SWIG_LUA_CONSTTAB_INT(B, C) LSTRKEY(B), LNUMVAL(C) # define SWIG_LUA_CONSTTAB_FLOAT(B, C) LSTRKEY(B), LNUMVAL(C) # define SWIG_LUA_CONSTTAB_STRING(B, C) LSTRKEY(B), LSTRVAL(C) # define SWIG_LUA_CONSTTAB_CHAR(B, C) LSTRKEY(B), LNUMVAL(C) + /* Those two types of constants are not supported in elua */ + +#ifndef SWIG_LUA_CONSTTAB_POINTER +#warning eLua does not support pointers as constants. By default, nil will be used as value +#define SWIG_LUA_CONSTTAB_POINTER(B,C,D) LSTRKEY(B), LNILVAL +#endif + +#ifndef SWIG_LUA_CONSTTAB_BINARY +#warning eLua does not support pointers to member as constants. By default, nil will be used as value +#define SWIG_LUA_CONSTTAB_BINARY(B, S, C, D) LSTRKEY(B), LNILVAL +#endif #else /* SWIG_LUA_FLAVOR_LUA */ # define SWIG_LUA_CONSTTAB_INT(B, C) SWIG_LUA_INT, (char *)B, (long)C, 0, 0, 0 # define SWIG_LUA_CONSTTAB_FLOAT(B, C) SWIG_LUA_FLOAT, (char *)B, 0, (double)C, 0, 0 # define SWIG_LUA_CONSTTAB_STRING(B, C) SWIG_LUA_STRING, (char *)B, 0, 0, (void *)C, 0 # define SWIG_LUA_CONSTTAB_CHAR(B, C) SWIG_LUA_CHAR, (char *)B, (long)C, 0, 0, 0 +# define SWIG_LUA_CONSTTAB_POINTER(B,C,D)\ + SWIG_LUA_POINTER, (char *)B, 0, 0, (void *)C, &D +# define SWIG_LUA_CONSTTAB_BINARY(B, S, C, D)\ + SWIG_LUA_BINARY, (char *)B, S, 0, (void *)C, &D #endif +#ifndef SWIG_LUA_ELUA_EMULATE #if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC) # define LRO_STRVAL(v) {{.p = (char *) v}, LUA_TSTRING} # define LSTRVAL LRO_STRVAL #endif +#endif /* SWIG_LUA_ELUA_EMULATE*/ + +#ifndef SWIG_LUA_ELUA_EMULATE +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC) + +#ifndef MIN_OPT_LEVEL +#define MIN_OPT_LEVEL 2 +#endif +#include "lrodefs.h" +#include "lrotable.h" +#endif +#endif /* SWIG_LUA_ELUA_EMULATE*/ /* ----------------------------------------------------------------------------- * compatibility defines * ----------------------------------------------------------------------------- */ @@ -70,6 +157,23 @@ extern "C" { # define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX) #endif +/* lua_absindex was introduced in Lua 5.2 */ +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 +# define lua_absindex(L,i) ((i)>0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1) +#endif + +/* lua_rawsetp was introduced in Lua 5.2 */ +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 +#define lua_rawsetp(L,index,ptr)\ + lua_pushlightuserdata(L,(void*)(ptr));\ + lua_insert(L,-2);\ + lua_rawset(L,index); + +#define lua_rawgetp(L,index,ptr)\ + lua_pushlightuserdata(L,(void*)(ptr));\ + lua_rawget(L,index); + +#endif /* -------------------------------------------------------------------------- * Helper functions for error handling @@ -119,6 +223,12 @@ typedef struct { lua_CFunction set; } swig_lua_var_info; +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC) +typedef const LUA_REG_TYPE swig_lua_method; +typedef const LUA_REG_TYPE swig_lua_const_info; +#else /* Normal lua */ +typedef luaL_Reg swig_lua_method; + /* Constant information structure */ typedef struct { int type; @@ -129,10 +239,7 @@ typedef struct { swig_type_info **ptype; } swig_lua_const_info; -typedef struct { - const char *name; - lua_CFunction method; -} swig_lua_method; +#endif typedef struct { const char *name; @@ -140,23 +247,28 @@ typedef struct { lua_CFunction setmethod; } swig_lua_attribute; -// Can be used to create namespaces. Currently used to -// wrap class static methods/variables/constants -typedef struct { + +struct swig_lua_class; +/* Can be used to create namespaces. Currently used to wrap class static methods/variables/constants */ +typedef struct swig_lua_namespace { const char *name; swig_lua_method *ns_methods; swig_lua_attribute *ns_attributes; swig_lua_const_info *ns_constants; + struct swig_lua_class **ns_classes; + struct swig_lua_namespace **ns_namespaces; } swig_lua_namespace; typedef struct swig_lua_class { - const char *name; + const char *name; /* Name that this class has in Lua */ + const char *fqname; /* Fully qualified name - Scope + class name */ swig_type_info **type; lua_CFunction constructor; void (*destructor)(void *); swig_lua_method *methods; swig_lua_attribute *attributes; - swig_lua_namespace cls_static; + swig_lua_namespace *cls_static; + swig_lua_method *metatable; // 0 for -eluac struct swig_lua_class **bases; const char **base_names; } swig_lua_class; @@ -226,12 +338,12 @@ typedef struct { #ifdef __cplusplus /* Special helper for member function pointers it gets the address, casts it, then dereferences it */ -//#define SWIG_mem_fn_as_voidptr(a) (*((char**)&(a))) +/*#define SWIG_mem_fn_as_voidptr(a) (*((char**)&(a))) */ #endif /* storing/access of swig_module_info */ SWIGRUNTIME swig_module_info * -SWIG_Lua_GetModule(lua_State* L) { +SWIG_Lua_GetModule(lua_State *L) { swig_module_info *ret = 0; lua_pushstring(L,"swig_runtime_data_type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME); lua_rawget(L,LUA_REGISTRYINDEX); @@ -242,7 +354,7 @@ SWIG_Lua_GetModule(lua_State* L) { } SWIGRUNTIME void -SWIG_Lua_SetModule(lua_State* L, swig_module_info *module) { +SWIG_Lua_SetModule(lua_State *L, swig_module_info *module) { /* add this all into the Lua registry: */ lua_pushstring(L,"swig_runtime_data_type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME); lua_pushlightuserdata(L,(void*)module); @@ -256,7 +368,7 @@ SWIG_Lua_SetModule(lua_State* L, swig_module_info *module) { /* this function is called when trying to set an immutable. default action is to print an error. This can removed with a compile flag SWIGLUA_IGNORE_SET_IMMUTABLE */ -SWIGINTERN int SWIG_Lua_set_immutable(lua_State* L) +SWIGINTERN int SWIG_Lua_set_immutable(lua_State *L) { /* there should be 1 param passed in: the new value */ #ifndef SWIGLUA_IGNORE_SET_IMMUTABLE @@ -266,170 +378,184 @@ SWIGINTERN int SWIG_Lua_set_immutable(lua_State* L) return 0; /* should not return anything */ } -/* the module.get method used for getting linked data */ -SWIGINTERN int SWIG_Lua_module_get(lua_State* L) +#ifdef SWIG_LUA_ELUA_EMULATE +//#define report(...) printf(__VA_ARGS__) // TODO: REMOVE +#define report(...) // TODO : REMOVE + +SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State *L,void *ptr,swig_type_info *type, int own); +SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State *L,void *ptr,size_t size,swig_type_info *type); +static int swig_lua_elua_emulate_unique_key; +/* This is function that emulates eLua rotables behaviour. It loads rotable definition + * into the usual lua table. + */ +SWIGINTERN void SWIG_Lua_elua_emulate_register(lua_State *L, const swig_elua_entry *table) { -/* there should be 2 params passed in - (1) table (not the meta table) - (2) string name of the attribute - printf("SWIG_Lua_module_get %p(%s) '%s'\n", - lua_topointer(L,1),lua_typename(L,lua_type(L,1)), - lua_tostring(L,2)); -*/ - /* get the metatable */ -#if ((SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)) - assert(lua_isrotable(L,1)); /* just in case */ -#else - assert(lua_istable(L,1)); /* default Lua action */ -#endif - lua_getmetatable(L,1); /* get the metatable */ -#if ((SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)) - assert(lua_isrotable(L,-1)); /* just in case */ -#else assert(lua_istable(L,-1)); -#endif - SWIG_Lua_get_table(L,".get"); /* get the .get table */ - lua_remove(L,3); /* remove metatable */ -#if ((SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)) - if (lua_isrotable(L,-1)) -#else - if (lua_istable(L,-1)) -#endif - { - /* look for the key in the .get table */ - lua_pushvalue(L,2); /* key */ - lua_rawget(L,-2); - lua_remove(L,3); /* remove .get */ - if (lua_iscfunction(L,-1)) - { /* found it so call the fn & return its value */ - lua_call(L,0,1); - return 1; - } - lua_pop(L,1); /* remove the top */ + int target_table = lua_gettop(L); + /* Get the registry where we put all parsed tables to avoid loops */ + lua_rawgetp(L, LUA_REGISTRYINDEX, &swig_lua_elua_emulate_unique_key); + if(lua_isnil(L,-1)) { + lua_pop(L,1); + lua_newtable(L); + lua_pushvalue(L,-1); + lua_rawsetp(L,LUA_REGISTRYINDEX,(void*)(&swig_lua_elua_emulate_unique_key)); } - lua_pop(L,1); /* remove the .get */ - lua_pushnil(L); /* return a nil */ - return 1; -} - -/* the module.set method used for setting linked data */ -SWIGINTERN int SWIG_Lua_module_set(lua_State* L) -{ -/* there should be 3 params passed in - (1) table (not the meta table) - (2) string name of the attribute - (3) any for the new value -*/ - /* get the metatable */ -#if ((SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)) - assert(lua_isrotable(L,1)); /* just in case */ -#else - assert(lua_istable(L,1)); /* default Lua action */ -#endif - lua_getmetatable(L,1); /* get the metatable */ -#if ((SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)) - assert(lua_isrotable(L,-1)); /* just in case */ -#else - assert(lua_istable(L,-1)); -#endif - SWIG_Lua_get_table(L,".set"); /* get the .set table */ - lua_remove(L,4); /* remove metatable */ -#if ((SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)) - if (lua_isrotable(L,-1)) -#else - if (lua_istable(L,-1)) -#endif + int parsed_tables_array = lua_gettop(L); + lua_pushvalue(L,target_table); + lua_rawsetp(L, parsed_tables_array, table); + int i; + int table_parsed = 0; + int pairs_start = lua_gettop(L); + static int tabs_count = 0; // TODO: REMOVE + for(i = 0;table[i].key.type != LUA_TNIL || table[i].value.type != LUA_TNIL;i++) { - /* look for the key in the .set table */ - lua_pushvalue(L,2); /* key */ - lua_rawget(L,-2); - lua_remove(L,4); /* remove .set */ - if (lua_iscfunction(L,-1)) - { /* found it so call the fn & return its value */ - lua_pushvalue(L,3); /* value */ - lua_call(L,1,0); - return 0; + /* TODO: REMOVE */ + int j = 0; + for(j=0;j<tabs_count;j++) report(" "); + /* END OF REMOVE */ + + report("Registering %d", int(i)); // TODO: REMOVE + const swig_elua_entry *entry = table + i; + int is_metatable = 0; + switch(entry->key.type) { + case LUA_TSTRING: + lua_pushstring(L,entry->key.key.strkey); + report(" %s :", entry->key.key.strkey); // TODO: REMOVE + if(strcmp(entry->key.key.strkey, SWIG_LUA_ELUA_EMUL_METATABLE_KEY) == 0) + is_metatable = 1; + break; + case LUA_TNUMBER: + lua_pushnumber(L,entry->key.key.numkey); + report(" %f :", (double)(entry->key.key.numkey)); // TODO: REMOVE + break; + case LUA_TNIL: + report(" nil :"); // TODO: REMOVE + lua_pushnil(L); + break; + default: + assert(0); } -#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) - else { - return 0; // Exits stoically if an invalid key is initialized. + switch(entry->value.type) { + case LUA_TSTRING: + lua_pushstring(L,entry->value.value.string); + report(" %s", entry->value.value.string); // TODO: REMOVE + break; + case LUA_TNUMBER: + lua_pushnumber(L,entry->value.value.number); + report(" %f", (double)(entry->value.value.number)); // TODO: REMOVE + break; + case LUA_TFUNCTION: + report(" %p", (void*)(entry->value.value.function)); // TODO: REMOVE + lua_pushcfunction(L,entry->value.value.function); + break; + case LUA_TTABLE: + /* TODO: REMOVE */ + report(" table"); + tabs_count++; + /* END OF REMOVE */ + lua_rawgetp(L,parsed_tables_array, entry->value.value.table); + table_parsed = !lua_isnil(L,-1); + if(!table_parsed) { + lua_pop(L,1); /*remove nil */ + report("\n"); // TODO: REMOVE + lua_newtable(L); + SWIG_Lua_elua_emulate_register(L,entry->value.value.table); + } else { + report(" already parsed"); // TODO: REMOVE + } + if(is_metatable) { + report(" (registering metatable)"); // TODO: REMOVE + assert(lua_istable(L,-1)); + lua_pushvalue(L,-1); + lua_setmetatable(L,target_table); + } + + tabs_count--; /*TODO: REMOVE*/ + break; + case LUA_TUSERDATA: + if(entry->value.value.userdata.member) + SWIG_NewMemberObj(L,entry->value.value.userdata.pvalue, + entry->value.value.userdata.lvalue, + *(entry->value.value.userdata.ptype)); + else + SWIG_NewPointerObj(L,entry->value.value.userdata.pvalue, + *(entry->value.value.userdata.ptype),0); + break; + case LUA_TNIL: + report(" nil"); // TODO: REMOVE + lua_pushnil(L); + break; + default: + assert(0); } -#endif + assert(lua_gettop(L) == pairs_start + 2); + lua_rawset(L,target_table); + report("\n"); // TODO: REMOVE } - lua_settop(L,3); /* reset back to start */ - /* we now have the table, key & new value, so just set directly */ - lua_rawset(L,1); /* add direct */ - return 0; + lua_pop(L,1); /* Removing parsed tables storage */ + assert(lua_gettop(L) == target_table); } -#if ((SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUA) && (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC)) -/* registering a module in lua. Pushes the module table on the stack. */ -SWIGINTERN void SWIG_Lua_module_begin(lua_State* L,const char* name) +SWIGINTERN void SWIG_Lua_elua_emulate_register_clear(lua_State *L) { - assert(lua_istable(L,-1)); /* just in case */ - lua_pushstring(L,name); - lua_newtable(L); /* the table */ - /* add meta table */ - lua_newtable(L); /* the meta table */ - SWIG_Lua_add_function(L,"__index",SWIG_Lua_module_get); - SWIG_Lua_add_function(L,"__newindex",SWIG_Lua_module_set); - lua_pushstring(L,".get"); - lua_newtable(L); /* the .get table */ - lua_rawset(L,-3); /* add .get into metatable */ - lua_pushstring(L,".set"); - lua_newtable(L); /* the .set table */ - lua_rawset(L,-3); /* add .set into metatable */ - lua_setmetatable(L,-2); /* sets meta table in module */ -#ifdef SWIG_LUA_MODULE_GLOBAL - /* If requested, install the module directly into the global namespace. */ - lua_rawset(L,-3); /* add module into parent */ - SWIG_Lua_get_table(L,name); /* get the table back out */ -#else - /* Do not install the module table as global name. The stack top has - the module table with the name below. We pop the top and replace - the name with it. */ - lua_replace(L,-2); -#endif + lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, &swig_lua_elua_emulate_unique_key); } -/* ending the register */ -SWIGINTERN void SWIG_Lua_module_end(lua_State* L) -{ - lua_pop(L,1); /* tidy stack (remove module) */ -} +/* TODO: REMOVE */ +SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L); -/* adding a linked variable to the module */ -SWIGINTERN void SWIG_Lua_module_add_variable(lua_State* L,const char* name,lua_CFunction getFn,lua_CFunction setFn) +SWIGINTERN int SWIG_Lua_emulate_elua_getmetatable(lua_State *L) { - assert(lua_istable(L,-1)); /* just in case */ - lua_getmetatable(L,-1); /* get the metatable */ - assert(lua_istable(L,-1)); /* just in case */ - SWIG_Lua_get_table(L,".get"); /* find the .get table */ - assert(lua_istable(L,-1)); /* should be a table: */ - SWIG_Lua_add_function(L,name,getFn); - lua_pop(L,1); /* tidy stack (remove table) */ - if (setFn) /* if there is a set fn */ - { - SWIG_Lua_get_table(L,".set"); /* find the .set table */ - assert(lua_istable(L,-1)); /* should be a table: */ - SWIG_Lua_add_function(L,name,setFn); - lua_pop(L,1); /* tidy stack (remove table) */ + SWIG_check_num_args("getmetatable(SWIG eLua emulation)", 1, 1); + SWIG_Lua_get_class_registry(L); + lua_getfield(L,-1,"lua_getmetatable"); + lua_remove(L,-2); /* remove the registry*/ + assert(!lua_isnil(L,-1)); + lua_pushvalue(L,1); + assert(lua_gettop(L) == 3); /* object | function | object again */ + lua_call(L,1,1); + if(!lua_isnil(L,-1)) /*There is an ordinary metatable */ + return 1; + /*if it is a table, then emulate elua behaviour - check for __metatable attribute of a table*/ + assert(lua_gettop(L) == 2); + if(lua_istable(L,-2)) { + printf("getmetatable: elua emulation part\n"); // TODO: REMOVE + lua_pop(L,1); /*remove the nil*/ + lua_getfield(L,-1, SWIG_LUA_ELUA_EMUL_METATABLE_KEY); } - lua_pop(L,1); /* tidy stack (remove meta) */ + assert(lua_gettop(L) == 2); + return 1; + +fail: + lua_error(L); + return 0; } -#endif -/* adding a function module */ -SWIGINTERN void SWIG_Lua_module_add_function(lua_State* L,const char* name,lua_CFunction fn) +SWIGINTERN void SWIG_Lua_emulate_elua_swap_getmetatable(lua_State *L) { - SWIG_Lua_add_function(L,name,fn); + int begin = lua_gettop(L); // TODO: REMOVE + SWIG_Lua_get_class_registry(L); + lua_pushglobaltable(L); + lua_pushstring(L,"lua_getmetatable"); + lua_getfield(L,-2,"getmetatable"); + assert(!lua_isnil(L,-1)); + lua_rawset(L,-4); + lua_pushstring(L, "getmetatable"); + lua_pushcfunction(L, SWIG_Lua_emulate_elua_getmetatable); + lua_rawset(L,-3); + lua_pop(L,2); + assert(lua_gettop(L) == begin); // TODO: REMOVE + } +/* END OF REMOVE */ +#endif /* ----------------------------------------------------------------------------- - * global variable support code: namespaces + * global variable support code: namespaces and modules (which are the same thing) * ----------------------------------------------------------------------------- */ -SWIGINTERN int SWIG_Lua_namespace_get(lua_State* L) +SWIGINTERN int SWIG_Lua_namespace_get(lua_State *L) { /* there should be 2 params passed in (1) table (not the meta table) @@ -466,7 +592,7 @@ SWIGINTERN int SWIG_Lua_namespace_get(lua_State* L) return 0; } -SWIGINTERN int SWIG_Lua_namespace_set(lua_State* L) +SWIGINTERN int SWIG_Lua_namespace_set(lua_State *L) { /* there should be 3 params passed in (1) table (not the meta table) @@ -493,46 +619,69 @@ SWIGINTERN int SWIG_Lua_namespace_set(lua_State* L) lua_pop(L,1); /* remove the value */ } lua_pop(L,1); /* remove the value .set table */ + lua_pop(L,1); /* remote metatable */ + assert(lua_gettop(L) == 3); // TODO: REMOVE + lua_rawset(L,-3); return 0; } -SWIGINTERN void SWIG_Lua_InstallConstants(lua_State* L, swig_lua_const_info constants[]); // forward declaration -SWIGINTERN void SWIG_Lua_add_class_variable(lua_State* L,const char* name,lua_CFunction getFn,lua_CFunction setFn); // forward declaration +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) /* In elua this is useless */ +SWIGINTERN void SWIG_Lua_InstallConstants(lua_State *L, swig_lua_const_info constants[]); /* forward declaration */ +SWIGINTERN void SWIG_Lua_add_variable(lua_State *L,const char *name,lua_CFunction getFn,lua_CFunction setFn); /* forward declaration */ +SWIGINTERN void SWIG_Lua_class_register(lua_State *L,swig_lua_class *clss); /* helper function - register namespace methods and attributes into namespace */ -SWIGINTERN int SWIG_Lua_add_namespace_details(lua_State* L, swig_lua_namespace* ns) +SWIGINTERN int SWIG_Lua_add_namespace_details(lua_State *L, swig_lua_namespace *ns) { int i = 0; + /* There must be namespace table (not metatable) at the top of the stack */ assert(lua_istable(L,-1)); - /* There must be table at the top of the stack */ SWIG_Lua_InstallConstants(L, ns->ns_constants); + /* add methods to the namespace/module table */ + for(i=0;ns->ns_methods[i].name;i++){ + SWIG_Lua_add_function(L,ns->ns_methods[i].name,ns->ns_methods[i].func); + } lua_getmetatable(L,-1); /* add fns */ for(i=0;ns->ns_attributes[i].name;i++){ - SWIG_Lua_add_class_variable(L,ns->ns_attributes[i].name,ns->ns_attributes[i].getmethod,ns->ns_attributes[i].setmethod); - } - - /* add methods to the metatable */ - SWIG_Lua_get_table(L,".fn"); /* find the .fn table */ - assert(lua_istable(L,-1)); /* just in case */ - for(i=0;ns->ns_methods[i].name;i++){ - SWIG_Lua_add_function(L,ns->ns_methods[i].name,ns->ns_methods[i].method); + SWIG_Lua_add_variable(L,ns->ns_attributes[i].name,ns->ns_attributes[i].getmethod,ns->ns_attributes[i].setmethod); } - lua_pop(L,1); /* clear stack - remove metatble */ lua_pop(L,1); return 0; } -/* helper function. creates namespace table and add it to module table */ -SWIGINTERN int SWIG_Lua_namespace_register(lua_State* L, swig_lua_namespace* ns) +/* Register all classes in the namespace + */ +SWIGINTERN void SWIG_Lua_add_namespace_classes(lua_State *L, swig_lua_namespace *ns) { - assert(lua_istable(L,-1)); /* just in case. This is supposed to be module table */ + /* There must be module/namespace table at the top of the stack */ + assert(lua_istable(L,-1)); + + swig_lua_class **classes = ns->ns_classes; + + if( classes != 0 ) { + while(*classes != 0) { + SWIG_Lua_class_register(L, *classes); + classes++; + } + } +} + +/* helper function. creates namespace table and add it to module table + if 'reg' is true, then will register namespace table to parent one (must be on top of the stack + when function is called) + Function always returns newly registered table on top of the stack +*/ +SWIGINTERN int SWIG_Lua_namespace_register(lua_State *L, swig_lua_namespace *ns, int reg) +{ + /* 1 argument - table on the top of the stack */ + int begin = lua_gettop(L); + assert(lua_istable(L,-1)); /* just in case. This is supposed to be module table or parent namespace table */ lua_checkstack(L,5); - lua_pushstring(L, ns->name); lua_newtable(L); /* namespace itself */ lua_newtable(L); /* metatable for namespace */ @@ -554,47 +703,177 @@ SWIGINTERN int SWIG_Lua_namespace_register(lua_State* L, swig_lua_namespace* ns) SWIG_Lua_add_function(L,"__newindex",SWIG_Lua_namespace_set); lua_setmetatable(L,-2); /* set metatable */ - lua_rawset(L,-3); /* add namespace to module table */ - return 0; + + /* Register all functions, variables etc */ + SWIG_Lua_add_namespace_details(L,ns); + /* Register classes */ + SWIG_Lua_add_namespace_classes(L,ns); + + swig_lua_namespace **sub_namespace = ns->ns_namespaces; + if( sub_namespace != 0) { + while(*sub_namespace != 0) { + SWIG_Lua_namespace_register(L, *sub_namespace, 1); + lua_pop(L,1); /* removing sub-namespace table */ + sub_namespace++; + } + } + + if (reg) { + lua_pushstring(L,ns->name); + lua_pushvalue(L,-2); + lua_rawset(L,-4); /* add namespace to module table */ + } + assert(lua_gettop(L) == begin+1); } +#endif /* SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA */ /* ----------------------------------------------------------------------------- * global variable support code: classes * ----------------------------------------------------------------------------- */ -/* the class.get method, performs the lookup of class attributes */ -SWIGINTERN int SWIG_Lua_class_get(lua_State* L) +SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State *L,const char *cname); + +/* Macroses for iteration among class bases */ +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) +#define SWIG_LUA_INIT_BASE_SEARCH(bases_count)\ + SWIG_Lua_get_table(L,".bases");\ + assert(lua_istable(L,-1));\ + bases_count = lua_rawlen(L,-1);\ + int bases_table = lua_gettop(L); +#define SWIG_LUA_GET_BASE_METATABLE(i,base_swig_type, valid)\ + lua_rawgeti(L,bases_table,i+1);\ + base_swig_type = 0;\ + if(lua_isnil(L,-1)) {\ + valid = 0;\ + lua_pop(L,1);\ + } else\ + valid = 1; + +#else /* en elua .bases table doesn't exist. Use table from swig_lua_class */ + +#define SWIG_LUA_INIT_BASE_SEARCH(bases_count)\ + assert(swig_type!=0);\ + swig_module_info *module=SWIG_GetModule(L);\ + swig_lua_class **bases= ((swig_lua_class*)(swig_type->clientdata))->bases;\ + const char **base_names= ((swig_lua_class*)(swig_type->clientdata))->base_names;\ + bases_count = 0;\ + for(;base_names[bases_count];bases_count++);/* get length of bases */ + +#define SWIG_LUA_GET_BASE_METATABLE(i,base_swig_type, valid)\ + swig_lua_class *base_class = bases[i];\ + if(!base_class)\ + valid = 0;\ + else {\ + valid = 1;\ + SWIG_Lua_get_class_metatable(L,base_class->fqname);\ + base_swig_type = SWIG_TypeQueryModule(module,module,base_names[i]);\ + assert(base_swig_type != 0);\ + } + +#endif + +typedef int (*swig_lua_base_iterator_func)(lua_State*,swig_type_info*, int, int *ret); + +SWIGINTERN int SWIG_Lua_iterate_bases(lua_State *L, swig_type_info *swig_type, int first_arg, swig_lua_base_iterator_func func, int *const ret) +{ + /* first_arg - position of the object in stack. Everything that is above are arguments + * and is passed to every evocation of the func */ + int last_arg = lua_gettop(L);/* position of last argument */ + lua_getmetatable(L,first_arg); + int original_metatable = last_arg + 1; + int bases_count; + SWIG_LUA_INIT_BASE_SEARCH(bases_count); + int result = SWIG_ERROR; + if(ret) *ret = 0; + if(bases_count>0) + { + int i; + int j; + int subcall_first_arg = lua_gettop(L) + 1;/* Here a copy of first_arg and arguments begin */ + int valid = 1; + for(j=first_arg;j<=last_arg;j++) + lua_pushvalue(L,j); + int subcall_last_arg = lua_gettop(L); + swig_type_info *base_swig_type = 0; + + /* Trick: temporaly replacing original metatable + * with metatable for base class and call getter */ + for(i=0;i<bases_count;i++) { + SWIG_LUA_GET_BASE_METATABLE(i,base_swig_type,valid); + if(!valid) + continue; + assert(lua_isuserdata(L, subcall_first_arg)); + assert(lua_istable(L,-1)); + lua_setmetatable(L,subcall_first_arg); /* Set new metatable */ + assert(lua_gettop(L) == subcall_last_arg); + result = func(L, base_swig_type,subcall_first_arg, ret); /* Forward call */ + if(ret) assert(lua_gettop(L) == subcall_last_arg + *ret); // TODO: REMOVE + if(result != SWIG_ERROR) { + break; + } + } + /* Return original metatable back */ + lua_pushvalue(L,original_metatable); + lua_setmetatable(L,first_arg); + /* Clear - remove everything between last_arg and subcall_last_arg including */ + const int to_remove = subcall_last_arg - last_arg; + for(j=0;j<to_remove;j++) + lua_remove(L,last_arg+1); + if(ret) assert(lua_gettop(L) == last_arg + *ret); // TODO: REMOVE + } else { + /* Remove everything after last_arg */ + lua_pop(L, lua_gettop(L) - last_arg); + } + if(ret) assert(lua_gettop(L) == last_arg + *ret); + return result; +} + +/* the class.get method helper, performs the lookup of class attributes + * It returns error code. Number of function return values is passed inside 'ret' + * first_arg is not used in this function because function always has 2 arguments. + */ +SWIGINTERN int SWIG_Lua_class_do_get(lua_State *L, swig_type_info *type, int first_arg, int *ret) { /* there should be 2 params passed in (1) userdata (not the meta table) (2) string name of the attribute */ + int substack_start = lua_gettop(L)-2; + assert(first_arg == substack_start+1); + lua_checkstack(L,5); assert(lua_isuserdata(L,-2)); /* just in case */ lua_getmetatable(L,-2); /* get the meta table */ assert(lua_istable(L,-1)); /* just in case */ + // TODO: REMOVE + //SWIG_Lua_get_table(L,".type"); + //printf("class %s get %s\n", lua_tostring(L,-1), lua_tostring(L,substack_start+2)); + //lua_pop(L,1); + // END OF REMOVE SWIG_Lua_get_table(L,".get"); /* find the .get table */ assert(lua_istable(L,-1)); /* just in case */ /* look for the key in the .get table */ - lua_pushvalue(L,2); /* key */ + lua_pushvalue(L,substack_start+2); /* key */ lua_rawget(L,-2); lua_remove(L,-2); /* stack tidy, remove .get table */ if (lua_iscfunction(L,-1)) { /* found it so call the fn & return its value */ - lua_pushvalue(L,1); /* the userdata */ + lua_pushvalue(L,substack_start+1); /* the userdata */ lua_call(L,1,1); /* 1 value in (userdata),1 out (result) */ lua_remove(L,-2); /* stack tidy, remove metatable */ - return 1; + if(ret) *ret = 1; + return SWIG_OK; } lua_pop(L,1); /* remove whatever was there */ /* ok, so try the .fn table */ - SWIG_Lua_get_table(L,".fn"); /* find the .get table */ + SWIG_Lua_get_table(L,".fn"); /* find the .fn table */ assert(lua_istable(L,-1)); /* just in case */ - lua_pushvalue(L,2); /* key */ + lua_pushvalue(L,substack_start+2); /* key */ lua_rawget(L,-2); /* look for the fn */ lua_remove(L,-2); /* stack tidy, remove .fn table */ 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; + if(ret) *ret = 1; + return SWIG_OK; } lua_pop(L,1); /* remove whatever was there */ /* NEW: looks for the __getitem() fn @@ -602,69 +881,150 @@ SWIGINTERN int SWIG_Lua_class_get(lua_State* L) SWIG_Lua_get_table(L,"__getitem"); /* find the __getitem fn */ if (lua_iscfunction(L,-1)) /* if its there */ { /* found it so call the fn & return its value */ - lua_pushvalue(L,1); /* the userdata */ - lua_pushvalue(L,2); /* the parameter */ + lua_pushvalue(L,substack_start+1); /* the userdata */ + lua_pushvalue(L,substack_start+2); /* the parameter */ lua_call(L,2,1); /* 2 value in (userdata),1 out (result) */ lua_remove(L,-2); /* stack tidy, remove metatable */ - return 1; + if(ret) *ret = 1; + return SWIG_OK; } - return 0; /* sorry not known */ + lua_pop(L,1); + /* Remove the metatable */ + lua_pop(L,1); + /* Search in base classes */ + assert(lua_gettop(L) == substack_start + 2); // TODO: REMOVE + + /* TODO: REMOVE +#ifdef SWIG_LUA_SQUASH_BASES + if(ret) *ret = 0; + return SWIG_ERROR; // TODO:ERROR:FIX:REMOVE!!!! +//#warning REMOVE REMOVE REMOVE +#endif + END OF REMOVE */ + + //printf("failed, searching bases\n"); // TODO: REMOVE + int bases_search_result = SWIG_Lua_iterate_bases(L,type,substack_start+1,SWIG_Lua_class_do_get,ret); + if(ret) assert(lua_gettop(L) == substack_start + 2 + *ret); // TODO: REMOVE + // TODO: REMOVE + if(bases_search_result != SWIG_OK) { + //printf("failed.\n"); + } + // END OF REMOVE + return bases_search_result; /* sorry not known */ +} + +/* the class.get method, performs the lookup of class attributes + */ +SWIGINTERN int SWIG_Lua_class_get(lua_State *L) +{ +/* there should be 2 params passed in + (1) userdata (not the meta table) + (2) string name of the attribute +*/ + assert(lua_isuserdata(L,1)); + swig_lua_userdata *usr=(swig_lua_userdata*)lua_touserdata(L,1); /* get data */ + swig_type_info *type = usr->type; + int ret = 0; + int result = SWIG_Lua_class_do_get(L,type,1,&ret); + if(result == SWIG_OK) + return ret; + + return 0; } -/* the class.set method, performs the lookup of class attributes */ -SWIGINTERN int SWIG_Lua_class_set(lua_State* L) +/* helper for the class.set method, performs the lookup of class attributes + * It returns error code. Number of function return values is passed inside 'ret' + */ +SWIGINTERN int SWIG_Lua_class_do_set(lua_State *L, swig_type_info *type, int first_arg, int *ret) { /* there should be 3 params passed in (1) table (not the meta table) (2) string name of the attribute (3) any for the new value -printf("SWIG_Lua_class_set %p(%s) '%s' %p(%s)\n", - lua_topointer(L,1),lua_typename(L,lua_type(L,1)), - lua_tostring(L,2), - lua_topointer(L,3),lua_typename(L,lua_type(L,3)));*/ + */ - assert(lua_isuserdata(L,1)); /* just in case */ - lua_getmetatable(L,1); /* get the meta table */ + int substack_start = lua_gettop(L) - 3; + lua_checkstack(L,5); + assert(lua_isuserdata(L,substack_start+1)); /* just in case */ + lua_getmetatable(L,substack_start+1); /* get the meta table */ assert(lua_istable(L,-1)); /* just in case */ + if(ret) *ret = 0; /* it is setter - number of return values is always 0 */ SWIG_Lua_get_table(L,".set"); /* find the .set table */ if (lua_istable(L,-1)) { /* look for the key in the .set table */ - lua_pushvalue(L,2); /* key */ + lua_pushvalue(L,substack_start+2); /* key */ lua_rawget(L,-2); + lua_remove(L,-2); /* tidy stack, remove .set table */ if (lua_iscfunction(L,-1)) { /* found it so call the fn & return its value */ - lua_pushvalue(L,1); /* userdata */ - lua_pushvalue(L,3); /* value */ + lua_pushvalue(L,substack_start+1); /* userdata */ + lua_pushvalue(L,substack_start+3); /* value */ lua_call(L,2,0); - return 0; + lua_remove(L,substack_start+4); /*remove metatable*/ + return SWIG_OK; } lua_pop(L,1); /* remove the value */ + } else { + lua_pop(L,1); /* remove the answer for .set table request*/ } - lua_pop(L,1); /* remove the value .set table */ + assert(lua_gettop(L) == substack_start + 4); // TODO: REMOVE /* NEW: looks for the __setitem() fn this is a user provided set fn */ SWIG_Lua_get_table(L,"__setitem"); /* find the fn */ if (lua_iscfunction(L,-1)) /* if its there */ { /* found it so call the fn & return its value */ - lua_pushvalue(L,1); /* the userdata */ - lua_pushvalue(L,2); /* the parameter */ - lua_pushvalue(L,3); /* the value */ + lua_pushvalue(L,substack_start+1); /* the userdata */ + lua_pushvalue(L,substack_start+2); /* the parameter */ + lua_pushvalue(L,substack_start+3); /* the value */ lua_call(L,3,0); /* 3 values in ,0 out */ lua_remove(L,-2); /* stack tidy, remove metatable */ - return 1; + return SWIG_OK; + } + lua_pop(L,1); /* remove value */ + assert(lua_gettop(L) == substack_start + 4); // TODO: REMOVE + + lua_pop(L,1); /* remove metatable */ + /* Search among bases */ + assert(lua_gettop(L) == first_arg+2); // TODO: REMOVE + int bases_search_result = SWIG_Lua_iterate_bases(L,type,first_arg,SWIG_Lua_class_do_set,ret); + if(ret) assert(*ret == 0); + assert(lua_gettop(L) == substack_start + 3); + return bases_search_result; +} + +/* This is actuall method exported to Lua. It calls SWIG_Lua_class_do_set and correctly + * handlers return value + */ +SWIGINTERN int SWIG_Lua_class_set(lua_State *L) +{ +/* there should be 3 params passed in + (1) table (not the meta table) + (2) string name of the attribute + (3) any for the new value + */ + assert(lua_isuserdata(L,1)); + swig_lua_userdata *usr=(swig_lua_userdata*)lua_touserdata(L,1); /* get data */ + swig_type_info *type = usr->type; + int ret = 0; + int result = SWIG_Lua_class_do_set(L,type,1,&ret); + if(result != SWIG_OK) { + SWIG_Lua_pushferrstring(L,"Assignment not possible. No setter/member with this name. For custom assignments implement __setitem method"); + lua_error(L); + } else { + assert(ret==0); + return 0; } - return 0; } /* the class.destruct method called by the interpreter */ -SWIGINTERN int SWIG_Lua_class_destruct(lua_State* L) +SWIGINTERN int SWIG_Lua_class_destruct(lua_State *L) { /* there should be 1 params passed in (1) userdata (not the meta table) */ - swig_lua_userdata* usr; - swig_lua_class* clss; + swig_lua_userdata *usr; + swig_lua_class *clss; assert(lua_isuserdata(L,-1)); /* just in case */ usr=(swig_lua_userdata*)lua_touserdata(L,-1); /* get it */ /* if must be destroyed & has a destructor */ @@ -680,7 +1040,7 @@ SWIGINTERN int SWIG_Lua_class_destruct(lua_State* L) } /* the class.__tostring method called by the interpreter and print */ -SWIGINTERN int SWIG_Lua_class_tostring(lua_State* L) +SWIGINTERN int SWIG_Lua_class_tostring(lua_State *L) { /* there should be 1 param passed in (1) userdata (not the metatable) */ @@ -688,23 +1048,23 @@ SWIGINTERN int SWIG_Lua_class_tostring(lua_State* L) unsigned long userData = (unsigned long)lua_touserdata(L,1); /* get the userdata address for later */ lua_getmetatable(L,1); /* get the meta table */ assert(lua_istable(L,-1)); /* just in case */ - + lua_getfield(L, -1, ".type"); - const char* className = lua_tostring(L, -1); - + const char *className = lua_tostring(L, -1); + char output[256]; - sprintf(output, "<%s userdata: %lX>", className, userData); - + snprintf(output, 255, "<%s userdata: %lX>", className, userData); + lua_pushstring(L, (const char*)output); return 1; } /* to manually disown some userdata */ -SWIGINTERN int SWIG_Lua_class_disown(lua_State* L) +SWIGINTERN int SWIG_Lua_class_disown(lua_State *L) { /* there should be 1 params passed in (1) userdata (not the meta table) */ - swig_lua_userdata* usr; + swig_lua_userdata *usr; assert(lua_isuserdata(L,-1)); /* just in case */ usr=(swig_lua_userdata*)lua_touserdata(L,-1); /* get it */ @@ -712,25 +1072,8 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State* L) return 0; } -/* Constructor proxy. Used when class name entry in module is not class constructor, -but special table instead. */ -SWIGINTERN int SWIG_Lua_constructor_proxy(lua_State* L) -{ - /* unlimited number of parameters - First one is our proxy table and we should remove it - Other we should pass to real constructor - */ - assert(lua_istable(L,1)); - lua_pushstring(L,".constructor"); - lua_rawget(L,1); - assert(!lua_isnil(L,-1)); - lua_replace(L,1); /* replace our table with real constructor */ - lua_call(L,lua_gettop(L)-1,1); - return 1; -} - /* gets the swig class registry (or creates it) */ -SWIGINTERN void SWIG_Lua_get_class_registry(lua_State* L) +SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L) { /* add this all into the swig registry: */ lua_pushstring(L,"SWIG"); @@ -748,7 +1091,7 @@ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State* L) } /* helper fn to get the classes metatable from the register */ -SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State* L,const char* cname) +SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State *L,const char *cname) { SWIG_Lua_get_class_registry(L); /* get the registry */ lua_pushstring(L,cname); /* get the name */ @@ -756,8 +1099,102 @@ SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State* L,const char* cname) lua_remove(L,-2); /* tidy up (remove registry) */ } +/* 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; + } + } +} + +#if defined(SWIG_LUA_SQUASH_BASES) && (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) +/* Merges two tables */ +SWIGINTERN int SWIG_Lua_merge_tables_by_index(lua_State *L, int target, int source) +{ + /* iterating */ + lua_pushnil(L); + while (lua_next(L,source) != 0) { + /* -1 - value, -2 - index */ + /* have to copy to assign */ + lua_pushvalue(L,-2); /* copy of index */ + lua_pushvalue(L,-2); /* copy of value */ + lua_rawset(L, target); + lua_pop(L,1); + /* only key is left */ + } +} + +/* Merges two tables with given name. original - index of target metatable, base - index of source metatable */ +SWIGINTERN int SWIG_Lua_merge_tables(lua_State *L, const char* name, int original, int base) +{ + int begin = lua_gettop(L); // TODO:REMOVE + /* push original[name], then base[name] */ + lua_pushstring(L,name); + lua_rawget(L,original); + int original_table = lua_gettop(L); + lua_pushstring(L,name); + lua_rawget(L,base); + int base_table = lua_gettop(L); + SWIG_Lua_merge_tables_by_index(L, original_table, base_table); + /* clearing stack */ + lua_pop(L,2); + assert(lua_gettop(L) == begin); // TODO: REMOVE +} + +/* Function takes all symbols from base and adds it to derived class. It's just a helper*/ +SWIGINTERN int SWIG_Lua_class_squash_base(lua_State *L, swig_lua_class *base_cls) +{ + int begin = lua_gettop(L); // TODO:REMOVE + /* There is one parameter - original, i.e. 'derived' class metatable */ + assert(lua_istable(L,-1)); + int original = lua_gettop(L); + SWIG_Lua_get_class_metatable(L,base_cls->fqname); + int base = lua_gettop(L); + SWIG_Lua_merge_tables(L, ".fn", original, base ); + SWIG_Lua_merge_tables(L, ".set", original, base ); + SWIG_Lua_merge_tables(L, ".get", original, base ); + lua_pop(L,1); + assert(lua_gettop(L) == begin); // TODO: REMOVE +} + +/* Function squashes all symbols from 'clss' bases into itself */ +SWIGINTERN int SWIG_Lua_class_squash_bases(lua_State *L, swig_lua_class *clss) +{ + int begin = lua_gettop(L); // TODO: REMOVE + int i; + SWIG_Lua_get_class_metatable(L,clss->fqname); + for(i=0;clss->base_names[i];i++) + { + if (clss->bases[i]==0) /* Somehow it's not found. Skip it */ + continue; + /* Thing is: all bases are already registered. Thus they have already executed + * this function. So we just need to squash them into us, because their bases + * are already squashed into them. No need for recursion here! + */ + SWIG_Lua_class_squash_base(L, clss->bases[i]); + } + lua_pop(L,1); /*tidy stack*/ + assert(lua_gettop(L) == begin); // TODO: REMOVE +} +#endif + +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) /* In elua this is useless */ /* helper add a variable to a registered class */ -SWIGINTERN void SWIG_Lua_add_class_variable(lua_State* L,const char* name,lua_CFunction getFn,lua_CFunction setFn) +SWIGINTERN void SWIG_Lua_add_variable(lua_State *L,const char *name,lua_CFunction getFn,lua_CFunction setFn) { assert(lua_istable(L,-1)); /* just in case */ SWIG_Lua_get_table(L,".get"); /* find the .get table */ @@ -774,7 +1211,7 @@ SWIGINTERN void SWIG_Lua_add_class_variable(lua_State* L,const char* name,lua_C } /* helper to recursively add class static details (static attributes, operations and constants) */ -SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State* L, swig_lua_class* clss) +SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State *L, swig_lua_class *clss) { int i = 0; /* The class namespace table must be on the top of the stack */ @@ -785,72 +1222,60 @@ SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State* L, swig_lua_class* SWIG_Lua_add_class_static_details(L,clss->bases[i]); } - SWIG_Lua_add_namespace_details(L, &clss->cls_static); + SWIG_Lua_add_namespace_details(L, clss->cls_static); } /* helper to recursively add class details (attributes & operations) */ -SWIGINTERN void SWIG_Lua_add_class_details(lua_State* L,swig_lua_class* clss) +SWIGINTERN void SWIG_Lua_add_class_instance_details(lua_State *L,swig_lua_class *clss) { int i; - /* call all the base classes first: we can then override these later: */ + /* Add bases to .bases table */ + SWIG_Lua_get_table(L,".bases"); + assert(lua_istable(L,-1)); /* just in case */ + int bases_count = 0; for(i=0;clss->bases[i];i++) { - SWIG_Lua_add_class_details(L,clss->bases[i]); + SWIG_Lua_get_class_metatable(L,clss->bases[i]->fqname); + /* Base class must be already registered */ + assert(lua_istable(L,-1)); + lua_rawseti(L,-2,i+1); /* In lua indexing starts from 1 */ + bases_count++; } - /* add fns */ + assert(lua_rawlen(L,-1) == bases_count); + lua_pop(L,1); /* remove .bases table */ + /* add attributes */ for(i=0;clss->attributes[i].name;i++){ - SWIG_Lua_add_class_variable(L,clss->attributes[i].name,clss->attributes[i].getmethod,clss->attributes[i].setmethod); + SWIG_Lua_add_variable(L,clss->attributes[i].name,clss->attributes[i].getmethod,clss->attributes[i].setmethod); } /* add methods to the metatable */ SWIG_Lua_get_table(L,".fn"); /* find the .fn table */ assert(lua_istable(L,-1)); /* just in case */ for(i=0;clss->methods[i].name;i++){ - SWIG_Lua_add_function(L,clss->methods[i].name,clss->methods[i].method); + SWIG_Lua_add_function(L,clss->methods[i].name,clss->methods[i].func); } lua_pop(L,1); /* tidy stack (remove table) */ /* add operator overloads - these look ANY method which start with "__" and assume they - are operator overloads & add them to the metatable - (this might mess up is someone defines a method __gc (the destructor)*/ - for(i=0;clss->methods[i].name;i++){ - if (clss->methods[i].name[0]=='_' && clss->methods[i].name[1]=='_'){ - SWIG_Lua_add_function(L,clss->methods[i].name,clss->methods[i].method); - } - } -} - -/* 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; + This adds methods from metatable array to metatable. Can mess up garbage + collectind if someone defines __gc method + */ + if(clss->metatable) { + for(i=0;clss->metatable[i].name;i++) { + assert(clss->metatable[i].func != 0); // TODO: REMOVE + SWIG_Lua_add_function(L,clss->metatable[i].name,clss->metatable[i].func); } } } /* Register class static methods,attributes etc as well as constructor proxy */ -SWIGINTERN void SWIG_Lua_class_register_static(lua_State* L, swig_lua_class* clss) +SWIGINTERN void SWIG_Lua_class_register_static(lua_State *L, swig_lua_class *clss) { + int begin = lua_gettop(L); lua_checkstack(L,5); /* just in case */ assert(lua_istable(L,-1)); /* just in case */ - assert(strcmp(clss->name, clss->cls_static.name) == 0); /* in class those 2 must be equal */ + assert(strcmp(clss->name, clss->cls_static->name) == 0); /* in class those 2 must be equal */ - SWIG_Lua_namespace_register(L,&clss->cls_static); + SWIG_Lua_namespace_register(L,clss->cls_static, 1); - SWIG_Lua_get_table(L,clss->name); // Get namespace table back assert(lua_istable(L,-1)); /* just in case */ /* add its constructor to module with the name of the class @@ -859,10 +1284,9 @@ SWIGINTERN void SWIG_Lua_class_register_static(lua_State* L, swig_lua_class* cls (this overcomes the problem of pure virtual classes without constructors)*/ if (clss->constructor) { - SWIG_Lua_add_function(L,".constructor", clss->constructor); lua_getmetatable(L,-1); assert(lua_istable(L,-1)); /* just in case */ - SWIG_Lua_add_function(L,"__call", SWIG_Lua_constructor_proxy); + SWIG_Lua_add_function(L,"__call", clss->constructor); lua_pop(L,1); } @@ -871,19 +1295,59 @@ SWIGINTERN void SWIG_Lua_class_register_static(lua_State* L, swig_lua_class* cls /* clear stack */ lua_pop(L,1); + assert( lua_gettop(L) == begin ); } -/* performs the entire class registration process */ -SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) +/* performs the instance(non-static) class registration process. Metatable for class is created + * and added to the class registry. + */ +SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *clss) { - SWIG_Lua_class_register_static(L,clss); - + int begin = lua_gettop(L); + /* if name already there (class is already registered) then do nothing */ SWIG_Lua_get_class_registry(L); /* get the registry */ - lua_pushstring(L,clss->name); /* get the name */ + lua_pushstring(L,clss->fqname); /* get the name */ + lua_rawget(L,-2); + if(!lua_isnil(L,-1)) { + lua_pop(L,2); + assert(lua_gettop(L)==begin); + return; + } + lua_pop(L,2); /* tidy stack */ + /* Recursively initialize all bases */ + int i = 0; + for(i=0;clss->bases[i];i++) + { + SWIG_Lua_class_register_instance(L,clss->bases[i]); + } + /* Again, get registry and push name */ + SWIG_Lua_get_class_registry(L); /* get the registry */ + lua_pushstring(L,clss->fqname); /* get the name */ lua_newtable(L); /* create the metatable */ +#if defined(SWIG_LUA_SQUASH_BASES) && (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) + /* If squashing is requested, then merges all bases metatable into this one. + * It would get us all special methods: __getitem, __add etc. + * This would set .fn, .type, and other .xxx incorrectly, but we will overwrite it right away + */ + int squash_begin = lua_gettop(L); // TODO:REMOVE + int new_metatable_index = lua_absindex(L,-1); + for(i=0;clss->bases[i];i++) + { + SWIG_Lua_get_class_metatable(L,clss->bases[i]->fqname); + int base_metatable = lua_absindex(L,-1); + SWIG_Lua_merge_tables_by_index(L,new_metatable_index, base_metatable); + lua_pop(L,1); + } + assert(lua_gettop(L) == squash_begin); // TODO: REMOVE + /* And now we will overwrite all incorrectly set data */ +#endif /* add string of class name called ".type" */ lua_pushstring(L,".type"); - lua_pushstring(L,clss->name); + lua_pushstring(L,clss->fqname); + lua_rawset(L,-3); + /* add a table called bases */ + lua_pushstring(L,".bases"); + lua_newtable(L); lua_rawset(L,-3); /* add a table called ".get" */ lua_pushstring(L,".get"); @@ -908,22 +1372,95 @@ SWIGINTERN void SWIG_Lua_class_register(lua_State* L,swig_lua_class* clss) /* add it */ lua_rawset(L,-3); /* metatable into registry */ lua_pop(L,1); /* tidy stack (remove registry) */ + assert(lua_gettop(L)==begin); - SWIG_Lua_get_class_metatable(L,clss->name); - SWIG_Lua_add_class_details(L,clss); /* recursive adding of details (atts & ops) */ +#if defined(SWIG_LUA_SQUASH_BASES) && (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) + /* Now merge all symbols from .fn, .set, .get etc from bases to our tables */ + SWIG_Lua_class_squash_bases(L,clss); +#endif + SWIG_Lua_get_class_metatable(L,clss->fqname); + SWIG_Lua_add_class_instance_details(L,clss); /* recursive adding of details (atts & ops) */ lua_pop(L,1); /* tidy stack (remove class metatable) */ + assert( lua_gettop(L) == begin ); +} + +SWIGINTERN void SWIG_Lua_class_register(lua_State *L,swig_lua_class *clss) +{ + assert(lua_istable(L,-1)); /* This is table(module or namespace) where class will be added */ + SWIG_Lua_class_register_instance(L,clss); + SWIG_Lua_class_register_static(L,clss); + + /* Add links from static part to instance part and vice versa */ + /* [SWIG registry] [Module] + * "MyClass" ----> [MyClass metatable] <===== "MyClass" -+> [static part] + * ".get" ----> ... | | getmetatable()----| + * ".set" ----> ... | | | + * ".static" --------------)----------------/ [static part metatable] + * | ".get" --> ... + * | ".set" --> .... + * |=============================== ".instance" + */ + int begin = lua_gettop(L); + lua_pushstring(L,clss->cls_static->name); + lua_rawget(L,-2); /* get class static table */ + assert(lua_istable(L,-1)); + lua_getmetatable(L,-1); + assert(lua_istable(L,-1)); /* get class static metatable */ + lua_pushstring(L,".instance"); /* prepare key */ + + SWIG_Lua_get_class_metatable(L,clss->fqname); /* get class metatable */ + assert(lua_istable(L,-1)); + lua_pushstring(L,".static"); /* prepare key */ + lua_pushvalue(L, -4); /* push static class TABLE */ + assert(lua_istable(L,-1)); + lua_rawset(L,-3); /* assign static class table(!NOT metatable) as ".static" member of class metatable */ + lua_rawset(L,-3); /* assign class metatable as ".instance" member of class static METATABLE */ + lua_pop(L,2); + assert(lua_gettop(L) == begin); +} +#endif /* SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA */ + +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC) +SWIGINTERN void SWIG_Lua_elua_class_register_instance(lua_State *L, swig_lua_class *clss) +{ + int begin = lua_gettop(L); + /* if name already there (class is already registered) then do nothing */ + SWIG_Lua_get_class_registry(L); /* get the registry */ + lua_pushstring(L,clss->fqname); /* get the name */ + lua_rawget(L,-2); + if(!lua_isnil(L,-1)) { + lua_pop(L,2); + assert(lua_gettop(L)==begin); + return; + } + lua_pop(L,2); /* tidy stack */ + /* Recursively initialize all bases */ + int i = 0; + for(i=0;clss->bases[i];i++) + { + SWIG_Lua_elua_class_register_instance(L,clss->bases[i]); + } + /* Again, get registry and push name */ + SWIG_Lua_get_class_registry(L); /* get the registry */ + lua_pushstring(L,clss->fqname); /* get the name */ + assert(clss->metatable); + lua_pushrotable(L, (void*)(clss->metatable)); /* create the metatable */ + lua_rawset(L,-3); + lua_pop(L,1); + assert(lua_gettop(L) == begin); } +#endif // elua && eluac /* ----------------------------------------------------------------------------- * Class/structure conversion fns * ----------------------------------------------------------------------------- */ /* helper to add metatable to new lua object */ -SWIGINTERN void _SWIG_Lua_AddMetatable(lua_State* L,swig_type_info *type) +SWIGINTERN void _SWIG_Lua_AddMetatable(lua_State *L,swig_type_info *type) { if (type->clientdata) /* there is clientdata: so add the metatable */ { - SWIG_Lua_get_class_metatable(L,((swig_lua_class*)(type->clientdata))->name); + SWIG_Lua_get_class_metatable(L,((swig_lua_class*)(type->clientdata))->fqname); if (lua_istable(L,-1)) { lua_setmetatable(L,-2); @@ -936,9 +1473,9 @@ SWIGINTERN void _SWIG_Lua_AddMetatable(lua_State* L,swig_type_info *type) } /* pushes a new object into the lua stack */ -SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own) +SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State *L,void *ptr,swig_type_info *type, int own) { - swig_lua_userdata* usr; + swig_lua_userdata *usr; if (!ptr){ lua_pushnil(L); return; @@ -954,9 +1491,9 @@ SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *t /* takes a object from the lua stack & converts it into an object of the correct type (if possible) */ -SWIGRUNTIME int SWIG_Lua_ConvertPtr(lua_State* L,int index,void** ptr,swig_type_info *type,int flags) +SWIGRUNTIME int SWIG_Lua_ConvertPtr(lua_State *L,int index,void **ptr,swig_type_info *type,int flags) { - swig_lua_userdata* usr; + swig_lua_userdata *usr; swig_cast_info *cast; if (lua_isnil(L,index)){*ptr=0; return SWIG_OK;} /* special case: lua nil => NULL pointer */ usr=(swig_lua_userdata*)lua_touserdata(L,index); /* get data */ @@ -983,9 +1520,9 @@ SWIGRUNTIME int SWIG_Lua_ConvertPtr(lua_State* L,int index,void** ptr,swig_type return SWIG_ERROR; /* error */ } -SWIGRUNTIME void* SWIG_Lua_MustGetPtr(lua_State* L,int index,swig_type_info *type,int flags, - int argnum,const char* func_name){ - void* result; +SWIGRUNTIME void* SWIG_Lua_MustGetPtr(lua_State *L,int index,swig_type_info *type,int flags, + int argnum,const char *func_name){ + void *result; if (!SWIG_IsOK(SWIG_ConvertPtr(L,index,&result,type,flags))){ luaL_error (L,"Error in %s, expected a %s at argument number %d\n", func_name,(type && type->str)?type->str:"void*",argnum); @@ -994,9 +1531,9 @@ SWIGRUNTIME void* SWIG_Lua_MustGetPtr(lua_State* L,int index,swig_type_info *typ } /* pushes a packed userdata. user for member fn pointers only */ -SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State* L,void* ptr,size_t size,swig_type_info *type) +SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State *L,void *ptr,size_t size,swig_type_info *type) { - swig_lua_rawdata* raw; + swig_lua_rawdata *raw; assert(ptr); /* not acceptable to pass in a NULL value */ raw=(swig_lua_rawdata*)lua_newuserdata(L,sizeof(swig_lua_rawdata)-1+size); /* alloc data */ raw->type=type; @@ -1006,9 +1543,9 @@ SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State* L,void* ptr,size_t size,swig_t } /* converts a packed userdata. user for member fn pointers only */ -SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State* L,int index,void* ptr,size_t size,swig_type_info *type) +SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State *L,int index,void *ptr,size_t size,swig_type_info *type) { - swig_lua_rawdata* raw; + swig_lua_rawdata *raw; raw=(swig_lua_rawdata*)lua_touserdata(L,index); /* get data */ if (!raw) return SWIG_ERROR; /* error */ if (type==0 || type==raw->type) /* void* or identical type */ @@ -1022,7 +1559,7 @@ SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State* L,int index,void* ptr,size_t /* a function to get the typestring of a piece of data */ SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp) { - swig_lua_userdata* usr; + swig_lua_userdata *usr; if (lua_isuserdata(L,tp)) { usr=(swig_lua_userdata*)lua_touserdata(L,tp); /* get data */ @@ -1034,7 +1571,7 @@ SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp) } /* lua callable function to get the userdata's type */ -SWIGRUNTIME int SWIG_Lua_type(lua_State* L) +SWIGRUNTIME int SWIG_Lua_type(lua_State *L) { lua_pushstring(L,SWIG_Lua_typename(L,1)); return 1; @@ -1043,7 +1580,7 @@ SWIGRUNTIME int SWIG_Lua_type(lua_State* L) /* lua callable function to compare userdata's value the issue is that two userdata may point to the same thing but to lua, they are different objects */ -SWIGRUNTIME int SWIG_Lua_equal(lua_State* L) +SWIGRUNTIME int SWIG_Lua_equal(lua_State *L) { int result; swig_lua_userdata *usr1,*usr2; @@ -1064,7 +1601,7 @@ SWIGRUNTIME int SWIG_Lua_equal(lua_State* L) #if ((SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUA) && (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC)) /* Install Constants */ SWIGINTERN void -SWIG_Lua_InstallConstants(lua_State* L, swig_lua_const_info constants[]) { +SWIG_Lua_InstallConstants(lua_State *L, swig_lua_const_info constants[]) { int i; for (i = 0; constants[i].type; i++) { switch(constants[i].type) { @@ -1118,7 +1655,7 @@ In lua 5.0.X its lua_dostring() In lua 5.1.X its luaL_dostring() */ SWIGINTERN int -SWIG_Lua_dostring(lua_State *L, const char* str) { +SWIG_Lua_dostring(lua_State *L, const char *str) { int ok,top; if (str==0 || str[0]==0) return 0; /* nothing to do */ top=lua_gettop(L); /* save stack */ diff --git a/Lib/lua/luaruntime.swg b/Lib/lua/luaruntime.swg index 3ca489ffa..ebb997897 100644 --- a/Lib/lua/luaruntime.swg +++ b/Lib/lua/luaruntime.swg @@ -36,20 +36,10 @@ SWIGEXPORT int SWIG_init(lua_State* L) /* default Lua action */ SWIG_PropagateClientData(); #endif -#if ((SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUA) && (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC)) +#if ((SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUA) && (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC)) || defined(SWIG_LUA_ELUA_EMULATE) /* add a global fn */ SWIG_Lua_add_function(L,"swig_type",SWIG_Lua_type); SWIG_Lua_add_function(L,"swig_equals",SWIG_Lua_equal); - /* begin the module (its a table with the same name as the module) */ - SWIG_Lua_module_begin(L,SWIG_name); - /* add commands/functions */ - for (i = 0; swig_commands[i].name; i++){ - SWIG_Lua_module_add_function(L,swig_commands[i].name,swig_commands[i].func); - } - /* add variables */ - 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); - } #endif #if (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC) @@ -59,17 +49,35 @@ SWIGEXPORT int SWIG_init(lua_State* L) /* default Lua action */ SWIG_Lua_init_base_class(L,(swig_lua_class*)(swig_types[i]->clientdata)); } } - /* additional registration structs & classes in lua */ + int globalRegister = 0; +#ifdef SWIG_LUA_MODULE_GLOBAL + globalRegister = 1; +#endif + + +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) + SWIG_Lua_namespace_register(L,&swig___Module, globalRegister); +#endif + +#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC) for (i = 0; swig_types[i]; i++){ if (swig_types[i]->clientdata){ - SWIG_Lua_class_register(L,(swig_lua_class*)(swig_types[i]->clientdata)); + SWIG_Lua_elua_class_register_instance(L,(swig_lua_class*)(swig_types[i]->clientdata)); } } #endif -#if ((SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUA) && (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC)) - /* constants */ - SWIG_Lua_InstallConstants(L,swig_constants); +#if defined(SWIG_LUA_ELUA_EMULATE) + lua_newtable(L); + SWIG_Lua_elua_emulate_register(L,swig___Module.ns_methods); + SWIG_Lua_elua_emulate_register_clear(L); + if(globalRegister) { + lua_pushstring(L,swig___Module.name); + lua_pushvalue(L,-2); + lua_rawset(L,-4); + } +#endif + #endif #if (SWIG_LUA_TARGET != SWIG_LUA_FLAVOR_ELUAC) diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index 3940a3001..9420ea719 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -319,8 +319,7 @@ overloading(0), multiinput(0), cplus_runtime(0), directors(0) { - Hash *symbols = NewHash(); - Setattr(symtabs, "", symbols); // create top level/global symbol table scope + symbolAddScope(""); // create top level/global symbol table scope argc_template_string = NewString("argc"); argv_template_string = NewString("argv[%d]"); @@ -1490,6 +1489,7 @@ int Language::membervariableHandler(Node *n) { Setattr(n, "type", type); Setattr(n, "name", name); Setattr(n, "sym:name", symname); + Delattr(n, "memberset"); /* Delete all attached typemaps and typemap attributes */ Iterator ki; @@ -1507,6 +1507,7 @@ int Language::membervariableHandler(Node *n) { Setattr(n, "sym:name", mrename_get); Setattr(n, "memberget", "1"); functionWrapper(n); + Delattr(n, "memberget"); } Delete(mrename_get); Delete(mrename_set); @@ -2951,11 +2952,14 @@ int Language::constantWrapper(Node *n) { * ---------------------------------------------------------------------- */ int Language::variableWrapper(Node *n) { - Swig_require("variableWrapper", n, "*name", "*sym:name", "*type", "?parms", NIL); + Swig_require("variableWrapper", n, "*name", "*sym:name", "*type", "?parms", "?varset", "?varget", NIL); String *symname = Getattr(n, "sym:name"); SwigType *type = Getattr(n, "type"); String *name = Getattr(n, "name"); + Delattr(n,"varset"); + Delattr(n,"varget"); + /* If no way to set variables. We simply create functions */ int assignable = is_assignable(n); int flags = use_naturalvar_mode(n); @@ -2986,12 +2990,16 @@ int Language::variableWrapper(Node *n) { Delete(pname0); } if (make_set_wrapper) { + Setattr(n, "varset", "1"); functionWrapper(n); + } else { + Setattr(n, "feature:immutable", "1"); } /* Restore parameters */ Setattr(n, "sym:name", symname); Setattr(n, "type", type); Setattr(n, "name", name); + Delattr(n, "varset"); /* Delete all attached typemaps and typemap attributes */ Iterator ki; @@ -3005,7 +3013,9 @@ int Language::variableWrapper(Node *n) { String *gname = Swig_name_get(NSpace, symname); Setattr(n, "sym:name", gname); Delete(gname); + Setattr(n, "varget", "1"); functionWrapper(n); + Delattr(n, "varget"); Swig_restore(n); return SWIG_OK; } @@ -3049,11 +3059,10 @@ void Language::main(int argc, char *argv[]) { * ----------------------------------------------------------------------------- */ int Language::addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { + //Printf( stdout, "addSymbol: %s %s\n", s, scope ); Hash *symbols = Getattr(symtabs, scope ? scope : ""); if (!symbols) { - // New scope which has not been added by the target language - lazily created. - symbols = NewHash(); - Setattr(symtabs, scope, symbols); + symbols = symbolAddScope(scope); } else { Node *c = Getattr(symbols, s); if (c && (c != n)) { @@ -3070,6 +3079,71 @@ int Language::addSymbol(const String *s, const Node *n, const_String_or_char_ptr } /* ----------------------------------------------------------------------------- + * Lanugage::symbolAddScope( const_String_or_char_ptr scopeName ) + * + * Creates a scope (symbols Hash) for given name. This method is auxilary, + * you don't have to call it - addSymbols will lazily create scopes automatically. + * If scope with given name already exists, then do nothing. + * Returns newly created (or already existing) scope. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolAddScope(const_String_or_char_ptr scope) { + Hash *symbols = symbolScopeLookup(scope); + if(!symbols) { + // Order in which to following parts are executed is important. In Lanugage + // constructor addScope("") is called to create a top level scope itself. + // Thus we must first add symbols hash to symtab and only then add pseudo + // symbol to top-level scope + + // New scope which has not been added by the target language - lazily created. + symbols = NewHash(); + Setattr(symtabs, scope, symbols); + + // Add the new scope as a symbol in the top level scope. + // Alternatively the target language must add it in before attempting to add symbols into the scope. + const_String_or_char_ptr top_scope = ""; + Hash *topscope_symbols = Getattr(symtabs, top_scope); + Hash *pseudo_symbol = NewHash(); + Setattr(pseudo_symbol, "sym:is_scope", "1"); + Setattr(topscope_symbols, scope, pseudo_symbol); + } + return symbols; +} + +/* ----------------------------------------------------------------------------- + * Lanugage::symbolSscopeLookup( const_String_or_char_ptr scope ) + * + * Lookup and returns a symtable (hash) representing given scope. Hash contains + * all symbols in this scope. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolScopeLookup( const_String_or_char_ptr scope ) { + Hash *symbols = Getattr(symtabs, scope ? scope : ""); + return symbols; +} + +/* ----------------------------------------------------------------------------- + * Lanugage::symbolScopeSymbolLookup( const_String_or_char_ptr scope ) + * + * For every scope there is a special pseudo-symbol in the top scope (""). It + * exists solely to detect name clashes. This pseudo symbol may contain a few properties, + * but you can more if you need to. This is also true fro top level scope (""). + * It contains a pseudo symbol with name "" (empty). Pseudo symbol contains the + * following properties: + * sym:scope = "1" - a flag that this is scope pseudo symbol + * + * Pseudo symbols are a Hash*, not a Node* (not that there is a difference + * in DOH) + * There is no difference from symbolLookup() method except for signature + * and return type. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolScopePseudoSymbolLookup( const_String_or_char_ptr scope ) +{ + /* Getting top scope */ + const_String_or_char_ptr top_scope = ""; + Hash *symbols = Getattr(symtabs, top_scope); + return Getattr(symbols, scope); +} + +/* ----------------------------------------------------------------------------- * Language::dumpSymbols() * ----------------------------------------------------------------------------- */ diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx index b76945b95..6c9e69050 100644 --- a/Source/Modules/lua.cxx +++ b/Source/Modules/lua.cxx @@ -54,7 +54,7 @@ */ #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" %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 @@ -73,8 +73,6 @@ void display_mapping(DOH *d) { } } - - /* NEW LANGUAGE NOTE:*********************************************** most of the default options are handled by SWIG you can add new ones here @@ -84,13 +82,35 @@ static const char *usage = (char *) "\ Lua Options (available with -lua)\n\ -elua - Generates LTR compatible wrappers for smaller devices running elua\n\ -eluac - LTR compatible wrappers in \"crass compress\" mode for elua\n\ + -elua-emulate - Emulates behaviour of eLua. Usefull only for testing.\n\ + Incompatible with -elua/-eluac options.\n\ -nomoduleglobal - Do not register the module name as a global variable \n\ but return the module table from calls to require.\n\ + -no-old-metatable-bindings\n\ + - Disable support for old-style bindings name generation, some\n\ + old-style members scheme etc.\n\ + -squash-bases - Squashes symbols from all inheritance tree of a given class\n\ + into itself. Emulates pre-SWIG3.0 inheritance. Insignificantly\n\ + speeds things up, but increases memory consumption.\n\ \n"; static int nomoduleglobal = 0; static int elua_ltr = 0; static int eluac_ltr = 0; +static int elua_emulate = 0; +static int squash_bases = 0; +/* This variable defines internal(!) module API level and compatibility options. + * This variable is controled by -no-old-metatable-bindings option. + * v2_compatibility - + * 1. static methods will be put into the scope their respective class + * belongs to as well as into the class scope itself. + * 2. The layout in elua mode is somewhat different + * 3. C enums defined inside struct will oblige to C Standard and + * will be defined in the scope surrounding the struct, not scope + * associated with it/ + */ +static int v2_compatibility = 0; +static const int default_api_level = 2; /* NEW LANGUAGE NOTE:*********************************************** To add a new language, you need to derive your class from @@ -107,36 +127,50 @@ private: File *f_wrappers; File *f_init; File *f_initbeforefunc; - String *s_cmd_tab; // table of command names - String *s_var_tab; // table of global variables - String *s_const_tab; // table of global constants - String *s_methods_tab; // table of class methods - String *s_attr_tab; // table of class attributes - String *s_cls_attr_tab; // table of class static attributes - String *s_cls_methods_tab; // table of class static methods - String *s_cls_const_tab; // tables of class constants(including enums) String *s_luacode; // luacode to be called during init - String *s_dot_get; // table of variable 'get' functions - String *s_dot_set; // table of variable 'set' functions - String *s_vars_meta_tab; // metatable for variables + String *module; //name of the module + // Parameters for current class. NIL if not parsing class int have_constructor; int have_destructor; String *destructor_action; - String *class_name; + // This variable holds the name of the current class in Lua. Usually it is + // the same as C++ class name, but rename directives can change it. + String *proxy_class_name; + // This is a so calld fully qualified symname - the above proxy class name + // prepended with class namespace. If class Lua name is the same as class C++ name, + // then it is basically C++ fully qualified name with colons replaced with dots. + String *full_proxy_class_name; + // All static methods and/or variables are treated as if they were in the + // special C++ namespace $(classname).__Static. This is internal mechanism only + // and is not visible to user in any manner. This variable holds the name + // of such pseudo-namespace a.k.a the result of above expression evaluation + String *class_static_nspace; + // This variable holds the name of generated C function that acts as constructor + // for currently parsed class. String *constructor_name; - enum { + // Many wrappers forward calls to each other, for example staticmembervariableHandler + // forwards call to variableHandler, which, in turn, makes to call to functionWrapper. + // In order to access information about whether it is static member of class or just + // plain old variable an array current is kept and used as 'log' of call stack. + enum TState { NO_CPP, VARIABLE, + GLOBAL_FUNC, + GLOBAL_VAR, MEMBER_FUNC, CONSTRUCTOR, DESTRUCTOR, MEMBER_VAR, - CLASS_CONST, STATIC_FUNC, - STATIC_VAR - }current; + STATIC_VAR, + STATIC_CONST, // enums and things like static const int x = 5; + ENUM_CONST, // This is only needed for backward compatibility in C mode + + STATES_COUNT + }; + bool current[STATES_COUNT]; public: @@ -146,74 +180,108 @@ public: * Initialize member data * --------------------------------------------------------------------- */ - LUA() : - f_begin(0), - f_runtime(0), - f_header(0), - f_wrappers(0), - f_init(0), - f_initbeforefunc(0), - s_cmd_tab(0), - s_var_tab(0), - s_const_tab(0), - s_methods_tab(0), - s_attr_tab(0), - s_cls_attr_tab(0), - s_cls_methods_tab(0), - s_cls_const_tab(0), - s_luacode(0), - s_dot_get(0), - s_dot_set(0), - s_vars_meta_tab(0), - have_constructor(0), - have_destructor(0), - destructor_action(0), - class_name(0), - constructor_name(0), - current(NO_CPP) { + LUA(): + f_begin(0), + f_runtime(0), + f_header(0), + f_wrappers(0), + f_init(0), + f_initbeforefunc(0), + s_luacode(0), + module(0), + have_constructor(0), + have_destructor(0), + destructor_action(0), + proxy_class_name(0), + full_proxy_class_name(0), + class_static_nspace(0), + constructor_name(0) { + for (int i = 0; i < STATES_COUNT; i++) + current[i] = false; + } + ~LUA() { } + bool strToInt(const char *string, int &value) { + long int tmp; + char *p_end = 0; + if (string == 0) + return false; + tmp = strtol(string, &p_end, 10); + if (p_end == 0 || *p_end != 0) + return false; + value = tmp; + return true; + } /* NEW LANGUAGE NOTE:*********************************************** This is called to initalise the system & read any command line args most of this is boilerplate code, except the command line args which depends upon what args your code supports - NEW LANGUAGE NOTE:END ************************************************/ + NEW LANGUAGE NOTE:END *********************************************** */ /* --------------------------------------------------------------------- - * main() - * - * Parse command line options and initializes variables. - * --------------------------------------------------------------------- */ + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ virtual void main(int argc, char *argv[]) { + int api_level = default_api_level; // Default api level /* Set location of SWIG library */ SWIG_library_directory("lua"); /* Look for certain command line options */ for (int i = 1; i < argc; i++) { if (argv[i]) { - if (strcmp(argv[i], "-help") == 0) { // usage flags - fputs(usage, stdout); - } else if (strcmp(argv[i], "-nomoduleglobal") == 0) { - nomoduleglobal = 1; - Swig_mark_arg(i); - } else if(strcmp(argv[i], "-elua") == 0) { - elua_ltr = 1; - Swig_mark_arg(i); - } else if(strcmp(argv[i], "-eluac") == 0) { - eluac_ltr = 1; - Swig_mark_arg(i); - } + if (strcmp(argv[i], "-help") == 0) { // usage flags + fputs(usage, stdout); + } else if (strcmp(argv[i], "-nomoduleglobal") == 0) { + nomoduleglobal = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-elua") == 0) { + elua_ltr = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-eluac") == 0) { + eluac_ltr = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-no-old-metatable-bindings") == 0) { + Swig_mark_arg(i); + api_level = 3; + } else if (strcmp(argv[i], "-squash-bases") == 0) { + Swig_mark_arg(i); + squash_bases = 1; + } else if (strcmp(argv[i], "-elua-emulate") == 0) { + Swig_mark_arg(i); + elua_emulate = 1; + } } } + if (elua_emulate && (eluac_ltr || elua_ltr )) { + Printf(stderr, "Can't have -elua-emulate and -eluac/-elua at the same time\n"); + Swig_arg_error(); + } + + // Set API-compatibility options + if (api_level <= 2) // Must be compatible with SWIG 2.* + v2_compatibility = 1; + // template for further API breaks + //if(api_level <= 3) + // v3_compatibility = 1; + //if(api_level <= 4) + // v4_compatibility = 1; + + // Set elua_ltr if elua_emulate is requested + if(elua_emulate) + elua_ltr = 1; + /* NEW LANGUAGE NOTE:*********************************************** - This is the boilerplate code, setting a few #defines - and which lib directory to use - the SWIG_library_directory() is also boilerplate code - but it always seems to be the first line of code - NEW LANGUAGE NOTE:END ************************************************/ + This is the boilerplate code, setting a few #defines + and which lib directory to use + the SWIG_library_directory() is also boilerplate code + but it always seems to be the first line of code + NEW LANGUAGE NOTE:END *********************************************** */ /* Add a symbol to the parser for conditional compilation */ Preprocessor_define("SWIGLUA 1", 0); @@ -231,22 +299,22 @@ public: /* NEW LANGUAGE NOTE:*********************************************** - After calling main, SWIG parses the code to wrap (I believe) - then calls top() - in this is more boilerplate code to set everything up - and a call to Language::top() - which begins the code generations by calling the member fns - after all that is more boilerplate code to close all down - (overall there is virtually nothing here that needs to be edited - just use as is) - NEW LANGUAGE NOTE:END ************************************************/ + After calling main, SWIG parses the code to wrap (I believe) + then calls top() + in this is more boilerplate code to set everything up + and a call to Language::top() + which begins the code generations by calling the member fns + after all that is more boilerplate code to close all down + (overall there is virtually nothing here that needs to be edited + just use as is) + NEW LANGUAGE NOTE:END *********************************************** */ /* --------------------------------------------------------------------- * top() * --------------------------------------------------------------------- */ virtual int top(Node *n) { /* Get the module name */ - String *module = Getattr(n, "name"); + module = Getattr(n, "name"); /* Get the output file name */ String *outfile = Getattr(n, "outfile"); @@ -271,27 +339,11 @@ public: Swig_register_filebyname("init", f_init); Swig_register_filebyname("initbeforefunc", f_initbeforefunc); - /* NEW LANGUAGE NOTE:*********************************************** - s_cmd_tab,s_var_tab & s_const_tab hold the names of the fns for - registering with SWIG. - These will be filled in when the functions/variables are wrapped & - then added to the end of the wrappering code - just before it is written to file - NEW LANGUAGE NOTE:END ************************************************/ - // Initialize some variables for the object interface - s_cmd_tab = NewString(""); - s_var_tab = NewString(""); - // s_methods_tab = NewString(""); - s_const_tab = NewString(""); - - s_dot_get = NewString(""); - s_dot_set = NewString(""); - s_vars_meta_tab = NewString(""); - + s_luacode = NewString(""); Swig_register_filebyname("luacode", s_luacode); - - current=NO_CPP; + + current[NO_CPP] = true; /* Standard stuff for the SWIG runtime section */ Swig_banner(f_begin); @@ -306,6 +358,8 @@ public: } else { Printf(f_runtime, "#define SWIG_LUA_MODULE_GLOBAL\n"); } + if (squash_bases) + Printf(f_runtime, "#define SWIG_LUA_SQUASH_BASES\n"); // if (NoInclude) { // Printf(f_runtime, "#define SWIG_NOINCLUDE\n"); @@ -323,99 +377,40 @@ public: Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module); Printf(f_header, "#define SWIG_LUACODE luaopen_%s_luacode\n", module); - if (elua_ltr || eluac_ltr) - Printf(f_header, "#define swig_commands %s_map\n\n", module); - - if (elua_ltr || eluac_ltr) { - Printf(s_cmd_tab, "\n#define MIN_OPT_LEVEL 2\n#include \"lrodefs.h\"\n"); - Printf(s_cmd_tab, "#include \"lrotable.h\"\n"); - Printf(s_cmd_tab, "\nconst LUA_REG_TYPE swig_constants[];\n"); - if (elua_ltr) - Printf(s_cmd_tab, "const LUA_REG_TYPE mt[];\n"); - - Printf(s_cmd_tab, "\nconst LUA_REG_TYPE swig_commands[] = {\n"); - Printf(s_const_tab, "\nconst LUA_REG_TYPE swig_constants[] = {\n"); - Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); - if (elua_ltr) { - Printf(s_dot_get, "\nconst LUA_REG_TYPE dot_get[] = {\n"); - Printf(s_dot_set, "\nconst LUA_REG_TYPE dot_set[] = {\n"); - } - } else { - Printf(s_cmd_tab, "\nstatic const struct luaL_Reg swig_commands[] = {\n"); - Printf(s_var_tab, "\nstatic swig_lua_var_info swig_variables[] = {\n"); - Printf(s_const_tab, "\nstatic swig_lua_const_info swig_constants[] = {\n"); - Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); - } + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); /* %init code inclusion, effectively in the SWIG_init function */ Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n"); Language::top(n); - Printf(f_init,"/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); + Printf(f_init, "/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); Printf(f_init, "}\n"); - Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); - // Done. Close up the module & write to the wrappers - if (elua_ltr || eluac_ltr) { - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"const\"), LROVAL(swig_constants)},\n", NIL); - if (elua_ltr) - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"__metatable\"), LROVAL(mt)},\n", NIL); - Printv(s_cmd_tab, tab4, "{LNILKEY, LNILVAL}\n", "};\n", NIL); - Printv(s_const_tab, tab4, "{LNILKEY, LNILVAL}\n", "};\n", NIL); - } else { - Printv(s_cmd_tab, tab4, "{0,0}\n", "};\n", NIL); - Printv(s_var_tab, tab4, "{0,0,0}\n", "};\n", NIL); - Printv(s_const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); - } - - if (elua_ltr) { - /* Generate the metatable */ - Printf(s_vars_meta_tab, "\nconst LUA_REG_TYPE mt[] = {\n"); - Printv(s_vars_meta_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_module_get)},\n", NIL); - Printv(s_vars_meta_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_module_set)},\n", NIL); - Printv(s_vars_meta_tab, tab4, "{LSTRKEY(\".get\"), LROVAL(dot_get)},\n", NIL); - Printv(s_vars_meta_tab, tab4, "{LSTRKEY(\".set\"), LROVAL(dot_set)},\n", NIL); - Printv(s_vars_meta_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); - - Printv(s_dot_get, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); - Printv(s_dot_set, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); - } + closeNamespaces(f_wrappers); + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); - if (elua_ltr || eluac_ltr) { - /* Final close up of wrappers */ - Printv(f_wrappers, s_cmd_tab, s_dot_get, s_dot_set, s_vars_meta_tab, s_var_tab, s_const_tab, NIL); - SwigType_emit_type_table(f_runtime, f_wrappers); - } else { - Printv(f_wrappers, s_cmd_tab, s_var_tab, s_const_tab, NIL); - SwigType_emit_type_table(f_runtime, f_wrappers); - } + SwigType_emit_type_table(f_runtime, f_wrappers); /* NEW LANGUAGE NOTE:*********************************************** - this basically combines several of the strings together - and then writes it all to a file - NEW LANGUAGE NOTE:END ************************************************/ + this basically combines several of the strings together + and then writes it all to a file + NEW LANGUAGE NOTE:END *********************************************** */ Dump(f_runtime, f_begin); Dump(f_header, f_begin); Dump(f_wrappers, f_begin); Dump(f_initbeforefunc, f_begin); /* for the Lua code it needs to be properly excaped to be added into the C/C++ code */ EscapeCode(s_luacode); - Printf(f_begin, "const char* SWIG_LUACODE=\n \"%s\";\n\n",s_luacode); + Printf(f_begin, "const char* SWIG_LUACODE=\n \"%s\";\n\n", s_luacode); Wrapper_pretty_print(f_init, f_begin); /* Close all of the files */ Delete(s_luacode); - Delete(s_cmd_tab); - Delete(s_var_tab); - Delete(s_const_tab); Delete(f_header); Delete(f_wrappers); Delete(f_init); Delete(f_initbeforefunc); Delete(f_runtime); Delete(f_begin); - Delete(s_dot_get); - Delete(s_dot_set); - Delete(s_vars_meta_tab); /* Done */ return SWIG_OK; @@ -429,48 +424,134 @@ public: return Language::importDirective(n); } + /* ------------------------------------------------------------ + * cDeclaration() + * It copies sym:name to lua:name to preserve it's original value + * ------------------------------------------------------------ */ + virtual int cDeclaration(Node *n) { + // class 'Language' is messing with symname in a really heavy way. + // Although documentation states that sym:name is a name in + // the target language space, it is not true. sym:name and + // it's derivatives are used in various places, including + // behind-the-scene C code generation. The best way is not to + // touch it at all. + // But we need to know what was the name of function/variable + // etc that user desired, that's why we store correct symname + // as lua:name + String *symname = Getattr(n, "sym:name"); + if (symname) + Setattr(n, "lua:name", symname); + return Language::cDeclaration(n); + } + virtual int constructorDeclaration(Node *n) { + Setattr(n, "lua:name", Getattr(n, "sym:name")); + return Language::constructorDeclaration(n); + } + virtual int destructorDeclaration(Node *n) { + Setattr(n, "lua:name", Getattr(n, "sym:name")); + return Language::destructorDeclaration(n); + } /* NEW LANGUAGE NOTE:*********************************************** - This is it! - you get this one right, and most of your work is done - but its going to take soem file to get it working right - quite a bit of this is generally boilerplate code - (or stuff I dont understand) - that which matters will have extra added comments - NEW LANGUAGE NOTE:END ************************************************/ + This is it! + you get this one right, and most of your work is done + but its going to take soem file to get it working right + quite a bit of this is generally boilerplate code + (or stuff I dont understand) + that which matters will have extra added comments + NEW LANGUAGE NOTE:END *********************************************** */ /* --------------------------------------------------------------------- * functionWrapper() * * Create a function declaration and register it with the interpreter. * --------------------------------------------------------------------- */ + /* ----------------------------------------------------------------------- + * registerMethod() + * + * Determines wrap name of a method, it's scope etc and calls + * registerMethod overload with correct arguments + * Overloaded variant adds method to the "methods" array of specified lua scope/class + * ---------------------------------------------------------------------- */ + void registerMethod(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { + String *symname = Getattr(n, "sym:name"); + assert(symname); + + if (Getattr(n, "sym:nextSibling")) + return; + + // Lua scope. It is not symbol NSpace, it is actuall key to revrieve + // getCArraysHash. + String *luaScope = luaCurrentSymbolNSpace(); + if (overwrite) + luaScope = overwriteLuaScope; + + String *wrapname = 0; + String *mrename; + if (current[NO_CPP] || !getCurrentClass()) { + mrename = symname; + } else { + assert(!current[NO_CPP]); + if (current[STATIC_FUNC] || current[MEMBER_FUNC]) { + mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); + } else { + mrename = symname; + } + } + wrapname = Swig_name_wrapper(mrename); + //Printf(stdout, "luaname %s, symname %s mrename %s wrapname %s\n\tscope %s\n", + // Getattr(n, "lua:name"), symname, mrename, wrapname, luaScope ); // TODO: REMOVE + registerMethod(n, wrapname, luaScope); + } + + // Add method to the "methods" C array of given namespace/class + void registerMethod(Node *n, String* wname, String *luaScope) { + assert(n); + Hash *nspaceHash = getCArraysHash(luaScope); + String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); + String *lua_name = Getattr(n, "lua:name"); + if (elua_ltr || eluac_ltr) + Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); + else + Printv(s_ns_methods_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); + // Add to the metatable if method starts with '__' + const char * tn = Char(lua_name); + if (tn[0]=='_' && tn[1] == '_' && !eluac_ltr) { + String *metatable_tab = Getattr(nspaceHash, "metatable"); + assert(metatable_tab); + if (elua_ltr) + Printv(metatable_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); + else + Printv(metatable_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); + } + } + virtual int functionWrapper(Node *n) { - REPORT("functionWrapper",n); + REPORT("functionWrapper", n); String *name = Getattr(n, "name"); String *iname = Getattr(n, "sym:name"); + String *lua_name = Getattr(n, "lua:name"); + assert(lua_name); SwigType *d = Getattr(n, "type"); ParmList *l = Getattr(n, "parms"); - //Printf(stdout,"functionWrapper %s %s\n",name,iname); Parm *p; String *tm; int i; //Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); - // int returnval=0; // number of arguments returned String *overname = 0; if (Getattr(n, "sym:overloaded")) { overname = Getattr(n, "sym:overname"); } else { - if (!addSymbol(iname, n)) { - Printf(stderr,"addSymbol(%s) failed\n",iname); - return SWIG_ERROR; + if (!luaAddSymbol(lua_name, n)) { + return SWIG_ERROR; } } /* NEW LANGUAGE NOTE:*********************************************** the wrapper object holds all the wrappering code - we need to add a couple of local variables - NEW LANGUAGE NOTE:END ************************************************/ + we need to add a couple of local variables + NEW LANGUAGE NOTE:END *********************************************** */ Wrapper *f = NewWrapper(); Wrapper_add_local(f, "SWIG_arg", "int SWIG_arg = 0"); @@ -479,21 +560,26 @@ public: if (overname) { Append(wname, overname); } + if (current[CONSTRUCTOR]) { + if (constructor_name != 0) + Delete(constructor_name); + constructor_name = Copy(wname); + } /* NEW LANGUAGE NOTE:*********************************************** the format of a lua fn is: - static int wrap_XXX(lua_State* L){...} + static int wrap_XXX(lua_State* L){...} this line adds this into the wrappering code - NEW LANGUAGE NOTE:END ************************************************/ + NEW LANGUAGE NOTE:END *********************************************** */ Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); /* NEW LANGUAGE NOTE:*********************************************** this prints the list of args, eg for a C fn int gcd(int x,int y); it will print - int arg1; - int arg2; - NEW LANGUAGE NOTE:END ************************************************/ + int arg1; + int arg2; + NEW LANGUAGE NOTE:END *********************************************** */ /* Write code to extract function parameters. */ emit_parameter_variables(l, f); @@ -516,36 +602,30 @@ public: } - /* Which input argument to start with? */ - // int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; - - /* Offset to skip over the attribute name */ - // int offset = (current == MEMBER_VAR) ? 1 : 0; - /* NEW LANGUAGE NOTE:*********************************************** from here on in, it gets rather hairy this is the code to convert from the scripting language to C/C++ some of the stuff will refer to the typemaps code written in your swig file (lua.swg), and some is done in the code here I suppose you could do all the conversion on C, but it would be a nightmare to do - NEW LANGUAGE NOTE:END ************************************************/ + NEW LANGUAGE NOTE:END *********************************************** */ /* Generate code for argument marshalling */ // String *description = NewString(""); /* NEW LANGUAGE NOTE:*********************************************** argument_check is a new feature I added to check types of arguments: eg for int gcd(int,int) I want to check that arg1 & arg2 really are integers - NEW LANGUAGE NOTE:END ************************************************/ + NEW LANGUAGE NOTE:END *********************************************** */ String *argument_check = NewString(""); String *argument_parse = NewString(""); String *checkfn = NULL; char source[64]; - Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",Swig_name_str(n),num_required+args_to_ignore,num_arguments+args_to_ignore); + Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n", Swig_name_str(n), num_required + args_to_ignore, num_arguments + args_to_ignore); for (i = 0, p = l; i < num_arguments; i++) { while (checkAttribute(p, "tmap:in:numinputs", "0")) { - p = Getattr(p, "tmap:in:next"); + p = Getattr(p, "tmap:in:next"); } SwigType *pt = Getattr(p, "type"); @@ -554,49 +634,49 @@ public: /* Look for an input typemap */ sprintf(source, "%d", i + 1); if ((tm = Getattr(p, "tmap:in"))) { - Replaceall(tm, "$source", source); - Replaceall(tm, "$target", ln); - Replaceall(tm, "$input", source); - Setattr(p, "emit:input", source); - if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { - Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); - } else { - Replaceall(tm, "$disown", "0"); - } - /* NEW LANGUAGE NOTE:*********************************************** - look for a 'checkfn' typemap - this an additional parameter added to the in typemap - if found the type will be tested for - this will result in code either in the - argument_check or argument_parse string - NEW LANGUAGE NOTE:END ************************************************/ - if ((checkfn = Getattr(p, "tmap:in:checkfn"))) { - if (i < num_required) { - Printf(argument_check, "if(!%s(L,%s))", checkfn, source); - } else { - Printf(argument_check, "if(lua_gettop(L)>=%s && !%s(L,%s))", source, checkfn, source); - } - Printf(argument_check, " SWIG_fail_arg(\"%s\",%s,\"%s\");\n", Swig_name_str(n), source, SwigType_str(pt, 0)); - } - /* NEW LANGUAGE NOTE:*********************************************** - lua states the number of arguments passed to a function using the fn - lua_gettop() - we can use this to deal with default arguments - NEW LANGUAGE NOTE:END ************************************************/ - if (i < num_required) { - Printf(argument_parse, "%s\n", tm); - } else { - Printf(argument_parse, "if(lua_gettop(L)>=%s){%s}\n", source, tm); - } - p = Getattr(p, "tmap:in:next"); - continue; + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + /* NEW LANGUAGE NOTE:*********************************************** + look for a 'checkfn' typemap + this an additional parameter added to the in typemap + if found the type will be tested for + this will result in code either in the + argument_check or argument_parse string + NEW LANGUAGE NOTE:END *********************************************** */ + if ((checkfn = Getattr(p, "tmap:in:checkfn"))) { + if (i < num_required) { + Printf(argument_check, "if(!%s(L,%s))", checkfn, source); + } else { + Printf(argument_check, "if(lua_gettop(L)>=%s && !%s(L,%s))", source, checkfn, source); + } + Printf(argument_check, " SWIG_fail_arg(\"%s\",%s,\"%s\");\n", Swig_name_str(n), source, SwigType_str(pt, 0)); + } + /* NEW LANGUAGE NOTE:*********************************************** + lua states the number of arguments passed to a function using the fn + lua_gettop() + we can use this to deal with default arguments + NEW LANGUAGE NOTE:END *********************************************** */ + if (i < num_required) { + Printf(argument_parse, "%s\n", tm); + } else { + Printf(argument_parse, "if(lua_gettop(L)>=%s){%s}\n", source, tm); + } + p = Getattr(p, "tmap:in:next"); + continue; } else { - /* NEW LANGUAGE NOTE:*********************************************** - // why is this code not called when I dont have a typemap? - // instead of giving a warning, no code is generated - NEW LANGUAGE NOTE:END ************************************************/ - Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); - break; + /* NEW LANGUAGE NOTE:*********************************************** + // why is this code not called when I dont have a typemap? + // instead of giving a warning, no code is generated + NEW LANGUAGE NOTE:END *********************************************** */ + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; } } @@ -606,19 +686,19 @@ public: /* Check for trailing varargs */ if (varargs) { if (p && (tm = Getattr(p, "tmap:in"))) { - Replaceall(tm, "$input", "varargs"); - Printv(f->code, tm, "\n", NIL); + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); } } /* Insert constraint checking code */ for (p = l; p;) { if ((tm = Getattr(p, "tmap:check"))) { - Replaceall(tm, "$target", Getattr(p, "lname")); - Printv(f->code, tm, "\n", NIL); - p = Getattr(p, "tmap:check:next"); + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); } else { - p = nextSibling(p); + p = nextSibling(p); } } @@ -626,11 +706,11 @@ public: String *cleanup = NewString(""); for (p = l; p;) { if ((tm = Getattr(p, "tmap:freearg"))) { - Replaceall(tm, "$source", Getattr(p, "lname")); - Printv(cleanup, tm, "\n", NIL); - p = Getattr(p, "tmap:freearg:next"); + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); } else { - p = nextSibling(p); + p = nextSibling(p); } } @@ -638,34 +718,35 @@ public: String *outarg = NewString(""); for (p = l; p;) { if ((tm = Getattr(p, "tmap:argout"))) { - // // managing the number of returning variables - // if (numoutputs=Getattr(p,"tmap:argout:numoutputs")){ - // int i=GetInt(p,"tmap:argout:numoutputs"); - // printf("got argout:numoutputs of %d\n",i); - // returnval+=GetInt(p,"tmap:argout:numoutputs"); - // } - // else returnval++; - Replaceall(tm, "$source", Getattr(p, "lname")); - Replaceall(tm, "$target", Swig_cresult_name()); - Replaceall(tm, "$arg", Getattr(p, "emit:input")); - Replaceall(tm, "$input", Getattr(p, "emit:input")); - Printv(outarg, tm, "\n", NIL); - p = Getattr(p, "tmap:argout:next"); + // // managing the number of returning variables + // if (numoutputs=Getattr(p,"tmap:argout:numoutputs")){ + // int i=GetInt(p,"tmap:argout:numoutputs"); + // printf("got argout:numoutputs of %d\n",i); + // returnval+=GetInt(p,"tmap:argout:numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", Swig_cresult_name()); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); } else { - p = nextSibling(p); + p = nextSibling(p); } } + // Remember C name of the wrapping function Setattr(n, "wrap:name", wname); /* Emit the function call */ String *actioncode = emit_action(n); /* NEW LANGUAGE NOTE:*********************************************** - FIXME: - returns 1 if there is a void return type - this is because there is a typemap for void - NEW LANGUAGE NOTE:END ************************************************/ + FIXME: + returns 1 if there is a void return type + this is because there is a typemap for void + NEW LANGUAGE NOTE:END *********************************************** */ // Return value if necessary if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { // managing the number of returning variables @@ -677,9 +758,9 @@ public: // else returnval++; Replaceall(tm, "$source", Swig_cresult_name()); if (GetFlag(n, "feature:new")) { - Replaceall(tm, "$owner", "1"); + Replaceall(tm, "$owner", "1"); } else { - Replaceall(tm, "$owner", "0"); + Replaceall(tm, "$owner", "0"); } Printf(f->code, "%s\n", tm); // returnval++; @@ -697,8 +778,8 @@ public: /* Look to see if there is any newfree cleanup code */ if (GetFlag(n, "feature:new")) { if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { - Replaceall(tm, "$source", Swig_cresult_name()); - Printf(f->code, "%s\n", tm); + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); } } @@ -727,38 +808,31 @@ public: /* Dump the function out */ /* 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); + 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 - NEW LANGUAGE NOTE:END ************************************************/ + register the function in SWIG + different language mappings seem to use different ideas + NEW LANGUAGE NOTE:END *********************************************** */ /* Now register the function with the interpreter. */ + int result = SWIG_OK; if (!Getattr(n, "sym:overloaded")) { - //REPORT("dispatchFunction", n); - // add_method(n, iname, wname, description); - if (current==NO_CPP || current==STATIC_FUNC) { // emit normal fns & static fns - String *wrapname = Swig_name_wrapper(iname); - if(elua_ltr || eluac_ltr) - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", iname, "\")", ", LFUNCVAL(", Swig_name_wrapper(iname), ")", "},\n", NIL); - else - Printv(s_cmd_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(iname), "},\n", NIL); - // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), "},\n", NIL); - if (getCurrentClass()) { - Setattr(n,"luaclassobj:wrap:name", wrapname); - } + /* TODO: REMOVE + if (functionWrapperRegisterNow()) { // emit normal fns & static fns + registerMethod(n); } + */ } else { if (!Getattr(n, "sym:nextSibling")) { - dispatchFunction(n); + result = dispatchFunction(n); } } @@ -768,10 +842,9 @@ public: Delete(cleanup); Delete(outarg); // Delete(description); - Delete(wname); DelWrapper(f); - return SWIG_OK; + return result; } /* ------------------------------------------------------------ @@ -781,12 +854,12 @@ public: * ------------------------------------------------------------ */ /* NEW LANGUAGE NOTE:*********************************************** - This is an extra function used for overloading of functions - it checks the args & then calls the relevant fn - nost of the real work in again typemaps: - look for %typecheck(SWIG_TYPECHECK_*) in the .swg file - NEW LANGUAGE NOTE:END ************************************************/ - void dispatchFunction(Node *n) { + This is an extra function used for overloading of functions + it checks the args & then calls the relevant fn + nost of the real work in again typemaps: + look for %typecheck(SWIG_TYPECHECK_*) in the .swg file + NEW LANGUAGE NOTE:END *********************************************** */ + int dispatchFunction(Node *n) { //REPORT("dispatchFunction", n); /* Last node in overloaded chain */ @@ -798,10 +871,16 @@ public: Wrapper *f = NewWrapper(); String *symname = Getattr(n, "sym:name"); + String *lua_name = Getattr(n, "lua:name"); + assert(lua_name); String *wname = Swig_name_wrapper(symname); //Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); + if (!luaAddSymbol(lua_name, n)) { + return SWIG_ERROR; + } + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); Wrapper_add_local(f, "argc", "int argc"); Printf(tmp, "int argv[%d]={1", maxargs + 1); @@ -814,7 +893,7 @@ public: Replaceall(dispatch, "$args", "self,args"); Printv(f->code, dispatch, "\n", NIL); - + Node *sibl = n; while (Getattr(sibl, "sym:previousSibling")) sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up @@ -825,86 +904,165 @@ public: Delete(fulldecl); } while ((sibl = Getattr(sibl, "sym:nextSibling"))); Printf(f->code, "SWIG_Lua_pusherrstring(L,\"Wrong arguments for overloaded function '%s'\\n\"\n" - "\" Possible C/C++ prototypes are:\\n\"%s);\n",symname,protoTypes); + "\" 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); - //add_method(symname,wname,0); - if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns - Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wname, "},\n", NIL); - if (getCurrentClass()) - Setattr(n,"luaclassobj:wrap:name", wname); - else - Delete(wname); + // Remember C name of the wrapping function + Setattr(n, "wrap:name", wname); + + /* TODO: REMOVE + if (functionWrapperRegisterNow()) { // emit normal fns & static fns + registerMethod(n); + }*/ + if (current[CONSTRUCTOR]) { + if (constructor_name != 0) + Delete(constructor_name); + constructor_name = Copy(wname); + } DelWrapper(f); Delete(dispatch); Delete(tmp); - } + return SWIG_OK; + } /* ------------------------------------------------------------ - * variableWrapper() + * Add variable to "attributes" C arrays of given namespace or class. + * Input is node. Base on the state of "current" array it determines + * the name of getter function, setter function etc and calls + * registeVariable overload with necessary params + * Lua scope could be overwritten. (Used only for backward compatibility) * ------------------------------------------------------------ */ + void registerVariable(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { + int assignable = is_assignable(n); + String *symname = Getattr(n, "sym:name"); + assert(symname); - virtual int variableWrapper(Node *n) { - /* NEW LANGUAGE NOTE:*********************************************** - Language::variableWrapper(n) will generate two wrapper fns - Foo_get & Foo_set by calling functionWrapper() - so we will just add these into the variable lists - ideally we should not have registered these as functions, - only WRT this variable will look into this later. - NEW LANGUAGE NOTE:END ************************************************/ - // REPORT("variableWrapper", n); - String *iname = Getattr(n, "sym:name"); - current=VARIABLE; - // let SWIG generate the wrappers - int result = Language::variableWrapper(n); - current=NO_CPP; - // normally SWIG will generate 2 wrappers, a get and a set - // but in certain scenarios (immutable, or if its arrays), it will not - String *getName = Swig_name_wrapper(Swig_name_get(NSPACE_TODO, iname)); - String *setName = 0; - // checking whether it can be set to or not appears to be a very error prone issue - // I referred to the Language::variableWrapper() to find this out - bool assignable=is_assignable(n) ? true : false; - SwigType *type = Getattr(n, "type"); - String *tm = Swig_typemap_lookup("globalin", n, iname, 0); - if (!tm && SwigType_isarray(type)) - assignable=false; - Delete(tm); + // Lua scope. It is not symbol NSpace, it is actuall key to revrieve + // getCArraysHash. + String *luaScope = luaCurrentSymbolNSpace(); + if (overwrite) + luaScope = overwriteLuaScope; - if (assignable) { - setName = Swig_name_wrapper(Swig_name_set(NSPACE_TODO, iname)); + // Getter and setter + String *getName = 0; + String *setName = 0; + String *mrename = 0; + if (current[NO_CPP] || !getCurrentClass()) { + // Global variable + getName = Swig_name_get(getNSpace(), symname); + if (assignable) + setName = Swig_name_set(getNSpace(), symname); } else { - // how about calling a 'this is not settable' error message? - setName = NewString("SWIG_Lua_set_immutable"); // error message - //setName = NewString("0"); + assert(!current[NO_CPP]); + if (current[STATIC_VAR] ) { + mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); + getName = Swig_name_get(0, mrename); + if (assignable) + setName = Swig_name_set(0, mrename); + } else if (current[MEMBER_VAR]) { + mrename = Swig_name_member(0, getClassPrefix(), symname); + getName = Swig_name_get(getNSpace(), mrename); + if (assignable) + setName = Swig_name_set(getNSpace(), mrename); + } else { + assert(false); + } } - // register the variable + getName = Swig_name_wrapper(getName); + if (setName) + setName = Swig_name_wrapper(setName); + //Printf(stdout, "luaname %s, symname %s mrename %s getName %s\n\tscope %s\n\tassignable %d\n", + // Getattr(n, "lua:name"), symname, mrename, getName, luaScope, assignable ); // TODO: REMOVE + registerVariable(luaScope, n, getName, setName); + } + + /* ------------------------------------------------------------ + * registerVariable() + * + * Add variable to the "attributes" (or "get"/"set" in + * case of elua_ltr) C arrays of given namespace or class + * ------------------------------------------------------------ */ + void registerVariable(String *lua_nspace_or_class_name, Node *n, String *getName, String *setName) { + String *unassignable = NewString("SWIG_Lua_set_immutable"); + if (setName == 0 || GetFlag(n, "feature:immutable")) { + setName = unassignable; + } + Hash *nspaceHash = getCArraysHash(lua_nspace_or_class_name); + String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); + String *s_ns_var_tab = Getattr(nspaceHash, "attributes"); + String *lua_name = Getattr(n, "lua:name"); if (elua_ltr) { - Printf(s_dot_get, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, iname, getName); - Printf(s_dot_set, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, iname, setName); + String *s_ns_dot_get = Getattr(nspaceHash, "get"); + String *s_ns_dot_set = Getattr(nspaceHash, "set"); + Printf(s_ns_dot_get, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, getName); + Printf(s_ns_dot_set, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, setName); } else if (eluac_ltr) { - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", iname, "_get", "\")", ", LFUNCVAL(", getName, ")", "},\n", NIL); - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", iname, "_set", "\")", ", LFUNCVAL(", setName, ")", "},\n", NIL); - } else { - Printf(s_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, iname, getName, setName); - } - if (getCurrentClass()) { - Setattr(n, "luaclassobj:wrap:get", getName); - Setattr(n, "luaclassobj:wrap:set", setName); + Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_get", "\")", ", LFUNCVAL(", getName, ")", "},\n", NIL); + Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_set", "\")", ", LFUNCVAL(", setName, ")", "},\n", NIL); } else { - Delete(getName); - Delete(setName); + Printf(s_ns_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, lua_name, getName, setName); } + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + virtual int variableWrapper(Node *n) { + /* NEW LANGUAGE NOTE:*********************************************** + Language::variableWrapper(n) will generate two wrapper fns + Foo_get & Foo_set by calling functionWrapper() + so we will just add these into the variable lists + ideally we should not have registered these as functions, + only WRT this variable will look into this later. + NEW LANGUAGE NOTE:END *********************************************** */ + // REPORT("variableWrapper", n); + String *lua_name = Getattr(n, "lua:name"); + assert(lua_name); + current[VARIABLE] = true; + // let SWIG generate the wrappers + int result = Language::variableWrapper(n); + // TODO: REMOVE + //registerVariable(luaCurrentSymbolNSpace(), n, "varget:wrap:name", "varset:wrap:name"); + + // It is impossible to use registerVariable, because sym:name of the Node is currenly + // in undefined states - the callees of this function may have modified it. + // registerVariable should be used from respective callees.* + current[VARIABLE] = false; return result; } + + /* ------------------------------------------------------------ + * Add constant to appropriate C array. constantRecord is an array record. + * Actually, in current implementation it is resolved consttab typemap + * ------------------------------------------------------------ */ + void registerConstant(String *nspace, String *constantRecord) { + Hash *nspaceHash = getCArraysHash(nspace); + String *s_const_tab = 0; + if (eluac_ltr || elua_ltr) + // In elua everything goes to "methods" tab + s_const_tab = Getattr(nspaceHash, "methods"); + else + s_const_tab = Getattr(nspaceHash, "constants"); + + assert(s_const_tab); + Printf(s_const_tab, " %s,\n", constantRecord); + + if ((eluac_ltr || elua_ltr) && v2_compatibility) { + s_const_tab = Getattr(nspaceHash, "constants"); + assert(s_const_tab); + Printf(s_const_tab, " %s,\n", constantRecord); + } + + } + /* ------------------------------------------------------------ * constantWrapper() * ------------------------------------------------------------ */ @@ -912,15 +1070,24 @@ public: REPORT("constantWrapper", n); String *name = Getattr(n, "name"); String *iname = Getattr(n, "sym:name"); + String *lua_name = Getattr(n, "lua:name"); + if (lua_name == 0) + lua_name = iname; String *nsname = Copy(iname); SwigType *type = Getattr(n, "type"); String *rawval = Getattr(n, "rawval"); String *value = rawval ? rawval : Getattr(n, "value"); String *tm; + String *lua_name_v2 = 0; + String *tm_v2 = 0; + String *iname_v2 = 0; + Node *n_v2 = 0; - if (!addSymbol(iname, n)) + if (!luaAddSymbol(lua_name, n)) return SWIG_ERROR; + Swig_save("lua_constantMember", n, "sym:name", NIL); + Setattr(n, "sym:name", lua_name); /* Special hook for member pointer */ if (SwigType_type(type) == T_MPOINTER) { String *wname = Swig_name_wrapper(iname); @@ -929,36 +1096,73 @@ public: } if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + //Printf(stdout, "tm v1: %s\n", tm); // TODO:REMOVE Replaceall(tm, "$source", value); - Replaceall(tm, "$target", name); + Replaceall(tm, "$target", lua_name); Replaceall(tm, "$value", value); Replaceall(tm, "$nsname", nsname); - Printf(s_const_tab, " %s,\n", tm); + registerConstant(luaCurrentSymbolNSpace(), tm); } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { Replaceall(tm, "$source", value); - Replaceall(tm, "$target", name); + Replaceall(tm, "$target", lua_name); Replaceall(tm, "$value", value); Replaceall(tm, "$nsname", nsname); Printf(f_init, "%s\n", tm); } else { Delete(nsname); + nsname = 0; Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + Swig_restore(n); return SWIG_NOWRAP; } - if (cparse_cplusplus && getCurrentClass()) { - // Additionally add to class constants - Swig_require("luaclassobj_constantWrapper", n, "*sym:name", "luaclassobj:symname", NIL); - Setattr(n, "sym:name", Getattr(n, "luaclassobj:symname")); - String *cls_nsname = Getattr(n, "sym:name"); - if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { - Replaceall(tm, "$source", value); - Replaceall(tm, "$target", name); - Replaceall(tm, "$value", value); - Replaceall(tm, "$nsname", cls_nsname); - Printf(s_cls_const_tab, " %s,\n", tm); + + bool make_v2_compatible = v2_compatibility && getCurrentClass() != 0; + + if (make_v2_compatible) { + // Special handling for enums in C mode - they are not prefixed with structure name + if(!CPlusPlus && current[ENUM_CONST]) { + lua_name_v2 = lua_name; + DohIncref(lua_name_v2); + iname_v2 = iname; + DohIncref(iname_v2); + } else { + lua_name_v2 = Swig_name_member(0, proxy_class_name, lua_name); + iname_v2 = Swig_name_member(0, proxy_class_name, iname); } - Swig_restore(n); + n_v2 = Copy(n); + //Printf( stdout, "target name v2: %s, symname v2 %s\n", lua_name_v2.ptr(), iname_v2.ptr());// TODO:REMOVE + if (!luaAddSymbol(iname_v2, n, getNSpace())) { + Swig_restore(n); + return SWIG_ERROR; + } + + Setattr(n_v2, "sym:name", lua_name_v2); + tm_v2 = Swig_typemap_lookup("consttab", n_v2, name, 0); + if (tm_v2) { + //Printf(stdout, "tm v2: %s\n", tm_v2.ptr()); // TODO:REMOVE + Replaceall(tm_v2, "$source", value); + Replaceall(tm_v2, "$target", lua_name_v2); + Replaceall(tm_v2, "$value", value); + Replaceall(tm_v2, "$nsname", nsname); + registerConstant(getNSpace(), tm_v2); + } else { + tm_v2 = Swig_typemap_lookup("constcode", n_v2, name, 0); + if (!tm_v2) { + // This can't be. + assert(false); + Swig_restore(n); + return SWIG_ERROR; + } + Replaceall(tm_v2, "$source", value); + Replaceall(tm_v2, "$target", lua_name_v2); + Replaceall(tm_v2, "$value", value); + Replaceall(tm_v2, "$nsname", nsname); + Printf(f_init, "%s\n", tm_v2); + } + Delete(n_v2); } + + Swig_restore(n); Delete(nsname); return SWIG_OK; } @@ -971,10 +1175,12 @@ public: // REPORT("nativeWrapper", n); String *symname = Getattr(n, "sym:name"); String *wrapname = Getattr(n, "wrap:name"); - if (!addSymbol(wrapname, n)) + if (!luaAddSymbol(wrapname, n)) return SWIG_ERROR; - Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); + Hash *nspaceHash = getCArraysHash(getNSpace()); + String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); + Printv(s_ns_methods_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); // return Language::nativeWrapper(n); // this does nothing... return SWIG_OK; } @@ -984,7 +1190,12 @@ public: * ------------------------------------------------------------ */ virtual int enumDeclaration(Node *n) { - return Language::enumDeclaration(n); + current[STATIC_CONST] = true; + current[ENUM_CONST] = true; + int result = Language::enumDeclaration(n); + current[STATIC_CONST] = false; + current[ENUM_CONST] = false; + return result; } /* ------------------------------------------------------------ @@ -992,7 +1203,26 @@ public: * ------------------------------------------------------------ */ virtual int enumvalueDeclaration(Node *n) { - return Language::enumvalueDeclaration(n); + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + Setattr(n, "value", tmpValue); + + Setattr(n, "name", tmpValue); /* for wrapping of enums in a namespace when emit_action is used */ + int result = constantWrapper(n); + + Delete(tmpValue); + Swig_restore(n); + return result; } /* ------------------------------------------------------------ @@ -1003,28 +1233,68 @@ public: return Language::classDeclaration(n); } + + /* ------------------------------------------------------------ + * Helper function that adds record to appropriate + * C arrays + * ------------------------------------------------------------ */ + void registerClass(String *scope, String *wrap_class) { + assert(wrap_class); + Hash *nspaceHash = getCArraysHash(scope); + String *ns_classes = Getattr(nspaceHash, "classes"); + Printv(ns_classes, "&", wrap_class, ",\n", NIL); + if (elua_ltr || eluac_ltr) { + String *ns_methods = Getattr(nspaceHash, "methods"); + Hash *class_hash = getCArraysHash(class_static_nspace); + assert(class_hash); + String *cls_methods = Getattr(class_hash, "methods:name"); + assert(cls_methods); + Printv(ns_methods, tab4, "{LSTRKEY(\"", proxy_class_name, "\")", ", LROVAL(", cls_methods, ")", "},\n", NIL); + } + } /* ------------------------------------------------------------ * classHandler() * ------------------------------------------------------------ */ - virtual int classHandler(Node *n) { //REPORT("classHandler", n); - String *mangled_classname = 0; - String *real_classname = 0; + String *mangled_full_proxy_class_name = 0; + String *destructor_name = 0; + String *nspace = getNSpace(); constructor_name = 0; have_constructor = 0; have_destructor = 0; destructor_action = 0; + assert(class_static_nspace == 0); + assert(full_proxy_class_name == 0); + assert(proxy_class_name == 0); - class_name = Getattr(n, "sym:name"); - if (!addSymbol(class_name, n)) + current[NO_CPP] = false; + + proxy_class_name = Getattr(n, "sym:name"); + // We have to enforce nspace here, because technically we are already + // inside class parsing (getCurrentClass != 0), but we should register + // class in the it's parent namespace + if (!luaAddSymbol(proxy_class_name, n, nspace)) return SWIG_ERROR; - real_classname = Getattr(n, "name"); - mangled_classname = Swig_name_mangle(real_classname); + if (nspace == 0) + full_proxy_class_name = NewStringf("%s", proxy_class_name); + else + full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); + + assert(full_proxy_class_name); + mangled_full_proxy_class_name = Swig_name_mangle(full_proxy_class_name); + SwigType *t = Copy(Getattr(n, "name")); + SwigType *fr_t = SwigType_typedef_resolve_all(t); /* Create fully resolved type */ + SwigType *t_tmp = 0; + t_tmp = SwigType_typedef_qualified(fr_t); // Temporal variable + Delete(fr_t); + fr_t = SwigType_strip_qualifiers(t_tmp); + String *mangled_fr_t = 0; + mangled_fr_t = SwigType_manglestr(fr_t); // not sure exactly how this works, // but tcl has a static hashtable of all classes emitted and then only emits code for them once. // this fixes issues in test suites: template_default2 & template_specialization @@ -1033,84 +1303,123 @@ public: // * consider effect on template_specialization_defarg static Hash *emitted = NewHash(); - if (Getattr(emitted, mangled_classname)) + if (Getattr(emitted, mangled_fr_t)) { + full_proxy_class_name = 0; + proxy_class_name = 0; return SWIG_NOWRAP; - Setattr(emitted, mangled_classname, "1"); - - s_attr_tab = NewString(""); - Printf(s_attr_tab, "static swig_lua_attribute swig_"); - Printv(s_attr_tab, mangled_classname, "_attributes[] = {\n", NIL); - - s_methods_tab = NewString(""); - Printf(s_methods_tab, "static swig_lua_method swig_"); - Printv(s_methods_tab, mangled_classname, "_methods[] = {\n", NIL); - - s_cls_methods_tab = NewString(""); - Printf(s_cls_methods_tab, "static swig_lua_method swig_"); - Printv(s_cls_methods_tab, mangled_classname, "_cls_methods[] = {\n", NIL); - - s_cls_attr_tab = NewString(""); - Printf(s_cls_attr_tab, "static swig_lua_attribute swig_"); - Printv(s_cls_attr_tab, mangled_classname, "_cls_attributes[] = {\n", NIL); - - s_cls_const_tab = NewString(""); - Printf(s_cls_const_tab, "static swig_lua_const_info swig_"); - Printv(s_cls_const_tab, mangled_classname, "_cls_constants[] = {\n", NIL); - - + } + Setattr(emitted, mangled_fr_t, "1"); + + // We treat class T as both 'class' and 'namespace'. All static members, attributes + // and constants are considered part of namespace T, all members - part of the 'class' + // Now, here is a trick. Static methods, attributes and non-static methods and attributes + // are described with same structures - swig_lua_attribute/swig_lua_method. Instead of calling + // getCArraysHash(class name) to initialize things for static methods/attributes and then + // manually doing same initialization for non-static methods, we call getCArraysHash 2 times: + // 1) With name "class name" + "." + "__Static" to initialize static things + // 2) With "class name" to initialize non-static things + // And we can guarantee that there will not be any name collision because names starting with 2 underscores + // and capital letter are forbiden to use in C++. So, under know circumstances could our class contain + // any member or subclass with name "__Static". Thus, never any name clash. + Hash *instance_cls = getCArraysHash(full_proxy_class_name, false); + assert(instance_cls); + String *s_attr_tab_name = Getattr(instance_cls, "attributes:name"); + String *s_methods_tab_name = Getattr(instance_cls, "methods:name"); + Setattr(instance_cls, "lua:no_namespaces", "1"); + Setattr(instance_cls, "lua:no_classes", "1"); + Setattr(instance_cls, "lua:class_instance", "1"); + + /* There is no use for "constants", "classes" and "namespaces" arrays. + * All constants are considered part of static part of class. + */ + + class_static_nspace = NewStringf("%s%s__Static", full_proxy_class_name, NSPACE_SEPARATOR); + Hash *static_cls = getCArraysHash(class_static_nspace, false); + assert(static_cls); + Setattr(static_cls, "lua:no_namespaces", "1"); + Setattr(static_cls, "lua:class_static", "1"); + + // Notifying instance_cls and static_cls hashes about each other + Setattr(instance_cls, "lua:class_instance:static_hash", static_cls); + Setattr(static_cls, "lua:class_static:instance_hash", instance_cls); + + /* There is no use for "classes" and "namespaces" arrays. Subclasses are not supported + * by SWIG and namespaces couldn't be nested inside classes (C++ Standard) + */ // Generate normal wrappers Language::classHandler(n); - SwigType *t = Copy(Getattr(n, "name")); SwigType_add_pointer(t); // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' - String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); + String *wrap_class_name = Swig_name_wrapper(NewStringf("class_%s", mangled_full_proxy_class_name)); + String *wrap_class = NewStringf("&%s", wrap_class_name); SwigType_remember_clientdata(t, wrap_class); String *rt = Copy(getClassType()); SwigType_add_pointer(rt); + // Adding class to apropriate namespace + registerClass(nspace, wrap_class_name); + Hash *nspaceHash = getCArraysHash(nspace); + // 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); - + // Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_full_proxy_class_name); + // 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); + destructor_name = NewStringf("swig_delete_%s", mangled_full_proxy_class_name); + Printv(f_wrappers, "static void ", destructor_name, "(void *obj) {\n", NIL); if (destructor_action) { - Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); - Printv(f_wrappers, destructor_action, "\n", NIL); + Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); + Printv(f_wrappers, destructor_action, "\n", NIL); } else { - if (CPlusPlus) { - Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); - } else { - Printv(f_wrappers, " free((char *) obj);\n", NIL); - } + if (CPlusPlus) { + Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); + } else { + Printv(f_wrappers, " free((char *) obj);\n", NIL); + } } Printf(f_wrappers, "}\n"); } + // Wrap constructor wrapper into one more proxy function. It will be used as class namespace __call method, thus + // allowing both + // Module.ClassName.StaticMethod to access static method/variable/constant + // Module.ClassName() to create new object + if (have_constructor) { + assert(constructor_name); + String *constructor_proxy_name = NewStringf("_proxy_%s", constructor_name); + Printv(f_wrappers, "static int ", constructor_proxy_name, "(lua_State *L) {\n", NIL); + Printv(f_wrappers, + tab4, "assert(lua_istable(L,1));\n", + tab4, "lua_pushcfunction(L,", constructor_name, ");\n", + tab4, "assert(!lua_isnil(L,-1));\n", + tab4, "lua_replace(L,1); /* replace our table with real constructor */\n", + tab4, "lua_call(L,lua_gettop(L)-1,1);\n", + tab4, "return 1;\n}\n", NIL); + Delete(constructor_name); + constructor_name = constructor_proxy_name; + if (elua_ltr) { + String *static_cls_metatable_tab = Getattr(static_cls, "metatable"); + assert(static_cls_metatable_tab); + Printf(static_cls_metatable_tab, " {LSTRKEY(\"__call\"), LFUNCVAL(%s)},\n", constructor_name); + } else if (eluac_ltr) { + String *ns_methods_tab = Getattr(nspaceHash, "methods"); + assert(ns_methods_tab); + Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "new_", proxy_class_name, "\")", ", LFUNCVAL(", constructor_name, ")", "},\n", NIL); + } + } + if (have_destructor) { + if (eluac_ltr) { + String *ns_methods_tab = Getattr(nspaceHash, "methods"); + assert(ns_methods_tab); + Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "free_", mangled_full_proxy_class_name, "\")", ", LFUNCVAL(", destructor_name, ")", "},\n", NIL); + } + } - Printf(s_methods_tab, " {0,0}\n};\n"); - Printv(f_wrappers, s_methods_tab, NIL); - - Printf(s_attr_tab, " {0,0,0}\n};\n"); - Printv(f_wrappers, s_attr_tab, NIL); - - Printf(s_cls_attr_tab, " {0,0,0}\n};\n"); - Printv(f_wrappers, s_cls_attr_tab, NIL); - - Printf(s_cls_methods_tab, " {0,0}\n};\n"); - Printv(f_wrappers, s_cls_methods_tab, NIL); - - Printf(s_cls_const_tab, " {0,0,0,0,0,0}\n};\n"); - Printv(f_wrappers, s_cls_const_tab, NIL); - + closeCArraysHash(full_proxy_class_name, f_wrappers); + closeCArraysHash(class_static_nspace, f_wrappers); - Delete(s_methods_tab); - Delete(s_attr_tab); - Delete(s_cls_methods_tab); - Delete(s_cls_attr_tab); - Delete(s_cls_const_tab); // Handle inheritance // note: with the idea of class hierarchies spread over multiple modules @@ -1130,44 +1439,39 @@ public: int index = 0; b = First(baselist); while (b.item) { - String *bname = Getattr(b.item, "name"); - if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { - b = Next(b); - continue; - } - // old code: (used the pointer to the base class) - //String *bmangle = Swig_name_mangle(bname); - //Printf(base_class, "&_wrap_class_%s", bmangle); - //Putc(',', base_class); - //Delete(bmangle); - // new code: stores a null pointer & the name - Printf(base_class, "0,"); - Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); - - b = Next(b); - index++; + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + // stores a null pointer & the name + Printf(base_class, "0,"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + + b = Next(b); + index++; } } - - Printv(f_wrappers, "static swig_lua_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); + // First, print class static part + printCArraysDefinition(class_static_nspace, proxy_class_name, f_wrappers); + + assert(mangled_full_proxy_class_name); + assert(base_class); + assert(base_class_names); + assert(proxy_class_name); + assert(full_proxy_class_name); + + // Then print class isntance part + Printv(f_wrappers, "static swig_lua_class *swig_", mangled_full_proxy_class_name, "_bases[] = {", base_class, "0};\n", NIL); Delete(base_class); - Printv(f_wrappers, "static const char *swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); + Printv(f_wrappers, "static const char *swig_", mangled_full_proxy_class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); Delete(base_class_names); - Printv(f_wrappers, "static swig_lua_class _wrap_class_", mangled_classname, " = { \"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + Printv(f_wrappers, "static swig_lua_class _wrap_class_", mangled_full_proxy_class_name, " = { \"", proxy_class_name, "\", \"", full_proxy_class_name, "\", &SWIGTYPE", + SwigType_manglestr(t), ",", NIL); if (have_constructor) { - if (elua_ltr) { - Printf(s_cmd_tab, " {LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", class_name, \ - Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name))); - Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name))); - } else if (eluac_ltr) { - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", "new_", class_name, "\")", ", LFUNCVAL(", \ - Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name)), ")", "},\n", NIL); - Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name))); - } else { - Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name))); - } + Printv(f_wrappers, constructor_name, NIL); Delete(constructor_name); constructor_name = 0; } else { @@ -1175,24 +1479,31 @@ public: } if (have_destructor) { - if (eluac_ltr) { - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", "free_", class_name, "\")", ", LFUNCVAL(", "swig_delete_", class_name, ")", "},\n", NIL); - Printv(f_wrappers, ", swig_delete_", class_name, NIL); - } else { - Printv(f_wrappers, ", swig_delete_", class_name, NIL); - } + Printv(f_wrappers, ", ", destructor_name, NIL); } else { Printf(f_wrappers, ",0"); } - Printf(f_wrappers, ", swig_%s_methods, swig_%s_attributes, { \"%s\", swig_%s_cls_methods, swig_%s_cls_attributes, swig_%s_cls_constants }, swig_%s_bases, swig_%s_base_names };\n\n", - mangled_classname, mangled_classname, - class_name, mangled_classname, mangled_classname, mangled_classname, - mangled_classname, mangled_classname); - - // Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases };\n\n", NIL); - // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, &_wrap_class_", mangled_classname, "},\n", NIL); - Delete(t); - Delete(mangled_classname); + Printf(f_wrappers, ", %s, %s, &%s", s_methods_tab_name, s_attr_tab_name, Getattr(static_cls, "cname")); + + if (!eluac_ltr) { + assert(Getattr(instance_cls, "metatable:name")); // TODO: REMOVE + Printf(f_wrappers, ", %s", Getattr(instance_cls,"metatable:name")); + } + else + Printf(f_wrappers, ", 0"); + + Printf(f_wrappers, ", swig_%s_bases, swig_%s_base_names };\n\n", mangled_full_proxy_class_name, mangled_full_proxy_class_name); + + current[NO_CPP] = true; + Delete(class_static_nspace); + class_static_nspace = 0; + Delete(mangled_full_proxy_class_name); + mangled_full_proxy_class_name = 0; + Delete(destructor_name); + destructor_name = 0; + Delete(full_proxy_class_name); + full_proxy_class_name = 0; + proxy_class_name = 0; return SWIG_OK; } @@ -1201,31 +1512,24 @@ public: * ------------------------------------------------------------ */ virtual int memberfunctionHandler(Node *n) { - String *name = Getattr(n, "name"); - String *iname = GetChar(n, "sym:name"); + String *symname = GetChar(n, "sym:name"); //Printf(stdout,"memberfunctionHandler %s %s\n",name,iname); // Special case unary minus: LUA passes two parameters for the // wrapper function while we want only one. Tell our // functionWrapper to ignore a parameter. - if (Cmp(Getattr(n, "sym:name"), "__unm") == 0) { + if (Cmp(symname, "__unm") == 0) { //Printf(stdout, "unary minus: ignore one argument\n"); SetInt(n, "lua:ignore_args", 1); } - String *realname, *rname; - - current = MEMBER_FUNC; + current[MEMBER_FUNC] = true; Language::memberfunctionHandler(n); - current = NO_CPP; - realname = iname ? iname : name; - rname = Swig_name_wrapper(Swig_name_member(NSPACE_TODO, class_name, realname)); - if (!Getattr(n, "sym:nextSibling")) { - Printv(s_methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); - } - Delete(rname); + //Printf( stdout, "add member function: %s to %s\n", symname, luaCurrentSymbolNSpace());// TODO: REMOVE + registerMethod(n); + current[MEMBER_FUNC] = false; return SWIG_OK; } @@ -1235,28 +1539,10 @@ public: virtual int membervariableHandler(Node *n) { // REPORT("membervariableHandler",n); - String *symname = Getattr(n, "sym:name"); - String *gname, *sname; - - current = MEMBER_VAR; + current[MEMBER_VAR] = true; Language::membervariableHandler(n); - current = NO_CPP; - gname = Swig_name_wrapper(Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname))); - if (!GetFlag(n, "feature:immutable")) { - sname = Swig_name_wrapper(Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname))); - } else { - //sname = NewString("0"); - sname = NewString("SWIG_Lua_set_immutable"); // error message - } - Printf(s_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,gname,sname); - if (eluac_ltr) { - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", class_name, "_", symname, "_get", "\")", \ - ", LFUNCVAL(", gname, ")", "},\n", NIL); - Printv(s_cmd_tab, tab4, "{LSTRKEY(\"", class_name, "_", symname, "_set", "\")", \ - ", LFUNCVAL(", sname, ")", "},\n", NIL); - } - Delete(gname); - Delete(sname); + registerVariable(n); + current[MEMBER_VAR] = false; return SWIG_OK; } @@ -1268,10 +1554,10 @@ public: virtual int constructorHandler(Node *n) { // REPORT("constructorHandler", n); - current = CONSTRUCTOR; + current[CONSTRUCTOR] = true; Language::constructorHandler(n); - current = NO_CPP; - constructor_name = NewString(Getattr(n, "sym:name")); + current[CONSTRUCTOR] = false; + //constructor_name = NewString(Getattr(n, "sym:name")); have_constructor = 1; return SWIG_OK; } @@ -1282,14 +1568,53 @@ public: virtual int destructorHandler(Node *n) { REPORT("destructorHandler", n); - current = DESTRUCTOR; + current[DESTRUCTOR] = true; Language::destructorHandler(n); - current = NO_CPP; + current[DESTRUCTOR] = false; have_destructor = 1; destructor_action = Getattr(n, "wrap:action"); return SWIG_OK; } + /* ---------------------------------------------------------------------- + * globalfunctionHandler() + * It can be called: + * 1. Usual C/C++ global function. + * 2. During class parsing for functions declared/defined as friend + * 3. During class parsing from staticmemberfunctionHandler + * ---------------------------------------------------------------------- */ + virtual int globalfunctionHandler(Node *n) { + bool oldVal = current[NO_CPP]; + if (!current[STATIC_FUNC]) // If static funct, don't switch to NO_CPP + current[NO_CPP] = true; + const int result = Language::globalfunctionHandler(n); + + if (!current[STATIC_FUNC]) // Register only if not called from static funct handler + registerMethod(n); + current[NO_CPP] = oldVal; + return result; + } + + /* ---------------------------------------------------------------------- + * globalvariableHandler() + * globalfunctionHandler() + * Sets "current" array correctly and calls + * Language::globalvariableHandler() + * ---------------------------------------------------------------------- */ + virtual int globalvariableHandler(Node *n) { + bool oldVal = current[NO_CPP]; + current[GLOBAL_VAR] = true; + current[NO_CPP] = true; + + const int result = Language::globalvariableHandler(n); + registerVariable(n); + + current[GLOBAL_VAR] = false; + current[NO_CPP] = oldVal; + return result; + } + + /* ----------------------------------------------------------------------- * staticmemberfunctionHandler() * @@ -1298,29 +1623,26 @@ public: virtual int staticmemberfunctionHandler(Node *n) { REPORT("staticmemberfunctionHandler", n); - current = STATIC_FUNC; - String *symname = Getattr(n, "sym:name"); - int result = Language::staticmemberfunctionHandler(n); - - if (cparse_cplusplus && getCurrentClass()) { + current[STATIC_FUNC] = true; + + const int result = Language::staticmemberfunctionHandler(n); + registerMethod(n); + + if (v2_compatibility && result == SWIG_OK) { + Swig_require("lua_staticmemberfunctionHandler", n, "*lua:name", NIL); + String *lua_name = Getattr(n, "lua:name"); + // Although this function uses Swig_name_member, it actually generateds Lua name, + // not C++ name. It is because previous version used such scheme for static func + // name generation and we have to maintain backward compatibility + String *compat_name = Swig_name_member(0, proxy_class_name, lua_name); + Setattr(n, "lua:name", compat_name); + registerMethod(n, true, getNSpace()); + Delete(compat_name); Swig_restore(n); } - current = NO_CPP; - if (result != SWIG_OK) - return result; - - if (Getattr(n, "sym:nextSibling")) - return SWIG_OK; - Swig_require("luaclassobj_staticmemberfunctionHandler", n, "luaclassobj:wrap:name", NIL); - String *name = Getattr(n, "name"); - String *rname, *realname; - realname = symname ? symname : name; - rname = Getattr(n, "luaclassobj:wrap:name"); - Printv(s_cls_methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); - Swig_restore(n); - - return SWIG_OK; + current[STATIC_FUNC] = false;; + return result; } /* ------------------------------------------------------------ @@ -1330,15 +1652,8 @@ public: * ------------------------------------------------------------ */ virtual int memberconstantHandler(Node *n) { - REPORT("memberconstantHandler",n); - String *symname = Getattr(n, "sym:name"); - if (cparse_cplusplus && getCurrentClass()) { - Swig_save("luaclassobj_memberconstantHandler", n, "luaclassobj:symname", NIL); - Setattr(n, "luaclassobj:symname", symname); - } + REPORT("memberconstantHandler", n); int result = Language::memberconstantHandler(n); - if (cparse_cplusplus && getCurrentClass()) - Swig_restore(n); return result; } @@ -1348,24 +1663,42 @@ public: * --------------------------------------------------------------------- */ virtual int staticmembervariableHandler(Node *n) { - REPORT("staticmembervariableHandler",n); - current = STATIC_VAR; - String *symname = Getattr(n, "sym:name"); + REPORT("staticmembervariableHandler", n); + current[STATIC_VAR] = true; + //String *symname = Getattr(n, "sym:name"); int result = Language::staticmembervariableHandler(n); + if (!GetFlag(n, "wrappedasconstant")) { + registerVariable(n); + } - if (result != SWIG_OK) - return result; - - - if (Getattr(n, "wrappedasconstant")) - return SWIG_OK; + if (result == SWIG_OK) { + // This will add static member variable to the class namespace with name ClassName_VarName + if (v2_compatibility) { + Swig_save("lua_staticmembervariableHandler", n, "lua:name", NIL); + String *lua_name = Getattr(n, "lua:name"); + // Although this function uses Swig_name_member, it actually generateds Lua name, + // not C++ name. It is because previous version used such scheme for static vars + // name generation and we have to maintain backward compatibility + String *v2_name = Swig_name_member(NIL, proxy_class_name, lua_name); + //Printf( stdout, "Name %s, class %s, compt. name %s\n", lua_name, proxy_class_name, v2_name ); // TODO: REMOVE + if (!GetFlag(n, "wrappedasconstant")) { + Setattr(n, "lua:name", v2_name); + // Registering static var in the class parent nspace + registerVariable(n, true, getNSpace()); + } + // If static member variable was wrapped as constant, then + // constant wrapper has already performed all actions + // necessary for v2_compatibility + Delete(v2_name); + Swig_restore(n); + } + } + current[STATIC_VAR] = false; - Swig_require("luaclassobj_staticmembervariableHandler", n, "luaclassobj:wrap:get", "luaclassobj:wrap:set", NIL); - Printf(s_cls_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,Getattr(n,"luaclassobj:wrap:get"), Getattr(n,"luaclassobj:wrap:set")); - Swig_restore(n); - return SWIG_OK; + return result; } + /* --------------------------------------------------------------------- * external runtime generation * --------------------------------------------------------------------- */ @@ -1379,18 +1712,18 @@ public: */ String *runtimeCode() { String *s = NewString(""); - const char *filenames[] = { "luarun.swg", 0 } ; // must be 0 terminated + const char *filenames[] = { "luarun.swg", 0 }; // must be 0 terminated emitLuaFlavor(s); - String *sfile; + String *sfile = 0; for (int i = 0; filenames[i] != 0; i++) { sfile = Swig_include_sys(filenames[i]); if (!sfile) { - Printf(stderr, "*** Unable to open '%s'\n", filenames[i]); + Printf(stderr, "*** Unable to open '%s'\n", filenames[i]); } else { - Append(s, sfile); - Delete(sfile); + Append(s, sfile); + Delete(sfile); } } @@ -1400,34 +1733,483 @@ public: String *defaultExternalRuntimeFilename() { return NewString("swigluarun.h"); } - + /* --------------------------------------------------------------------- * helpers * --------------------------------------------------------------------- */ void emitLuaFlavor(String *s) { - if (elua_ltr) + if (elua_emulate) { + Printf(s, "/*This is only emulation!*/\n"); + Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); + Printf(s, "#define SWIG_LUA_ELUA_EMULATE\n"); + } else if (elua_ltr) Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); else if (eluac_ltr) Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUAC\n"); else Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_LUA\n"); } - - /* This is to convert the string of Lua code into a proper string, which can then be - emitted into the C/C++ code. - Basically is is a lot of search & replacing of odd sequences - */ - void EscapeCode(String* str) - { + + /* ----------------------------------------------------------------------------- + * EscapeCode() + * This is to convert the string of Lua code into a proper string, which can then be + * emitted into the C/C++ code. + * Basically is is a lot of search & replacing of odd sequences + * ---------------------------------------------------------------------------- */ + void EscapeCode(String *str) { //Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str); - Chop(str); // trim - Replace(str,"\\","\\\\",DOH_REPLACE_ANY); // \ to \\ (this must be done first) - Replace(str,"\"","\\\"",DOH_REPLACE_ANY); // " to \" - Replace(str,"\n","\\n\"\n \"",DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line) + Chop(str); // trim + Replace(str, "\\", "\\\\", DOH_REPLACE_ANY); // \ to \\ (this must be done first) + Replace(str, "\"", "\\\"", DOH_REPLACE_ANY); // " to \" + Replace(str, "\n", "\\n\"\n \"", DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line) //Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str); - } + } + + /* ----------------------------------------------------------------------------- + * rawGetCArraysHash(String *name) + * + * A small helper to hide impelementation of how CArrays hashes are stored + * ---------------------------------------------------------------------------- */ + Hash *rawGetCArraysHash(const_String_or_char_ptr name) { + Hash *scope = symbolScopeLookup( name ? name : "" ); + if(!scope) + return 0; + + Hash *carrays_hash = Getattr(scope, "lua:cdata"); + return carrays_hash; + } + + /* ----------------------------------------------------------------------------- + * getCArraysHash() + * Each namespace can be described with hash that stores C arrays + * where members of the namespace should be added. All these hashes are stored + * inside symbols table, in pseudo-symbol for every namespace. + * nspace could be NULL (NSPACE_TODO), that means functions and variables and classes + * that are not in any namespace (this is default for SWIG unless %nspace feature is used) + * You can later set some attributes that will affect behaviour of functions that use this hash: + * "lua:no_namespaces" will disable "namespaces" array. + * "lua:no_classes" will disable "classes" array. + * For every component ("attributes", "methods", etc) there are subcomponents: + * XXX:name - name of the C array that stores data for component + * XXX:decl - statement with forward declaration of this array; + * Namespace could be automatically registered to it's parent if 'reg' == true. It can be done + * only at first call (a.k.a when nspace is created). + * ---------------------------------------------------------------------------- */ + Hash *getCArraysHash(String *nspace, bool reg = true) { + Hash *scope = symbolScopeLookup(nspace ? nspace : ""); + if(!scope) { + symbolAddScope( nspace ? nspace : "" ); + scope = symbolScopeLookup(nspace ? nspace : ""); + assert(scope); + } + Hash *carrays_hash = Getattr(scope, "lua:cdata"); + if (carrays_hash != 0) + return carrays_hash; + carrays_hash = NewHash(); + String *mangled_name = 0; + if (nspace == 0 || Len(nspace) == 0) + mangled_name = NewString("__Module"); // C++ names can't start with "__ + capital letter" + else + mangled_name = Swig_name_mangle(nspace); + String *cname = NewStringf("swig_%s", mangled_name); + + Setattr(carrays_hash, "cname", cname); + + String *attr_tab = NewString(""); + String *attr_tab_name = NewStringf("swig_%s_attributes", mangled_name); + String *attr_tab_decl = NewString(""); + Printv(attr_tab, "static swig_lua_attribute ", NIL); + Printv(attr_tab, attr_tab_name, "[]", NIL); + Printv(attr_tab_decl, attr_tab, ";\n", NIL); + Printv(attr_tab, " = {\n", NIL); + Setattr(carrays_hash, "attributes", attr_tab); + Setattr(carrays_hash, "attributes:name", attr_tab_name); + Setattr(carrays_hash, "attributes:decl", attr_tab_decl); + + String *methods_tab = NewString(""); + String *methods_tab_name = NewStringf("swig_%s_methods", mangled_name); + String *methods_tab_decl = NewString(""); + if (elua_ltr || eluac_ltr) // In this case methods array also acts as namespace rotable + Printf(methods_tab, "const LUA_REG_TYPE "); + else + Printf(methods_tab, "static swig_lua_method "); + Printv(methods_tab, methods_tab_name, "[]", NIL); + Printv(methods_tab_decl, methods_tab, ";\n", NIL); + Printv(methods_tab, "= {\n", NIL); + Setattr(carrays_hash, "methods", methods_tab); + Setattr(carrays_hash, "methods:name", methods_tab_name); + Setattr(carrays_hash, "methods:decl", methods_tab_decl); + + String *const_tab = NewString(""); + String *const_tab_name = NewStringf("swig_%s_constants", mangled_name); + String *const_tab_decl = NewString(""); + if (elua_ltr || eluac_ltr) // In this case const array holds rotable with namespace constants + Printf(const_tab, "const LUA_REG_TYPE "); + else + Printf(const_tab, "static swig_lua_const_info "); + Printv(const_tab, const_tab_name, "[]", NIL); + Printv(const_tab_decl, const_tab, ";", NIL); + Printv(const_tab, "= {\n", NIL); + Setattr(carrays_hash, "constants", const_tab); + Setattr(carrays_hash, "constants:name", const_tab_name); + Setattr(carrays_hash, "constants:decl", const_tab_decl); + + String *classes_tab = NewString(""); + String *classes_tab_name = NewStringf("swig_%s_classes", mangled_name); + String *classes_tab_decl = NewString(""); + Printf(classes_tab, "static swig_lua_class* "); + Printv(classes_tab, classes_tab_name, "[]", NIL); + Printv(classes_tab_decl, classes_tab, ";", NIL); + Printv(classes_tab, "= {\n", NIL); + Setattr(carrays_hash, "classes", classes_tab); + Setattr(carrays_hash, "classes:name", classes_tab_name); + Setattr(carrays_hash, "classes:decl", classes_tab_decl); + + String *namespaces_tab = NewString(""); + String *namespaces_tab_name = NewStringf("swig_%s_namespaces", mangled_name); + String *namespaces_tab_decl = NewString(""); + Printf(namespaces_tab, "static swig_lua_namespace* "); + Printv(namespaces_tab, namespaces_tab_name, "[]", NIL); + Printv(namespaces_tab_decl, namespaces_tab, ";", NIL); + Printv(namespaces_tab, " = {\n", NIL); + Setattr(carrays_hash, "namespaces", namespaces_tab); + Setattr(carrays_hash, "namespaces:name", namespaces_tab_name); + Setattr(carrays_hash, "namespaces:decl", namespaces_tab_decl); + + if (elua_ltr) { + String *get_tab = NewString(""); + String *get_tab_name = NewStringf("swig_%s_get", mangled_name); + String *get_tab_decl = NewString(""); + Printv(get_tab, "const LUA_REG_TYPE ", get_tab_name, "[]", NIL); + Printv(get_tab_decl, get_tab, ";", NIL); + Printv(get_tab, " = {\n", NIL); + Setattr(carrays_hash, "get", get_tab); + Setattr(carrays_hash, "get:name", get_tab_name); + Setattr(carrays_hash, "get:decl", get_tab_decl); + + String *set_tab = NewString(""); + String *set_tab_name = NewStringf("swig_%s_set", mangled_name); + String *set_tab_decl = NewString(""); + Printv(set_tab, "const LUA_REG_TYPE ", set_tab_name, "[]", NIL); + Printv(set_tab_decl, set_tab, ";", NIL); + Printv(set_tab, " = {\n", NIL); + Setattr(carrays_hash, "set", set_tab); + Setattr(carrays_hash, "set:name", set_tab_name); + Setattr(carrays_hash, "set:decl", set_tab_decl); + + } + if (!eluac_ltr) { + String *metatable_tab = NewString(""); + String *metatable_tab_name = NewStringf("swig_%s_meta", mangled_name); + String *metatable_tab_decl = NewString(""); + if (elua_ltr) // In this case const array holds rotable with namespace constants + Printf(metatable_tab, "const LUA_REG_TYPE "); + else + Printf(metatable_tab, "static swig_lua_method "); + assert(metatable_tab); // TODO: REMOVE + assert(metatable_tab_name); // TODO: REMOVE + Printv(metatable_tab, metatable_tab_name, "[]", NIL); + Printv(metatable_tab_decl, metatable_tab, ";", NIL); + Printv(metatable_tab, " = {\n", NIL); + Setattr(carrays_hash, "metatable", metatable_tab); + Setattr(carrays_hash, "metatable:name", metatable_tab_name); + Setattr(carrays_hash, "metatable:decl", metatable_tab_decl); + } + + Setattr(scope, "lua:cdata", carrays_hash); + assert(rawGetCArraysHash(nspace)); + + if (reg && nspace != 0 && Len(nspace) != 0 && Getattr(carrays_hash, "lua:no_reg") == 0) { + // Split names into components + List *components = Split(nspace, '.', -1); + String *parent_path = NewString(""); + int len = Len(components); + String *name = Copy(Getitem(components, len - 1)); + for (int i = 0; i < len - 1; i++) { + if (i > 0) + Printv(parent_path, NSPACE_SEPARATOR, NIL); + String *item = Getitem(components, i); + Printv(parent_path, item, NIL); + } + //Printf(stdout, "Registering %s. User name %s. C-name %s, Parent is %s\n", mangled_name, name, cname, parent_path); // TODO: REMOVE + Hash *parent = getCArraysHash(parent_path, true); + String *namespaces_tab = Getattr(parent, "namespaces"); + Printv(namespaces_tab, "&", cname, ",\n", NIL); + if (elua_ltr || eluac_ltr) { + String *methods_tab = Getattr(parent, "methods"); + Printv(methods_tab, tab4, "{LSTRKEY(\"", name, "\")", ", LROVAL(", methods_tab_name, ")", "},\n", NIL); + } + Setattr(carrays_hash, "name", name); + + Delete(components); + Delete(parent_path); + } else if (!reg) // This namespace shouldn't be registered. Lets remember it + Setattr(carrays_hash, "lua:no_reg", "1"); + + + Delete(mangled_name); + mangled_name = 0; + return carrays_hash; + } + + /* ----------------------------------------------------------------------------- + * closeCArraysHash() + * Functions add end markers {0,0,...,0} to all arrays, prints them to + * output and marks hash as closed (lua:closed). Consequent attempts to + * close same hash will result in error + * closeCArraysHash DOES NOT print structure that describes namespace, it only + * prints array. You can use printCArraysDefinition to print structure. + * if "lua:no_namespaces" is set, then array for "namespaces" won't be printed + * if "lua:no_classes" is set, then array for "classes" won't be printed + * ----------------------------------------------------------------------------- */ + void closeCArraysHash(String *nspace, File *output) { + Hash *carrays_hash = rawGetCArraysHash(nspace); + assert(carrays_hash); + assert(Getattr(carrays_hash, "lua:closed") == 0); + + Setattr(carrays_hash, "lua:closed", "1"); + + String *attr_tab = Getattr(carrays_hash, "attributes"); + Printf(attr_tab, " {0,0,0}\n};\n"); + Printv(output, attr_tab, NIL); + + String *const_tab = Getattr(carrays_hash, "constants"); + String *const_tab_name = Getattr(carrays_hash, "constants:name"); + if (elua_ltr || eluac_ltr) + Printv(const_tab, tab4, "{LNILKEY, LNILVAL}\n", "};\n", NIL); + else + Printf(const_tab, " {0,0,0,0,0,0}\n};\n"); + Printv(output, const_tab, NIL); + + if (elua_ltr) { + // Put forward declaration of metatable array + Printv(output, "extern ", Getattr(carrays_hash, "metatable:decl"), "\n", NIL); + } + String *methods_tab = Getattr(carrays_hash, "methods"); + String *metatable_tab_name = Getattr(carrays_hash, "metatable:name"); + assert(methods_tab); // TODO: REMOVE + if (elua_ltr || eluac_ltr) { + if (v2_compatibility) + Printv(methods_tab, tab4, "{LSTRKEY(\"const\"), LROVAL(", const_tab_name, ")},\n", NIL); + if (elua_ltr) { + assert(metatable_tab_name); // TODO: REMOVE + Printv(methods_tab, tab4, "{LSTRKEY(\"__metatable\"), LROVAL(", metatable_tab_name, ")},\n", NIL); + } + + Printv(methods_tab, tab4, "{LSTRKEY(\"__disown\"), LFUNCVAL(SWIG_Lua_class_disown)},\n", NIL); + Printv(methods_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + } else + Printf(methods_tab, " {0,0}\n};\n"); + Printv(output, methods_tab, NIL); + + if (!Getattr(carrays_hash, "lua:no_classes")) { + String *classes_tab = Getattr(carrays_hash, "classes"); + Printf(classes_tab, " 0\n};\n"); + Printv(output, classes_tab, NIL); + } + + if (!Getattr(carrays_hash, "lua:no_namespaces")) { + String *namespaces_tab = Getattr(carrays_hash, "namespaces"); + Printf(namespaces_tab, " 0\n};\n"); + Printv(output, namespaces_tab, NIL); + } + if (elua_ltr) { + String *get_tab = Getattr(carrays_hash, "get"); + String *set_tab = Getattr(carrays_hash, "set"); + Printv(get_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + Printv(set_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + Printv(output, get_tab, NIL); + Printv(output, set_tab, NIL); + } + + if (!eluac_ltr) { + String *metatable_tab = Getattr(carrays_hash, "metatable"); + assert(metatable_tab); + if (elua_ltr) { + String *get_tab_name = Getattr(carrays_hash, "get:name"); + String *set_tab_name = Getattr(carrays_hash, "set:name"); + + if (Getattr(carrays_hash, "lua:class_instance")) { + Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_class_get)},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_class_set)},\n", NIL); + } else { + Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_namespace_get)},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_namespace_set)},\n", NIL); + } + + Printv(metatable_tab, tab4, "{LSTRKEY(\"__gc\"), LFUNCVAL(SWIG_Lua_class_destruct)},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\".get\"), LROVAL(", get_tab_name, ")},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\".set\"), LROVAL(", set_tab_name, ")},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\".fn\"), LROVAL(", Getattr(carrays_hash, "methods:name"), ")},\n", NIL); + + if (Getattr(carrays_hash, "lua:class_instance")) { + String *static_cls = Getattr(carrays_hash, "lua:class_instance:static_hash"); + assert(static_cls); + // static_cls is swig_lua_namespace. This structure can't be use with eLua(LTR) + // Instead structure describing its methods isused + String *static_cls_cname = Getattr(static_cls, "methods:name"); + assert(static_cls_cname); + Printv(metatable_tab, tab4, "{LSTRKEY(\".static\"), LROVAL(", static_cls_cname, ")},\n", NIL); + // Put forward declaration of this array + Printv(output, "extern ", Getattr(static_cls, "methods:decl"), "\n", NIL); + } else if (Getattr(carrays_hash, "lua:class_static")) { + Hash *instance_cls = Getattr(carrays_hash, "lua:class_static:instance_hash"); + assert(instance_cls); + String *instance_cls_metatable_name = Getattr(instance_cls, "metatable:name"); + assert(instance_cls_metatable_name); + Printv(metatable_tab, tab4, "{LSTRKEY(\".instance\"), LROVAL(", instance_cls_metatable_name, ")},\n", NIL); + } + + Printv(metatable_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + } else { + Printf(metatable_tab, " {0,0}\n};\n"); + } + + Printv(output, metatable_tab, NIL); + } + + Printv(output, "\n", NIL); + } + + static int compareByLen(const DOH *f, const DOH *s) { + return Len(s) - Len(f); + } + + /* ----------------------------------------------------------------------------- + * closeCArraysHash() + * Recursively close all non-closed namespaces. Prints data to dataOutput. + * ----------------------------------------------------------------------------- */ + void closeNamespaces(File *dataOutput) { + // Special handling for empty module. + if (symbolScopeLookup("") == 0 || rawGetCArraysHash("") == 0) { + // Module is empty. Create hash for global scope in order to have swig__Module + // variable in resulting file + getCArraysHash(0); + } + // Because we cant access directly 'symtabs', instead we access + // top-level scope and look on all scope pseudo-symbols in it. + Hash *top_scope = symbolScopeLookup(""); + assert(top_scope); + Iterator ki = First(top_scope); + List *to_close = NewList(); + while (ki.key) { + assert(ki.item); + if (Getattr(ki.item, "sym:is_scope")) { + // We have a pseudo symbol. Lets get actuall scope for this + // pseudo symbol + Hash *carrays_hash = rawGetCArraysHash(ki.key); + assert(carrays_hash); + if (Getattr(carrays_hash, "lua:closed") == 0) + Append(to_close, ki.key); + } + ki = Next(ki); + } + SortList(to_close, &compareByLen); + int len = Len(to_close); + for (int i = 0; i < len; i++) { + String *key = Getitem(to_close, i); + closeCArraysHash(key, dataOutput); + Hash *carrays_hash = rawGetCArraysHash(key); + String *name = 0; // name - name of the namespace as it should be visible in Lua + if (DohLen(key) == 0) // This is global module + name = module; + else + name = Getattr(carrays_hash, "name"); + assert(name); + printCArraysDefinition(key, name, dataOutput); + } + Delete(to_close); + } + + /* ----------------------------------------------------------------------------- + * printCArraysDefinition() + * This function prints to output a definition of namespace in + * form + * swig_lua_namespace $cname = { attr_array, methods_array, ... , namespaces_array }; + * You can call this function as many times as necessary. + * 'name' is a user-visible name that this namespace will have in Lua. It shouldn't + * be fully qualified name, just it's own name. + * ----------------------------------------------------------------------------- */ + void printCArraysDefinition(String *nspace, String *name, File *output) { + Hash *carrays_hash = getCArraysHash(nspace, false); + + String *cname = Getattr(carrays_hash, "cname"); // cname - name of the C structure that describes namespace + assert(cname); + Printv(output, "static swig_lua_namespace ", cname, " = ", NIL); + + String *null_string = NewString("0"); + String *attr_tab_name = Getattr(carrays_hash, "attributes:name"); + String *methods_tab_name = Getattr(carrays_hash, "methods:name"); + String *const_tab_name = Getattr(carrays_hash, "constants:name"); + String *classes_tab_name = Getattr(carrays_hash, "classes:name"); + String *namespaces_tab_name = Getattr(carrays_hash, "namespaces:name"); + bool has_classes = Getattr(carrays_hash, "lua:no_classes") == 0; + bool has_namespaces = Getattr(carrays_hash, "lua:no_namespaces") == 0; + + Printv(output, "{\n", + tab4, "\"", name, "\",\n", + tab4, methods_tab_name, ",\n", + tab4, attr_tab_name, ",\n", + tab4, const_tab_name, ",\n", + tab4, (has_classes) ? classes_tab_name : null_string, ",\n", + tab4, (has_namespaces) ? namespaces_tab_name : null_string, "\n};\n", NIL); + Delete(null_string); + } + + /* ----------------------------------------------------------------------------- + * luaCurrentSymbolNSpace() + * This function determines actual namespace/scope where any symbol at the + * current moment should be placed. It looks at the 'current' array + * and depending on where are we - static class member/function, + * instance class member/function or just global functions decides + * where symbol should be put. + * The namespace/scope doesn't depend from symbol, only from 'current' + * ----------------------------------------------------------------------------- */ + String *luaCurrentSymbolNSpace() { + String *scope = 0; + // If ouside class, than NSpace is used. + // If inside class, but current[NO_CPP], then this is friend function. It belongs to NSpace + if (!getCurrentClass() || current[NO_CPP]) { + scope = getNSpace(); + } else { + // If inside class, then either class static namespace or class fully qualified name is used + assert(!current[NO_CPP]); + if (current[STATIC_FUNC] || current[STATIC_VAR] || current[STATIC_CONST]) { + scope = class_static_nspace; + } else if (current[MEMBER_VAR] || current[CONSTRUCTOR] || current[DESTRUCTOR] + || current[MEMBER_FUNC]) { + scope = full_proxy_class_name; + } else { // Friend functions are handled this way + scope = class_static_nspace; + } + assert(scope); + } + return scope; + } + + /* ----------------------------------------------------------------------------- + * luaAddSymbol() + * Our implementation of addSymbol. Determines scope correctly, then + * forwards to Language::addSymbol + * ----------------------------------------------------------------------------- */ + int luaAddSymbol(const String *s, const Node *n) { + String *scope = luaCurrentSymbolNSpace(); + return luaAddSymbol(s, n, scope); + } + + /* ----------------------------------------------------------------------------- + * luaAddSymbol() + * Overload. Enforces given scope. Actually, it simply forwards call to Language::addSymbol + * ----------------------------------------------------------------------------- */ + int luaAddSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { + int result = Language::addSymbol(s, n, scope); + if (!result) + Printf(stderr, "addSymbol(%s to scope %s) failed\n", s, scope); + return result; + } + }; /* NEW LANGUAGE NOTE:*********************************************** diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h index 2929993b3..afffebef9 100644 --- a/Source/Modules/swigmod.h +++ b/Source/Modules/swigmod.h @@ -215,7 +215,10 @@ public: virtual int validIdentifier(String *s); /* valid identifier? */ virtual int addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope = ""); /* Add symbol */ virtual void dumpSymbols(); - virtual Node *symbolLookup(String *s, const_String_or_char_ptr scope = ""); /* Symbol lookup */ + virtual Node *symbolLookup(String *s, const_String_or_char_ptr scope = ""); /* Symbol lookup */ + virtual Hash* symbolAddScope(const_String_or_char_ptr scope); + virtual Hash* symbolScopeLookup( const_String_or_char_ptr scope ); + virtual Hash* symbolScopePseudoSymbolLookup( const_String_or_char_ptr scope ); virtual Node *classLookup(const SwigType *s) const; /* Class lookup */ virtual Node *enumLookup(SwigType *s); /* Enum lookup */ virtual int abstractClassTest(Node *n); /* Is class really abstract? */ |