diff options
author | David Nadlinger <code@klickverbot.at> | 2011-03-13 00:32:26 +0000 |
---|---|---|
committer | David Nadlinger <code@klickverbot.at> | 2011-03-13 00:32:26 +0000 |
commit | ce6516fb4ca0b749b6614dce67302d0cdf1e746e (patch) | |
tree | 14a27a24574ccaa1c5607ffbf4c7ca1ef1d58da7 | |
parent | a63cde3827e6c86ca4de28b25a7d3a29cbebc1ca (diff) | |
download | swig-ce6516fb4ca0b749b6614dce67302d0cdf1e746e.tar.gz |
[D] nspace support.
As for C# and Java, this doesn't work for free functions/variables yet.
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12534 626c5289-ae23-0410-ae9c-e8d60b6d4f22
-rw-r--r-- | Doc/Manual/D.html | 22 | ||||
-rw-r--r-- | Examples/test-suite/csharp/nspace_runme.cs | 4 | ||||
-rw-r--r-- | Examples/test-suite/d/Makefile.in | 4 | ||||
-rw-r--r-- | Examples/test-suite/d/nspace_extend_runme.1.d | 32 | ||||
-rw-r--r-- | Examples/test-suite/d/nspace_extend_runme.2.d | 32 | ||||
-rw-r--r-- | Examples/test-suite/d/nspace_runme.1.d | 87 | ||||
-rw-r--r-- | Examples/test-suite/d/nspace_runme.2.d | 77 | ||||
-rw-r--r-- | Examples/test-suite/java/nspace_runme.java | 2 | ||||
-rw-r--r-- | Examples/test-suite/nspace.i | 18 | ||||
-rw-r--r-- | Examples/test-suite/nspace_extend.i | 10 | ||||
-rw-r--r-- | Lib/d/boost_shared_ptr.i | 2 | ||||
-rw-r--r-- | Lib/d/dclassgen.swg | 2 | ||||
-rw-r--r-- | Source/Modules/d.cxx | 629 |
13 files changed, 757 insertions, 164 deletions
diff --git a/Doc/Manual/D.html b/Doc/Manual/D.html index 6f65db1e4..3e4ad9bc5 100644 --- a/Doc/Manual/D.html +++ b/Doc/Manual/D.html @@ -28,6 +28,7 @@ <li><a href="#D_directors">D Directors</a> <li><a href="#D_other_features">Other features</a> <ul> +<li><a href="#D_nspace">Extended namespace support (<tt>nspace</tt>)</a></li> <li><a href="#D_native_pointer_support">Native pointer support</a> <li><a href="#D_operator_overloading">Operator overloading</a> <li><a href="#D_test_suite">Running the test-suite</a> @@ -187,6 +188,12 @@ <p>There are two other variants available, <tt>$&dclassname</tt> and <tt>$*dclassname</tt>. The former adds a level of indirection, while the latter removes one. For instance, when wrapping <tt>Foo **</tt>, <tt>$*dclassname</tt> would be replaced by the proxy class name corresponding to <tt>Foo *</tt>.</p> </dd> + <dt><tt>$dclazzname</tt> (C#: <tt>$csclazzname</tt>)</dt> + <dd> + <p>This special variable expands the fully qualified C++ class into the package name, if used by the <a href="SWIGPlus.html#SWIGPlus_nspace"><tt>nspace</tt> feature</a>, and the proxy class name, mangled for use as a function name. For example, <tt>Namespace1::Namespace2::Klass</tt> is expanded into <tt>Namespace1_Namespace2_Klass_</tt>.</p> + <p>This special variable might be useful for calling certain functions in the wrapper layer (e.g. upcast wrappers) which are mangled like this.</p> + </dd> + <dt><tt>$null</tt></dt> <dd><p>In code inserted into the generated C/C++ wrapper functions, this variable is replaced by either <tt>0</tt> or nothing at all, depending on whether the function has a return value or not. It can be used to bail out early e.g. in case of errors (<tt>return $null;</tt>).</p></dd> @@ -249,7 +256,7 @@ SomeClass bar() { <p>This macro is only valid inside the <tt><a href="D.html#D_class_code_typemaps">dconstructor</a></tt> typemap and contains the value of the <tt>dconstructor</tt> typemap attribute if the currently wrapped class has directors enabled.</p> <p>This is how the default <tt>dconstructor</tt> typemap looks like (you usually do not want to specify a custom one):</p> <div class="code"><pre> -%typemap(dconstructor, excode=SWIGEXCODE, +%typemap(dconstructor, excode=SWIGEXCODE, directorconnect="\n swigDirectorConnect();") SWIGTYPE { this($imcall, true);$excode$directorconnect } @@ -331,7 +338,7 @@ struct A { <dd><p>Additional code to be emitted to the imports section of the intermediary D module (the <a href="D.html#D_importtype">$importtype</a> macro can be used here). You probably want to use this in conjunction with the <tt>imdmodulecode</tt> pragma.</p></dd> <dt><tt>%pragma(d) proxydmodulecode</tt></dt> - <dd><p>Just like <tt>proxydmodulecode</tt>, the argument is copied to the proxy D module (if SWIG is in <a href="D.html#D_splitproxy">split proxy mode</a>, it is emitted to the main proxy D module only).</p></dd> + <dd><p>Just like <tt>proxydmodulecode</tt>, the argument is copied to the proxy D module (if SWIG is in <a href="D.html#D_splitproxy">split proxy mode</a> and/or the <tt>nspace</tt> feature is used, it is emitted to the main proxy D module only).</p></dd> <dt><tt>%pragma(d) globalproxyimports</tt></dt> <dd> @@ -379,10 +386,13 @@ struct A { <H2><a name="D_other_features"></a>20.8 Other features</H2> -<p>The <a href="SWIGPlus.html#SWIGPlus_nspace"><tt>nspace</tt></a> feature of SWIG is not yet supported for D - all class modules are written to the same package, regardless of which C++ namespace they are in.</p> +<H3><a name="D_nspace"></a>20.8.1 Extended namespace support (<tt>nspace</tt>)</H3> + + +<p>By default, SWIG flattens all C++ namespaces into a single target language namespace, but as for Java and C#, the <a href="SWIGPlus.html#SWIGPlus_nspace"><tt>nspace</tt></a> feature is supported for D. If it is active, C++ namespaces are mapped to D packages/modules. Note, however, that like for the other languages, <em>free</em> variables and functions are not supported yet; currently, they are all allows written to the main proxy D module.</p> -<H3><a name="D_native_pointer_support"></a>20.8.1 Native pointer support</H3> +<H3><a name="D_native_pointer_support"></a>20.8.2 Native pointer support</H3> <p>Contrary to many of the scripting languages supported by SWIG, D fully supports C-style pointers. The D module thus includes a custom mechanism to wrap C pointers directly as D pointers where applicable, that is, if the type that is pointed to is represented the same in C and D (on the bit-level), dubbed a »primtive type« below.</p> @@ -394,7 +404,7 @@ struct A { <p>To determine if a type should be considered primitive, the <tt>cprimitive</tt> attribute on its <tt>dtype</tt> attribute is used. For example, the <tt>dtype</tt> typemap for <tt>float</tt> has <tt>cprimitive="1"</tt>, so the code from the <tt>nativepointer</tt> attribute is taken into account e.g. for <tt>float **</tt> or the function pointer <tt>float (*)(float *)</tt>.</p> -<H3><a name="D_operator_overloading"></a>20.8.2 Operator overloading</H3> +<H3><a name="D_operator_overloading"></a>20.8.3 Operator overloading</H3> <p>The D module comes with basic operator overloading support for both D1 and D2. There are, however, a few limitations arising from conceptual differences between C++ and D:</p> @@ -406,7 +416,7 @@ struct A { <p>There are also some cases where the operators can be translated to D, but the differences in the implementation details are big enough that a rather involved scheme would be required for automatic wrapping them, which has not been implemented yet. This affects, for example, the array subscript operator, <tt>[]</tt>, in combination with assignments - while <tt>operator []</tt> in C++ simply returns a reference which is then written to, D resorts to a separate <tt>opIndexAssign</tt> method -, or implicit casting (which was introduced in D2 via <tt>alias this</tt>). Despite the lack of automatic support, manually handling these cases should be perfectly possible.</p> -<H3><a name="D_test_suite"></a>20.8.3 Running the test-suite</H3> +<H3><a name="D_test_suite"></a>20.8.4 Running the test-suite</H3> <p>As with any other language, the SWIG test-suite can be built for D using the <tt>*-d-test-suite</tt> targets of the top-level Makefile. By default, D1 is targeted, to build it with D2, use the optional <tt>D_VERSION</tt> variable, e.g. <tt>make check-d-test-suite D_VERSION=2</tt>.</p> diff --git a/Examples/test-suite/csharp/nspace_runme.cs b/Examples/test-suite/csharp/nspace_runme.cs index 9cf593857..fb6462541 100644 --- a/Examples/test-suite/csharp/nspace_runme.cs +++ b/Examples/test-suite/csharp/nspace_runme.cs @@ -2,7 +2,7 @@ using System; public class runme { - static void Main() + static void Main() { // constructors and destructors nspaceNamespace.Outer.Inner1.Color color1 = new nspaceNamespace.Outer.Inner1.Color(); @@ -62,7 +62,7 @@ public class runme throw new ApplicationException("Transmission2 wrong"); // turn feature off / ignoring - nspaceNamespace.Outer.nspace ns = new nspaceNamespace.Outer.nspace(); + nspaceNamespace.Outer.namespce ns = new nspaceNamespace.Outer.namespce(); ns.Dispose(); nspaceNamespace.NoNSpacePlease nons = new nspaceNamespace.NoNSpacePlease(); nons.Dispose(); diff --git a/Examples/test-suite/d/Makefile.in b/Examples/test-suite/d/Makefile.in index 0f5bf8cbb..53b9f2859 100644 --- a/Examples/test-suite/d/Makefile.in +++ b/Examples/test-suite/d/Makefile.in @@ -65,13 +65,13 @@ run_testcase = \ cd $*$(VERSIONSUFFIX) && \ $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \ DFLAGS='-of$*_runme' \ - DSRCS='../$(srcdir)/$(TESTPREFIX)$*$(TESTSUFFIX) $*/*.d' d_compile && \ + DSRCS='../$(srcdir)/$(TESTPREFIX)$*$(TESTSUFFIX) `find $* -name *.d`' d_compile && \ env LD_LIBRARY_PATH=".:$$LD_LIBRARY_PATH" $(RUNTOOL) ./$*_runme; \ else \ cd $*$(VERSIONSUFFIX) && \ $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \ DFLAGS='-c' \ - DSRCS='$*/*.d' d_compile && cd .. ; \ + DSRCS='`find $* -name *.d`' d_compile && cd .. ; \ fi # Clean: remove testcase directories diff --git a/Examples/test-suite/d/nspace_extend_runme.1.d b/Examples/test-suite/d/nspace_extend_runme.1.d new file mode 100644 index 000000000..82ccfec90 --- /dev/null +++ b/Examples/test-suite/d/nspace_extend_runme.1.d @@ -0,0 +1,32 @@ +module nspace_extend_runme; + +static import oi1c = nspace_extend.Outer.Inner1.Color; +static import oi2c = nspace_extend.Outer.Inner2.Color; + +void main() { + { + // constructors and destructors + scope color1 = new oi1c.Color(); + scope color = new oi1c.Color(color1); + + // class methods + color.colorInstanceMethod(20.0); + oi1c.Color.colorStaticMethod(20.0); + auto created = oi1c.Color.create(); + } + { + // constructors and destructors + scope color2 = new oi2c.Color(); + scope color = new oi2c.Color(color2); + + // class methods + color.colorInstanceMethod(20.0); + oi2c.Color.colorStaticMethod(20.0); + auto created = oi2c.Color.create(); + + // Same class different namespaces + auto col1 = new oi1c.Color(); + auto col2 = oi2c.Color.create(); + col2.colors(col1, col1, col2, col2, col2); + } +} diff --git a/Examples/test-suite/d/nspace_extend_runme.2.d b/Examples/test-suite/d/nspace_extend_runme.2.d new file mode 100644 index 000000000..82ccfec90 --- /dev/null +++ b/Examples/test-suite/d/nspace_extend_runme.2.d @@ -0,0 +1,32 @@ +module nspace_extend_runme; + +static import oi1c = nspace_extend.Outer.Inner1.Color; +static import oi2c = nspace_extend.Outer.Inner2.Color; + +void main() { + { + // constructors and destructors + scope color1 = new oi1c.Color(); + scope color = new oi1c.Color(color1); + + // class methods + color.colorInstanceMethod(20.0); + oi1c.Color.colorStaticMethod(20.0); + auto created = oi1c.Color.create(); + } + { + // constructors and destructors + scope color2 = new oi2c.Color(); + scope color = new oi2c.Color(color2); + + // class methods + color.colorInstanceMethod(20.0); + oi2c.Color.colorStaticMethod(20.0); + auto created = oi2c.Color.create(); + + // Same class different namespaces + auto col1 = new oi1c.Color(); + auto col2 = oi2c.Color.create(); + col2.colors(col1, col1, col2, col2, col2); + } +} diff --git a/Examples/test-suite/d/nspace_runme.1.d b/Examples/test-suite/d/nspace_runme.1.d new file mode 100644 index 000000000..8d3b81f76 --- /dev/null +++ b/Examples/test-suite/d/nspace_runme.1.d @@ -0,0 +1,87 @@ +module nspace_runme; + +import nspace.nspace; +static import nspace.NoNSpacePlease; +static import nspace.Outer.namespce; +static import nspace.Outer.Inner1.Channel; +static import oi1c = nspace.Outer.Inner1.Color; +static import nspace.Outer.Inner2.Channel; +static import nspace.Outer.Inner2.Color; +static import nspace.Outer.Inner3.Blue; +static import nspace.Outer.Inner4.Blue; +static import nspace.Outer.SomeClass; + +void main() { + // constructors and destructors + auto color1 = new oi1c.Color(); + auto color = new oi1c.Color(color1); + + // class methods + color.colorInstanceMethod(20.0); + oi1c.Color.colorStaticMethod(20.0); + auto created = oi1c.Color.create(); + + // class enums + auto someClass = new nspace.Outer.SomeClass.SomeClass(); + auto channel = someClass.GetInner1ColorChannel(); + if (channel != oi1c.Color.Channel.Transmission) { + throw new Exception("Transmission wrong"); + } + + // class anonymous enums + int val1 = oi1c.Color.ColorEnumVal1; + int val2 = oi1c.Color.ColorEnumVal2; + if (val1 != 0 || val2 != 0x22) { + throw new Exception("ColorEnumVal wrong"); + } + + // instance member variables + color.instanceMemberVariable = 123; + if (color.instanceMemberVariable != 123) { + throw new Exception("instance member variable failed"); + } + + // static member variables + oi1c.Color.staticMemberVariable = 789; + if (oi1c.Color.staticMemberVariable != 789) { + throw new Exception("static member variable failed"); + } + if (oi1c.Color.staticConstMemberVariable != 222) { + throw new Exception("static const member variable failed"); + } + if (oi1c.Color.staticConstEnumMemberVariable != oi1c.Color.Channel.Transmission) { + throw new Exception("static const enum member variable failed"); + } + + // check globals in a namespace don't get mangled with the nspace option + nspace.nspace.namespaceFunction(color); + nspace.nspace.namespaceVar = 111; + if (nspace.nspace.namespaceVar != 111) { + throw new Exception("global var failed"); + } + + // Same class different namespaces + auto col1 = new oi1c.Color(); + auto col2 = nspace.Outer.Inner2.Color.Color.create(); + col2.colors(col1, col1, col2, col2, col2); + + // global enums + auto outerChannel1 = someClass.GetInner1Channel(); + if (outerChannel1 != nspace.Outer.Inner1.Channel.Channel.Transmission1) { + throw new Exception("Transmission1 wrong"); + } + auto outerChannel2 = someClass.GetInner2Channel(); + if (outerChannel2 != nspace.Outer.Inner2.Channel.Channel.Transmission2) { + throw new Exception("Transmission2 wrong"); + } + + // turn feature off / ignoring + auto ns = new nspace.Outer.namespce.namespce(); + auto nons = new nspace.NoNSpacePlease.NoNSpacePlease(); + + // Derived class + auto blue3 = new nspace.Outer.Inner3.Blue.Blue(); + blue3.blueInstanceMethod(); + auto blue4 = new nspace.Outer.Inner4.Blue.Blue(); + blue4.blueInstanceMethod(); +} diff --git a/Examples/test-suite/d/nspace_runme.2.d b/Examples/test-suite/d/nspace_runme.2.d new file mode 100644 index 000000000..a86e4db9e --- /dev/null +++ b/Examples/test-suite/d/nspace_runme.2.d @@ -0,0 +1,77 @@ +module nspace_runme; + +import std.exception; +import nspace.nspace; +static import nspace.NoNSpacePlease; +static import nspace.Outer.namespce; +static import nspace.Outer.Inner1.Channel; +static import oi1c = nspace.Outer.Inner1.Color; +static import nspace.Outer.Inner2.Channel; +static import nspace.Outer.Inner2.Color; +static import nspace.Outer.Inner3.Blue; +static import nspace.Outer.Inner4.Blue; +static import nspace.Outer.SomeClass; + +void main() { + // constructors and destructors + auto color1 = new oi1c.Color(); + auto color = new oi1c.Color(color1); + + // class methods + color.colorInstanceMethod(20.0); + oi1c.Color.colorStaticMethod(20.0); + auto created = oi1c.Color.create(); + + // class enums + auto someClass = new nspace.Outer.SomeClass.SomeClass(); + auto channel = someClass.GetInner1ColorChannel(); + enforce(channel == oi1c.Color.Channel.Transmission, + "Transmission wrong"); + + // class anonymous enums + int val1 = oi1c.Color.ColorEnumVal1; + int val2 = oi1c.Color.ColorEnumVal2; + enforce(val1 == 0 && val2 == 0x22, "ColorEnumVal wrong"); + + // instance member variables + color.instanceMemberVariable = 123; + enforce(color.instanceMemberVariable == 123, + "instance member variable failed"); + + // static member variables + oi1c.Color.staticMemberVariable = 789; + enforce(oi1c.Color.staticMemberVariable == 789, + "static member variable failed"); + enforce(oi1c.Color.staticConstMemberVariable == 222, + "static const member variable failed"); + enforce(oi1c.Color.staticConstEnumMemberVariable == oi1c.Color.Channel.Transmission, + "static const enum member variable failed"); + + // check globals in a namespace don't get mangled with the nspace option + nspace.nspace.namespaceFunction(color); + nspace.nspace.namespaceVar = 111; + enforce(nspace.nspace.namespaceVar == 111, "global var failed"); + + // Same class different namespaces + auto col1 = new oi1c.Color(); + auto col2 = nspace.Outer.Inner2.Color.Color.create(); + col2.colors(col1, col1, col2, col2, col2); + + // global enums + auto outerChannel1 = someClass.GetInner1Channel(); + enforce(outerChannel1 == nspace.Outer.Inner1.Channel.Channel.Transmission1, + "Transmission1 wrong"); + auto outerChannel2 = someClass.GetInner2Channel(); + enforce(outerChannel2 == nspace.Outer.Inner2.Channel.Channel.Transmission2, + "Transmission2 wrong"); + + // turn feature off / ignoring + auto ns = new nspace.Outer.namespce.namespce(); + auto nons = new nspace.NoNSpacePlease.NoNSpacePlease(); + + // Derived class + auto blue3 = new nspace.Outer.Inner3.Blue.Blue(); + blue3.blueInstanceMethod(); + auto blue4 = new nspace.Outer.Inner4.Blue.Blue(); + blue4.blueInstanceMethod(); +} diff --git a/Examples/test-suite/java/nspace_runme.java b/Examples/test-suite/java/nspace_runme.java index 9800e79cd..4b58c6b54 100644 --- a/Examples/test-suite/java/nspace_runme.java +++ b/Examples/test-suite/java/nspace_runme.java @@ -68,7 +68,7 @@ public class nspace_runme { throw new RuntimeException("Transmission2 wrong"); // turn feature off / ignoring - nspacePackage.Outer.nspace ns = new nspacePackage.Outer.nspace(); + nspacePackage.Outer.namespce ns = new nspacePackage.Outer.namespce(); nspacePackage.NoNSpacePlease nons = new nspacePackage.NoNSpacePlease(); // Derived class diff --git a/Examples/test-suite/nspace.i b/Examples/test-suite/nspace.i index 4e4e461c0..89009b939 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) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) %nspace; %nonspace Outer::Inner2::NoNSpacePlease; @@ -15,7 +15,7 @@ %inline %{ namespace Outer { - class nspace { + class namespce { }; namespace Inner1 { enum Channel { Diffuse, Specular = 0x10, Transmission1 }; @@ -33,12 +33,12 @@ namespace Outer { static const Channel staticConstEnumMemberVariable = Transmission; void colorInstanceMethod(double d) {} static void colorStaticMethod(double d) {} - }; // Color + }; // Color int Color::staticMemberVariable = 0; Color namespaceFunction(Color k) { return k; } int namespaceVar = 0; - } // Inner1 + } // Inner1 namespace Inner2 { enum Channel { Diffuse, Specular = 0x30, Transmission2 }; @@ -56,12 +56,12 @@ namespace Outer { static const Channel staticConstEnumMemberVariable = Transmission; void colorInstanceMethod(double d) {} static void colorStaticMethod(double d) {} - void colors(const Inner1::Color& col1a, - const Outer::Inner1::Color& col1b, - const Color &col2a, - const Inner2::Color& col2b, + void colors(const Inner1::Color& col1a, + const Outer::Inner1::Color& col1b, + const Color &col2a, + const Inner2::Color& col2b, const Outer::Inner2::Color& col2c) {} - }; // Color + }; // Color int Color::staticMemberVariable = 0; class NoNSpacePlease {}; } // Inner2 diff --git a/Examples/test-suite/nspace_extend.i b/Examples/test-suite/nspace_extend.i index 88f40bc69..47ede95d0 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) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD) %nspace; @@ -39,10 +39,10 @@ namespace Outer { void colorInstanceMethod(double d) {} static void colorStaticMethod(double d) {} - void colors(const Inner1::Color& col1a, - const Outer::Inner1::Color& col1b, - const Color &col2a, - const Inner2::Color& col2b, + void colors(const Inner1::Color& col1a, + const Outer::Inner1::Color& col1b, + const Color &col2a, + const Inner2::Color& col2b, const Outer::Inner2::Color& col2c) {} } diff --git a/Lib/d/boost_shared_ptr.i b/Lib/d/boost_shared_ptr.i index 37ce26d00..bfa2aa646 100644 --- a/Lib/d/boost_shared_ptr.i +++ b/Lib/d/boost_shared_ptr.i @@ -162,7 +162,7 @@ private void* swigCPtr; private bool swigCMemOwn; public this(void* cObject, bool ownCObject) { - super($imdmodule.$dclassnameSmartPtrUpcast(cObject), ownCObject); + super($imdmodule.$dclazznameSmartPtrUpcast(cObject), ownCObject); swigCPtr = cObject; swigCMemOwn = ownCObject; } diff --git a/Lib/d/dclassgen.swg b/Lib/d/dclassgen.swg index 467621f4a..ceaf50727 100644 --- a/Lib/d/dclassgen.swg +++ b/Lib/d/dclassgen.swg @@ -84,7 +84,7 @@ mixin $imdmodule.SwigOperatorDefinitions; private void* swigCPtr; public this(void* cObject, bool ownCObject) { - super($imdmodule.$dclassnameUpcast(cObject), ownCObject); + super($imdmodule.$dclazznameUpcast(cObject), ownCObject); swigCPtr = cObject; } diff --git a/Source/Modules/d.cxx b/Source/Modules/d.cxx index 4b55d2b4d..e2ce9f384 100644 --- a/Source/Modules/d.cxx +++ b/Source/Modules/d.cxx @@ -131,23 +131,37 @@ class D : public Language { // split proxy module mode, the proxy class modules) from // %pragma(d) globalproxyimports. String *global_proxy_imports; - - // Imports written to the proxy D module header from global_proxy_imports - // and, if in split proxy module mode, from D::requireDType(). + + // The D code for the main proxy modules. nspace_proxy_dmodules is a hash from + // the namespace name as key to an {"imports", "code"}. If the nspace feature + // is not active, only proxy_dmodule_imports and proxy_dmodule_code are used, + // which contain the code for the root proxy module. + // + // These variables should not be accessed directly but rather via the + // proxy{Imports, Code}Buffer)() helper functions which return the right + // buffer for a given namespace. If not in split proxy mode, they contain the + // whole proxy code. String *proxy_dmodule_imports; - - // The D code for proxy functions/classes which is written to the proxy D - // module. If not in split proxy mode, this contains the whole proxy code. String *proxy_dmodule_code; - + Hash *nspace_proxy_dmodules; + // The D code generated for the currently processed enum. String *proxy_enum_code; /* * D data for the current proxy class. + * + * These strings are mainly used to temporarily accumulate code from the + * various member handling functions while a single class is processed and are + * no longer relevant once that class has been finished, i.e. after + * classHandler() has returned. */ - // The name of the current proxy class. + // The unqualified name of the current proxy class. String *proxy_class_name; + + // The name of the current proxy class, qualified with the name of the + // namespace it is in, if any. + String *proxy_class_qname; // The import directives for the current proxy class. They are written to the // same D module the proxy class is written to. @@ -243,8 +257,10 @@ public: global_proxy_imports(NULL), proxy_dmodule_imports(NULL), proxy_dmodule_code(NULL), + nspace_proxy_dmodules(NULL), proxy_enum_code(NULL), proxy_class_name(NULL), + proxy_class_qname(NULL), proxy_class_imports(NULL), proxy_class_enums_code(NULL), proxy_class_body_code(NULL), @@ -439,6 +455,7 @@ public: destructor_call = NewString(""); proxy_dmodule_code = NewString(""); proxy_dmodule_imports = NewString(""); + nspace_proxy_dmodules = NewHash(); im_dmodule_imports = NewString(""); upcasts_code = NewString(""); global_proxy_imports = NewString(""); @@ -524,7 +541,7 @@ public: Close(im_d_file); } - // Generate the D proxy module for the wrapped module. + // Generate the main D proxy module. { String *filen = NewStringf("%s%s.d", dmodule_directory, proxy_dmodule_name); File *proxy_d_file = NewFile(filen, "w", SWIG_output_files()); @@ -556,6 +573,34 @@ public: Close(proxy_d_file); } + + // Generate the additional proxy modules for nspace support. + for (Iterator it = First(nspace_proxy_dmodules); it.key; it = Next(it)) { + String *module_name = createLastNamespaceName(it.key); + + String *filename = NewStringf("%s%s.d", outputDirectory(it.key), module_name); + File *file = NewFile(filename, "w", SWIG_output_files()); + if (!file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(filename); + + emitBanner(file); + + Printf(file, "module %s%s.%s;\n", package, it.key, module_name); + Printf(file, "\nstatic import %s;\n", im_dmodule_fq_name); + Printv(file, global_proxy_imports, NIL); + Printv(file, Getattr(it.item, "imports"), NIL); + Printv(file, "\n", NIL); + + String *code = Getattr(it.item, "code"); + replaceModuleVariables(code); + Printv(file, code, NIL); + + Close(file); + Delete(module_name); + } if (upcasts_code) Printv(f_wrappers, upcasts_code, NIL); @@ -613,6 +658,8 @@ public: proxy_dmodule_code = NULL; Delete(proxy_dmodule_imports); proxy_dmodule_imports = NULL; + Delete(nspace_proxy_dmodules); + nspace_proxy_dmodules = NULL; Delete(im_dmodule_imports); im_dmodule_imports = NULL; Delete(upcasts_code); @@ -709,7 +756,7 @@ public: Chop(strvalue); Printf(im_dmodule_imports, "%s\n", strvalue); } else if (Strcmp(code, "proxydmodulecode") == 0) { - Printf(proxy_dmodule_code, "%s\n", strvalue); + Printf(proxyCodeBuffer(0), "%s\n", strvalue); } else if (Strcmp(code, "globalproxyimports") == 0) { replaceImportTypeMacros(strvalue); Chop(strvalue); @@ -798,7 +845,11 @@ public: if (split_proxy_dmodule && typemap_lookup_type) { assertClassNameValidity(proxy_class_name); - String *filename = NewStringf("%s%s.d", dmodule_directory, symname); + String *nspace = Getattr(n, "sym:nspace"); + String *output_directory = outputDirectory(nspace); + String *filename = NewStringf("%s%s.d", output_directory, symname); + Delete(output_directory); + File *class_file = NewFile(filename, "w", SWIG_output_files()); if (!class_file) { FileErrorDisplay(filename); @@ -808,7 +859,11 @@ public: Delete(filename); emitBanner(class_file); - Printf(class_file, "module %s%s;\n", package, symname); + if (nspace) { + Printf(class_file, "module %s%s.%s;\n", package, nspace, symname); + } else { + Printf(class_file, "module %s%s;\n", package, symname); + } Printv(class_file, imports_trimmed, NIL); Printv(class_file, proxy_enum_code, NIL); @@ -816,8 +871,9 @@ public: Close(class_file); Delete(class_file); } else { - Printv(proxy_dmodule_imports, imports, NIL); - Printv(proxy_dmodule_code, proxy_enum_code, NIL); + String *nspace = Getattr(n, "sym:nspace"); + Printv(proxyImportsBuffer(nspace), imports, NIL); + Printv(proxyCodeBuffer(nspace), proxy_enum_code, NIL); } } @@ -834,7 +890,7 @@ public: virtual int enumvalueDeclaration(Node *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"); @@ -850,14 +906,12 @@ public: // Note that this is used in enumValue() amongst other places Setattr(n, "value", tmpValue); - String *proxy_name = Getattr(n, "sym:name"); - // Emit the enum item. { if (!GetFlag(n, "firstenumitem")) Printf(proxy_enum_code, ",\n"); - Printf(proxy_enum_code, " %s", proxy_name); + Printf(proxy_enum_code, " %s", Getattr(n, "sym:name")); // Check for the %dconstvalue feature String *value = Getattr(n, "feature:d:constvalue"); @@ -886,7 +940,7 @@ public: String *overloaded_name = getOverloadedName(n); String *intermediary_function_name = - Swig_name_member(NSPACE_TODO,proxy_class_name, overloaded_name); + Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); Setattr(n, "imfuncname", intermediary_function_name); String *proxy_func_name = Getattr(n, "sym:name"); @@ -897,6 +951,7 @@ public: // If we are in split proxy mode and the function is named like the // target package, the D compiler is unable to resolve the ambiguity // between the package name and an argument-less function call. + // TODO: This might occur with nspace as well, augment the check. Swig_warning(WARN_D_NAME_COLLISION, input_file, line_number, "%s::%s might collide with the package name, consider using %%rename to resolve the ambiguity.\n", proxy_class_name, proxy_func_name); @@ -935,7 +990,7 @@ public: String *overloaded_name = getOverloadedName(n); String *intermediary_function_name = - Swig_name_member(NSPACE_TODO,proxy_class_name, overloaded_name); + Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); Setattr(n, "imfuncname", intermediary_function_name); writeProxyClassFunction(n); @@ -1006,7 +1061,7 @@ public: virtual int constructorHandler(Node *n) { Language::constructorHandler(n); - // Wrappers not wanted for some methods where the parameters cannot be overloaded in D. + // Wrappers not wanted for some methods where the parameters cannot be overloadedprocess in D. if (Getattr(n, "overload:ignore")) { return SWIG_OK; } @@ -1026,7 +1081,7 @@ public: NewString(""); String *overloaded_name = getOverloadedName(n); - String *mangled_overname = Swig_name_construct(NSPACE_TODO,overloaded_name); + String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name); String *imcall = NewString(""); const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); @@ -1223,7 +1278,7 @@ public: virtual int destructorHandler(Node *n) { Language::destructorHandler(n); String *symname = Getattr(n, "sym:name"); - Printv(destructor_call, im_dmodule_fq_name, ".", Swig_name_destroy(NSPACE_TODO,symname), "(cast(void*)swigCPtr)", NIL); + Printv(destructor_call, im_dmodule_fq_name, ".", Swig_name_destroy(getNSpace(),symname), "(cast(void*)swigCPtr)", NIL); return SWIG_OK; } @@ -1231,19 +1286,27 @@ public: * D::classHandler() * --------------------------------------------------------------------------- */ virtual int classHandler(Node *n) { + String *nspace = getNSpace(); File *class_file = NULL; proxy_class_name = Copy(Getattr(n, "sym:name")); + if (nspace) { + proxy_class_qname = NewStringf("%s.%s", nspace, proxy_class_name); + } else { + proxy_class_qname = Copy(proxy_class_name); + } - if (!addSymbol(proxy_class_name, n)) { + if (!addSymbol(proxy_class_name, n, nspace)) { return SWIG_ERROR; } assertClassNameValidity(proxy_class_name); if (split_proxy_dmodule) { - String *filename = NewStringf("%s%s.d", dmodule_directory, proxy_class_name); + String *output_directory = outputDirectory(nspace); + String *filename = NewStringf("%s%s.d", output_directory, proxy_class_name); class_file = NewFile(filename, "w", SWIG_output_files()); + Delete(output_directory); if (!class_file) { FileErrorDisplay(filename); SWIG_exit(EXIT_FAILURE); @@ -1252,7 +1315,11 @@ public: Delete(filename); emitBanner(class_file); - Printf(class_file, "module %s%s;\n", package, proxy_class_name); + if (nspace) { + Printf(class_file, "module %s%s.%s;\n", package, nspace, proxy_class_name); + } else { + Printf(class_file, "module %s%s;\n", package, proxy_class_name); + } Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name); } @@ -1264,6 +1331,8 @@ public: Clear(destructor_call); + // Traverse the tree for this class, using the *Handler()s to generate code + // to the proxy_class_* variables. Language::classHandler(n); @@ -1271,6 +1340,10 @@ public: writeDirectorConnectWrapper(n); Replaceall(proxy_class_code, "$dclassname", proxy_class_name); + + String *dclazzname = Swig_name_member(getNSpace(), proxy_class_name, ""); + Replaceall(proxy_class_code, "$dclazzname", dclazzname); + Delete(dclazzname); if (split_proxy_dmodule) { Printv(class_file, global_proxy_imports, NIL); @@ -1282,10 +1355,12 @@ public: Close(class_file); Delete(class_file); } else { - Printv(proxy_dmodule_imports, proxy_class_imports, NIL); - Printv(proxy_dmodule_code, proxy_class_code, NIL); + Printv(proxyImportsBuffer(getNSpace()), proxy_class_imports, NIL); + Printv(proxyCodeBuffer(getNSpace()), proxy_class_code, NIL); } + Delete(proxy_class_qname); + proxy_class_qname = NULL; Delete(proxy_class_name); proxy_class_name = NULL; @@ -1402,7 +1477,7 @@ public: if (wrapping_member_flag) { Printv(proxy_class_body_code, constants_code, NIL); } else { - Printv(proxy_dmodule_code, constants_code, NIL); + Printv(proxyCodeBuffer(getNSpace()), constants_code, NIL); } // Cleanup. @@ -1780,10 +1855,18 @@ public: * D::classDirector() * --------------------------------------------------------------------------- */ virtual int classDirector(Node *n) { + String *nspace = Getattr(n, "sym:nspace"); proxy_class_name = NewString(Getattr(n, "sym:name")); + if (nspace) { + proxy_class_qname = NewStringf("%s.%s", nspace, proxy_class_name); + } else { + proxy_class_qname = Copy(proxy_class_name); + } int success = Language::classDirector(n); + Delete(proxy_class_qname); + proxy_class_qname = NULL; Delete(proxy_class_name); proxy_class_name = NULL; @@ -1874,7 +1957,8 @@ public: // we're consistent with the sym:overload name in functionWrapper. (?? when // does the overloaded method name get set?) - imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(NSPACE_TODO,classname, overloaded_name)); + imclass_dmethod = NewStringf("SwigDirector_%s", + Swig_name_member(getNSpace(), classname, overloaded_name)); if (returntype) { qualified_return = SwigType_rcaststr(returntype, "c_result"); @@ -2507,6 +2591,8 @@ private: * intermediary D module. * * d_name - The name the function in the intermediary D module will get. + * return type - The return type of the function in the C wrapper. + * parameters - The parameter list of the C wrapper function. * wrapper_function_name - The name of the exported function in the C wrapper * (usually d_name prefixed by »D_«). * --------------------------------------------------------------------------- */ @@ -2587,8 +2673,12 @@ private: if (wrapping_member_flag) { // Check if this is a setter method for a public member. - setter_flag = (Cmp(Getattr(n, "sym:name"), - Swig_name_set(NSPACE_TODO,Swig_name_member(NSPACE_TODO,proxy_class_name, variable_name))) == 0); + const String *setter_name = Swig_name_set(getNSpace(), + Swig_name_member(0, proxy_class_name, variable_name)); + + if (Cmp(Getattr(n, "sym:name"), setter_name) == 0) { + setter_flag = true; + } } // Write function modifiers. @@ -2630,7 +2720,7 @@ private: if (!static_flag) { Printf(imcall, "cast(void*)swigCPtr"); } - + String *proxy_param_types = NewString(""); // Write the parameter list for the proxy function declaration and the @@ -2769,7 +2859,7 @@ private: Node *explicit_n = Getattr(n, "explicitcallnode"); if (explicit_n) { String *ex_overloaded_name = getOverloadedName(explicit_n); - String *ex_intermediary_function_name = Swig_name_member(NSPACE_TODO,proxy_class_name, ex_overloaded_name); + String *ex_intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, ex_overloaded_name); String *ex_imcall = Copy(imcall); Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); @@ -2795,7 +2885,7 @@ private: Swig_warning(WARN_D_TYPEMAP_DOUT_UNDEF, input_file, line_number, "No dout typemap defined for %s\n", SwigType_str(t, 0)); } - + Delete(proxy_param_types); // The whole function body is now in stored tm (if there was a matching type @@ -3003,7 +3093,7 @@ private: // The whole function code is now stored in tm (if there was a matching // type map, of course), so simply append it to the code buffer. Printf(function_code, "%s\n", tm ? (const String *) tm : empty_string); - Printv(proxy_dmodule_code, function_code, NIL); + Printv(proxyCodeBuffer(getNSpace()), function_code, NIL); Delete(pre_code); Delete(post_code); @@ -3016,6 +3106,16 @@ private: /* --------------------------------------------------------------------------- * D::writeProxyClassAndUpcasts() + * + * Collects all the code fragments generated by the handler function while + * traversing the tree from the proxy_class_* variables and writes the + * class definition (including any epilogue code) to proxy_class_code. + * + * Also writes the upcast function to the wrapper layer when processing a + * derived class. + * + * Inputs: + * n – The class node currently processed. * --------------------------------------------------------------------------- */ void writeProxyClassAndUpcasts(Node *n) { SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); @@ -3026,7 +3126,8 @@ private: String *c_classname = SwigType_namestr(Getattr(n, "name")); String *c_baseclass = NULL; - String *baseclass = NULL; + Node *basenode = NULL; + String *basename = NULL; String *c_baseclassname = NULL; // Inheritance from pure D classes. @@ -3046,9 +3147,10 @@ private: base = Next(base); } if (base.item) { + basenode = base.item; c_baseclassname = Getattr(base.item, "name"); - baseclass = Copy(getProxyName(c_baseclassname)); - if (baseclass) + basename = Copy(getProxyName(c_baseclassname)); + if (basename) c_baseclass = SwigType_namestr(Getattr(base.item, "name")); base = Next(base); /* Warn about multiple inheritance for additional base class(es) */ @@ -3067,24 +3169,25 @@ private: } } - bool derived = baseclass && getProxyName(c_baseclassname); + bool derived = (basename != NULL); if (derived && purebase_notderived) { pure_baseclass = empty_string; } - const String *wanted_base = baseclass ? baseclass : pure_baseclass; + const String *wanted_base = basename ? basename : pure_baseclass; if (purebase_replace) { wanted_base = pure_baseclass; derived = false; - Delete(baseclass); - baseclass = NULL; + basenode = NULL; + Delete(basename); + basename = NULL; if (purebase_notderived) { Swig_error(Getfile(n), Getline(n), "The dbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); } - } else if (baseclass && Len(pure_baseclass) > 0) { + } else if (basename && Len(pure_baseclass) > 0) { Swig_warning(WARN_D_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base class %s ignored. Multiple inheritance is not supported in D. " "Perhaps you need one of the 'replace' or 'notderived' attributes in the dbase typemap?\n", typemap_lookup_type, pure_baseclass); @@ -3101,14 +3204,10 @@ private: // If this class is derived from a C++ class, we need to have the D class // generated for it in scope. if (derived) { - requireDType(baseclass); + requireDType(Getattr(basenode, "sym:nspace"), Getattr(basenode, "sym:name")); - if (split_proxy_dmodule) { - // Fully qualify the baseclass name. - String *module = NewStringf("%s%s.", package, baseclass); - Insert(baseclass, 0, module); - Delete(module); - } + // Fully qualify the baseclass name. + Insert(basename, 0, package); } // Write any custom import statements to the proxy module header. @@ -3238,8 +3337,8 @@ private: // Write the class body and the curly bracket closing the class definition // to the proxy module. indentCode(body); - Replaceall(body, "$dbaseclass", baseclass); - Delete(baseclass); + Replaceall(body, "$dbaseclass", basename); + Delete(basename); Printv(proxy_class_code, body, "\n}\n", NIL); Delete(body); @@ -3256,9 +3355,8 @@ private: String* c_class_name, String* c_base_name) { String *smartptr = Getattr(n, "feature:smartptr"); - String *upcast_name = NewString(""); - Printv(upcast_name, d_class_name, - (smartptr != 0 ? "SmartPtrUpcast" : "Upcast"), NIL); + String *upcast_name = Swig_name_member(getNSpace(), d_class_name, + (smartptr != 0 ? "SmartPtrUpcast" : "Upcast")); String *upcast_wrapper_name = Swig_name_wrapper(upcast_name); @@ -3338,8 +3436,8 @@ private: imports_target = NewString(""); code_target = NewString(""); } else { - imports_target = proxy_dmodule_imports; - code_target = proxy_dmodule_code; + imports_target = proxyImportsBuffer(0); + code_target = proxyCodeBuffer(0); } // Import statements. @@ -3461,7 +3559,8 @@ private: // Output the director connect method. String *norm_name = SwigType_namestr(Getattr(n, "name")); - String *connect_name = NewStringf("%s_director_connect", proxy_class_name); + String *connect_name = Swig_name_member(getNSpace(), + proxy_class_name, "director_connect"); String *sym_name = Getattr(n, "sym:name"); Wrapper *code_wrap; @@ -3504,19 +3603,40 @@ private: /* --------------------------------------------------------------------------- * D::requireDType() * - * Adds an import statement for the given module to the header of current - * module. This is only used for dependencies created in generated code, user- - * (read: typemap-) specified import statements are handeled seperately. + * If the given type is not already in scope in the current module, adds an + * import statement for it. The name is considered relative to the global root + * package if one is set. + * + * This is only used for dependencies created in generated code, user- + * (i.e. typemap-) specified import statements are handeled seperately. * --------------------------------------------------------------------------- */ - void requireDType(const String *dmodule_name) { - String *import = createImportStatement(dmodule_name); - Append(import, "\n"); - if (is_wrapping_class()) { - addImportStatement(proxy_class_imports, import); + void requireDType(const String *nspace, const String *symname) { + String *dmodule; + if (nspace) { + dmodule = NewStringf("%s.", nspace); } else { - addImportStatement(proxy_dmodule_imports, import); + dmodule = NewString(""); } - Delete(import); + + if (split_proxy_dmodule) { + Printv(dmodule, symname, NIL); + } else { + String *inner = createLastNamespaceName(nspace); + Printv(dmodule, inner, NIL); + Delete(inner); + } + + if (!inProxyModule(dmodule)) { + String *import = createImportStatement(dmodule); + Append(import, "\n"); + if (is_wrapping_class()) { + addImportStatement(proxy_class_imports, import); + } else { + addImportStatement(proxyImportsBuffer(getNSpace()), import); + } + Delete(import); + } + Delete(dmodule); } /* --------------------------------------------------------------------------- @@ -3550,46 +3670,41 @@ private: /* --------------------------------------------------------------------------- * D::createImportStatement() * - * Creates a string containing an import statement for the given module if it - * is needed in the currently generated proxy D module (i.e. if it is not the - * current module itself). + * Creates a string containing an import statement for the given module. * --------------------------------------------------------------------------- */ String *createImportStatement(const String *dmodule_name, bool static_import = true) const { - if (inProxyModule(dmodule_name)) { - return NewStringf(""); + if (static_import) { + return NewStringf("static import %s%s;", package, dmodule_name); } else { - if (static_import) { - return NewStringf("static import %s%s;", package, dmodule_name); - } else { - return NewStringf("import %s%s;", package, dmodule_name); - } + return NewStringf("import %s%s;", package, dmodule_name); } } /* --------------------------------------------------------------------------- * D::inProxyModule() * - * Determines if the specified proxy class is decleared in the currently + * Determines if the specified proxy type is declared in the currently * processed proxy D module. * * This function is used to determine if fully qualified type names have to be - * used (package, module and type name). This is never the case if the split - * proxy mode is not used, all proxy types are written to the same module then. + * used (package, module and type name). If the split proxy mode is not used, + * this solely depends on whether the type is in the current namespace or. * --------------------------------------------------------------------------- */ bool inProxyModule(const String *type_name) const { if (!split_proxy_dmodule) { - // If we are not in split proxy module mode, proxy code is always written - // to the same module. - return true; + String *nspace = createOuterNamespaceNames(type_name); + bool result = (getNSpace() || !nspace) && (Strcmp(nspace, getNSpace()) == 0); + Delete(nspace); + return result; } - if (!Len(proxy_class_name)) { + if (!Len(proxy_class_qname)) { return false; } - return (Strcmp(proxy_class_name, type_name) == 0); + return (Strcmp(proxy_class_qname, type_name) == 0); } /* --------------------------------------------------------------------------- @@ -3637,17 +3752,57 @@ private: * D::assertClassNameValidity() * --------------------------------------------------------------------------- */ void assertClassNameValidity(const String* class_name) const { + // TODO: With nspace support, there could arise problems also when not in + // split proxy mode, warnings for these should be added. if (split_proxy_dmodule) { if (Cmp(class_name, im_dmodule_name) == 0) { - Swig_error(input_file, line_number, "Class name cannot be equal to intermediary D module name: %s\n", + Swig_error(input_file, line_number, + "Class name cannot be equal to intermediary D module name: %s\n", class_name); SWIG_exit(EXIT_FAILURE); } - if (Cmp(class_name, proxy_dmodule_name) == 0) { - Swig_error(input_file, line_number, "Class name cannot be equal to proxy D module name: %s\n", - class_name); - SWIG_exit(EXIT_FAILURE); + String *nspace = getNSpace(); + if (nspace) { + // Check the root package/outermost namespace (a class A in module + // A.B leads to problems if another module A.C is also imported)… + if (Len(package) > 0) { + String *dotless_package = NewStringWithSize(package, Len(package) - 1); + if (Cmp(class_name, dotless_package) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be the same as the root package it is in: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + Delete(dotless_package); + } else { + String *outer = createFirstNamespaceName(nspace); + if (Cmp(class_name, outer) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be the same as the outermost namespace it is in: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + Delete(outer); + } + + // … and the innermost one (because of the conflict with the main proxy + // module named like the namespace). + String *inner = createLastNamespaceName(nspace); + if (Cmp(class_name, inner) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be the same as the innermost namespace it is in: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + Delete(inner); + } else { + if (Cmp(class_name, proxy_dmodule_name) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be equal to proxy D module name: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } } } } @@ -3927,48 +4082,69 @@ private: // import when a type is used in another generated module. If we are not // working in split proxy module mode, this is not relevant and the // generated module name is discarded. - String *import_name; + String *type_name; - String *qualified_type_name; if (SwigType_isenum(type)) { // RESEARCH: Make sure that we really cannot get here for anonymous enums. Node *n = enumLookup(type); - const String *symname = Getattr(n, "sym:name"); - - // Add in class scope when referencing enum if not a global enum. - const String *parent_name = NULL; - String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); - if (scopename_prefix) { - parent_name = getProxyName(scopename_prefix); - Delete(scopename_prefix); - } - - if (parent_name) { - qualified_type_name = createQualifiedName(parent_name); - Printv(qualified_type_name, ".", symname, NIL); + String *enum_name = Getattr(n, "sym:name"); + + Node *p = parentNode(n); + if (p && !Strcmp(nodeType(p), "class")) { + // This is a nested enum. + String *parent_name = Getattr(p, "sym:name"); + String *nspace = Getattr(p, "sym:nspace"); // An enum nested in a class is not written to a seperate module (this // would not even be possible in D), so just import the parent. - import_name = Copy(parent_name); - } else { - qualified_type_name = createQualifiedName(symname); + requireDType(nspace, parent_name); + String *module = createModuleName(nspace, parent_name); + if (inProxyModule(module)) { + type_name = NewStringf("%s.%s", parent_name, enum_name); + } else { + type_name = NewStringf("%s%s.%s.%s", package, module, parent_name, enum_name); + } + } else { // A non-nested enum is written to a seperate module, import it. - import_name = Copy(symname); + String *nspace = Getattr(n, "sym:nspace"); + requireDType(nspace, enum_name); + + String *module = createModuleName(nspace, enum_name); + if (inProxyModule(module)) { + type_name = Copy(enum_name); + } else { + type_name = NewStringf("%s%s.%s", package, module, enum_name); + } } } else { - const String *class_name = getProxyName(type); - if (class_name) { - // This is something wrapped as a proxy class (getProxyName() works for - // pointers to classes too). - qualified_type_name = createQualifiedName(class_name); - import_name = Copy(class_name); + Node *n = classLookup(type); + if (n) { + String *class_name = Getattr(n, "sym:name"); + String *nspace = Getattr(n, "sym:nspace"); + requireDType(nspace, class_name); + + String *module = createModuleName(nspace, class_name); + if (inProxyModule(module)) { + type_name = Copy(class_name); + } else { + type_name = NewStringf("%s%s.%s", package, module, class_name); + } } else { // SWIG does not know anything about the type (after resolving typedefs). // Just mangle the type name string like $descriptor(type) would do. String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); - qualified_type_name = createQualifiedName(descriptor); - import_name = Copy(descriptor); + requireDType(NULL, descriptor); + + String *module = NULL; + if (split_proxy_dmodule) { + module = Copy(descriptor); + } + if (inProxyModule(module)) { + type_name = Copy(descriptor); + } else { + type_name = NewStringf("%s%s.%s", package, module, descriptor); + } // Add to hash table so that a type wrapper class can be created later. Setattr(unknown_types, descriptor, type); @@ -3977,23 +4153,36 @@ private: } } - Replaceall(target, variable, qualified_type_name); - Delete(qualified_type_name); - - requireDType(import_name); - Delete(import_name); + Replaceall(target, variable, type_name); + Delete(type_name); } /* --------------------------------------------------------------------------- - * D::createQualifiedName() + * D::createModuleName() + * + * Returns a string holding the name of the module to import to bring the + * given type in scope. * --------------------------------------------------------------------------- */ - String *createQualifiedName(const String *class_name) const { - if (inProxyModule(class_name)) { - return Copy(class_name); + String *createModuleName(const String *nspace, const String *type_name) const { + String *module; + if (nspace) { + module = NewStringf("%s.", nspace); + if (split_proxy_dmodule) { + Printv(module, type_name, NIL); + } else { + String *inner = createLastNamespaceName(nspace); + Printv(module, inner, NIL); + Delete(inner); + } } else { - return NewStringf("%s%s.%s", package, class_name, class_name); + if (split_proxy_dmodule) { + module = Copy(type_name); + } else { + module = proxy_dmodule_name; + } } -} + return module; + } /* --------------------------------------------------------------------------- * D::replaceModuleVariables() @@ -4070,9 +4259,14 @@ private: String *current_macro = NewStringWithSize(start, (int)(end - start)); String *current_param = NewStringWithSize(param_start, (int)(param_end - param_start)); - String *import = createImportStatement(current_param, false); - Replace(target, current_macro, import, DOH_REPLACE_ANY); - Delete(import); + + if (inProxyModule(current_param)) { + Replace(target, current_macro, "", DOH_REPLACE_ANY); + } else { + String *import = createImportStatement(current_param, false); + Replace(target, current_macro, import, DOH_REPLACE_ANY); + Delete(import); + } Delete(current_param); Delete(current_macro); @@ -4107,13 +4301,35 @@ private: * Returns the D class name if a type corresponds to something wrapped with a * proxy class, NULL otherwise. * --------------------------------------------------------------------------- */ - const String *getProxyName(SwigType *t) { + const String *getProxyName(SwigType *t) { + String *proxyname = NULL; Node *n = classLookup(t); if (n) { - return Getattr(n, "sym:name"); - } else { - return NULL; + proxyname = Getattr(n, "proxyname"); + if (!proxyname) { + String *nspace = Getattr(n, "sym:nspace"); + String *symname = Getattr(n, "sym:name"); + + if (nspace) { + proxyname = NewStringf("%s.%s", nspace, symname); + } else { + proxyname = Copy(symname); + } + if (split_proxy_dmodule) { + Printf(proxyname, ".%s", symname); + } else { + if (!inProxyModule(proxyname)) { + Delete(proxyname); + String *inner = createLastNamespaceName(nspace); + proxyname = NewStringf("%s.%s.%s", nspace, inner, symname); + Delete(inner); + } + } + Setattr(n, "proxyname", proxyname); + Delete(proxyname); // Return value still valid because of the ref from n. + } } + return proxyname; } /* --------------------------------------------------------------------------- @@ -4324,6 +4540,145 @@ private: Swig_banner_target_lang(f, " *"); Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); } + + /* --------------------------------------------------------------------------- + * D::outputDirectory() + * + * Returns the directory to write the D modules for the given namespace to and + * and creates the subdirectory if it doesn't exist. + * --------------------------------------------------------------------------- */ + String *outputDirectory(String *nspace) { + String *output_directory = Copy(dmodule_directory); + if (nspace) { + String *nspace_subdirectory = Copy(nspace); + Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); + String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); + if (newdir_error) { + Printf(stderr, "%s\n", newdir_error); + Delete(newdir_error); + SWIG_exit(EXIT_FAILURE); + } + Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); + Delete(nspace_subdirectory); + } + return output_directory; + } + + /* --------------------------------------------------------------------------- + * D::proxyCodeBuffer() + * + * Returns the buffer to write proxy code for the given namespace to. + * --------------------------------------------------------------------------- */ + String *proxyCodeBuffer(String *nspace) { + if (!nspace) { + return proxy_dmodule_code; + } + + Hash *hash = Getattr(nspace_proxy_dmodules, nspace); + if (!hash) { + hash = NewHash(); + Setattr(hash, "code", NewString("")); + Setattr(hash, "imports", NewString("")); + Setattr(nspace_proxy_dmodules, nspace, hash); + } + return Getattr(hash, "code"); + } + + /* --------------------------------------------------------------------------- + * D::proxyCodeBuffer() + * + * Returns the buffer to write imports for the proxy code for the given + * namespace to. + * --------------------------------------------------------------------------- */ + String *proxyImportsBuffer(String *nspace) { + if (!nspace) { + return proxy_dmodule_imports; + } + + Hash *hash = Getattr(nspace_proxy_dmodules, nspace); + if (!hash) { + hash = NewHash(); + Setattr(hash, "code", NewString("")); + Setattr(hash, "imports", NewString("")); + Setattr(nspace_proxy_dmodules, nspace, hash); + } + return Getattr(hash, "imports"); + } + + /* --------------------------------------------------------------------------- + * D::createFirstNamespaceName() + * + * Returns a new string containing the name of the outermost namespace, e.g. + * »A« for the argument »A.B.C«. + * --------------------------------------------------------------------------- */ + String *createFirstNamespaceName(const String *nspace) const { + char *tmp = Char(nspace); + char *c = tmp; + char *co = 0; + if (!strstr(c, ".")) + return 0; + + co = c + Len(nspace); + + while (*c && (c != co)) { + if ((*c == '.')) { + break; + } + c++; + } + if (!*c || (c == tmp)) { + return NULL; + } + return NewStringWithSize(tmp, (int)(c - tmp)); + } + + /* --------------------------------------------------------------------------- + * D::createLastNamespaceName() + * + * Returns a new string containing the name of the innermost namespace, e.g. + * »C« for the argument »A.B.C«. + * --------------------------------------------------------------------------- */ + String *createLastNamespaceName(const String *nspace) const { + if (!nspace) return NULL; + char *c = Char(nspace); + char *cc = c; + if (!strstr(c, ".")) + return NewString(nspace); + + while (*c) { + if (*c == '.') { + cc = c; + } + ++c; + } + return NewString(cc + 1); + } + + /* --------------------------------------------------------------------------- + * D::createOuterNamespaceNames() + * + * Returns a new string containing the name of the outer namespace, e.g. + * »A.B« for the argument »A.B.C«. + * --------------------------------------------------------------------------- */ + String *createOuterNamespaceNames(const String *nspace) const { + if (!nspace) return NULL; + char *tmp = Char(nspace); + char *c = tmp; + char *cc = c; + if (!strstr(c, ".")) + return NULL; + + while (*c) { + if (*c == '.') { + cc = c; + } + ++c; + } + if (cc == tmp) { + return NULL; + } + return NewStringWithSize(tmp, (int)(cc - tmp)); + } }; static Language *new_swig_d() { |