[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
This commit is contained in:
David Nadlinger 2011-03-13 00:32:26 +00:00
commit ce6516fb4c
13 changed files with 757 additions and 164 deletions

View file

@ -28,6 +28,7 @@
<li><a href="#D_directors">D Directors</a> <li><a href="#D_directors">D Directors</a>
<li><a href="#D_other_features">Other features</a> <li><a href="#D_other_features">Other features</a>
<ul> <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_native_pointer_support">Native pointer support</a>
<li><a href="#D_operator_overloading">Operator overloading</a> <li><a href="#D_operator_overloading">Operator overloading</a>
<li><a href="#D_test_suite">Running the test-suite</a> <li><a href="#D_test_suite">Running the test-suite</a>
@ -187,6 +188,12 @@
<p>There are two other variants available, <tt>$&amp;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> <p>There are two other variants available, <tt>$&amp;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> </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> <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> <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>
@ -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> <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> <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> <dt><tt>%pragma(d) globalproxyimports</tt></dt>
<dd> <dd>
@ -379,10 +386,13 @@ struct A {
<H2><a name="D_other_features"></a>20.8 Other features</H2> <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>
<H3><a name="D_native_pointer_support"></a>20.8.1 Native pointer support</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.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> <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> <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> <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> <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> <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>

View file

@ -62,7 +62,7 @@ public class runme
throw new ApplicationException("Transmission2 wrong"); throw new ApplicationException("Transmission2 wrong");
// turn feature off / ignoring // turn feature off / ignoring
nspaceNamespace.Outer.nspace ns = new nspaceNamespace.Outer.nspace(); nspaceNamespace.Outer.namespce ns = new nspaceNamespace.Outer.namespce();
ns.Dispose(); ns.Dispose();
nspaceNamespace.NoNSpacePlease nons = new nspaceNamespace.NoNSpacePlease(); nspaceNamespace.NoNSpacePlease nons = new nspaceNamespace.NoNSpacePlease();
nons.Dispose(); nons.Dispose();

View file

@ -65,13 +65,13 @@ run_testcase = \
cd $*$(VERSIONSUFFIX) && \ cd $*$(VERSIONSUFFIX) && \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \ $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \
DFLAGS='-of$*_runme' \ 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; \ env LD_LIBRARY_PATH=".:$$LD_LIBRARY_PATH" $(RUNTOOL) ./$*_runme; \
else \ else \
cd $*$(VERSIONSUFFIX) && \ cd $*$(VERSIONSUFFIX) && \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \ $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile \
DFLAGS='-c' \ DFLAGS='-c' \
DSRCS='$*/*.d' d_compile && cd .. ; \ DSRCS='`find $* -name *.d`' d_compile && cd .. ; \
fi fi
# Clean: remove testcase directories # Clean: remove testcase directories

View file

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

View file

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

View file

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

View file

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

View file

@ -68,7 +68,7 @@ public class nspace_runme {
throw new RuntimeException("Transmission2 wrong"); throw new RuntimeException("Transmission2 wrong");
// turn feature off / ignoring // 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(); nspacePackage.NoNSpacePlease nons = new nspacePackage.NoNSpacePlease();
// Derived class // Derived class

View file

@ -2,7 +2,7 @@
%module nspace %module nspace
// nspace feature only supported by these languages // nspace feature only supported by these languages
#if defined(SWIGJAVA) || defined(SWIGCSHARP) #if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD)
%nspace; %nspace;
%nonspace Outer::Inner2::NoNSpacePlease; %nonspace Outer::Inner2::NoNSpacePlease;
@ -15,7 +15,7 @@
%inline %{ %inline %{
namespace Outer { namespace Outer {
class nspace { class namespce {
}; };
namespace Inner1 { namespace Inner1 {
enum Channel { Diffuse, Specular = 0x10, Transmission1 }; enum Channel { Diffuse, Specular = 0x10, Transmission1 };

View file

@ -2,7 +2,7 @@
%module nspace_extend %module nspace_extend
// nspace feature only supported by these languages // nspace feature only supported by these languages
#if defined(SWIGJAVA) || defined(SWIGCSHARP) #if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGD)
%nspace; %nspace;

View file

@ -162,7 +162,7 @@ private void* swigCPtr;
private bool swigCMemOwn; private bool swigCMemOwn;
public this(void* cObject, bool ownCObject) { public this(void* cObject, bool ownCObject) {
super($imdmodule.$dclassnameSmartPtrUpcast(cObject), ownCObject); super($imdmodule.$dclazznameSmartPtrUpcast(cObject), ownCObject);
swigCPtr = cObject; swigCPtr = cObject;
swigCMemOwn = ownCObject; swigCMemOwn = ownCObject;
} }

View file

@ -84,7 +84,7 @@ mixin $imdmodule.SwigOperatorDefinitions;
private void* swigCPtr; private void* swigCPtr;
public this(void* cObject, bool ownCObject) { public this(void* cObject, bool ownCObject) {
super($imdmodule.$dclassnameUpcast(cObject), ownCObject); super($imdmodule.$dclazznameUpcast(cObject), ownCObject);
swigCPtr = cObject; swigCPtr = cObject;
} }

View file

@ -132,23 +132,37 @@ class D : public Language {
// %pragma(d) globalproxyimports. // %pragma(d) globalproxyimports.
String *global_proxy_imports; String *global_proxy_imports;
// Imports written to the proxy D module header from global_proxy_imports // The D code for the main proxy modules. nspace_proxy_dmodules is a hash from
// and, if in split proxy module mode, from D::requireDType(). // 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; 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; String *proxy_dmodule_code;
Hash *nspace_proxy_dmodules;
// The D code generated for the currently processed enum. // The D code generated for the currently processed enum.
String *proxy_enum_code; String *proxy_enum_code;
/* /*
* D data for the current proxy class. * 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; 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 // The import directives for the current proxy class. They are written to the
// same D module the proxy class is written to. // same D module the proxy class is written to.
String *proxy_class_imports; String *proxy_class_imports;
@ -243,8 +257,10 @@ public:
global_proxy_imports(NULL), global_proxy_imports(NULL),
proxy_dmodule_imports(NULL), proxy_dmodule_imports(NULL),
proxy_dmodule_code(NULL), proxy_dmodule_code(NULL),
nspace_proxy_dmodules(NULL),
proxy_enum_code(NULL), proxy_enum_code(NULL),
proxy_class_name(NULL), proxy_class_name(NULL),
proxy_class_qname(NULL),
proxy_class_imports(NULL), proxy_class_imports(NULL),
proxy_class_enums_code(NULL), proxy_class_enums_code(NULL),
proxy_class_body_code(NULL), proxy_class_body_code(NULL),
@ -439,6 +455,7 @@ public:
destructor_call = NewString(""); destructor_call = NewString("");
proxy_dmodule_code = NewString(""); proxy_dmodule_code = NewString("");
proxy_dmodule_imports = NewString(""); proxy_dmodule_imports = NewString("");
nspace_proxy_dmodules = NewHash();
im_dmodule_imports = NewString(""); im_dmodule_imports = NewString("");
upcasts_code = NewString(""); upcasts_code = NewString("");
global_proxy_imports = NewString(""); global_proxy_imports = NewString("");
@ -524,7 +541,7 @@ public:
Close(im_d_file); 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); String *filen = NewStringf("%s%s.d", dmodule_directory, proxy_dmodule_name);
File *proxy_d_file = NewFile(filen, "w", SWIG_output_files()); File *proxy_d_file = NewFile(filen, "w", SWIG_output_files());
@ -557,6 +574,34 @@ public:
Close(proxy_d_file); 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) if (upcasts_code)
Printv(f_wrappers, upcasts_code, NIL); Printv(f_wrappers, upcasts_code, NIL);
@ -613,6 +658,8 @@ public:
proxy_dmodule_code = NULL; proxy_dmodule_code = NULL;
Delete(proxy_dmodule_imports); Delete(proxy_dmodule_imports);
proxy_dmodule_imports = NULL; proxy_dmodule_imports = NULL;
Delete(nspace_proxy_dmodules);
nspace_proxy_dmodules = NULL;
Delete(im_dmodule_imports); Delete(im_dmodule_imports);
im_dmodule_imports = NULL; im_dmodule_imports = NULL;
Delete(upcasts_code); Delete(upcasts_code);
@ -709,7 +756,7 @@ public:
Chop(strvalue); Chop(strvalue);
Printf(im_dmodule_imports, "%s\n", strvalue); Printf(im_dmodule_imports, "%s\n", strvalue);
} else if (Strcmp(code, "proxydmodulecode") == 0) { } 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) { } else if (Strcmp(code, "globalproxyimports") == 0) {
replaceImportTypeMacros(strvalue); replaceImportTypeMacros(strvalue);
Chop(strvalue); Chop(strvalue);
@ -798,7 +845,11 @@ public:
if (split_proxy_dmodule && typemap_lookup_type) { if (split_proxy_dmodule && typemap_lookup_type) {
assertClassNameValidity(proxy_class_name); 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()); File *class_file = NewFile(filename, "w", SWIG_output_files());
if (!class_file) { if (!class_file) {
FileErrorDisplay(filename); FileErrorDisplay(filename);
@ -808,7 +859,11 @@ public:
Delete(filename); Delete(filename);
emitBanner(class_file); 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, imports_trimmed, NIL);
Printv(class_file, proxy_enum_code, NIL); Printv(class_file, proxy_enum_code, NIL);
@ -816,8 +871,9 @@ public:
Close(class_file); Close(class_file);
Delete(class_file); Delete(class_file);
} else { } else {
Printv(proxy_dmodule_imports, imports, NIL); String *nspace = Getattr(n, "sym:nspace");
Printv(proxy_dmodule_code, proxy_enum_code, NIL); Printv(proxyImportsBuffer(nspace), imports, NIL);
Printv(proxyCodeBuffer(nspace), proxy_enum_code, NIL);
} }
} }
@ -850,14 +906,12 @@ public:
// Note that this is used in enumValue() amongst other places // Note that this is used in enumValue() amongst other places
Setattr(n, "value", tmpValue); Setattr(n, "value", tmpValue);
String *proxy_name = Getattr(n, "sym:name");
// Emit the enum item. // Emit the enum item.
{ {
if (!GetFlag(n, "firstenumitem")) if (!GetFlag(n, "firstenumitem"))
Printf(proxy_enum_code, ",\n"); 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 // Check for the %dconstvalue feature
String *value = Getattr(n, "feature:d:constvalue"); String *value = Getattr(n, "feature:d:constvalue");
@ -886,7 +940,7 @@ public:
String *overloaded_name = getOverloadedName(n); String *overloaded_name = getOverloadedName(n);
String *intermediary_function_name = 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); Setattr(n, "imfuncname", intermediary_function_name);
String *proxy_func_name = Getattr(n, "sym: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 // 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 // target package, the D compiler is unable to resolve the ambiguity
// between the package name and an argument-less function call. // 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, 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", "%s::%s might collide with the package name, consider using %%rename to resolve the ambiguity.\n",
proxy_class_name, proxy_func_name); proxy_class_name, proxy_func_name);
@ -935,7 +990,7 @@ public:
String *overloaded_name = getOverloadedName(n); String *overloaded_name = getOverloadedName(n);
String *intermediary_function_name = 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, "proxyfuncname", Getattr(n, "sym:name"));
Setattr(n, "imfuncname", intermediary_function_name); Setattr(n, "imfuncname", intermediary_function_name);
writeProxyClassFunction(n); writeProxyClassFunction(n);
@ -1006,7 +1061,7 @@ public:
virtual int constructorHandler(Node *n) { virtual int constructorHandler(Node *n) {
Language::constructorHandler(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")) { if (Getattr(n, "overload:ignore")) {
return SWIG_OK; return SWIG_OK;
} }
@ -1026,7 +1081,7 @@ public:
NewString(""); NewString("");
String *overloaded_name = getOverloadedName(n); 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(""); String *imcall = NewString("");
const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); const String *methodmods = Getattr(n, "feature:d:methodmodifiers");
@ -1223,7 +1278,7 @@ public:
virtual int destructorHandler(Node *n) { virtual int destructorHandler(Node *n) {
Language::destructorHandler(n); Language::destructorHandler(n);
String *symname = Getattr(n, "sym:name"); 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; return SWIG_OK;
} }
@ -1231,19 +1286,27 @@ public:
* D::classHandler() * D::classHandler()
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
virtual int classHandler(Node *n) { virtual int classHandler(Node *n) {
String *nspace = getNSpace();
File *class_file = NULL; File *class_file = NULL;
proxy_class_name = Copy(Getattr(n, "sym:name")); 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; return SWIG_ERROR;
} }
assertClassNameValidity(proxy_class_name); assertClassNameValidity(proxy_class_name);
if (split_proxy_dmodule) { 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()); class_file = NewFile(filename, "w", SWIG_output_files());
Delete(output_directory);
if (!class_file) { if (!class_file) {
FileErrorDisplay(filename); FileErrorDisplay(filename);
SWIG_exit(EXIT_FAILURE); SWIG_exit(EXIT_FAILURE);
@ -1252,7 +1315,11 @@ public:
Delete(filename); Delete(filename);
emitBanner(class_file); 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); Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name);
} }
@ -1264,6 +1331,8 @@ public:
Clear(destructor_call); Clear(destructor_call);
// Traverse the tree for this class, using the *Handler()s to generate code
// to the proxy_class_* variables.
Language::classHandler(n); Language::classHandler(n);
@ -1272,6 +1341,10 @@ public:
Replaceall(proxy_class_code, "$dclassname", proxy_class_name); 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) { if (split_proxy_dmodule) {
Printv(class_file, global_proxy_imports, NIL); Printv(class_file, global_proxy_imports, NIL);
Printv(class_file, proxy_class_imports, NIL); Printv(class_file, proxy_class_imports, NIL);
@ -1282,10 +1355,12 @@ public:
Close(class_file); Close(class_file);
Delete(class_file); Delete(class_file);
} else { } else {
Printv(proxy_dmodule_imports, proxy_class_imports, NIL); Printv(proxyImportsBuffer(getNSpace()), proxy_class_imports, NIL);
Printv(proxy_dmodule_code, proxy_class_code, NIL); Printv(proxyCodeBuffer(getNSpace()), proxy_class_code, NIL);
} }
Delete(proxy_class_qname);
proxy_class_qname = NULL;
Delete(proxy_class_name); Delete(proxy_class_name);
proxy_class_name = NULL; proxy_class_name = NULL;
@ -1402,7 +1477,7 @@ public:
if (wrapping_member_flag) { if (wrapping_member_flag) {
Printv(proxy_class_body_code, constants_code, NIL); Printv(proxy_class_body_code, constants_code, NIL);
} else { } else {
Printv(proxy_dmodule_code, constants_code, NIL); Printv(proxyCodeBuffer(getNSpace()), constants_code, NIL);
} }
// Cleanup. // Cleanup.
@ -1780,10 +1855,18 @@ public:
* D::classDirector() * D::classDirector()
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
virtual int classDirector(Node *n) { virtual int classDirector(Node *n) {
String *nspace = Getattr(n, "sym:nspace");
proxy_class_name = NewString(Getattr(n, "sym:name")); 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); int success = Language::classDirector(n);
Delete(proxy_class_qname);
proxy_class_qname = NULL;
Delete(proxy_class_name); Delete(proxy_class_name);
proxy_class_name = NULL; proxy_class_name = NULL;
@ -1874,7 +1957,8 @@ public:
// we're consistent with the sym:overload name in functionWrapper. (?? when // we're consistent with the sym:overload name in functionWrapper. (?? when
// does the overloaded method name get set?) // 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) { if (returntype) {
qualified_return = SwigType_rcaststr(returntype, "c_result"); qualified_return = SwigType_rcaststr(returntype, "c_result");
@ -2507,6 +2591,8 @@ private:
* intermediary D module. * intermediary D module.
* *
* d_name - The name the function in the intermediary D module will get. * 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 * wrapper_function_name - The name of the exported function in the C wrapper
* (usually d_name prefixed by »D_«). * (usually d_name prefixed by »D_«).
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
@ -2587,8 +2673,12 @@ private:
if (wrapping_member_flag) { if (wrapping_member_flag) {
// Check if this is a setter method for a public member. // Check if this is a setter method for a public member.
setter_flag = (Cmp(Getattr(n, "sym:name"), const String *setter_name = Swig_name_set(getNSpace(),
Swig_name_set(NSPACE_TODO,Swig_name_member(NSPACE_TODO,proxy_class_name, variable_name))) == 0); Swig_name_member(0, proxy_class_name, variable_name));
if (Cmp(Getattr(n, "sym:name"), setter_name) == 0) {
setter_flag = true;
}
} }
// Write function modifiers. // Write function modifiers.
@ -2769,7 +2859,7 @@ private:
Node *explicit_n = Getattr(n, "explicitcallnode"); Node *explicit_n = Getattr(n, "explicitcallnode");
if (explicit_n) { if (explicit_n) {
String *ex_overloaded_name = getOverloadedName(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); String *ex_imcall = Copy(imcall);
Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name);
@ -3003,7 +3093,7 @@ private:
// The whole function code is now stored in tm (if there was a matching // 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. // type map, of course), so simply append it to the code buffer.
Printf(function_code, "%s\n", tm ? (const String *) tm : empty_string); 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(pre_code);
Delete(post_code); Delete(post_code);
@ -3016,6 +3106,16 @@ private:
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
* D::writeProxyClassAndUpcasts() * 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) { void writeProxyClassAndUpcasts(Node *n) {
SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); SwigType *typemap_lookup_type = Getattr(n, "classtypeobj");
@ -3026,7 +3126,8 @@ private:
String *c_classname = SwigType_namestr(Getattr(n, "name")); String *c_classname = SwigType_namestr(Getattr(n, "name"));
String *c_baseclass = NULL; String *c_baseclass = NULL;
String *baseclass = NULL; Node *basenode = NULL;
String *basename = NULL;
String *c_baseclassname = NULL; String *c_baseclassname = NULL;
// Inheritance from pure D classes. // Inheritance from pure D classes.
@ -3046,9 +3147,10 @@ private:
base = Next(base); base = Next(base);
} }
if (base.item) { if (base.item) {
basenode = base.item;
c_baseclassname = Getattr(base.item, "name"); c_baseclassname = Getattr(base.item, "name");
baseclass = Copy(getProxyName(c_baseclassname)); basename = Copy(getProxyName(c_baseclassname));
if (baseclass) if (basename)
c_baseclass = SwigType_namestr(Getattr(base.item, "name")); c_baseclass = SwigType_namestr(Getattr(base.item, "name"));
base = Next(base); base = Next(base);
/* Warn about multiple inheritance for additional base class(es) */ /* 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) { if (derived && purebase_notderived) {
pure_baseclass = empty_string; pure_baseclass = empty_string;
} }
const String *wanted_base = baseclass ? baseclass : pure_baseclass; const String *wanted_base = basename ? basename : pure_baseclass;
if (purebase_replace) { if (purebase_replace) {
wanted_base = pure_baseclass; wanted_base = pure_baseclass;
derived = false; derived = false;
Delete(baseclass); basenode = NULL;
baseclass = NULL; Delete(basename);
basename = NULL;
if (purebase_notderived) { if (purebase_notderived) {
Swig_error(Getfile(n), Getline(n), Swig_error(Getfile(n), Getline(n),
"The dbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", "The dbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n",
typemap_lookup_type); 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), 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. " "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); "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 // If this class is derived from a C++ class, we need to have the D class
// generated for it in scope. // generated for it in scope.
if (derived) { if (derived) {
requireDType(baseclass); requireDType(Getattr(basenode, "sym:nspace"), Getattr(basenode, "sym:name"));
if (split_proxy_dmodule) { // Fully qualify the baseclass name.
// Fully qualify the baseclass name. Insert(basename, 0, package);
String *module = NewStringf("%s%s.", package, baseclass);
Insert(baseclass, 0, module);
Delete(module);
}
} }
// Write any custom import statements to the proxy module header. // 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 // Write the class body and the curly bracket closing the class definition
// to the proxy module. // to the proxy module.
indentCode(body); indentCode(body);
Replaceall(body, "$dbaseclass", baseclass); Replaceall(body, "$dbaseclass", basename);
Delete(baseclass); Delete(basename);
Printv(proxy_class_code, body, "\n}\n", NIL); Printv(proxy_class_code, body, "\n}\n", NIL);
Delete(body); Delete(body);
@ -3256,9 +3355,8 @@ private:
String* c_class_name, String* c_base_name) { String* c_class_name, String* c_base_name) {
String *smartptr = Getattr(n, "feature:smartptr"); String *smartptr = Getattr(n, "feature:smartptr");
String *upcast_name = NewString(""); String *upcast_name = Swig_name_member(getNSpace(), d_class_name,
Printv(upcast_name, d_class_name, (smartptr != 0 ? "SmartPtrUpcast" : "Upcast"));
(smartptr != 0 ? "SmartPtrUpcast" : "Upcast"), NIL);
String *upcast_wrapper_name = Swig_name_wrapper(upcast_name); String *upcast_wrapper_name = Swig_name_wrapper(upcast_name);
@ -3338,8 +3436,8 @@ private:
imports_target = NewString(""); imports_target = NewString("");
code_target = NewString(""); code_target = NewString("");
} else { } else {
imports_target = proxy_dmodule_imports; imports_target = proxyImportsBuffer(0);
code_target = proxy_dmodule_code; code_target = proxyCodeBuffer(0);
} }
// Import statements. // Import statements.
@ -3461,7 +3559,8 @@ private:
// Output the director connect method. // Output the director connect method.
String *norm_name = SwigType_namestr(Getattr(n, "name")); 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"); String *sym_name = Getattr(n, "sym:name");
Wrapper *code_wrap; Wrapper *code_wrap;
@ -3504,19 +3603,40 @@ private:
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
* D::requireDType() * D::requireDType()
* *
* Adds an import statement for the given module to the header of current * If the given type is not already in scope in the current module, adds an
* module. This is only used for dependencies created in generated code, user- * import statement for it. The name is considered relative to the global root
* (read: typemap-) specified import statements are handeled seperately. * 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) { void requireDType(const String *nspace, const String *symname) {
String *import = createImportStatement(dmodule_name); String *dmodule;
Append(import, "\n"); if (nspace) {
if (is_wrapping_class()) { dmodule = NewStringf("%s.", nspace);
addImportStatement(proxy_class_imports, import);
} else { } 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() * D::createImportStatement()
* *
* Creates a string containing an import statement for the given module if it * Creates a string containing an import statement for the given module.
* is needed in the currently generated proxy D module (i.e. if it is not the
* current module itself).
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
String *createImportStatement(const String *dmodule_name, String *createImportStatement(const String *dmodule_name,
bool static_import = true) const { bool static_import = true) const {
if (inProxyModule(dmodule_name)) { if (static_import) {
return NewStringf(""); return NewStringf("static import %s%s;", package, dmodule_name);
} else { } else {
if (static_import) { return NewStringf("import %s%s;", package, dmodule_name);
return NewStringf("static import %s%s;", package, dmodule_name);
} else {
return NewStringf("import %s%s;", package, dmodule_name);
}
} }
} }
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
* D::inProxyModule() * 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. * processed proxy D module.
* *
* This function is used to determine if fully qualified type names have to be * 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 * used (package, module and type name). If the split proxy mode is not used,
* proxy mode is not used, all proxy types are written to the same module then. * this solely depends on whether the type is in the current namespace or.
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
bool inProxyModule(const String *type_name) const { bool inProxyModule(const String *type_name) const {
if (!split_proxy_dmodule) { if (!split_proxy_dmodule) {
// If we are not in split proxy module mode, proxy code is always written String *nspace = createOuterNamespaceNames(type_name);
// to the same module. bool result = (getNSpace() || !nspace) && (Strcmp(nspace, getNSpace()) == 0);
return true; Delete(nspace);
return result;
} }
if (!Len(proxy_class_name)) { if (!Len(proxy_class_qname)) {
return false; 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() * D::assertClassNameValidity()
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
void assertClassNameValidity(const String* class_name) const { 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 (split_proxy_dmodule) {
if (Cmp(class_name, im_dmodule_name) == 0) { 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); class_name);
SWIG_exit(EXIT_FAILURE); SWIG_exit(EXIT_FAILURE);
} }
if (Cmp(class_name, proxy_dmodule_name) == 0) { String *nspace = getNSpace();
Swig_error(input_file, line_number, "Class name cannot be equal to proxy D module name: %s\n", if (nspace) {
class_name); // Check the root package/outermost namespace (a class A in module
SWIG_exit(EXIT_FAILURE); // 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 // 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 // working in split proxy module mode, this is not relevant and the
// generated module name is discarded. // generated module name is discarded.
String *import_name; String *type_name;
String *qualified_type_name;
if (SwigType_isenum(type)) { if (SwigType_isenum(type)) {
// RESEARCH: Make sure that we really cannot get here for anonymous enums. // RESEARCH: Make sure that we really cannot get here for anonymous enums.
Node *n = enumLookup(type); Node *n = enumLookup(type);
const String *symname = Getattr(n, "sym:name"); String *enum_name = Getattr(n, "sym:name");
// Add in class scope when referencing enum if not a global enum. Node *p = parentNode(n);
const String *parent_name = NULL; if (p && !Strcmp(nodeType(p), "class")) {
String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); // This is a nested enum.
if (scopename_prefix) { String *parent_name = Getattr(p, "sym:name");
parent_name = getProxyName(scopename_prefix); String *nspace = Getattr(p, "sym:nspace");
Delete(scopename_prefix);
}
if (parent_name) {
qualified_type_name = createQualifiedName(parent_name);
Printv(qualified_type_name, ".", symname, NIL);
// An enum nested in a class is not written to a seperate module (this // 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. // would not even be possible in D), so just import the parent.
import_name = Copy(parent_name); requireDType(nspace, parent_name);
} else {
qualified_type_name = createQualifiedName(symname);
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. // 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 { } else {
const String *class_name = getProxyName(type); Node *n = classLookup(type);
if (class_name) { if (n) {
// This is something wrapped as a proxy class (getProxyName() works for String *class_name = Getattr(n, "sym:name");
// pointers to classes too). String *nspace = Getattr(n, "sym:nspace");
qualified_type_name = createQualifiedName(class_name); requireDType(nspace, class_name);
import_name = Copy(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 { } else {
// SWIG does not know anything about the type (after resolving typedefs). // SWIG does not know anything about the type (after resolving typedefs).
// Just mangle the type name string like $descriptor(type) would do. // Just mangle the type name string like $descriptor(type) would do.
String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type));
qualified_type_name = createQualifiedName(descriptor); requireDType(NULL, descriptor);
import_name = Copy(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. // Add to hash table so that a type wrapper class can be created later.
Setattr(unknown_types, descriptor, type); Setattr(unknown_types, descriptor, type);
@ -3977,23 +4153,36 @@ private:
} }
} }
Replaceall(target, variable, qualified_type_name); Replaceall(target, variable, type_name);
Delete(qualified_type_name); Delete(type_name);
requireDType(import_name);
Delete(import_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 { String *createModuleName(const String *nspace, const String *type_name) const {
if (inProxyModule(class_name)) { String *module;
return Copy(class_name); 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 { } 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() * D::replaceModuleVariables()
@ -4070,9 +4259,14 @@ private:
String *current_macro = NewStringWithSize(start, (int)(end - start)); String *current_macro = NewStringWithSize(start, (int)(end - start));
String *current_param = NewStringWithSize(param_start, (int)(param_end - param_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); if (inProxyModule(current_param)) {
Delete(import); 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_param);
Delete(current_macro); Delete(current_macro);
@ -4107,13 +4301,35 @@ private:
* Returns the D class name if a type corresponds to something wrapped with a * Returns the D class name if a type corresponds to something wrapped with a
* proxy class, NULL otherwise. * proxy class, NULL otherwise.
* --------------------------------------------------------------------------- */ * --------------------------------------------------------------------------- */
const String *getProxyName(SwigType *t) { const String *getProxyName(SwigType *t) {
String *proxyname = NULL;
Node *n = classLookup(t); Node *n = classLookup(t);
if (n) { if (n) {
return Getattr(n, "sym:name"); proxyname = Getattr(n, "proxyname");
} else { if (!proxyname) {
return NULL; 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, " *"); Swig_banner_target_lang(f, " *");
Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); 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() { static Language *new_swig_d() {