diff options
author | Derrick <a11426@users.sourceforge.net> | 2011-02-14 20:11:58 +0000 |
---|---|---|
committer | Derrick <a11426@users.sourceforge.net> | 2011-02-14 20:11:58 +0000 |
commit | 5815f7ec289e067e765fb8e893a2f337d8b48303 (patch) | |
tree | ebe9e0534a089fe431cedc6fdbc1a53ac523d70c /Source/Modules | |
parent | 3e1af1f698d5d02d7905431bcb3549c0f7bc9aa7 (diff) | |
parent | 1fab53b2046b97702e1de4cfab06cb8fa8fc129d (diff) | |
download | swig-a11426-fortran.tar.gz |
update fortran branch. merge of 12160:12460a11426-fortran
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/a11426-fortran@12461 626c5289-ae23-0410-ae9c-e8d60b6d4f22
Diffstat (limited to 'Source/Modules')
-rw-r--r-- | Source/Modules/allocate.cxx | 8 | ||||
-rw-r--r-- | Source/Modules/clisp.cxx | 16 | ||||
-rw-r--r-- | Source/Modules/csharp.cxx | 82 | ||||
-rw-r--r-- | Source/Modules/d.cxx | 4351 | ||||
-rw-r--r-- | Source/Modules/go.cxx | 59 | ||||
-rw-r--r-- | Source/Modules/java.cxx | 32 | ||||
-rw-r--r-- | Source/Modules/lang.cxx | 36 | ||||
-rw-r--r-- | Source/Modules/lua.cxx | 2 | ||||
-rw-r--r-- | Source/Modules/main.cxx | 16 | ||||
-rw-r--r-- | Source/Modules/modula3.cxx | 11 | ||||
-rw-r--r-- | Source/Modules/mzscheme.cxx | 2 | ||||
-rw-r--r-- | Source/Modules/ocaml.cxx | 45 | ||||
-rw-r--r-- | Source/Modules/php.cxx | 21 | ||||
-rw-r--r-- | Source/Modules/python.cxx | 6 | ||||
-rw-r--r-- | Source/Modules/r.cxx | 17 | ||||
-rw-r--r-- | Source/Modules/ruby.cxx | 13 | ||||
-rw-r--r-- | Source/Modules/swigmain.cxx | 2 | ||||
-rw-r--r-- | Source/Modules/swigmod.h | 11 | ||||
-rw-r--r-- | Source/Modules/tcl8.cxx | 5 | ||||
-rw-r--r-- | Source/Modules/typepass.cxx | 23 | ||||
-rw-r--r-- | Source/Modules/utils.cxx | 113 |
21 files changed, 4686 insertions, 185 deletions
diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx index 2e05fd190..110a92939 100644 --- a/Source/Modules/allocate.cxx +++ b/Source/Modules/allocate.cxx @@ -216,7 +216,7 @@ class Allocate:public Dispatcher { if (!most_base_covariant_type) { // Eliminate the derived virtual method. - if (virtual_elimination_mode) + if (virtual_elimination_mode && !is_member_director(n)) if (both_have_public_access) if (!is_non_public_base(inclass, b)) if (!Swig_symbol_isoverloaded(n)) { @@ -824,9 +824,12 @@ Allocate(): int isconst = 0; Delete(SwigType_pop(type)); if (SwigType_isconst(type)) { - isconst = 1; + isconst = !Getattr(inclass, "allocate:smartpointermutable"); Setattr(inclass, "allocate:smartpointerconst", "1"); } + else { + Setattr(inclass, "allocate:smartpointermutable", "1"); + } List *methods = smart_pointer_methods(sc, 0, isconst); Setattr(inclass, "allocate:smartpointer", methods); Setattr(inclass, "allocate:smartpointerbase", base); @@ -834,7 +837,6 @@ Allocate(): /* Hmmm. The return value is not a pointer. If the type is a value or reference. We're going to chase it to see if another operator->() can be found */ - if ((SwigType_check_decl(type, "")) || (SwigType_check_decl(type, "r."))) { Node *nn = Swig_symbol_clookup((char *) "operator ->", Getattr(sc, "symtab")); if (nn) { diff --git a/Source/Modules/clisp.cxx b/Source/Modules/clisp.cxx index b1a6f5610..d26df36c2 100644 --- a/Source/Modules/clisp.cxx +++ b/Source/Modules/clisp.cxx @@ -293,16 +293,18 @@ int CLISP::classDeclaration(Node *n) { } String *temp = Copy(Getattr(c, "decl")); - Append(temp, Getattr(c, "type")); //appending type to the end, otherwise wrong type - String *lisp_type = get_ffi_type(n, temp); - Delete(temp); + if (temp) { + Append(temp, Getattr(c, "type")); //appending type to the end, otherwise wrong type + String *lisp_type = get_ffi_type(n, temp); + Delete(temp); - String *slot_name = Getattr(c, "sym:name"); - Printf(f_cl, "\n\t(%s %s)", slot_name, lisp_type); + String *slot_name = Getattr(c, "sym:name"); + Printf(f_cl, "\n\t(%s %s)", slot_name, lisp_type); - Append(entries, NewStringf("%s-%s", name, slot_name)); + Append(entries, NewStringf("%s-%s", name, slot_name)); - Delete(lisp_type); + Delete(lisp_type); + } } Printf(f_cl, ")\n"); diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx index 8ffd9768a..1444dbd87 100644 --- a/Source/Modules/csharp.cxx +++ b/Source/Modules/csharp.cxx @@ -1640,10 +1640,10 @@ public: base = Next(base); continue; } - String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); - String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); - Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, - "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#.\n", proxyclassname, baseclassname); + String *proxyclassname = Getattr(n, "classtypeobj"); + String *baseclassname = Getattr(base.item, "name"); + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname)); base = Next(base); } } @@ -1661,9 +1661,9 @@ public: Delete(baseclass); baseclass = NULL; if (purebase_notderived) - Swig_error(input_file, line_number, "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + Swig_error(Getfile(n), Getline(n), "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { - Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#. " "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); } @@ -1704,10 +1704,10 @@ public: } if (tm && *Char(tm)) { if (!destruct_methodname) { - Swig_error(input_file, line_number, "No methodname attribute defined in csdestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in csdestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); } if (!destruct_methodmodifiers) { - Swig_error(input_file, line_number, + Swig_error(Getfile(n), Getline(n), "No methodmodifiers attribute defined in csdestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); } } @@ -2292,17 +2292,24 @@ public: String *ex_imcall = Copy(imcall); Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); Replaceall(imcall, "$imfuncname", intermediary_function_name); - String *excode = NewString(""); - if (!Cmp(return_type, "void")) - Printf(excode, "if (this.GetType() == typeof(%s)) %s; else %s", proxy_class_name, imcall, ex_imcall); - else - Printf(excode, "((this.GetType() == typeof(%s)) ? %s : %s)", proxy_class_name, imcall, ex_imcall); + Node *directorNode = Getattr(n, "directorNode"); + if (directorNode) { + UpcallData *udata = Getattr(directorNode, "upcalldata"); + String *methid = Getattr(udata, "class_methodidx"); - Clear(imcall); - Printv(imcall, excode, NIL); - Delete(ex_overloaded_name); + if (!Cmp(return_type, "void")) + Printf(excode, "if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s)) %s; else %s", proxy_function_name, methid, ex_imcall, imcall); + else + Printf(excode, "(SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s) ? %s : %s)", proxy_function_name, methid, ex_imcall, imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + } else { + // probably an ignored method or nodirector + } Delete(excode); + Delete(ex_overloaded_name); } else { Replaceall(imcall, "$imfuncname", intermediary_function_name); } @@ -2343,6 +2350,7 @@ public: SwigType *pt = Getattr(p, "type"); if ((tm = Getattr(p, "tmap:csvarin"))) { substituteClassname(pt, tm); + Replaceall(tm, "$csinput", "value"); Replaceall(tm, "$imcall", imcall); excodeSubstitute(n, tm, "csvarin", p); Printf(proxy_class_code, "%s", tm); @@ -3472,7 +3480,6 @@ public: String *callback_def = NewString(""); String *callback_code = NewString(""); String *imcall_args = NewString(""); - int gencomma = 0; bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; // Kludge Alert: functionWrapper sets sym:overload properly, but it @@ -3616,14 +3623,14 @@ public: Printf(w->code, "} else {\n"); /* Go through argument list, convert from native to Java */ - for (p = l; p; /* empty */ ) { + for (i = 0, p = l; p; ++i) { /* Is this superfluous? */ while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { p = Getattr(p, "tmap:directorin:next"); } SwigType *pt = Getattr(p, "type"); - String *ln = Copy(Getattr(p, "name")); + String *ln = makeParameterName(n, p, i, false); String *c_param_type = NULL; String *c_decl = NewString(""); String *arg = NewString(""); @@ -3631,7 +3638,7 @@ public: Printf(arg, "j%s", ln); /* And add to the upcall args */ - if (gencomma > 0) + if (i > 0) Printf(jupcall_args, ", "); Printf(jupcall_args, "%s", arg); @@ -3641,17 +3648,13 @@ public: if (ctypeout) c_param_type = ctypeout; - Parm *tp = NewParm(c_param_type, empty_str, n); - String *desc_tm = NULL; - /* Add to local variables */ Printf(c_decl, "%s %s", c_param_type, arg); if (!ignored_method) Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); /* Add input marshalling code */ - if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) - && (tm = Getattr(p, "tmap:directorin"))) { + if ((tm = Getattr(p, "tmap:directorin"))) { Replaceall(tm, "$input", arg); Replaceall(tm, "$owner", "0"); @@ -3663,7 +3666,7 @@ public: Delete(tm); /* Add C type to callback typedef */ - if (gencomma > 0) + if (i > 0) Printf(callback_typedef_parms, ", "); Printf(callback_typedef_parms, "%s", c_param_type); @@ -3684,7 +3687,7 @@ public: substituteClassname(pt, din); Replaceall(din, "$iminput", ln); - if (gencomma > 0) { + if (i > 0) { Printf(delegate_parms, ", "); Printf(proxy_method_types, ", "); Printf(imcall_args, ", "); @@ -3716,24 +3719,13 @@ public: p = Getattr(p, "tmap:directorin:next"); - Delete(desc_tm); } else { - if (!desc_tm) { - Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, - "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", - SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); - p = nextSibling(p); - } else if (!tm) { - Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, - "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", - SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); - p = nextSibling(p); - } - + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); output_director = false; } - - Delete(tp); } else { Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); @@ -3741,7 +3733,7 @@ public: p = nextSibling(p); } - gencomma++; + Delete(ln); Delete(arg); Delete(c_decl); Delete(c_param_type); @@ -3884,6 +3876,10 @@ public: /* Emit the actual upcall through */ UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name); String *methid = Getattr(udata, "class_methodidx"); + Setattr(n, "upcalldata", udata); + /* + Printf(stdout, "setting upcalldata, nodeType: %s %s::%s %p\n", nodeType(n), classname, Getattr(n, "name"), n); + */ Printf(director_callback_typedefs, " typedef %s (SWIGSTDCALL* SWIG_Callback%s_t)(", c_ret_type, methid); Printf(director_callback_typedefs, "%s);\n", callback_typedef_parms); diff --git a/Source/Modules/d.cxx b/Source/Modules/d.cxx new file mode 100644 index 000000000..cc1bd2365 --- /dev/null +++ b/Source/Modules/d.cxx @@ -0,0 +1,4351 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at http://www.swig.org/legal.html. + * + * d.cxx + * + * D language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_d_cxx[] = "$Id$"; + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +// Hash type used for storing information about director callbacks for a class. +typedef DOH UpcallData; + +class D : public Language { + static const char *usage; + const String *empty_string; + const String *public_string; + const String *protected_string; + const String *static_string; + + /* + * Files and file sections containing C/C++ code. + */ + File *f_begin; + File *f_runtime; + File *f_runtime_h; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_directors; + File *f_directors_h; + List *filenames_list; + + /* + * Command line-set modes of operation. + */ + // Whether a single proxy D module is generated or classes and enums are + // written to their own files. + bool split_proxy_dmodule; + + // The major D version targeted (currently 1 or 2). + unsigned short d_version; + + /* + * State variables which indicate what is being wrapped at the moment. + * This is probably not the most elegant way of handling state, but it has + * proven to work in the C# and Java modules. + */ + // Indicates if wrapping a native function. + bool native_function_flag; + + // Indicates if wrapping a static functions or member variables + bool static_flag; + + // Indicates if wrapping a nonstatic member variable + bool variable_wrapper_flag; + + // Indicates if wrapping a member variable/enum/const. + bool wrapping_member_flag; + + // Indicates if wrapping a global variable. + bool global_variable_flag; + + // Name of a variable being wrapped. + String *variable_name; + + /* + * Variables temporarily holding the generated C++ code. + */ + // C++ code for the generated wrapper functions for casts up the C++ + // for inheritance hierarchies. + String *upcasts_code; + + // Function pointer typedefs for handling director callbacks on the C++ side. + String *director_callback_typedefs; + + // Variables for storing the function pointers to the director callbacks on + // the C++ side. + String *director_callback_pointers; + + /* + * Names of generated D entities. + */ + // The name of the D module containing the interface to the C wrapper. + String *im_dmodule_name; + + // The fully qualified name of the wrap D module (package name included). + String *im_dmodule_fq_name; + + // The name of the proxy module which exposes the (SWIG) module contents as a + // D module. + String *proxy_dmodule_name; + + // The fully qualified name of the proxy D module. + String *proxy_dmodule_fq_name; + + // Optional: Package the D modules are placed in (set via the -package + // command line option). + String *package; + + // The directory the generated D module files are written to. Is constructed + // from the package path if a target package is set, points to the general + // output directory otherwise. + String *dmodule_directory; + + // The name of the library which contains the C wrapper (used when generating + // the dynamic library loader). Can be overridden via the -wrapperlibrary + // command line flag. + String *wrap_library_name; + + /* + * Variables temporarily holding the generated D code. + */ + // Import statements written to the intermediary D module header set via + // %pragma(d) imdmoduleimports. + String *im_dmodule_imports; + + // The code for the intermediary D module body. + String *im_dmodule_code; + + // Import statements for all proxy modules (the main proxy module and, if in + // 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(). + 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; + + // The D code generated for the currently processed enum. + String *proxy_enum_code; + + /* + * D data for the current proxy class. + */ + // The name of the current proxy class. + String *proxy_class_name; + + // The import directives for the current proxy class. They are written to the + // same D module the proxy class is written to. + String *proxy_class_imports; + + // Code for enumerations nested in the current proxy class. Is emitted earlier + // than the rest of the body to work around forward referencing-issues. + String *proxy_class_enums_code; + + // The generated D code making up the body of the current proxy class. + String *proxy_class_body_code; + + // D code which is emitted right after the proxy class. + String *proxy_class_epilogue_code; + + // The full code for the current proxy class, including the epilogue. + String* proxy_class_code; + + // Contains a D call to the function wrapping C++ the destructor of the + // current class (if there is a public C++ destructor). + String *destructor_call; + + // D code for the director callbacks generated for the current class. + String *director_dcallbacks_code; + + /* + * Code for dynamically loading the wrapper library on the D side. + */ + // D code which is inserted into the im D module if dynamic linking is used. + String *wrapper_loader_code; + + // The D code to bind a function pointer to a library symbol. + String *wrapper_loader_bind_command; + + // The cumulated binding commands binding all the functions declared in the + // intermediary D module to the C/C++ library symbols. + String *wrapper_loader_bind_code; + + /* + * Director data. + */ + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int first_class_dmethod; + int curr_class_dmethod; + + /* + * SWIG types data. + */ + // Collects information about encountered types SWIG does not know about (e.g. + // incomplete types). This is used later to generate type wrapper proxy + // classes for the unknown types. + Hash *unknown_types; + + +public: + /* --------------------------------------------------------------------------- + * D::D() + * --------------------------------------------------------------------------- */ + D():empty_string(NewString("")), + public_string(NewString("public")), + protected_string(NewString("protected")), + f_begin(NULL), + f_runtime(NULL), + f_runtime_h(NULL), + f_header(NULL), + f_wrappers(NULL), + f_init(NULL), + f_directors(NULL), + f_directors_h(NULL), + filenames_list(NULL), + split_proxy_dmodule(false), + d_version(1), + native_function_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + variable_name(NULL), + upcasts_code(NULL), + director_callback_typedefs(NULL), + director_callback_pointers(NULL), + im_dmodule_name(NULL), + im_dmodule_fq_name(NULL), + proxy_dmodule_name(NULL), + proxy_dmodule_fq_name(NULL), + package(NULL), + dmodule_directory(NULL), + wrap_library_name(NULL), + im_dmodule_imports(NULL), + im_dmodule_code(NULL), + global_proxy_imports(NULL), + proxy_dmodule_imports(NULL), + proxy_dmodule_code(NULL), + proxy_enum_code(NULL), + proxy_class_name(NULL), + proxy_class_imports(NULL), + proxy_class_enums_code(NULL), + proxy_class_body_code(NULL), + proxy_class_epilogue_code(NULL), + proxy_class_code(NULL), + destructor_call(NULL), + director_dcallbacks_code(NULL), + wrapper_loader_code(NULL), + wrapper_loader_bind_command(NULL), + wrapper_loader_bind_code(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + unknown_types(NULL) { + + // For now, multiple inheritance with directors is not possible. It should be + // easy to implement though. + director_multiple_inheritance = 0; + director_language = 1; + + // Not used: + Delete(none_comparison); + none_comparison = NewString(""); + } + + /* --------------------------------------------------------------------------- + * D::main() + * --------------------------------------------------------------------------- */ + virtual void main(int argc, char *argv[]) { + SWIG_library_directory("d"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if ((strcmp(argv[i], "-d2") == 0)) { + Swig_mark_arg(i); + d_version = 2; + } else if (strcmp(argv[i], "-wrapperlibrary") == 0) { + if (argv[i + 1]) { + wrap_library_name = NewString(""); + Printf(wrap_library_name, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-package") == 0) { + if (argv[i + 1]) { + package = NewString(""); + Printf(package, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-splitproxy") == 0)) { + Swig_mark_arg(i); + split_proxy_dmodule = true; + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGD 1", 0); + + // Also make the target D version available as preprocessor symbol for + // use in our library files. + String *version_define = NewStringf("SWIG_D_VERSION %u", d_version); + Preprocessor_define(version_define, 0); + Delete(version_define); + + // Add typemap definitions + SWIG_typemap_lang("d"); + SWIG_config_file("d.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------------- + * D::top() + * --------------------------------------------------------------------------- */ + virtual int top(Node *n) { + // Get any options set in the module directive + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + + if (optionsnode) { + if (Getattr(optionsnode, "imdmodulename")) { + im_dmodule_name = Copy(Getattr(optionsnode, "imdmodulename")); + } + + if (Getattr(optionsnode, "directors")) { + // Check if directors are enabled for this module. Note: This is a + // "master switch", if it is not set, not director code will be emitted + // at all. %feature("director") statements are also required to enable + // directors for individual classes or methods. + // + // Use the »directors« attributte of the %module directive to enable + // director generation (e.g. »%module(directors="1") modulename«). + allow_directors(); + } + + if (Getattr(optionsnode, "dirprot")) { + allow_dirprot(); + } + + allow_allprotected(GetFlag(optionsnode, "allprotected")); + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + if (!outfile) { + Printf(stderr, "Unable to determine outfile\n"); + SWIG_exit(EXIT_FAILURE); + } + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + if (directorsEnabled()) { + if (!outfile_h) { + Printf(stderr, "Unable to determine outfile_h\n"); + SWIG_exit(EXIT_FAILURE); + } + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + unknown_types = NewHash(); + filenames_list = NewList(); + + // Make the package name and the resulting module output path. + if (package) { + // Append a dot so we can prepend the package variable directly to the + // module names in the rest of the code. + Printv(package, ".", NIL); + } else { + // Write the generated D modules to the »root« package by default. + package = NewString(""); + } + + dmodule_directory = Copy(SWIG_output_directory()); + if (Len(package) > 0) { + String *package_directory = Copy(package); + Replaceall(package_directory, ".", SWIG_FILE_DELIMITER); + Printv(dmodule_directory, package_directory, NIL); + Delete(package_directory); + } + + // Make the wrap and proxy D module names. + // The wrap module name can be set in the module directive. + if (!im_dmodule_name) { + im_dmodule_name = NewStringf("%s_im", Getattr(n, "name")); + } + im_dmodule_fq_name = NewStringf("%s%s", package, im_dmodule_name); + proxy_dmodule_name = Copy(Getattr(n, "name")); + proxy_dmodule_fq_name = NewStringf("%s%s", package, proxy_dmodule_name); + + im_dmodule_code = NewString(""); + proxy_class_imports = NewString(""); + proxy_class_enums_code = NewString(""); + proxy_class_body_code = NewString(""); + proxy_class_epilogue_code = NewString(""); + proxy_class_code = NewString(""); + destructor_call = NewString(""); + proxy_dmodule_code = NewString(""); + proxy_dmodule_imports = NewString(""); + im_dmodule_imports = NewString(""); + upcasts_code = NewString(""); + global_proxy_imports = NewString(""); + wrapper_loader_code = NewString(""); + wrapper_loader_bind_command = NewString(""); + wrapper_loader_bind_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + + // By default, expect the dynamically loaded wrapper library to be named + // [lib]<module>_wrap[.so/.dll]. + if (!wrap_library_name) + wrap_library_name = NewStringf("%s_wrap", Getattr(n, "name")); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGD\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + + /* Emit initial director header and director code: */ + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", proxy_dmodule_name); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", proxy_dmodule_name); + + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + if (outfile_h) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + Printf(f_runtime, "\n"); + + Swig_name_register("wrapper", "D_%f"); + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + // Emit all the wrapper code. + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (before %header section). + Swig_insert_file("director.swg", f_runtime); + } + + // Generate the wrap D module. + // TODO: Add support for »static« linking. + { + String *filen = NewStringf("%s%s.d", dmodule_directory, im_dmodule_name); + File *im_d_file = NewFile(filen, "w", SWIG_output_files()); + if (!im_d_file) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the intermediary class file. + emitBanner(im_d_file); + + Printf(im_d_file, "module %s;\n", im_dmodule_fq_name); + + Printv(im_d_file, im_dmodule_imports, "\n", NIL); + + Replaceall(wrapper_loader_code, "$wraplibrary", wrap_library_name); + Replaceall(wrapper_loader_code, "$wrapperloaderbindcode", wrapper_loader_bind_code); + Replaceall(wrapper_loader_code, "$module", proxy_dmodule_name); + Printf(im_d_file, "%s\n", wrapper_loader_code); + + // Add the wrapper function declarations. + replaceModuleVariables(im_dmodule_code); + Printv(im_d_file, im_dmodule_code, NIL); + + Close(im_d_file); + } + + // Generate the D proxy module for the wrapped module. + { + String *filen = NewStringf("%s%s.d", dmodule_directory, proxy_dmodule_name); + File *proxy_d_file = NewFile(filen, "w", SWIG_output_files()); + if (!proxy_d_file) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + emitBanner(proxy_d_file); + + Printf(proxy_d_file, "module %s;\n", proxy_dmodule_fq_name); + Printf(proxy_d_file, "\nstatic import %s;\n", im_dmodule_fq_name); + Printv(proxy_d_file, global_proxy_imports, NIL); + Printv(proxy_d_file, proxy_dmodule_imports, NIL); + Printv(proxy_d_file, "\n", NIL); + + // Write a D type wrapper class for each SWIG type to the proxy module code. + for (Iterator swig_type = First(unknown_types); swig_type.key; swig_type = Next(swig_type)) { + writeTypeWrapperClass(swig_type.key, swig_type.item); + } + + // Add the proxy functions (and classes, if they are not written to a + // seperate file). + replaceModuleVariables(proxy_dmodule_code); + Printv(proxy_d_file, proxy_dmodule_code, NIL); + + Close(proxy_d_file); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Check for overwriting file problems on filesystems that are case insensitive + Iterator it1; + Iterator it2; + for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { + String *item1_lower = Swig_string_lower(it1.item); + for (it2 = Next(it1); it2.item; it2 = Next(it2)) { + String *item2_lower = Swig_string_lower(it2.item); + if (it1.item && it2.item) { + if (Strcmp(item1_lower, item2_lower) == 0) { + Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, + "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " + "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); + } + } + Delete(item2_lower); + } + Delete(item1_lower); + } + + Delete(unknown_types); + unknown_types = NULL; + Delete(filenames_list); + filenames_list = NULL; + Delete(im_dmodule_name); + im_dmodule_name = NULL; + Delete(im_dmodule_fq_name); + im_dmodule_fq_name = NULL; + Delete(im_dmodule_code); + im_dmodule_code = NULL; + Delete(proxy_class_imports); + proxy_class_imports = NULL; + Delete(proxy_class_enums_code); + proxy_class_enums_code = NULL; + Delete(proxy_class_body_code); + proxy_class_body_code = NULL; + Delete(proxy_class_epilogue_code); + proxy_class_epilogue_code = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(destructor_call); + destructor_call = NULL; + Delete(proxy_dmodule_name); + proxy_dmodule_name = NULL; + Delete(proxy_dmodule_fq_name); + proxy_dmodule_fq_name = NULL; + Delete(proxy_dmodule_code); + proxy_dmodule_code = NULL; + Delete(proxy_dmodule_imports); + proxy_dmodule_imports = NULL; + Delete(im_dmodule_imports); + im_dmodule_imports = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(global_proxy_imports); + global_proxy_imports = NULL; + Delete(wrapper_loader_code); + wrapper_loader_code = NULL; + Delete(wrapper_loader_bind_code); + wrapper_loader_bind_code = NULL; + Delete(wrapper_loader_bind_command); + wrapper_loader_bind_command = NULL; + Delete(dmethods_seq); + dmethods_seq = NULL; + Delete(dmethods_table); + dmethods_table = NULL; + Delete(package); + package = NULL; + Delete(dmodule_directory); + dmodule_directory = NULL; + n_dmethods = 0; + + // Merge all the generated C/C++ code and close the output files. + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors, f_begin); + Dump(f_directors_h, f_runtime_h); + + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + + Close(f_runtime_h); + Delete(f_runtime_h); + f_runtime_h = NULL; + Delete(f_directors); + f_directors = NULL; + Delete(f_directors_h); + f_directors_h = NULL; + } + + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::insertDirective() + * --------------------------------------------------------------------------- */ + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + replaceModuleVariables(code); + return Language::insertDirective(n); + } + + /* --------------------------------------------------------------------------- + * D::pragmaDirective() + * + * Valid Pragmas: + * imdmodulecode - text (D code) is copied verbatim to the wrap module + * imdmoduleimports - import statements for the im D module + * + * proxydmodulecode - text (D code) is copied verbatim to the proxy module + * (the main proxy module if in split proxy mode). + * globalproxyimports - import statements inserted into _all_ proxy modules. + * + * wrapperloadercode - D code for loading the wrapper library (is copied to + * the im D module). + * wrapperloaderbindcommand - D code for binding a symbol from the wrapper + * library to the declaration in the im D module. + * --------------------------------------------------------------------------- */ + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *code = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "d") == 0) { + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); + + if (Strcmp(code, "imdmodulecode") == 0) { + Printf(im_dmodule_code, "%s\n", strvalue); + } else if (Strcmp(code, "imdmoduleimports") == 0) { + replaceImportTypeMacros(strvalue); + Chop(strvalue); + Printf(im_dmodule_imports, "%s\n", strvalue); + } else if (Strcmp(code, "proxydmodulecode") == 0) { + Printf(proxy_dmodule_code, "%s\n", strvalue); + } else if (Strcmp(code, "globalproxyimports") == 0) { + replaceImportTypeMacros(strvalue); + Chop(strvalue); + Printf(global_proxy_imports, "%s\n", strvalue); + } else if (Strcmp(code, "wrapperloadercode") == 0) { + Delete(wrapper_loader_code); + wrapper_loader_code = Copy(strvalue); + } else if (Strcmp(code, "wrapperloaderbindcommand") == 0) { + Delete(wrapper_loader_bind_command); + wrapper_loader_bind_command = Copy(strvalue); + } else { + Swig_error(input_file, line_number, "Unrecognized pragma.\n"); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* --------------------------------------------------------------------------- + * D::enumDeclaration() + * + * Wraps C/C++ enums as D enums. + * --------------------------------------------------------------------------- */ + virtual int enumDeclaration(Node *n) { + if (ImportMode) + return SWIG_OK; + + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + proxy_enum_code = NewString(""); + String *symname = Getattr(n, "sym:name"); + String *typemap_lookup_type = Getattr(n, "name"); + + // Emit the enum declaration. + if (typemap_lookup_type) { + const String *enummodifiers = lookupCodeTypemap(n, "dclassmodifiers", typemap_lookup_type, WARN_D_TYPEMAP_CLASSMOD_UNDEF); + Printv(proxy_enum_code, "\n", enummodifiers, " ", symname, " {\n", NIL); + } else { + // Handle anonymous enums. + Printv(proxy_enum_code, "\nenum {\n", NIL); + } + + // Emit each enum item. + Language::enumDeclaration(n); + + if (!GetFlag(n, "nonempty")) { + // Do not wrap empty enums; the resulting D code would be illegal. + Delete(proxy_enum_code); + return SWIG_NOWRAP; + } + + // Finish the enum. + if (typemap_lookup_type) { + Printv(proxy_enum_code, + lookupCodeTypemap(n, "dcode", typemap_lookup_type, WARN_NONE), // Extra D code + "\n}\n", NIL); + } else { + // Handle anonymous enums. + Printv(proxy_enum_code, "\n}\n", NIL); + } + + Replaceall(proxy_enum_code, "$dclassname", symname); + + const String* imports = + lookupCodeTypemap(n, "dimports", typemap_lookup_type, WARN_NONE); + String* imports_trimmed; + if (Len(imports) > 0) { + imports_trimmed = Copy(imports); + Chop(imports_trimmed); + replaceImportTypeMacros(imports_trimmed); + Printv(imports_trimmed, "\n", NIL); + } else { + imports_trimmed = NewString(""); + } + + if (is_wrapping_class()) { + // Enums defined within the C++ class are written into the proxy + // class. + Printv(proxy_class_imports, imports_trimmed, NIL); + Printv(proxy_class_enums_code, proxy_enum_code, NIL); + } else { + // Write non-anonymous enums to their own file if in split proxy module + // mode. + if (split_proxy_dmodule && typemap_lookup_type) { + assertClassNameValidity(proxy_class_name); + + String *filename = NewStringf("%s%s.d", dmodule_directory, symname); + File *class_file = NewFile(filename, "w", SWIG_output_files()); + if (!class_file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filename)); + Delete(filename); + + emitBanner(class_file); + Printf(class_file, "module %s%s;\n", package, symname); + Printv(class_file, imports_trimmed, NIL); + + Printv(class_file, proxy_enum_code, NIL); + + Close(class_file); + Delete(class_file); + } else { + Printv(proxy_dmodule_imports, imports, NIL); + Printv(proxy_dmodule_code, proxy_enum_code, NIL); + } + } + + Delete(imports_trimmed); + + Delete(proxy_enum_code); + proxy_enum_code = NULL; + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::enumvalueDeclaration() + * --------------------------------------------------------------------------- */ + 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"); + Node *parent = parentNode(n); + String *tmpValue; + + // Strange hack from parent method. + // RESEARCH: What is this doing? + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + // 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); + + // Check for the %dconstvalue feature + String *value = Getattr(n, "feature:d:constvalue"); + + // Note that in D, enum values must be compile-time constants. Thus, + // %dmanifestconst(0) (getting the enum values at runtime) is not supported. + value = value ? value : Getattr(n, "enumvalue"); + if (value) { + Printf(proxy_enum_code, " = %s", value); + } + + // Keep track that the currently processed enum has at least one value. + SetFlag(parent, "nonempty"); + } + + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::memberfunctionHandler() + * --------------------------------------------------------------------------- */ + virtual int memberfunctionHandler(Node *n) { + Language::memberfunctionHandler(n); + + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = + Swig_name_member(NSPACE_TODO,proxy_class_name, overloaded_name); + Setattr(n, "imfuncname", intermediary_function_name); + + String *proxy_func_name = Getattr(n, "sym:name"); + Setattr(n, "proxyfuncname", proxy_func_name); + if (split_proxy_dmodule && + Len(Getattr(n, "parms")) == 0 && + Strncmp(proxy_func_name, package, Len(proxy_func_name)) == 0) { + // 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. + 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); + } + + writeProxyClassFunction(n); + + Delete(overloaded_name); + + // For each function, look if we have to alias in the parent class function + // for the overload resolution process to work as expected from C++ + // (http://www.digitalmars.com/d/2.0/function.html#function-inheritance). + // For multiple overloads, only emit the alias directive once (for the + // last method, »sym:nextSibling« is null then). + // Smart pointer classes do not mirror the inheritance hierarchy of the + // underlying types, so aliasing the base class methods in is not required + // for them. + // DMD BUG: We have to emit the alias after the last function becasue + // taking a delegate in the overload checking code fails otherwise + // (http://d.puremagic.com/issues/show_bug.cgi?id=4860). + if (!Getattr(n, "sym:nextSibling") && !is_smart_pointer() && + !areAllOverloadsOverridden(n)) { + String *name = Getattr(n, "sym:name"); + Printf(proxy_class_body_code, "\nalias $dbaseclass.%s %s;\n", name, name); + } + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::staticmemberfunctionHandler() + * --------------------------------------------------------------------------- */ + virtual int staticmemberfunctionHandler(Node *n) { + static_flag = true; + + Language::staticmemberfunctionHandler(n); + + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = + Swig_name_member(NSPACE_TODO,proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + writeProxyClassFunction(n); + Delete(overloaded_name); + + static_flag = false; + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::globalvariableHandler() + * --------------------------------------------------------------------------- */ + virtual int globalvariableHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + + return ret; + } + + /* --------------------------------------------------------------------------- + * D::membervariableHandler() + * --------------------------------------------------------------------------- */ + virtual int membervariableHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::staticmembervariableHandler() + * --------------------------------------------------------------------------- */ + virtual int staticmembervariableHandler(Node *n) { + if (GetFlag(n, "feature:d:manifestconst") != 1) { + Delattr(n, "value"); + } + + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::memberconstantHandler() + * --------------------------------------------------------------------------- */ + virtual int memberconstantHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + Language::memberconstantHandler(n); + wrapping_member_flag = false; + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::constructorHandler() + * --------------------------------------------------------------------------- */ + virtual int constructorHandler(Node *n) { + Language::constructorHandler(n); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in D. + if (Getattr(n, "overload:ignore")) { + return SWIG_OK; + } + + ParmList *l = Getattr(n, "parms"); + String *tm; + String *proxy_constructor_code = NewString(""); + int i; + + // Holds code for the constructor helper method generated only when the din + // typemap has code in the pre or post attributes. + String *helper_code = NewString(""); + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + NewString(""); + + String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(NSPACE_TODO,overloaded_name); + String *imcall = NewString(""); + + const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + // Typemaps were attached earlier to the node, get the return type of the + // call to the C++ constructor wrapper. + const String *wrapper_return_type = lookupDTypemap(n, "imtype", true); + + String *imtypeout = Getattr(n, "tmap:imtype:out"); + if (imtypeout) { + // The type in the imtype typemap's out attribute overrides the type in + // the typemap itself. + wrapper_return_type = imtypeout; + } + + Printf(proxy_constructor_code, "\n%s this(", methodmods); + Printf(helper_code, "static private %s SwigConstruct%s(", + wrapper_return_type, proxy_class_name); + + Printv(imcall, im_dmodule_fq_name, ".", mangled_overname, "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("dtype", l, NULL); + Swig_typemap_attach_parms("din", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + /* Output each parameter */ + Parm *p = l; + for (i = 0; p; i++) { + if (checkAttribute(p, "varargs:ignore", "1")) { + // Skip ignored varargs. + p = nextSibling(p); + continue; + } + + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + // Skip ignored parameters. + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + // Get the D parameter type. + if ((tm = lookupDTypemap(p, "dtype", true))) { + const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, false); + String *parmtype = 0; + + // Get the D code to convert the parameter value to the type used in the + // intermediary D module. + if ((tm = lookupDTypemap(p, "din"))) { + Replaceall(tm, "$dinput", arg); + String *pre = Getattr(p, "tmap:din:pre"); + if (pre) { + replaceClassname(pre, pt); + Replaceall(pre, "$dinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:din:post"); + if (post) { + replaceClassname(post, pt); + Replaceall(post, "$dinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:din:terminator"); + if (terminator) { + replaceClassname(terminator, pt); + Replaceall(terminator, "$dinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + parmtype = Getattr(p, "tmap:din:parmtype"); + if (parmtype) + Replaceall(parmtype, "$dinput", arg); + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, + "No din typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma) { + Printf(proxy_constructor_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } + Printf(proxy_constructor_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", parmtype ? parmtype : arg); + ++gencomma; + + Delete(parmtype); + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + + Printf(proxy_constructor_code, ")"); + Printf(helper_code, ")"); + + // Insert the dconstructor typemap (replacing $directorconnect as needed). + Hash *attributes = NewHash(); + String *construct_tm = Copy(lookupCodeTypemap(n, "dconstructor", + Getattr(n, "name"), WARN_D_TYPEMAP_DCONSTRUCTOR_UNDEF, attributes)); + if (construct_tm) { + const bool use_director = (parentNode(n) && Swig_directorclass(n)); + if (!use_director) { + Replaceall(construct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(attributes, "tmap:dconstructor:directorconnect"); + + if (connect_attr) { + Replaceall(construct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_D_NO_DIRECTORCONNECT_ATTR, input_file, line_number, + "\"directorconnect\" attribute missing in %s \"dconstructor\" typemap.\n", + Getattr(n, "name")); + Replaceall(construct_tm, "$directorconnect", ""); + } + } + + Printv(proxy_constructor_code, " ", construct_tm, NIL); + } + + replaceExcode(n, proxy_constructor_code, "dconstructor", attributes); + + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Printf(helper_code, " {\n"); + if (is_pre_code) { + Printv(helper_code, pre_code, "\n", NIL); + } + if (is_post_code) { + Printf(helper_code, " try {\n"); + Printv(helper_code, " return ", imcall, ";\n", NIL); + Printv(helper_code, " } finally {\n", post_code, "\n }", NIL); + } else { + Printv(helper_code, " return ", imcall, ";", NIL); + } + if (is_terminator_code) { + Printv(helper_code, "\n", terminator_code, NIL); + } + Printf(helper_code, "\n}\n"); + String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", + proxy_class_name, proxy_class_name, helper_args); + Replaceall(proxy_constructor_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(proxy_constructor_code, "$imcall", imcall); + } + + Printv(proxy_class_body_code, proxy_constructor_code, "\n", NIL); + + Delete(helper_args); + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(construct_tm); + Delete(attributes); + Delete(overloaded_name); + Delete(imcall); + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::destructorHandler() + * --------------------------------------------------------------------------- */ + 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); + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::classHandler() + * --------------------------------------------------------------------------- */ + virtual int classHandler(Node *n) { + File *class_file = NULL; + + proxy_class_name = Copy(Getattr(n, "sym:name")); + + if (!addSymbol(proxy_class_name, n)) { + return SWIG_ERROR; + } + + assertClassNameValidity(proxy_class_name); + + if (split_proxy_dmodule) { + String *filename = NewStringf("%s%s.d", dmodule_directory, proxy_class_name); + class_file = NewFile(filename, "w", SWIG_output_files()); + if (!class_file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filename)); + Delete(filename); + + emitBanner(class_file); + Printf(class_file, "module %s%s;\n", package, proxy_class_name); + Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name); + } + + Clear(proxy_class_imports); + Clear(proxy_class_enums_code); + Clear(proxy_class_body_code); + Clear(proxy_class_epilogue_code); + Clear(proxy_class_code); + Clear(destructor_call); + + + Language::classHandler(n); + + + writeProxyClassAndUpcasts(n); + writeDirectorConnectWrapper(n); + + Replaceall(proxy_class_code, "$dclassname", proxy_class_name); + + if (split_proxy_dmodule) { + Printv(class_file, global_proxy_imports, NIL); + Printv(class_file, proxy_class_imports, NIL); + + replaceModuleVariables(proxy_class_code); + Printv(class_file, proxy_class_code, NIL); + + Close(class_file); + Delete(class_file); + } else { + Printv(proxy_dmodule_imports, proxy_class_imports, NIL); + Printv(proxy_dmodule_code, proxy_class_code, NIL); + } + + Delete(proxy_class_name); + proxy_class_name = NULL; + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::constantWrapper() + * + * Used for wrapping constants declared by #define or %constant and also for + * (primitive) static member constants initialised inline. + * + * If the %dmanifestconst feature is used, the C/C++ constant value is used to + * initialize a D »const«. If not, a »getter« method is generated which + * retrieves the value via a call to the C wrapper. However, if there is a + * %dconstvalue specified, it overrides all other settings. + * --------------------------------------------------------------------------- */ + virtual int constantWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + // The %dmanifestconst feature determines if a D manifest constant + // (const/enum) or a getter function is created. + if (GetFlag(n, "feature:d:manifestconst") != 1) { + // Default constant handling will work with any type of C constant. It + // generates a getter function (which is the same as a read only property + // in D) which retrieves the value via by calling the C wrapper. + // Note that this is only called for global constants, static member + // constants are already handeled in staticmemberfunctionHandler(). + + Swig_save("constantWrapper", n, "value", NIL); + + // Add the stripped quotes back in. + String *old_value = Getattr(n, "value"); + SwigType *t = Getattr(n, "type"); + if (SwigType_type(t) == T_STRING) { + Setattr(n, "value", NewStringf("\"%s\"", old_value)); + Delete(old_value); + } else if (SwigType_type(t) == T_CHAR) { + Setattr(n, "value", NewStringf("\'%s\'", old_value)); + Delete(old_value); + } + + int result = globalvariableHandler(n); + + Swig_restore(n); + return result; + } + + String *constants_code = NewString(""); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + // Attach the non-standard typemaps to the parameter list. + Swig_typemap_attach_parms("dtype", l, NULL); + + // Get D return type. + String *return_type = NewString(""); + String *tm; + if ((tm = lookupDTypemap(n, "dtype"))) { + String *dtypeout = Getattr(n, "tmap:dtype:out"); + if (dtypeout) { + // The type in the out attribute of the typemap overrides the type + // in the dtype typemap. + tm = dtypeout; + replaceClassname(tm, t); + } + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + const String *itemname = wrapping_member_flag ? variable_name : symname; + + String *attributes = Getattr(n, "feature:d:methodmodifiers"); + if (attributes) { + attributes = Copy(attributes); + } else { + attributes = Copy(is_public(n) ? public_string : protected_string); + } + + if (d_version == 1) { + if (static_flag) { + Printv(attributes, " static", NIL); + } + Printf(constants_code, "\n%s const %s %s = ", attributes, return_type, itemname); + } else { + Printf(constants_code, "\n%s enum %s %s = ", attributes, return_type, itemname); + } + Delete(attributes); + + // Retrive the override value set via %dconstvalue, if any. + String *override_value = Getattr(n, "feature:d:constvalue"); + if (override_value) { + Printf(constants_code, "%s;\n", override_value); + } else { + // Just take the value from the C definition and hope it compiles in D. + String* value = Getattr(n, "wrappedasconstant") ? + Getattr(n, "staticmembervariableHandler:value") : Getattr(n, "value"); + + // Add the stripped quotes back in. + if (SwigType_type(t) == T_STRING) { + Printf(constants_code, "\"%s\";\n", value); + } else if (SwigType_type(t) == T_CHAR) { + Printf(constants_code, "\'%s\';\n", value); + } else { + Printf(constants_code, "%s;\n", value); + } + } + + // Emit the generated code to appropriate place. + if (wrapping_member_flag) { + Printv(proxy_class_body_code, constants_code, NIL); + } else { + Printv(proxy_dmodule_code, constants_code, NIL); + } + + // Cleanup. + Delete(return_type); + Delete(constants_code); + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::functionWrapper() + * + * Generates the C wrapper code for a function and the corresponding + * declaration in the wrap D module. + * --------------------------------------------------------------------------- */ + virtual int functionWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *c_return_type = NewString(""); + String *im_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + int num_arguments = 0; + int num_required = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(Getattr(n, "sym:name"), n)) + return SWIG_ERROR; + } + + // A new wrapper function object + Wrapper *f = NewWrapper(); + + // Make a wrapper name for this function + String *wname = Swig_name_wrapper(overloaded_name); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("ctype", l, f); + Swig_typemap_attach_parms("imtype", l, f); + + /* Get return types */ + if ((tm = lookupDTypemap(n, "ctype"))) { + String *ctypeout = Getattr(n, "tmap:ctype:out"); + if (ctypeout) { + // The type in the ctype typemap's out attribute overrides the type in + // the typemap itself. + tm = ctypeout; + } + Printf(c_return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, + "No ctype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if ((tm = lookupDTypemap(n, "imtype"))) { + String *imtypeout = Getattr(n, "tmap:imtype:out"); + if (imtypeout) { + // The type in the imtype typemap's out attribute overrides the type in + // the typemap itself. + tm = imtypeout; + } + Printf(im_return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + is_void_return = (Cmp(c_return_type, "void") == 0); + if (!is_void_return) + Wrapper_add_localv(f, "jresult", c_return_type, "jresult", NIL); + + Printv(f->def, " SWIGEXPORT ", c_return_type, " ", wname, "(", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + + // Parameter overloading + Setattr(n, "wrap:parms", l); + Setattr(n, "wrap:name", wname); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in D + if (Getattr(n, "sym:overloaded")) { + // Emit warnings for the few cases that can't be overloaded in D and give up on generating wrapper + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + } + + // Collect the parameter list for the intermediary D module declaration of + // the generated wrapper function. + String *im_dmodule_parameters = NewString("("); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + int gencomma = 0; + + // Now walk the function parameter list and generate code to get arguments + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + String *im_param_type = NewString(""); + String *c_param_type = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* Get the ctype types of the parameter */ + if ((tm = lookupDTypemap(p, "ctype", true))) { + Printv(c_param_type, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Get the intermediary class parameter types of the parameter */ + if ((tm = lookupDTypemap(p, "imtype", true))) { + const String *inattributes = Getattr(p, "tmap:imtype:inattributes"); + Printf(im_param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to intermediary class method */ + if (gencomma) + Printf(im_dmodule_parameters, ", "); + Printf(im_dmodule_parameters, "%s %s", im_param_type, arg); + + // Add parameter to C function + Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + + gencomma = 1; + + // Get typemap for this argument + if ((tm = Getattr(p, "tmap:in"))) { + canThrow(n, "in", p); + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + Delete(im_param_type); + Delete(c_param_type); + Delete(arg); + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + canThrow(n, "check", p); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + canThrow(n, "freearg", p); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + canThrow(n, "argout", p); + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Look for usage of throws typemap and the canthrow flag + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "catchlist"))) { + Swig_typemap_attach_parms("throws", throw_parm_list, f); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + canThrow(n, "throws", p); + } + } + } + + String *null_attribute = 0; + // Now write code to make the function call + if (!native_function_flag) { + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) + Swig_restore(n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + canThrow(n, "out", n); + Replaceall(tm, "$result", "jresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s", tm); + null_attribute = Getattr(n, "tmap:out:null"); + if (Len(tm)) + Printf(f->code, "\n"); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); + } + emit_return_variable(n, t, f); + } + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + canThrow(n, "newfree", n); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if (!native_function_flag) { + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + canThrow(n, "ret", n); + Printf(f->code, "%s\n", tm); + } + } + + // Complete D im parameter list and emit the declaration/binding code. + Printv(im_dmodule_parameters, ")", NIL); + writeImDModuleFunction(overloaded_name, im_return_type, + im_dmodule_parameters, wname); + Delete(im_dmodule_parameters); + + // Finish C function header. + Printf(f->def, ") {"); + + if (!is_void_return) + Printv(f->code, " return jresult;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + /* Contract macro modification */ + if (Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, ") > 0) { + Setattr(n, "d:canthrow", "1"); + } + + if (!null_attribute) + Replaceall(f->code, "$null", "0"); + else + Replaceall(f->code, "$null", null_attribute); + + /* Dump the function out */ + if (!native_function_flag) { + Wrapper_print(f, f_wrappers); + + // Handle %exception which sets the canthrow attribute. + if (Getattr(n, "feature:except:canthrow")) { + Setattr(n, "d:canthrow", "1"); + } + + // A very simple check (it is not foolproof) to assist typemap writers + // with setting the correct features when the want to throw D exceptions + // from C++ code. It checks for the common methods which set + // a pending D exception and issues a warning if one of them has been found + // in the typemap, but the »canthrow« attribute/feature is not set. + if (!Getattr(n, "d:canthrow")) { + if (Strstr(f->code, "SWIG_exception")) { + Swig_warning(WARN_D_CANTHROW_MISSING, input_file, line_number, + "C code contains a call to SWIG_exception and D code does not handle pending exceptions via the canthrow attribute.\n"); + } else if (Strstr(f->code, "SWIG_DSetPendingException")) { + Swig_warning(WARN_D_CANTHROW_MISSING, input_file, line_number, + "C code contains a call to a SWIG_DSetPendingException method and D code does not handle pending exceptions via the canthrow attribute.\n"); + } + } + } + + // If we are not processing an enum or constant, and we were not generating + // a wrapper function which will be accessed via a proxy class, write a + // function to the proxy D module. + if (!is_wrapping_class()) { + writeProxyDModuleFunction(n); + } + + // If we are processing a public member variable, write the property-style + // member function to the proxy class. + if (wrapping_member_flag) { + Setattr(n, "proxyfuncname", variable_name); + Setattr(n, "imfuncname", symname); + + writeProxyClassFunction(n); + } + + Delete(c_return_type); + Delete(im_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(overloaded_name); + DelWrapper(f); + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::nativeWrapper() + * --------------------------------------------------------------------------- */ + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + if (Getattr(n, "type")) { + Swig_save("nativeWrapper", n, "name", NIL); + Setattr(n, "name", wrapname); + native_function_flag = true; + functionWrapper(n); + Swig_restore(n); + native_function_flag = false; + } else { + Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name")); + } + + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::classDirector() + * --------------------------------------------------------------------------- */ + virtual int classDirector(Node *n) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + + int success = Language::classDirector(n); + + Delete(proxy_class_name); + proxy_class_name = NULL; + + return success; + } + + + /* --------------------------------------------------------------------------- + * D::classDirectorInit() + * --------------------------------------------------------------------------- */ + virtual int classDirectorInit(Node *n) { + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + // Write C++ director class declaration, for example: + // class SwigDirector_myclass : public myclass, public Swig::Director { + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *declaration = Swig_class_declaration(n, directorname); + const String *base = Getattr(n, "classtype"); + + Printf(f_directors_h, + "%s : public %s, public Swig::Director {\n", declaration, base); + Printf(f_directors_h, "\npublic:\n"); + + Delete(declaration); + Delete(directorname); + Delete(classname); + + // Stash for later. + Setattr(n, "director:ctor", NewString("Swig::Director()")); + + // Keep track of the director methods for this class. + first_class_dmethod = curr_class_dmethod = n_dmethods; + + director_callback_typedefs = NewString(""); + director_callback_pointers = NewString(""); + director_dcallbacks_code = NewString(""); + + return Language::classDirectorInit(n); + } + + /* --------------------------------------------------------------------------- + * D::classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying D object. + * --------------------------------------------------------------------------- */ + virtual int classDirectorMethod(Node *n, Node *parent, String *super) { + String *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *returntype = Getattr(n, "returntype"); + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *tm; + Parm *p; + int i; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(returntype, "void")); + String *qualified_return = NewString(""); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + int status = SWIG_OK; + bool output_director = true; + String *dirclassname = getDirectorClassName(parent); + String *qualified_name = NewStringf("%s::%s", dirclassname, name); + SwigType *c_ret_type = NULL; + String *dcallback_call_args = NewString(""); + String *imclass_dmethod; + String *callback_typedef_parms = NewString(""); + String *delegate_parms = NewString(""); + String *proxy_method_param_list = NewString(""); + String *proxy_callback_return_type = NewString(""); + String *callback_def = NewString(""); + String *callback_code = NewString(""); + String *imcall_args = NewString(""); + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + // Kludge Alert: functionWrapper sets sym:overload properly, but it + // isn't at this point, so we have to manufacture it ourselves. At least + // 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)); + + if (returntype) { + qualified_return = SwigType_rcaststr(returntype, "c_result"); + + if (!is_void && !ignored_method) { + if (!SwigType_isclass(returntype)) { + if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + String *base_typename = SwigType_base(returntype); + String *resolved_typename = SwigType_typedef_resolve_all(base_typename); + Symtab *symtab = Getattr(n, "sym:symtab"); + Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + + if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default - if a D exception occurs, then the pointer returns + something other than a NULL-initialized reference. */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= &result_default", NIL); + + Delete(non_ref_type); + } + + Delete(base_typename); + Delete(resolved_typename); + } + } else { + SwigType *vt; + + vt = cplus_value_type(returntype); + if (!vt) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); + Delete(vt); + } + } + } + + /* Create the intermediate class wrapper */ + Parm *tp = NewParm(returntype, empty_str, n); + + tm = lookupDTypemap(tp, "imtype"); + if (tm) { + String *imtypeout = Getattr(tp, "tmap:imtype:out"); + if (imtypeout) { + // The type in the imtype typemap's out attribute overrides the type + // in the typemap. + tm = imtypeout; + } + Printf(callback_def, "\nprivate extern(C) %s swigDirectorCallback_%s_%s(void* dObject", tm, classname, overloaded_name); + Printv(proxy_callback_return_type, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, + "No imtype typemap defined for %s\n", SwigType_str(returntype, 0)); + } + + Parm *retpm = NewParm(returntype, empty_str, n); + + if ((c_ret_type = Swig_typemap_lookup("ctype", retpm, "", 0))) { + if (!is_void && !ignored_method) { + String *jretval_decl = NewStringf("%s jresult", c_ret_type); + Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); + Delete(jretval_decl); + } + } else { + Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, + "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(retpm); + } + + /* Go through argument list, attach lnames for arguments */ + for (i = 0, p = l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + // Attach the standard typemaps. + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("ctype", l, 0); + Swig_typemap_attach_parms("imtype", l, 0); + Swig_typemap_attach_parms("dtype", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("ddirectorin", l, 0); + + // Preamble code. + if (!ignored_method) + Printf(w->code, "if (!swig_callback_%s) {\n", overloaded_name); + + if (!pure_virtual) { + String *super_call = Swig_method_call(super, l); + if (is_void) { + Printf(w->code, "%s;\n", super_call); + if (!ignored_method) + Printf(w->code, "return;\n"); + } else { + Printf(w->code, "return %s;\n", super_call); + } + Delete(super_call); + } else { + Printf(w->code, " throw Swig::DirectorPureVirtualException(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + } + + if (!ignored_method) + Printf(w->code, "} else {\n"); + + // Go through argument list. + for (i = 0, p = l; p; ++i) { + /* Is this superfluous? */ + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = makeParameterName(n, p, i, false); + String *c_param_type = NULL; + String *c_decl = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + // Add each parameter to the D callback invocation arguments. + Printf(dcallback_call_args, ", %s", arg); + + /* Get parameter's intermediary C type */ + if ((c_param_type = lookupDTypemap(p, "ctype", true))) { + String *ctypeout = Getattr(p, "tmap:ctype:out"); + if (ctypeout) { + // The type in the ctype typemap's out attribute overrides the type + // in the typemap itself. + c_param_type = ctypeout; + } + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + if (!ignored_method) + Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + + /* Add input marshalling code */ + if ((tm = Getattr(p, "tmap:directorin"))) { + + Replaceall(tm, "$input", arg); + Replaceall(tm, "$owner", "0"); + + if (Len(tm)) + if (!ignored_method) + Printf(w->code, "%s\n", tm); + + Delete(tm); + + // Add parameter type to the C typedef for the D callback function. + Printf(callback_typedef_parms, ", %s", c_param_type); + + /* Add parameter to the intermediate class code if generating the + * intermediate's upcall code */ + if ((tm = lookupDTypemap(p, "imtype", true))) { + String *imtypeout = Getattr(p, "tmap:imtype:out"); + if (imtypeout) { + // The type in the imtype typemap's out attribute overrides the + // type in the typemap itself. + tm = imtypeout; + } + const String *im_directorinattributes = Getattr(p, "tmap:imtype:directorinattributes"); + + // TODO: Is this copy really needed? + String *din = Copy(lookupDTypemap(p, "ddirectorin", true)); + + if (din) { + Replaceall(din, "$winput", ln); + + Printf(delegate_parms, ", "); + if (i > 0) { + Printf(proxy_method_param_list, ", "); + Printf(imcall_args, ", "); + } + Printf(delegate_parms, "%s%s %s", im_directorinattributes ? im_directorinattributes : empty_string, tm, ln); + + if (Cmp(din, ln)) { + Printv(imcall_args, din, NIL); + } else { + Printv(imcall_args, ln, NIL); + } + + Delete(din); + + // Get the parameter type in the proxy D class (used later when + // generating the overload checking code for the directorConnect + // function). + if ((tm = lookupDTypemap(p, "dtype", true))) { + Printf(proxy_method_param_list, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + Swig_warning(WARN_D_TYPEMAP_DDIRECTORIN_UNDEF, input_file, line_number, + "No ddirectorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + } else { + Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, + "No imtype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + p = Getattr(p, "tmap:directorin:next"); + } else { + Swig_warning(WARN_D_TYPEMAP_DDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + output_director = false; + } + } else { + Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number, + "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + Delete(ln); + } + + /* header declaration, start wrapper definition */ + String *target; + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Add any exception specifications to the methods in the director class + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + // Finish the callback function declaraction. + Printf(callback_def, "%s)", delegate_parms); + Printf(callback_def, " {\n"); + + /* Emit the intermediate class's upcall to the actual class */ + + String *upcall = NewStringf("(cast(%s)dObject).%s(%s)", classname, symname, imcall_args); + + if (!is_void) { + Parm *tp = NewParm(returntype, empty_str, n); + + // RESEARCH: What happens if there is no ddirectorout typemap? + if ((tm = lookupDTypemap(tp, "ddirectorout"))) { + Replaceall(tm, "$dcall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + Delete(tm); + Delete(tp); + } else { + Printf(callback_code, " %s;\n", upcall); + } + + Printf(callback_code, "}\n"); + Delete(upcall); + + if (!ignored_method) { + if (!is_void) + Printf(w->code, "jresult = (%s) ", c_ret_type); + + Printf(w->code, "swig_callback_%s(d_object%s);\n", overloaded_name, dcallback_call_args); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("c_result"); + Parm *tp = NewParm(returntype, result_str, n); + + /* Copy jresult into c_result... */ + // FIXME: lookupDTypemap? + if ((tm = Swig_typemap_lookup("directorout", tp, result_str, w))) { + Replaceall(tm, "$input", jresult_str); + Replaceall(tm, "$result", result_str); + Printf(w->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s used in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } + + /* Terminate wrapper code */ + Printf(w->code, "}\n"); + if (!is_void) + Printf(w->code, "return %s;", qualified_return); + } + + Printf(w->code, "}"); + + // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit code */ + if (status == SWIG_OK && output_director) { + if (!is_void) { + Replaceall(w->code, "$null", qualified_return); + } else { + Replaceall(w->code, "$null", ""); + } + if (!ignored_method) + Printv(director_dcallbacks_code, callback_def, callback_code, NIL); + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + if (!ignored_method) { + // Register the upcall method so that the callback registering code can + // be written later. + + // We cannot directly use n here because its »type« attribute does not + // the full return type any longer after Language::functionHandler has + // returned. + Parm *tp = NewParm(returntype, empty_str, n); + String *dp_return_type = lookupDTypemap(tp, "dtype"); + if (dp_return_type) { + String *dtypeout = Getattr(n, "tmap:dtype:out"); + if (dtypeout) { + // The type in the dtype typemap's out attribute overrides the type + // in the typemap itself. + dp_return_type = dtypeout; + replaceClassname(dp_return_type, returntype); + } + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(type, 0)); + dp_return_type = NewString(""); + } + + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name, dp_return_type, proxy_method_param_list); + Delete(dp_return_type); + + // Write the global callback function pointer on the C code. + String *methid = Getattr(udata, "class_methodidx"); + + Printf(director_callback_typedefs, " typedef %s (* SWIG_Callback%s_t)", c_ret_type, methid); + Printf(director_callback_typedefs, "(void *dobj%s);\n", callback_typedef_parms); + Printf(director_callback_pointers, " SWIG_Callback%s_t swig_callback_%s;\n", methid, overloaded_name); + + // Write the type alias for the callback to the intermediary D module. + String* proxy_callback_type = NewString(""); + Printf(proxy_callback_type, "SwigDirector_%s_Callback%s", classname, methid); + Printf(im_dmodule_code, "alias extern(C) %s function(void*%s) %s;\n", proxy_callback_return_type, delegate_parms, proxy_callback_type); + Delete(proxy_callback_type); + } + + Delete(qualified_return); + Delete(c_ret_type); + Delete(declaration); + Delete(callback_typedef_parms); + Delete(delegate_parms); + Delete(proxy_method_param_list); + Delete(callback_def); + Delete(callback_code); + DelWrapper(w); + + return status; + } + + /* --------------------------------------------------------------------------- + * D::classDirectorConstructor() + * --------------------------------------------------------------------------- */ + virtual int classDirectorConstructor(Node *n) { + Node *parent = parentNode(n); + String *decl = Getattr(n, "decl");; + String *supername = Swig_class_name(parent); + String *classname = getDirectorClassName(parent); + String *sub = NewString(""); + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms; + int argidx = 0; + + /* Assign arguments to superclass's parameters, if not already done */ + for (p = superparms; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + + if (!pname) { + pname = NewStringf("arg%d", argidx++); + Setattr(p, "name", pname); + } + } + + // TODO: Is this copy needed? + parms = CopyParmList(superparms); + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + String *call = Swig_csuperclass_call(0, basetype, superparms); + String *classtype = SwigType_namestr(Getattr(n, "name")); + + Printf(f_directors, "%s::%s : %s, %s {\n", classname, target, call, Getattr(parent, "director:ctor")); + Printf(f_directors, " swig_init_callbacks();\n"); + Printf(f_directors, "}\n\n"); + + Delete(classtype); + Delete(target); + Delete(call); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* --------------------------------------------------------------------------- + * D::classDirectorDefaultConstructor() + * --------------------------------------------------------------------------- */ + virtual int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + Wrapper *w = NewWrapper(); + + Printf(w->def, "SwigDirector_%s::SwigDirector_%s() : %s {", classname, classname, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " SwigDirector_%s();\n", classname); + DelWrapper(w); + Delete(classtype); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + /* --------------------------------------------------------------------------- + * D::classDirectorDestructor() + * --------------------------------------------------------------------------- */ + virtual int classDirectorDestructor(Node *n) { + Node *current_class = getCurrentClass(); + String *classname = Swig_class_name(current_class); + Wrapper *w = NewWrapper(); + + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() throw () {\n", classname, classname); + } else { + Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); + } + + Printv(w->code, "}\n", NIL); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(classname); + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::classDirectorEnd() + * --------------------------------------------------------------------------- */ + virtual int classDirectorEnd(Node *n) { + int i; + String *director_classname = getDirectorClassName(n); + + Wrapper *w = NewWrapper(); + + if (Len(director_callback_typedefs) > 0) { + Printf(f_directors_h, "\n%s", director_callback_typedefs); + } + + Printf(f_directors_h, " void swig_connect_director(void* dobj"); + + Printf(w->def, "void %s::swig_connect_director(void* dobj", director_classname); + Printf(w->code, "d_object = dobj;"); + + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + String *overname = Getattr(udata, "overname"); + + Printf(f_directors_h, ", SWIG_Callback%s_t callback%s", methid, overname); + Printf(w->def, ", SWIG_Callback%s_t callback_%s", methid, overname); + Printf(w->code, "swig_callback_%s = callback_%s;\n", overname, overname); + } + + Printf(f_directors_h, ");\n"); + Printf(w->def, ") {"); + + Printf(f_directors_h, "\nprivate:\n"); + Printf(f_directors_h, " void swig_init_callbacks();\n"); + Printf(f_directors_h, " void *d_object;\n"); + if (Len(director_callback_typedefs) > 0) { + Printf(f_directors_h, "%s", director_callback_pointers); + } + Printf(f_directors_h, "};\n\n"); + Printf(w->code, "}\n\n"); + + Printf(w->code, "void %s::swig_init_callbacks() {\n", director_classname); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *overname = Getattr(udata, "overname"); + Printf(w->code, "swig_callback_%s = 0;\n", overname); + } + Printf(w->code, "}"); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + + return Language::classDirectorEnd(n); + } + + /* --------------------------------------------------------------------------- + * D::classDirectorDisown() + * --------------------------------------------------------------------------- */ + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /* --------------------------------------------------------------------------- + * D::replaceSpecialVariables() + * --------------------------------------------------------------------------- */ + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + + // Just assume that this goes to the proxy class, we cannot know. + replaceClassname(tm, type); + } + +protected: + /* --------------------------------------------------------------------------- + * D::extraDirectorProtectedCPPMethodsRequired() + * --------------------------------------------------------------------------- */ + virtual bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + +private: + /* --------------------------------------------------------------------------- + * D::writeImDModuleFunction() + * + * Writes a function declaration for the given (C) wrapper function to the + * intermediary D module. + * + * d_name - The name the function in the intermediary D module will get. + * wrapper_function_name - The name of the exported function in the C wrapper + * (usually d_name prefixed by »D_«). + * --------------------------------------------------------------------------- */ + void writeImDModuleFunction(const_String_or_char_ptr d_name, + const_String_or_char_ptr return_type, const_String_or_char_ptr parameters, + const_String_or_char_ptr wrapper_function_name) { + + // TODO: Add support for static linking here. + Printf(im_dmodule_code, "extern(C) %s function%s %s;\n", return_type, + parameters, d_name); + Printv(wrapper_loader_bind_code, wrapper_loader_bind_command, NIL); + Replaceall(wrapper_loader_bind_code, "$function", d_name); + Replaceall(wrapper_loader_bind_code, "$symbol", wrapper_function_name); + } + + /* --------------------------------------------------------------------------- + * D::writeProxyClassFunction() + * + * Creates a D proxy function for a C++ function in the wrapped class. Used + * for both static and non-static C++ class functions. + * + * The Node must contain two extra attributes. + * - "proxyfuncname": The name of the D proxy function. + * - "imfuncname": The corresponding function in the intermediary D module. + * --------------------------------------------------------------------------- */ + void writeProxyClassFunction(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + // Wrappers not wanted for some methods where the parameters cannot be + // overloaded in D. + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in + // directors. + if (GetFlag(n, "explicitcall")) + return; + + // RESEARCH: What is this good for? + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("dtype", l, NULL); + Swig_typemap_attach_parms("din", l, NULL); + + // Get return types. + if ((tm = lookupDTypemap(n, "dtype"))) { + String *dtypeout = Getattr(n, "tmap:dtype:out"); + if (dtypeout) { + // The type in the dtype typemap's out attribute overrides the type in + // the typemap. + tm = dtypeout; + replaceClassname(tm, t); + } + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + 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); + } + + // Write function modifiers. + { + String *modifiers; + + const String *mods_override = Getattr(n, "feature:d:methodmodifiers"); + if (mods_override) { + modifiers = Copy(mods_override); + } else { + modifiers = Copy(is_public(n) ? public_string : protected_string); + + if (Getattr(n, "override")) { + Printf(modifiers, " override"); + } + } + + if (is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the + // underlying pointer type, so no override required. + Replaceall(modifiers, "override", ""); + } + + Chop(modifiers); + + if (static_flag) { + Printf(modifiers, " static"); + } + + Printf(function_code, "%s ", modifiers); + Delete(modifiers); + } + + // Complete the function declaration up to the parameter list. + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + // Write the wrapper function call up to the parameter list. + Printv(imcall, im_dmodule_fq_name, ".$imfuncname(", NIL); + if (!static_flag) { + Printf(imcall, "cast(void*)swigCPtr"); + } + + String *proxy_param_types = NewString(""); + + // Write the parameter list for the proxy function declaration and the + // wrapper function call. + emit_mark_varargs(l); + int gencomma = !static_flag; + for (i = 0, p = l; p; i++) { + // Ignored varargs. + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + // Ignored parameters. + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + // Ignore the 'this' argument for variable wrappers. + if (!(variable_wrapper_flag && i == 0)) { + String *param_name = makeParameterName(n, p, i, setter_flag); + SwigType *pt = Getattr(p, "type"); + + // Write the wrapper function call argument. + { + if (gencomma) { + Printf(imcall, ", "); + } + + if ((tm = lookupDTypemap(p, "din", true))) { + Replaceall(tm, "$dinput", param_name); + String *pre = Getattr(p, "tmap:din:pre"); + if (pre) { + replaceClassname(pre, pt); + Replaceall(pre, "$dinput", param_name); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:din:post"); + if (post) { + replaceClassname(post, pt); + Replaceall(post, "$dinput", param_name); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:din:terminator"); + if (terminator) { + replaceClassname(terminator, pt); + Replaceall(terminator, "$dinput", param_name); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, + "No din typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + + // Write the D proxy function parameter. + { + String *proxy_type = NewString(""); + + if ((tm = lookupDTypemap(p, "dtype"))) { + const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); + Printf(proxy_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma >= 2) { + Printf(function_code, ", "); + Printf(proxy_param_types, ", "); + } + gencomma = 2; + Printf(function_code, "%s %s", proxy_type, param_name); + Append(proxy_param_types, proxy_type); + + Delete(proxy_type); + } + + Delete(param_name); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ") "); + + if (d_version > 1 && wrapping_member_flag) { + Printf(function_code, "@property "); + } + + if (wrapMemberFunctionAsDConst(n)) { + Printf(function_code, "const "); + } + + // Lookup the code used to convert the wrapper return value to the proxy + // function return type. + if ((tm = lookupDTypemap(n, "dout"))) { + replaceExcode(n, tm, "dout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, "{"); + Printv(tm, "}", NIL); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + replaceClassname(tm, t); + + // For director methods: generate code to selectively make a normal + // polymorphic call or an explicit method call. Needed to prevent infinite + // recursion when calling director methods. + 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_imcall = Copy(imcall); + Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); + Replaceall(imcall, "$imfuncname", intermediary_function_name); + + String *excode = NewString(""); + if (!Cmp(return_type, "void")) + Printf(excode, "if (swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) %s; else %s", + return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall); + else + Printf(excode, "((swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) ? %s : %s)", + return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + Delete(ex_overloaded_name); + Delete(excode); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + Replaceall(tm, "$imcall", imcall); + } else { + 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 + // map, of course), so simply append it to the code buffer. The braces are + // included in the typemap. + Printv(function_code, tm, NIL); + + // Write function code buffer to the class code. + Printv(proxy_class_body_code, "\n", function_code, "\n", NIL); + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* --------------------------------------------------------------------------- + * D::writeProxyDModuleFunction() + * --------------------------------------------------------------------------- */ + void writeProxyDModuleFunction(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + int num_required = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + // RESEARCH: What is this good for? + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("dtype", l, NULL); + Swig_typemap_attach_parms("din", l, NULL); + + /* Get return types */ + if ((tm = lookupDTypemap(n, "dtype"))) { + String *dtypeout = Getattr(n, "tmap:dtype:out"); + if (dtypeout) { + // The type in the dtype typemap's out attribute overrides the type in + // the typemap. + tm = dtypeout; + replaceClassname(tm, t); + } + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (global_variable_flag) { + // RESEARCH: Is the Copy() needed here? + func_name = Copy(variable_name); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *outattributes = Getattr(n, "tmap:dtype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + + const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); + // TODO: Check if is_public(n) could possibly make any sense here + // (private global functions would be useless anyway?). + methodmods = methodmods ? methodmods : empty_string; + + Printf(function_code, "\n%s%s %s(", methodmods, return_type, func_name); + Printv(imcall, im_dmodule_fq_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; i < num_arguments; i++) { + + /* Ignored parameters */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + // Get the D parameter type. + if ((tm = lookupDTypemap(p, "dtype", true))) { + const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + const bool generating_setter = global_variable_flag || wrapping_member_flag; + String *arg = makeParameterName(n, p, i, generating_setter); + + // Get the D code to convert the parameter value to the type used in the + // wrapper D module. + if ((tm = lookupDTypemap(p, "din", true))) { + Replaceall(tm, "$dinput", arg); + String *pre = Getattr(p, "tmap:din:pre"); + if (pre) { + replaceClassname(pre, pt); + Replaceall(pre, "$dinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:din:post"); + if (post) { + replaceClassname(post, pt); + Replaceall(post, "$dinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:din:terminator"); + if (terminator) { + replaceClassname(terminator, pt); + Replaceall(terminator, "$dinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, + "No din typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to module class function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + p = Getattr(p, "tmap:in:next"); + Delete(arg); + Delete(param_type); + } + + Printf(imcall, ")"); + Printf(function_code, ") "); + + if (global_variable_flag && (d_version > 1)) { + Printf(function_code, "@property "); + } + + // Lookup the code used to convert the wrapper return value to the proxy + // function return type. + if ((tm = lookupDTypemap(n, "dout"))) { + replaceExcode(n, tm, "dout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, " {"); + Printf(tm, "\n}"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + replaceClassname(tm, t); + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_D_TYPEMAP_DOUT_UNDEF, input_file, line_number, + "No dout typemap defined for %s\n", SwigType_str(t, 0)); + } + + // 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); + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(func_name); + } + + /* --------------------------------------------------------------------------- + * D::writeProxyClassAndUpcasts() + * --------------------------------------------------------------------------- */ + void writeProxyClassAndUpcasts(Node *n) { + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + + /* + * Handle inheriting from D and C++ classes. + */ + + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + + // Inheritance from pure D classes. + Node *attributes = NewHash(); + const String *pure_baseclass = + lookupCodeTypemap(n, "dbase", typemap_lookup_type, WARN_NONE, attributes); + bool purebase_replace = GetFlag(attributes, "tmap:dbase:replace") ? true : false; + bool purebase_notderived = GetFlag(attributes, "tmap:dbase:notderived") ? true : false; + Delete(attributes); + + // C++ inheritance. + if (!purebase_replace) { + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (base.item) { + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + base = Next(base); + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_D_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Base %s of class %s ignored: multiple inheritance is not supported in D.\n", baseclassname, proxyclassname); + base = Next(base); + } + } + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + + if (derived && purebase_notderived) { + pure_baseclass = empty_string; + } + const String *wanted_base = baseclass ? baseclass : pure_baseclass; + + if (purebase_replace) { + wanted_base = pure_baseclass; + derived = false; + Delete(baseclass); + baseclass = 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) { + 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); + } + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + writeClassUpcast(n, proxy_class_name, c_classname, c_baseclass); + } + + /* + * Write needed imports. + */ + // 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); + + if (split_proxy_dmodule) { + // Fully qualify the baseclass name. + String *module = NewStringf("%s%s.", package, baseclass); + Insert(baseclass, 0, module); + Delete(module); + } + } + + // Write any custom import statements to the proxy module header. + const String *imports = lookupCodeTypemap(n, "dimports", typemap_lookup_type, WARN_NONE); + if (Len(imports) > 0) { + String* imports_trimmed = Copy(imports); + Chop(imports_trimmed); + replaceImportTypeMacros(imports_trimmed); + Printv(proxy_class_imports, imports_trimmed, "\n", NIL); + Delete(imports_trimmed); + } + + /* + * Write the proxy class header. + */ + // Class modifiers. + const String *modifiers = + lookupCodeTypemap(n, "dclassmodifiers", typemap_lookup_type, WARN_D_TYPEMAP_CLASSMOD_UNDEF); + + // User-defined interfaces. + const String *interfaces = + lookupCodeTypemap(n, derived ? "dinterfaces_derived" : "dinterfaces", typemap_lookup_type, WARN_NONE); + + Printv(proxy_class_code, + "\n", + modifiers, + " $dclassname", + (*Char(wanted_base) || *Char(interfaces)) ? " : " : "", wanted_base, + (*Char(wanted_base) && *Char(interfaces)) ? ", " : "", interfaces, " {", + NIL); + + /* + * Write the proxy class body. + */ + String* body = NewString(""); + + // Default class body. + const String *dbody; + if (derived) { + dbody = lookupCodeTypemap(n, "dbody_derived", typemap_lookup_type, WARN_D_TYPEMAP_DBODY_UNDEF); + } else { + dbody = lookupCodeTypemap(n, "dbody", typemap_lookup_type, WARN_D_TYPEMAP_DBODY_UNDEF); + } + + Printv(body, dbody, NIL); + + // Destructor and dispose(). + // If the C++ destructor is accessible (public), it is wrapped by the + // dispose() method which is also called by the emitted D constructor. If it + // is not accessible, no D destructor is written and the generated dispose() + // method throws an exception. + // This enables C++ classes with protected or private destructors to be used + // in D as it would be used in C++ (GC finalization is a no-op then because + // of the empty D destructor) while preventing usage in »scope« variables. + // The method name for the dispose() method is specified in a typemap + // attribute called »methodname«. + const String *tm = NULL; + + String *dispose_methodname; + String *dispose_methodmodifiers; + attributes = NewHash(); + if (derived) { + tm = lookupCodeTypemap(n, "ddispose_derived", typemap_lookup_type, WARN_NONE, attributes); + dispose_methodname = Getattr(attributes, "tmap:ddispose_derived:methodname"); + dispose_methodmodifiers = Getattr(attributes, "tmap:ddispose_derived:methodmodifiers"); + } else { + tm = lookupCodeTypemap(n, "ddispose", typemap_lookup_type, WARN_NONE, attributes); + dispose_methodname = Getattr(attributes, "tmap:ddispose:methodname"); + dispose_methodmodifiers = Getattr(attributes, "tmap:ddispose:methodmodifiers"); + } + + if (tm && *Char(tm)) { + if (!dispose_methodname) { + Swig_error(Getfile(n), Getline(n), + "No methodname attribute defined in the ddispose%s typemap for %s\n", + (derived ? "_derived" : ""), proxy_class_name); + } + if (!dispose_methodmodifiers) { + Swig_error(Getfile(n), Getline(n), + "No methodmodifiers attribute defined in ddispose%s typemap for %s.\n", + (derived ? "_derived" : ""), proxy_class_name); + } + } + + if (tm) { + // Write the destructor if the C++ one is accessible. + if (*Char(destructor_call)) { + Printv(body, + lookupCodeTypemap(n, "ddestructor", typemap_lookup_type, WARN_NONE), NIL); + } + + // Write the dispose() method. + String *dispose_code = NewString(""); + Printv(dispose_code, tm, NIL); + + if (*Char(destructor_call)) { + Replaceall(dispose_code, "$imcall", destructor_call); + } else { + Replaceall(dispose_code, "$imcall", "throw new object.Exception(\"C++ destructor does not have public access\")"); + } + + if (*Char(dispose_code)) { + Printv(body, "\n", dispose_methodmodifiers, + (derived ? " override" : ""), " void ", dispose_methodname, "() ", + dispose_code, "\n", NIL); + } + } + + if (Swig_directorclass(n)) { + // If directors are enabled for the current class, generate the + // director connect helper function which is called from the constructor + // and write it to the class body. + writeDirectorConnectProxy(); + } + + // Write all constants and enumerations first to prevent forward reference + // errors. + Printv(body, proxy_class_enums_code, NIL); + + // Write the code generated in other methods to the class body. + Printv(body, proxy_class_body_code, NIL); + + // Append extra user D code to the class body. + Printv(body, + lookupCodeTypemap(n, "dcode", typemap_lookup_type, WARN_NONE), "\n", NIL); + + // Write the class body and the curly bracket closing the class definition + // to the proxy module. + indentCode(body); + Replaceall(body, "$dbaseclass", baseclass); + Delete(baseclass); + + Printv(proxy_class_code, body, "\n}\n", NIL); + Delete(body); + + // Write the epilogue code if there is any. + Printv(proxy_class_code, proxy_class_epilogue_code, NIL); + } + + + /* --------------------------------------------------------------------------- + * D::writeClassUpcast() + * --------------------------------------------------------------------------- */ + void writeClassUpcast(Node *n, const String* d_class_name, + 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_wrapper_name = Swig_name_wrapper(upcast_name); + + writeImDModuleFunction(upcast_name, "void*", "(void* objectRef)", + upcast_wrapper_name); + + if (smartptr) { + SwigType *spt = Swig_cparse_type(smartptr); + if (spt) { + SwigType *smart = SwigType_typedef_resolve_all(spt); + Delete(spt); + SwigType *bsmart = Copy(smart); + SwigType *rclassname = SwigType_typedef_resolve_all(c_class_name); + SwigType *rbaseclass = SwigType_typedef_resolve_all(c_base_name); + Replaceall(bsmart, rclassname, rbaseclass); + Delete(rclassname); + Delete(rbaseclass); + String *smartnamestr = SwigType_namestr(smart); + String *bsmartnamestr = SwigType_namestr(bsmart); + Printv(upcasts_code, + "SWIGEXPORT ", bsmartnamestr, " * ", upcast_wrapper_name, + "(", smartnamestr, " *objectRef) {\n", + " return objectRef ? new ", bsmartnamestr, "(*objectRef) : 0;\n" + "}\n", + "\n", NIL); + Delete(bsmartnamestr); + Delete(smartnamestr); + Delete(bsmart); + } else { + Swig_error(Getfile(n), Getline(n), + "Invalid type (%s) in 'smartptr' feature for class %s.\n", + smartptr, c_class_name); + } + } else { + Printv(upcasts_code, + "SWIGEXPORT ", c_base_name, " * ", upcast_wrapper_name, + "(", c_base_name, " *objectRef) {\n", + " return (", c_base_name, " *)objectRef;\n" + "}\n", + "\n", NIL); + } + + Replaceall(upcasts_code, "$cclass", c_class_name); + Replaceall(upcasts_code, "$cbaseclass", c_base_name); + + Delete(upcast_name); + Delete(upcast_wrapper_name); + } + + /* --------------------------------------------------------------------------- + * D::writeTypeWrapperClass() + * --------------------------------------------------------------------------- */ + void writeTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + assertClassNameValidity(classname); + + String* imports_target; + String* code_target; + File *class_file = NULL; + if (split_proxy_dmodule) { + String *filename = NewStringf("%s%s.d", dmodule_directory, classname); + class_file = NewFile(filename, "w", SWIG_output_files()); + if (!class_file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filename)); + Delete(filename); + + emitBanner(class_file); + Printf(class_file, "module %s%s;\n", package, classname); + Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name); + + imports_target = NewString(""); + code_target = NewString(""); + } else { + imports_target = proxy_dmodule_imports; + code_target = proxy_dmodule_code; + } + + // Import statements. + const String *imports = lookupCodeTypemap(n, "dimports", type, WARN_NONE); + if (Len(imports) > 0) { + String *imports_trimmed = Copy(imports); + Chop(imports_trimmed); + replaceImportTypeMacros(imports_trimmed); + Printv(imports_target, imports_trimmed, "\n", NIL); + Delete(imports_trimmed); + } + + // Pure D baseclass and interfaces (no C++ inheritance possible. + const String *pure_baseclass = lookupCodeTypemap(n, "dbase", type, WARN_NONE); + const String *pure_interfaces = lookupCodeTypemap(n, "dinterfaces", type, WARN_NONE); + + // Emit the class. + Printv(code_target, + "\n", + lookupCodeTypemap(n, "dclassmodifiers", type, WARN_D_TYPEMAP_CLASSMOD_UNDEF), + " $dclassname", + (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, + ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? ", " : "", pure_interfaces, + " {", NIL); + + String* body = NewString(""); + Printv(body, lookupCodeTypemap(n, "dbody", type, WARN_D_TYPEMAP_DBODY_UNDEF), + lookupCodeTypemap(n, "dcode", type, WARN_NONE), NIL); + indentCode(body); + Printv(code_target, body, "\n}\n", NIL); + Delete(body); + + Replaceall(code_target, "$dclassname", classname); + + if (split_proxy_dmodule) { + Printv(class_file, imports_target, NIL); + Delete(imports_target); + + replaceModuleVariables(code_target); + Printv(class_file, code_target, NIL); + Delete(code_target); + + Close(class_file); + Delete(class_file); + } + + Delete(n); + } + + /* --------------------------------------------------------------------------- + * D::writeDirectorConnectProxy() + * + * Writes the helper method which registers the director callbacks by calling + * the director connect function from the D side to the proxy class. + * --------------------------------------------------------------------------- */ + void writeDirectorConnectProxy() { + Printf(proxy_class_body_code, "\nprivate void swigDirectorConnect() {\n"); + + int i; + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *method = Getattr(udata, "method"); + String *overloaded_name = Getattr(udata, "overname"); + String *return_type = Getattr(udata, "return_type"); + String *param_list = Getattr(udata, "param_list"); + String *methid = Getattr(udata, "class_methodidx"); + Printf(proxy_class_body_code, " %s.SwigDirector_%s_Callback%s callback%s;\n", im_dmodule_fq_name, proxy_class_name, methid, methid); + Printf(proxy_class_body_code, " if (swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) {\n", return_type, param_list, return_type, param_list, method); + Printf(proxy_class_body_code, " callback%s = &swigDirectorCallback_%s_%s;\n", methid, proxy_class_name, overloaded_name); + Printf(proxy_class_body_code, " }\n\n"); + } + Printf(proxy_class_body_code, " %s.%s_director_connect(cast(void*)swigCPtr, cast(void*)this", im_dmodule_fq_name, proxy_class_name); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + Printf(proxy_class_body_code, ", callback%s", methid); + } + Printf(proxy_class_body_code, ");\n"); + Printf(proxy_class_body_code, "}\n"); + + // Helper function to determine if a method has been overridden in a + // subclass of the wrapped class. If not, we just pass null to the + // director_connect_function since the method from the C++ class should + // be called as usual (see above). + // Only emit it if the proxy class has at least one method. + if (first_class_dmethod < curr_class_dmethod) { + Printf(proxy_class_body_code, "\n"); + Printf(proxy_class_body_code, "private bool swigIsMethodOverridden(DelegateType, FunctionType, alias fn)() %s{\n", (d_version > 1) ? "const " : ""); + Printf(proxy_class_body_code, " DelegateType dg = &fn;\n"); + Printf(proxy_class_body_code, " return dg.funcptr != SwigNonVirtualAddressOf!(FunctionType, fn);\n"); + Printf(proxy_class_body_code, "}\n"); + Printf(proxy_class_body_code, "\n"); + Printf(proxy_class_body_code, "private static Function SwigNonVirtualAddressOf(Function, alias fn)() {\n"); + Printf(proxy_class_body_code, " return cast(Function) &fn;\n"); + Printf(proxy_class_body_code, "}\n"); + } + + if (Len(director_dcallbacks_code) > 0) { + Printv(proxy_class_epilogue_code, director_dcallbacks_code, NIL); + } + + Delete(director_callback_typedefs); + director_callback_typedefs = NULL; + Delete(director_callback_pointers); + director_callback_pointers = NULL; + Delete(director_dcallbacks_code); + director_dcallbacks_code = NULL; + } + + /* --------------------------------------------------------------------------- + * D::writeDirectorConnectWrapper() + * + * Writes the director connect function and the corresponding declaration to + * the C++ wrapper respectively the D wrapper. + * --------------------------------------------------------------------------- */ + void writeDirectorConnectWrapper(Node *n) { + if (!Swig_directorclass(n)) + return; + + // Output the director connect method. + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *connect_name = NewStringf("%s_director_connect", proxy_class_name); + String *sym_name = Getattr(n, "sym:name"); + Wrapper *code_wrap; + + Printv(wrapper_loader_bind_code, wrapper_loader_bind_command, NIL); + Replaceall(wrapper_loader_bind_code, "$function", connect_name); + Replaceall(wrapper_loader_bind_code, "$symbol", Swig_name_wrapper(connect_name)); + + Printf(im_dmodule_code, "extern(C) void function(void* cObject, void* dObject"); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, "SWIGEXPORT void D_%s(void *objarg, void *dobj", connect_name); + + Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_connect_director(dobj"); + + for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + + Printf(code_wrap->def, ", SwigDirector_%s::SWIG_Callback%s_t callback%s", sym_name, methid, methid); + Printf(code_wrap->code, ", callback%s", methid); + Printf(im_dmodule_code, ", SwigDirector_%s_Callback%s callback%s", sym_name, methid, methid); + } + + Printf(code_wrap->def, ") {\n"); + Printf(code_wrap->code, ");\n"); + Printf(im_dmodule_code, ") %s;\n", connect_name); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(connect_name); + } + + /* --------------------------------------------------------------------------- + * 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. + * --------------------------------------------------------------------------- */ + void requireDType(const String *dmodule_name) { + String *import = createImportStatement(dmodule_name); + Append(import, "\n"); + if (is_wrapping_class()) { + addImportStatement(proxy_class_imports, import); + } else { + addImportStatement(proxy_dmodule_imports, import); + } + Delete(import); + } + + /* --------------------------------------------------------------------------- + * D::addImportStatement() + * + * Adds the given import statement to the given list of import statements if + * there is no statement importing that module present yet. + * --------------------------------------------------------------------------- */ + void addImportStatement(String *target, const String *import) const { + char *position = Strstr(target, import); + if (position) { + // If the import statement has been found in the target string, we have to + // check if the previous import was static, which would lead to problems + // if this import is not. + // Thus, we check if the seven characters in front of the occurence are + // »static «. If the import string passed is also static, the checks fail + // even if the found statement is also static because the last seven + // characters would be part of the previous import statement then. + + if (position - Char(target) < 7) { + return; + } + if (strncmp(position - 7, "static ", 7)) { + return; + } + } + + Printv(target, import, NIL); + } + + /* --------------------------------------------------------------------------- + * 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). + * --------------------------------------------------------------------------- */ + String *createImportStatement(const String *dmodule_name, + bool static_import = true) const { + + if (inProxyModule(dmodule_name)) { + return NewStringf(""); + } else { + if (static_import) { + return NewStringf("static import %s%s;", package, dmodule_name); + } else { + return NewStringf("import %s%s;", package, dmodule_name); + } + } + } + + /* --------------------------------------------------------------------------- + * D::inProxyModule() + * + * Determines if the specified proxy class is decleared 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. + * --------------------------------------------------------------------------- */ + 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; + } + + if (!Len(proxy_class_name)) { + return false; + } + + return (Strcmp(proxy_class_name, type_name) == 0); + } + + /* --------------------------------------------------------------------------- + * D::addUpcallMethod() + * + * Adds new director upcall signature. + * --------------------------------------------------------------------------- */ + UpcallData *addUpcallMethod(String *imclass_method, String *class_method, + String *decl, String *overloaded_name, String *return_type, String *param_list) { + + UpcallData *udata; + String *imclass_methodidx; + String *class_methodidx; + Hash *new_udata; + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, key))) { + Delete(key); + return Getattr(udata, "methodoff"); + } + + imclass_methodidx = NewStringf("%d", n_dmethods); + class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); + n_dmethods++; + + new_udata = NewHash(); + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, key, new_udata); + + Setattr(new_udata, "method", Copy(class_method)); + Setattr(new_udata, "class_methodidx", class_methodidx); + Setattr(new_udata, "decl", Copy(decl)); + Setattr(new_udata, "overname", Copy(overloaded_name)); + Setattr(new_udata, "return_type", Copy(return_type)); + Setattr(new_udata, "param_list", Copy(param_list)); + + Delete(key); + return new_udata; + } + + /* --------------------------------------------------------------------------- + * D::assertClassNameValidity() + * --------------------------------------------------------------------------- */ + void assertClassNameValidity(const String* class_name) const { + 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", + 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); + } + } + } + + /* --------------------------------------------------------------------------- + * D::getPrimitiveDptype() + * + * Returns the D proxy type for the passed type if it is a primitive type in + * both C and D. + * --------------------------------------------------------------------------- */ + String *getPrimitiveDptype(Node *node, SwigType *type) { + SwigType *stripped_type = SwigType_typedef_resolve_all(type); + + // A reference can only be the »outermost element« of a type. + bool mutable_ref = false; + if (SwigType_isreference(stripped_type)) { + SwigType_del_reference(stripped_type); + + if (SwigType_isconst(stripped_type)) { + SwigType_del_qualifier(stripped_type); + } else { + mutable_ref = true; + } + } + + // Strip all the pointers from the type. + int indirection_count = 0; + while (SwigType_ispointer(stripped_type)) { + ++indirection_count; + SwigType_del_pointer(stripped_type); + } + + // Now that we got rid of the pointers, see if we are dealing with a + // primitive type. + String *dtype = 0; + if (SwigType_isfunction(stripped_type) && indirection_count > 0) { + // type was a function pointer, split it up. + SwigType_add_pointer(stripped_type); + --indirection_count; + + SwigType *return_type = Copy(stripped_type); + SwigType *params_type = SwigType_functionpointer_decompose(return_type); + String *return_dtype = getPrimitiveDptype(node, return_type); + Delete(return_type); + if (!return_dtype) { + return 0; + } + + List *parms = SwigType_parmlist(params_type); + List *param_dtypes = NewList(); + for (Iterator it = First(parms); it.item; it = Next(it)) { + String *current_dtype = getPrimitiveDptype(node, it.item); + if (Cmp(current_dtype, "void") == 0) { + // void somefunc(void) is legal syntax in C, but not in D, so simply + // skip the void parameter. + Delete(current_dtype); + continue; + } + if (!current_dtype) { + Delete(return_dtype); + Delete(param_dtypes); + return 0; + } + Append(param_dtypes, current_dtype); + } + + String *param_list = NewString(""); + { + bool gen_comma = false; + for (Iterator it = First(param_dtypes); it.item; it = Next(it)) { + if (gen_comma) { + Append(param_list, ", "); + } + Append(param_list, it.item); + Delete(it.item); + gen_comma = true; + } + } + + dtype = NewStringf("%s function(%s)", return_dtype, param_list); + Delete(param_list); + Delete(param_dtypes); + Delete(return_dtype); + } else { + Hash *attributes = NewHash(); + const String *tm = + lookupCodeTypemap(node, "dtype", stripped_type, WARN_NONE, attributes); + if(!GetFlag(attributes, "tmap:dtype:cprimitive")) { + dtype = 0; + } else { + dtype = Copy(tm); + + // We need to call replaceClassname here with the stripped type to avoid + // $dclassname in the enum typemaps being replaced later with the full + // type. + replaceClassname(dtype, stripped_type); + } + Delete(attributes); + } + Delete(stripped_type); + + if (!dtype) { + // The type passed is no primitive type. + return 0; + } + + // The type is ultimately a primitive type, now append the right number of + // indirection levels (pointers). + for (int i = 0; i < indirection_count; ++i) { + Append(dtype, "*"); + } + + // Add a level of indirection for a mutable reference since it is wrapped + // as a pointer. + if (mutable_ref) { + Append(dtype, "*"); + } + + return dtype; + } + + /* --------------------------------------------------------------------------- + * D::lookupCodeTypemap() + * + * Looks up a D code fragment for generating the wrapper class for the given + * type. + * + * n - for input only and must contain info for Getfile(n) and Getline(n) to work + * tmap_method - typemap method name + * type - typemap type to lookup + * warning - warning number to issue if no typemaps found + * typemap_attributes - the typemap attributes are attached to this node and will + * also be used for temporary storage if non null + * return is never NULL, unlike Swig_typemap_lookup() + * --------------------------------------------------------------------------- */ + const String *lookupCodeTypemap(Node *n, const_String_or_char_ptr tmap_method, + SwigType *type, int warning, Node *typemap_attributes = 0) const { + + Node *node = !typemap_attributes ? NewHash() : typemap_attributes; + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + if (!tm) { + tm = empty_string; + if (warning != WARN_NONE) { + Swig_warning(warning, Getfile(n), Getline(n), + "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); + } + } + if (!typemap_attributes) { + Delete(node); + } + + return tm; + } + + /* --------------------------------------------------------------------------- + * D::lookupDTypemap() + * + * Looks up a D typemap for the given node, replacing D-specific special + * variables as needed. + * + * The method parameter specifies the typemap method to use. If attached is + * true, the value is just fetched from the tmap:<method> node attribute, + * Swig_typemap_lookup is used otherwise. + * --------------------------------------------------------------------------- */ + String *lookupDTypemap(Node *n, const_String_or_char_ptr method, bool attached = false) { + String *result = 0; + + if (attached) { + String *attr_name = NewStringf("tmap:%s", method); + result = Getattr(n, attr_name); + Delete(attr_name); + } else { + // FIXME: As a workaround for a bug so far only surfacing in the + // smart_pointer_const_overload test case, remove the nativepointer + // typemap attribute since it seems to be already there from a dout + // typemap of a different type in that test. + String *np_key = NewStringf("tmap:%s:nativepointer", method); + Delattr(n, np_key); + Delete(np_key); + + result = Swig_typemap_lookup(method, n, "", 0); + } + + if (!result) { + return 0; + } + + // Check if the passed node actually has type information attached. This + // is not the case e.g. in constructorWrapper. + SwigType *type = Getattr(n, "type"); + if (type) { + String *np_key = NewStringf("tmap:%s:nativepointer", method); + String *np_value = Getattr(n, np_key); + Delete(np_key); + String *dtype; + if (np_value && (dtype = getPrimitiveDptype(n, type))) { + // If the typemap in question has a »nativepointer« attribute and we + // are dealing with a primitive type, use it instead. + result = Copy(np_value); + Replaceall(result, "$dtype", dtype); + } + + replaceClassname(result, type); + } + + return result; + } + + /* --------------------------------------------------------------------------- + * D::replaceClassname() + * + * Replaces the special variable $dclassname with the proxy class name for + * classes/structs/unions SWIG knows about. Also substitutes the enumeration + * name for non-anonymous enums. Otherwise, $classname is replaced with a + * $descriptor(type)-like name. + * + * $*dclassname and $&classname work like with descriptors (see manual section + * 10.4.3), they remove a prointer from respectively add a pointer to the type. + * + * Inputs: + * tm - String to perform the substitution at (will usually come from a + * typemap. + * pt - The type to substitute for the variables. + * Outputs: + * tm - String with the variables substituted. + * Return: + * substitution_performed - flag indicating if a substitution was performed + * --------------------------------------------------------------------------- */ + bool replaceClassname(String *tm, SwigType *pt) { + bool substitution_performed = false; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + SwigType *strippedtype = SwigType_strip_qualifiers(type); + + if (Strstr(tm, "$dclassname")) { + SwigType *classnametype = Copy(strippedtype); + replaceClassnameVariable(tm, "$dclassname", classnametype); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$*dclassname")) { + SwigType *classnametype = Copy(strippedtype); + Delete(SwigType_pop(classnametype)); + replaceClassnameVariable(tm, "$*dclassname", classnametype); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$&dclassname")) { + SwigType *classnametype = Copy(strippedtype); + SwigType_add_pointer(classnametype); + replaceClassnameVariable(tm, "$&dclassname", classnametype); + substitution_performed = true; + Delete(classnametype); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* --------------------------------------------------------------------------- + * D::replaceClassnameVariable() + * + * See D::replaceClassname(). + * --------------------------------------------------------------------------- */ + void replaceClassnameVariable(String *target, const char *variable, SwigType *type) { + // TODO: Fix const-correctness of methods called in here and make type const. + + // We make use of the fact that this function is called at least once for + // every type encountered which is written to a seperate file, which allows + // us to handle imports here. + // When working in split proxy module mode, each generated proxy class/enum + // is written to a seperate module. This requires us to add a corresponding + // 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 *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); + + // 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); + + // A non-nested enum is written to a seperate module, import it. + import_name = Copy(symname); + } + } 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); + } 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); + + // Add to hash table so that a type wrapper class can be created later. + Setattr(unknown_types, descriptor, type); + + Delete(descriptor); + } + } + + Replaceall(target, variable, qualified_type_name); + Delete(qualified_type_name); + + requireDType(import_name); + Delete(import_name); + } + + /* --------------------------------------------------------------------------- + * D::createQualifiedName() + * --------------------------------------------------------------------------- */ + String *createQualifiedName(const String *class_name) const { + if (inProxyModule(class_name)) { + return Copy(class_name); + } else { + return NewStringf("%s%s.%s", package, class_name, class_name); + } +} + + /* --------------------------------------------------------------------------- + * D::replaceModuleVariables() + * + * Replaces the $imdmodule and $module variables with their values in the + * target string. + * --------------------------------------------------------------------------- */ + void replaceModuleVariables(String *target) const { + Replaceall(target, "$imdmodule", im_dmodule_fq_name); + Replaceall(target, "$module", proxy_dmodule_name); + } + + /* --------------------------------------------------------------------------- + * D::replaceExcode() + * + * If a C++ method can throw a exception, additional code is added to the + * proxy method to check if an exception is pending so that it can be + * rethrown on the D side. + * + * This method replaces the $excode variable with the exception handling code + * in the excode typemap attribute if it »canthrow« an exception. + * --------------------------------------------------------------------------- */ + void replaceExcode(Node *n, String *code, const String *typemap, Node *parameter) const { + String *excode_attribute = NewStringf("tmap:%s:excode", typemap); + String *excode = Getattr(parameter, excode_attribute); + if (Getattr(n, "d:canthrow")) { + int count = Replaceall(code, "$excode", excode); + if (count < 1 || !excode) { + Swig_warning(WARN_D_EXCODE_MISSING, input_file, line_number, + "D exception may not be thrown – no $excode or excode attribute in '%s' typemap.\n", + typemap); + } + } else { + Replaceall(code, "$excode", ""); + } + Delete(excode_attribute); + } + + /* --------------------------------------------------------------------------- + * D::replaceImportTypeMacros() + * + * Replaces the $importtype(SomeDClass) macro with an import statement if it + * is required to get SomeDClass in scope for the currently generated proxy + * D module. + * --------------------------------------------------------------------------- */ + void replaceImportTypeMacros(String *target) const { + // Code from replace_embedded_typemap. + char *start = 0; + while ((start = Strstr(target, "$importtype("))) { + char *end = 0; + char *param_start = 0; + char *param_end = 0; + int level = 0; + char *c = start; + while (*c) { + if (*c == '(') { + if (level == 0) { + param_start = c + 1; + } + level++; + } + if (*c == ')') { + level--; + if (level == 0) { + param_end = c; + end = c + 1; + break; + } + } + c++; + } + + if (end) { + String *current_macro = NewStringWithSize(start, (end - start)); + String *current_param = NewStringWithSize(param_start, (param_end - param_start)); + + String *import = createImportStatement(current_param, false); + Replace(target, current_macro, import, DOH_REPLACE_ANY); + Delete(import); + + Delete(current_param); + Delete(current_macro); + } else { + String *current_macro = NewStringWithSize(start, (c - start)); + Swig_error(Getfile(target), Getline(target), "Syntax error in: %s\n", current_macro); + Replace(target, current_macro, "<error in $importtype macro>", DOH_REPLACE_ANY); + Delete(current_macro); + } + } + } + + /* --------------------------------------------------------------------------- + * D::getOverloadedName() + * --------------------------------------------------------------------------- */ + String *getOverloadedName(Node *n) const { + // A void* parameter is used for all wrapped classes in the wrapper code. + // Thus, the wrapper function names for overloaded functions are postfixed + // with a counter string to make them unique. + String *overloaded_name = Copy(Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Append(overloaded_name, Getattr(n, "sym:overname")); + } + + return overloaded_name; + } + + /* --------------------------------------------------------------------------- + * D::getProxyName() + * + * Returns the D class name if a type corresponds to something wrapped with a + * proxy class, NULL otherwise. + * --------------------------------------------------------------------------- */ + const String *getProxyName(SwigType *t) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } else { + return NULL; + } + } + + /* --------------------------------------------------------------------------- + * D::directorClassName() + * --------------------------------------------------------------------------- */ + String *getDirectorClassName(Node *n) const { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = Getattr(n, "sym:name"); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + + return dirclassname; + } + + /* --------------------------------------------------------------------------- + * D::makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * --------------------------------------------------------------------------- */ + String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const { + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0; + arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn); + + if (setter && Cmp(arg, "self") != 0) { + // In theory, we could use the normal parameter name for setter functions. + // Unfortunately, it is set to "Class::VariableName" for static public + // members by the parser, which is not legal D syntax. Thus, we just force + // it to "value". + Delete(arg); + arg = NewString("value"); + } + + if (split_proxy_dmodule && Strncmp(arg, package, Len(arg)) == 0) { + // If we are in split proxy mode and the argument is named like the target + // package, we append an underscore to its name to avoid clashes. + Append(arg, "_"); + } + + return arg; + } + + /* --------------------------------------------------------------------------- + * D::canThrow() + * + * Determines whether the code in the typemap can throw a D exception. + * If so, note it for later when excodeSubstitute() is called. + * --------------------------------------------------------------------------- */ + void canThrow(Node *n, const String *typemap, Node *parameter) const { + String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap); + String *canthrow = Getattr(parameter, canthrow_attribute); + if (canthrow) + Setattr(n, "d:canthrow", "1"); + Delete(canthrow_attribute); + } + + /* --------------------------------------------------------------------------- + * D::wrapMemberFunctionAsDConst() + * + * Determines whether the member function represented by the passed node is + * wrapped as D »const« or not. + * --------------------------------------------------------------------------- */ + bool wrapMemberFunctionAsDConst(Node *n) const { + if (d_version == 1) return false; + if (static_flag) return false; // Never emit »const« for static member functions. + return GetFlag(n, "memberget") || SwigType_isconst(Getattr(n, "decl")); + } + + /* --------------------------------------------------------------------------- + * D::areAllOverloadsOverridden() + * + * Determines whether the class the passed function node belongs to overrides + * all the overlaods for the passed function node defined somewhere up the + * inheritance hierachy. + * --------------------------------------------------------------------------- */ + bool areAllOverloadsOverridden(Node *n) const { + List *base_list = Getattr(parentNode(n), "bases"); + if (!base_list) { + // If the class which contains n is not derived from any other class, + // there cannot be any not-overridden overloads. + return true; + } + + // In case of multiple base classes, skip to the one which has not been + // ignored. + // RESEARCH: Also emit a warning in case of multiple inheritance here? + Iterator it = First(base_list); + while (it.item && GetFlag(it.item, "feature:ignore")) { + it = Next(it); + } + Node *base_class = it.item; + + if (!base_class) { + // If all base classes have been ignored, there cannot be one either. + return true; + } + + // We try to find at least a single overload which exists in the base class + // so we can progress up the inheritance hierachy even if there have been + // new overloads introduced after the topmost class. + Node *base_function = NULL; + for (Node *tmp = firstChild(base_class); tmp; tmp = nextSibling(tmp)) { + if (Strcmp(Getattr(tmp, "sym:name"), Getattr(n, "sym:name")) == 0) { + base_function = tmp; + break; + } + } + + if (!base_function) { + // If there is no overload which also exists in the super class, there + // cannot be any base class overloads not overridden. + return true; + } + + size_t base_overload_count = 0; + for (Node *tmp = firstSibling(base_function); tmp; tmp = Getattr(tmp, "sym:nextSibling")) { + if (is_protected(base_function) && + !(Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode())) { + // If the base class function is »protected« and were are not in + // director mode, it is not emitted to the base class and thus we do + // not count it. Otherwise, we would run into issues if the visiblity + // of some functions was changed from protected to public in a child + // class with the using directive. + continue; + } + ++base_overload_count; + } + + return ((base_overload_count <= overridingOverloadCount(n)) && + areAllOverloadsOverridden(base_function)); + } + + /* --------------------------------------------------------------------------- + * D::overridingOverloadCount() + * + * Given a member function node, this function counts how many of the + * overloads of the function (including itself) override a function in the + * base class. + * --------------------------------------------------------------------------- */ + size_t overridingOverloadCount(Node *n) const { + size_t result = 0; + + Node *tmp = firstSibling(n); + do { + // KLUDGE: We also have to count the function if the access attribute is + // not present, since this means that it has been promoted into another + // protection level in the base class with the C++ »using« directive, and + // is thus taken into account when counting the base class overloads, even + // if it is not marked as »override« by the SWIG parser. + if (Getattr(n, "override") || !Getattr(n, "access")) { + ++result; + } + } while((tmp = Getattr(tmp, "sym:nextSibling"))); + + return result; + } + + /* --------------------------------------------------------------------------- + * D::firstSibling() + * + * Returns the first sibling of the passed node. + * --------------------------------------------------------------------------- */ + Node *firstSibling(Node *n) const { + Node *result = n; + while (Node *tmp = Getattr(result, "sym:previousSibling")) { + result = tmp; + } + return result; + } + + /* --------------------------------------------------------------------------- + * D::indentCode() + * + * Helper function to indent a code (string) by one level. + * --------------------------------------------------------------------------- */ + void indentCode(String* code) const { + Replaceall(code, "\n", "\n "); + Replaceall(code, " \n", "\n"); + Chop(code); + } + + /* --------------------------------------------------------------------------- + * D::emitBanner() + * --------------------------------------------------------------------------- */ + void emitBanner(File *f) const { + Printf(f, "/* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); + } +}; + +static Language *new_swig_d() { + return new D(); +} + +/* ----------------------------------------------------------------------------- + * swig_d() - Instantiate module + * ----------------------------------------------------------------------------- */ +extern "C" Language *swig_d(void) { + return new_swig_d(); +} + +/* ----------------------------------------------------------------------------- + * Usage information displayed at the command line. + * ----------------------------------------------------------------------------- */ +const char *D::usage = (char *) "\ +D Options (available with -d)\n\ + -splitproxy - Write each D type to a dedicated file instead of\n\ + generating a single proxy D module.\n\ + -noproxy - Generate the low-level functional interface instead\n\ + of proxy classes\n\ + -package <pkg> - Write generated D modules into package <pkg>\n\ + -wrapperlibrary <wl> - Sets the name of the wrapper library to <wl>\n\ +\n"; diff --git a/Source/Modules/go.cxx b/Source/Modules/go.cxx index f62586b92..094b1dd5a 100644 --- a/Source/Modules/go.cxx +++ b/Source/Modules/go.cxx @@ -43,11 +43,9 @@ class GO:public Language { File *f_go_runtime; File *f_go_header; File *f_go_wrappers; - File *f_go_once; File *f_gc_runtime; File *f_gc_header; File *f_gc_wrappers; - File *f_gc_once; // True if we imported a module. bool saw_import; @@ -100,11 +98,9 @@ public: f_go_runtime(NULL), f_go_header(NULL), f_go_wrappers(NULL), - f_go_once(NULL), f_gc_runtime(NULL), f_gc_header(NULL), f_gc_wrappers(NULL), - f_gc_once(NULL), saw_import(false), imported_package(NULL), interfaces(NULL), @@ -303,12 +299,10 @@ private: f_go_runtime = NewString(""); f_go_header = NewString(""); f_go_wrappers = NewString(""); - f_go_once = NewString(""); if (!gccgo_flag) { f_gc_runtime = NewString(""); f_gc_header = NewString(""); f_gc_wrappers = NewString(""); - f_gc_once = NewString(""); } Swig_register_filebyname("begin", f_c_begin); @@ -322,13 +316,11 @@ private: Swig_register_filebyname("go_runtime", f_go_runtime); Swig_register_filebyname("go_header", f_go_header); Swig_register_filebyname("go_wrapper", f_go_wrappers); - Swig_register_filebyname("go_once", f_go_once); if (!gccgo_flag) { Swig_register_filebyname("gc_begin", f_gc_begin); Swig_register_filebyname("gc_runtime", f_gc_runtime); Swig_register_filebyname("gc_header", f_gc_header); Swig_register_filebyname("gc_wrapper", f_gc_wrappers); - Swig_register_filebyname("gc_once", f_gc_once); } Swig_banner(f_c_begin); @@ -349,6 +341,7 @@ private: if (!gccgo_flag) { Swig_banner(f_gc_begin); Printf(f_gc_begin, "\n/* This file should be compiled with 6c/8c. */\n"); + Printf(f_gc_begin, "#pragma dynimport _ _ \"%s\"\n", soname); } // Output module initialization code. @@ -414,16 +407,10 @@ private: Dump(f_c_wrappers, f_c_begin); Dump(f_c_init, f_c_begin); Dump(f_go_header, f_go_begin); - if (!saw_import) { - Dump(f_go_once, f_go_begin); - } Dump(f_go_runtime, f_go_begin); Dump(f_go_wrappers, f_go_begin); if (!gccgo_flag) { Dump(f_gc_header, f_gc_begin); - if (!saw_import) { - Dump(f_gc_once, f_gc_begin); - } Dump(f_gc_runtime, f_gc_begin); Dump(f_gc_wrappers, f_gc_begin); } @@ -1011,8 +998,9 @@ private: int gcFunctionWrapper(Node *n, String *name, String *go_name, String *overname, String *wname, ParmList *parms, SwigType *result, bool is_static, bool needs_wrapper) { Wrapper *f = NewWrapper(); - Printv(f->def, "#pragma dynimport ", wname, " ", wname, " \"", soname, "\"\n", NULL); - Printv(f->def, "void (*", wname, ")(void*);\n", NULL); + Printv(f->def, "#pragma dynimport ", wname, " ", wname, " \"\"\n", NULL); + Printv(f->def, "extern void (*", wname, ")(void*);\n", NULL); + Printv(f->def, "static void (*x", wname, ")(void*) = ", wname, ";\n", NULL); Printv(f->def, "\n", NULL); Printv(f->def, "void\n", NULL); @@ -1068,7 +1056,7 @@ private: Delete(parm_size); Printv(f->code, "{\n", NULL); - Printv(f->code, "\tcgocall(", wname, ", &p);\n", NULL); + Printv(f->code, "\truntime\xc2\xb7" "cgocall(x", wname, ", &p);\n", NULL); Printv(f->code, "}\n", NULL); Printv(f->code, "\n", NULL); @@ -1128,7 +1116,7 @@ private: Parm *base_parm = NULL; if (base && !isStatic(n)) { - SwigType *base_type = Copy(Getattr(class_node, "classtype")); + SwigType *base_type = Copy(getClassType()); SwigType_add_pointer(base_type); base_parm = NewParm(base_type, NewString("arg1"), n); set_nextSibling(base_parm, parms); @@ -1166,7 +1154,7 @@ private: p = nextParm(p); } if (SwigType_type(result) != T_VOID) { - Printv(f->code, "\t\tint : 0;\n", NULL); + Printv(f->code, "\t\tlong : 0;\n", NULL); String *ln = NewString("result"); String *ct = gcCTypeForGoValue(n, result, ln); Delete(ln); @@ -1244,7 +1232,7 @@ private: Parm *base_parm = NULL; if (base && !isStatic(n)) { - SwigType *base_type = Copy(Getattr(class_node, "classtype")); + SwigType *base_type = Copy(getClassType()); SwigType_add_pointer(base_type); base_parm = NewParm(base_type, NewString("arg1"), n); set_nextSibling(base_parm, parms); @@ -1270,7 +1258,11 @@ private: Parm *p = parms; for (int i = 0; i < parm_count; ++i) { p = getParm(p); - SwigType *pt = Getattr(p, "type"); + SwigType *pt = Copy(Getattr(p, "type")); + if (SwigType_isarray(pt)) { + SwigType_del_array(pt); + SwigType_add_pointer(pt); + } String *pn = NewString("g"); Append(pn, Getattr(p, "lname")); String *ct = gccgoCTypeForGoValue(p, pt, pn); @@ -1280,6 +1272,7 @@ private: Printv(fnname, ct, NULL); Delete(ct); Delete(pn); + Delete(pt); p = nextParm(p); } @@ -1945,7 +1938,7 @@ private: String *ty = NewString(Getattr(ni, "type")); SwigType_push(ty, Getattr(ni, "decl")); String *fullty = SwigType_typedef_resolve_all(ty); - bool is_function = SwigType_isfunction(fullty); + bool is_function = SwigType_isfunction(fullty) ? true : false; Delete(ty); Delete(fullty); @@ -2426,7 +2419,7 @@ private: * ------------------------------------------------------------ */ int classDirectorConstructor(Node *n) { - bool is_ignored = GetFlag(n, "feature:ignore"); + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; String *name = Getattr(n, "sym:name"); if (!name) { @@ -2667,7 +2660,7 @@ private: return SWIG_OK; } - bool is_ignored = GetFlag(n, "feature:ignore"); + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; if (!is_ignored) { String *fnname = NewString("DeleteDirector"); @@ -2679,7 +2672,7 @@ private: Setattr(n, "wrap:name", fnname); - Swig_DestructorToFunction(n, getNSpace(), Getattr(parentNode(n), "classtype"), CPlusPlus, Extend); + Swig_DestructorToFunction(n, getNSpace(), getClassType(), CPlusPlus, Extend); ParmList *parms = Getattr(n, "parms"); Setattr(n, "wrap:parms", parms); @@ -2749,7 +2742,7 @@ private: Printv(f_gc_wrappers, "void\n", NULL); Printv(f_gc_wrappers, wname, "(void *a, int32 n)\n", NULL); Printv(f_gc_wrappers, "{\n", NULL); - Printv(f_gc_wrappers, "\tcgocallback(\xc2\xb7", go_name, ", a, n);\n", NULL); + Printv(f_gc_wrappers, "\truntime\xc2\xb7" "cgocallback(\xc2\xb7", go_name, ", a, n);\n", NULL); Printv(f_gc_wrappers, "}\n\n", NULL); } else { Printv(f_c_directors, " ", wname, "(go_val);\n", NULL); @@ -2781,7 +2774,7 @@ private: int classDirectorMethod(Node *n, Node *parent, String *super) { (void) super; - bool is_ignored = GetFlag(n, "feature:ignore"); + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; bool is_pure_virtual = (Cmp(Getattr(n, "storage"), "virtual") == 0 && Cmp(Getattr(n, "value"), "0") == 0); // We don't need explicit calls. @@ -2869,7 +2862,7 @@ private: * ------------------------------------------------------------ */ int oneClassDirectorMethod(Node *n, Node *parent) { - bool is_ignored = GetFlag(n, "feature:ignore"); + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; bool is_pure_virtual = (Cmp(Getattr(n, "storage"), "virtual") == 0 && Cmp(Getattr(n, "value"), "0") == 0); String *name = Getattr(n, "sym:name"); @@ -3415,7 +3408,7 @@ private: p = Getattr(p, "tmap:directorin:next"); } if (SwigType_type(result) != T_VOID) { - Printv(f->code, " int : 0;\n", NULL); + Printv(f->code, " long : 0;\n", NULL); String *rname = NewString("result"); String *cg = gcCTypeForGoValue(n, result, rname); Printv(f->code, " ", cg, ";\n", NULL); @@ -3475,7 +3468,7 @@ private: Printv(f_gc_wrappers, "void\n", NULL); Printv(f_gc_wrappers, callback_wname, "(void *a, int32 n)\n", NULL); Printv(f_gc_wrappers, "{\n", NULL); - Printv(f_gc_wrappers, "\tcgocallback(\xc2\xb7", callback_name, ", a, n);\n", NULL); + Printv(f_gc_wrappers, "\truntime\xc2\xb7" "cgocallback(\xc2\xb7", callback_name, ", a, n);\n", NULL); Printv(f_gc_wrappers, "}\n\n", NULL); } else { if (SwigType_type(result) != T_VOID) { @@ -3545,7 +3538,7 @@ private: } } else { assert(is_pure_virtual); - Printv(f->code, " _swig_gopanic(\"call to pure virtual function ", Getattr(parent, "sym:name"), name, "\");\n"); + Printv(f->code, " _swig_gopanic(\"call to pure virtual function ", Getattr(parent, "sym:name"), name, "\");\n", NULL); if (SwigType_type(result) != T_VOID) { String *retstr = SwigType_rcaststr(Getattr(n, "returntype"), "c_result"); Printv(f->code, " return ", retstr, ";\n", NULL); @@ -3782,7 +3775,7 @@ private: int num_required = emit_num_required(pi); int num_arguments = emit_num_arguments(pi); - bool varargs = emit_isvarargs(pi); + bool varargs = emit_isvarargs(pi) ? true : false; if (varargs) { Printf(f_go_wrappers, "\tif argc >= %d {\n", num_required); @@ -4138,7 +4131,7 @@ private: n1, name, n2); return false; } - bool r = addSymbol(name, n, scope); + bool r = addSymbol(name, n, scope) ? true : false; assert(r); return true; } diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index 4a6abd569..234a1e85b 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -1714,10 +1714,10 @@ public: base = Next(base); continue; } - String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); - String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); - Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, input_file, line_number, - "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", proxyclassname, baseclassname); + String *proxyclassname = Getattr(n, "classtypeobj"); + String *baseclassname = Getattr(base.item, "name"); + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname)); base = Next(base); } } @@ -1735,9 +1735,9 @@ public: Delete(baseclass); baseclass = NULL; if (purebase_notderived) - Swig_error(input_file, line_number, "The javabase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + Swig_error(Getfile(n), Getline(n), "The javabase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { - Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, input_file, line_number, + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java. " "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); } @@ -1772,12 +1772,10 @@ public: } if (tm && *Char(tm)) { if (!destruct_methodname) { - Swig_error(input_file, line_number, - "No methodname attribute defined in javadestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in javadestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); } if (!destruct_methodmodifiers) { - Swig_error(input_file, line_number, - "No methodmodifiers attribute defined in javadestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + Swig_error(Getfile(n), Getline(n), "No methodmodifiers attribute defined in javadestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); } } // Emit the finalize and delete methods @@ -3326,8 +3324,10 @@ public: } Printf(f_runtime, "namespace Swig {\n"); - Printf(f_runtime, " static jclass jclass_%s = NULL;\n", imclass_name); - Printf(f_runtime, " static jmethodID director_methids[%d];\n", n_methods); + Printf(f_runtime, " namespace {\n"); + Printf(f_runtime, " jclass jclass_%s = NULL;\n", imclass_name); + Printf(f_runtime, " jmethodID director_methids[%d];\n", n_methods); + Printf(f_runtime, " }\n"); Printf(f_runtime, "}\n"); Printf(w->def, "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls) {", jnipackage, jni_imclass_name, swig_module_init_jni); @@ -3548,7 +3548,6 @@ public: String *callback_def = NewString(""); String *callback_code = NewString(""); String *imcall_args = NewString(""); - int gencomma = 0; int classmeth_off = curr_class_dmethod - first_class_dmethod; bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; @@ -3767,14 +3766,14 @@ public: Delete(tp); /* Go through argument list, convert from native to Java */ - for (p = l; p; /* empty */ ) { + for (i = 0, p = l; p; ++i) { /* Is this superfluous? */ while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { p = Getattr(p, "tmap:directorin:next"); } SwigType *pt = Getattr(p, "type"); - String *ln = Copy(Getattr(p, "name")); + String *ln = makeParameterName(n, p, i, false); String *c_param_type = NULL; String *c_decl = NewString(""); String *arg = NewString(""); @@ -3833,7 +3832,7 @@ public: substituteClassname(pt, din); Replaceall(din, "$jniinput", ln); - if (++gencomma > 1) + if (i > 0) Printf(imcall_args, ", "); Printf(callback_def, ", %s %s", tm, ln); @@ -3896,6 +3895,7 @@ public: Delete(arg); Delete(c_decl); Delete(c_param_type); + Delete(ln); } /* header declaration, start wrapper definition */ diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index e28fcbb89..82af250f7 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -52,7 +52,7 @@ extern "C" { return all_protected_mode; } void Language_replace_special_variables(String *method, String *tm, Parm *parm) { - Language::instance()->replaceSpecialVariables(method, tm, parm); + Language::instance()->replaceSpecialVariables(method, tm, parm); } } @@ -1344,7 +1344,7 @@ int Language::variableHandler(Node *n) { Swig_save("variableHandler", n, "feature:immutable", NIL); if (SmartPointer) { /* If a smart-pointer and it's a constant access, we have to set immutable */ - if (Getattr(CurrentClass, "allocate:smartpointerconst")) { + if (!Getattr(CurrentClass, "allocate:smartpointermutable")) { SetFlag(n, "feature:immutable"); } } @@ -1391,7 +1391,7 @@ int Language::membervariableHandler(Node *n) { int assignable = is_assignable(n); if (SmartPointer) { - if (Getattr(CurrentClass, "allocate:smartpointerconst")) { + if (!Getattr(CurrentClass, "allocate:smartpointermutable")) { assignable = 0; } } @@ -1806,17 +1806,25 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_ classname = Getattr(n, "name"); for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { /* we only need to check the virtual members */ - if (!checkAttribute(ni, "storage", "virtual")) - continue; nodeType = Getattr(ni, "nodeType"); + int is_using = (Cmp(nodeType, "using") == 0); + Node *nn = is_using ? firstChild(ni) : ni; /* assume there is only one child node for "using" nodes */ + if (is_using) { + if (nn) + nodeType = Getattr(nn, "nodeType"); + else + continue; // A private "using" node + } + if (!checkAttribute(nn, "storage", "virtual")) + continue; /* we need to add methods(cdecl) and destructor (to check for throw decl) */ int is_destructor = (Cmp(nodeType, "destructor") == 0); if ((Cmp(nodeType, "cdecl") == 0) || is_destructor) { - decl = Getattr(ni, "decl"); + decl = Getattr(nn, "decl"); /* extra check for function type and proper access */ - if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(ni)) || need_nonpublic_member(ni))) { - String *name = Getattr(ni, "name"); - Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(ni); + if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(nn)) || need_nonpublic_member(nn))) { + String *name = Getattr(nn, "name"); + Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(nn); /* Make sure that the new method overwrites the existing: */ int len = Len(vm); const int DO_NOT_REPLACE = -1; @@ -1834,7 +1842,7 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_ String *fqdname = NewStringf("%s::%s", classname, name); Hash *item = NewHash(); Setattr(item, "fqdname", fqdname); - Node *m = Copy(ni); + Node *m = Copy(nn); /* Store the complete return type - needed for non-simple return types (pointers, references etc.) */ SwigType *ty = NewString(Getattr(m, "type")); @@ -1854,6 +1862,7 @@ int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_ Append(vm, item); else Setitem(vm, replace, item); + Setattr(nn, "directorNode", m); Delete(mname); } @@ -2443,6 +2452,9 @@ int Language::classHandler(Node *n) { List *methods = Getattr(n, "allocate:smartpointer"); cplus_mode = PUBLIC; SmartPointer = CWRAP_SMART_POINTER; + if (Getattr(n, "allocate:smartpointerconst") && Getattr(n, "allocate:smartpointermutable")) { + SmartPointer |= CWRAP_SMART_POINTER_OVERLOAD; + } Iterator c; for (c = First(methods); c.item; c = Next(c)) { emit_one(c.item); @@ -2803,7 +2815,7 @@ int Language::validIdentifier(String *s) { * ----------------------------------------------------------------------------- */ int Language::usingDeclaration(Node *n) { - if ((cplus_mode == PUBLIC)) { + if ((cplus_mode == PUBLIC) || (!is_public(n) && dirprot_mode())) { Node *np = Copy(n); Node *c; for (c = firstChild(np); c; c = nextSibling(c)) { @@ -3008,7 +3020,7 @@ Node *Language::symbolLookup(String *s, const_String_or_char_ptr scope) { * Tries to locate a class from a type definition * ----------------------------------------------------------------------------- */ -Node *Language::classLookup(SwigType *s) { +Node *Language::classLookup(const SwigType *s) { Node *n = 0; /* Look in hash of cached values */ diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx index d240d3d6f..d0cbc9195 100644 --- a/Source/Modules/lua.cxx +++ b/Source/Modules/lua.cxx @@ -919,7 +919,7 @@ public: String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); SwigType_remember_clientdata(t, wrap_class); - String *rt = Copy(Getattr(n, "classtype")); + String *rt = Copy(getClassType()); SwigType_add_pointer(rt); // Register the class structure with the type checker diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx index f0e941f22..95327018d 100644 --- a/Source/Modules/main.cxx +++ b/Source/Modules/main.cxx @@ -129,6 +129,7 @@ static const char *usage3 = (const char *) "\ -oh <headfile> - Set name of the output header file to <headfile>\n\ -outcurrentdir - Set default output dir to current dir instead of input file's path\n\ -outdir <dir> - Set language specific files output directory to <dir>\n\ + -pcreversion - Display PCRE version information\n\ -small - Compile in virtual elimination & compact mode\n\ -swiglib - Report location of SWIG library and exit\n\ -templatereduce - Reduce all the typedefs in templates\n\ @@ -515,6 +516,12 @@ void SWIG_getoptions(int argc, char *argv[]) { } else if (strcmp(argv[i], "-nodirprot") == 0) { Wrapper_director_protected_mode_set(0); Swig_mark_arg(i); + } else if (strcmp(argv[i], "-pcreversion") == 0) { + String *version = Swig_pcre_version(); + Printf(stdout, "%s\n", version); + Delete(version); + Swig_mark_arg(i); + SWIG_exit(EXIT_SUCCESS); } else if (strcmp(argv[i], "-small") == 0) { Wrapper_compact_print_mode_set(1); Wrapper_virtual_elimination_mode_set(1); @@ -622,7 +629,14 @@ void SWIG_getoptions(int argc, char *argv[]) { } else if (strcmp(argv[i], "-version") == 0) { fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); fprintf(stdout, "\nCompiled with %s [%s]\n", SWIG_CXX, SWIG_PLATFORM); - fprintf(stdout, "Please see %s for reporting bugs and further information\n", PACKAGE_BUGREPORT); + fprintf(stdout, "\nConfigured options: %cpcre\n", +#ifdef HAVE_PCRE + '+' +#else + '-' +#endif + ); + fprintf(stdout, "\nPlease see %s for reporting bugs and further information\n", PACKAGE_BUGREPORT); SWIG_exit(EXIT_SUCCESS); } else if (strcmp(argv[i], "-copyright") == 0) { fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); diff --git a/Source/Modules/modula3.cxx b/Source/Modules/modula3.cxx index edd6690ce..45ceba1a4 100644 --- a/Source/Modules/modula3.cxx +++ b/Source/Modules/modula3.cxx @@ -2222,8 +2222,7 @@ MODULA3(): } base = Next(base); if (base.item != NIL) { - Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, - line_number, + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", classDeclarationName, Getattr(base.item, "name")); } @@ -2236,8 +2235,7 @@ MODULA3(): // Inheritance from pure Modula 3 classes const String *pure_baseclass = typemapLookup(n, "m3base", classDeclarationName, WARN_NONE); if (hasContent(pure_baseclass) && hasContent(baseclass)) { - Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, - line_number, + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", classDeclarationName, pure_baseclass); } // Pure Modula 3 interfaces @@ -2273,7 +2271,7 @@ MODULA3(): destruct_methodname = Getattr(attributes, "tmap:m3destruct:methodname"); } if (!destruct_methodname) { - Swig_error(input_file, line_number, "No methodname attribute defined in m3destruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in m3destruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); } // Emit the Finalize and Dispose methods if (tm) { @@ -2466,8 +2464,7 @@ MODULA3(): Append(baseclassname, Getattr(base.item, "sym:name")); base = Next(base); if (base.item != NIL) { - Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, - line_number, + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", proxy_class_name, Getattr(base.item, "name")); } diff --git a/Source/Modules/mzscheme.cxx b/Source/Modules/mzscheme.cxx index 0bc3c8a68..d071dc870 100644 --- a/Source/Modules/mzscheme.cxx +++ b/Source/Modules/mzscheme.cxx @@ -682,7 +682,7 @@ public: String *mangled_classname = 0; String *real_classname = 0; String *scm_structname = NewString(""); - SwigType *ctype_ptr = NewStringf("p.%s", Getattr(n, "classtype")); + SwigType *ctype_ptr = NewStringf("p.%s", getClassType()); SwigType *t = NewStringf("p.%s", Getattr(n, "name")); swigtype_ptr = SwigType_manglestr(t); diff --git a/Source/Modules/ocaml.cxx b/Source/Modules/ocaml.cxx index 82e3f846a..6021cf276 100644 --- a/Source/Modules/ocaml.cxx +++ b/Source/Modules/ocaml.cxx @@ -35,7 +35,7 @@ static String *classname = 0; static String *module = 0; static String *init_func_def = 0; static String *f_classtemplate = 0; -static String *name_qualifier = 0; +static SwigType *name_qualifier_type = 0; static Hash *seen_enums = 0; static Hash *seen_enumvalues = 0; @@ -898,12 +898,12 @@ public: String *name = Getattr(n, "feature:symname"); SwigType *type = Getattr(n, "type"); String *value = Getattr(n, "value"); - String *qvalue = Getattr(n, "qualified:value"); + SwigType *qname = Getattr(n, "qualified:name"); String *rvalue = NewString(""); String *temp = 0; - if (qvalue) - value = qvalue; + if (qname) + value = qname; if (!name) { name = mangleNameForCaml(Getattr(n, "name")); @@ -1228,20 +1228,18 @@ public: return out; } - String *fully_qualify_enum_name(Node *n, String *name) { + SwigType *fully_qualified_enum_type(Node *n) { Node *parent = 0; - String *qualification = NewString(""); String *fully_qualified_name = NewString(""); String *parent_type = 0; - String *normalized_name; parent = parentNode(n); while (parent) { parent_type = nodeType(parent); if (Getattr(parent, "name")) { String *parent_copy = NewStringf("%s::", Getattr(parent, "name")); - if (!Cmp(parent_type, "class") || !Cmp(parent_type, "namespace")) - Insert(qualification, 0, parent_copy); + if (Cmp(parent_type, "class") == 0 || Cmp(parent_type, "namespace") == 0) + Insert(fully_qualified_name, 0, parent_copy); Delete(parent_copy); } if (!Cmp(parent_type, "class")) @@ -1249,25 +1247,18 @@ public: parent = parentNode(parent); } - Printf(fully_qualified_name, "%s%s", qualification, name); - - normalized_name = normalizeTemplatedClassName(fully_qualified_name); - if (!strncmp(Char(normalized_name), "enum ", 5)) { - Insert(normalized_name, 5, qualification); - } - - return normalized_name; + return fully_qualified_name; } /* Benedikt Grundmann inspired --> Enum wrap styles */ int enumvalueDeclaration(Node *n) { String *name = Getattr(n, "name"); - String *qvalue = 0; + SwigType *qtype = 0; - if (name_qualifier) { - qvalue = Copy(name_qualifier); - Printv(qvalue, name, NIL); + if (name_qualifier_type) { + qtype = Copy(name_qualifier_type); + Printv(qtype, name, NIL); } if (const_enum && name && !Getattr(seen_enumvalues, name)) { @@ -1275,10 +1266,10 @@ public: SetFlag(n, "feature:immutable"); Setattr(n, "feature:enumvalue", "1"); // this does not appear to be used - if (qvalue) - Setattr(n, "qualified:value", qvalue); + if (qtype) + Setattr(n, "qualified:name", SwigType_namestr(qtype)); - String *evname = SwigType_manglestr(qvalue); + String *evname = SwigType_manglestr(qtype); Insert(evname, 0, "SWIG_ENUM_"); Setattr(n, "feature:enumvname", name); @@ -1309,10 +1300,10 @@ public: /* name is now fully qualified */ String *fully_qualified_name = NewString(name); bool seen_enum = false; - if (name_qualifier) - Delete(name_qualifier); + if (name_qualifier_type) + Delete(name_qualifier_type); char *strip_position; - name_qualifier = fully_qualify_enum_name(n, NewString("")); + name_qualifier_type = fully_qualified_enum_type(n); strip_position = strstr(Char(oname), "::"); diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx index 365fcd370..554e40bb8 100644 --- a/Source/Modules/php.cxx +++ b/Source/Modules/php.cxx @@ -126,7 +126,7 @@ static enum { } wrapperType = standard; extern "C" { - static void (*r_prevtracefunc) (SwigType *t, String *mangled, String *clientdata) = 0; + static void (*r_prevtracefunc) (const SwigType *t, String *mangled, String *clientdata) = 0; } static void SwigPHP_emit_resource_registrations() { @@ -666,7 +666,7 @@ public: /* We have an extra 'this' parameter. */ SetFlag(n, "wrap:this"); } - String *dispatch = Swig_overload_dispatch(n, "return %s(INTERNAL_FUNCTION_PARAM_PASSTHRU);", &maxargs); + String *dispatch = Swig_overload_dispatch(n, "%s(INTERNAL_FUNCTION_PARAM_PASSTHRU); return;", &maxargs); /* Generate a dispatch wrapper for all overloaded functions */ @@ -915,8 +915,10 @@ public: } /* Insert argument output code */ + bool hasargout = false; for (i = 0, p = l; p; i++) { if ((tm = Getattr(p, "tmap:argout"))) { + hasargout = true; Replaceall(tm, "$source", Getattr(p, "lname")); // Replaceall(tm,"$input",Getattr(p,"lname")); Replaceall(tm, "$target", "return_value"); @@ -974,7 +976,7 @@ public: /* Error handling code */ Printf(f->code, "fail:\n"); Printv(f->code, cleanup, NIL); - Printv(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());", NIL); + Printv(f->code, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());", NIL); Printf(f->code, "}\n"); @@ -1599,10 +1601,9 @@ public: Delete(args); args = NewString("$res=null"); } - SwigType *t = Getattr(current_class, "classtype"); - String *mangled_type = SwigType_manglestr(SwigType_ltype(t)); + String *mangled_type = SwigType_manglestr(Getattr(n, "type")); Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args); - Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '_p%s') {\n", arg0, arg0, mangled_type); + Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '%s') {\n", arg0, arg0, mangled_type); Printf(output, "\t\t\t$this->%s=$%s;\n", SWIG_PTR, arg0); Printf(output, "\t\t\treturn;\n"); Printf(output, "\t\t}\n"); @@ -1663,7 +1664,7 @@ public: } } Printf(output, "%s", prepare); - } else if (Cmp(d, "void") == 0) { + } else if (Cmp(d, "void") == 0 && !hasargout) { if (Cmp(invoke, "$r") != 0) Printf(output, "\t\t%s;\n", invoke); } else if (is_class(d)) { @@ -2289,7 +2290,7 @@ done: Append(f->code, "return;\n"); Append(f->code, "fail:\n"); - Append(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); + Append(f->code, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); Printf(f->code, "}\n"); Wrapper_print(f, s_wrappers); @@ -2664,7 +2665,7 @@ done: } Append(w->code, "fail:\n"); - Append(w->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); + Append(w->code, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); Append(w->code, "}\n"); // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method @@ -2709,7 +2710,7 @@ static PHP *maininstance = 0; // We use this function to be able to write out zend_register_list_destructor_ex // lines for most things in the type table // NOTE: it's a function NOT A PHP::METHOD -extern "C" void typetrace(SwigType *ty, String *mangled, String *clientdata) { +extern "C" void typetrace(const SwigType *ty, String *mangled, String *clientdata) { Node *class_node; if (!zend_types) { zend_types = NewHash(); diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx index fed5205e1..6d5f500a4 100644 --- a/Source/Modules/python.cxx +++ b/Source/Modules/python.cxx @@ -130,7 +130,7 @@ static const char *usage2 = (char *) "\ -nofastproxy - Use traditional proxy mechanism for member methods (default) \n\ -nofastquery - Use traditional query mechanism for types (default) \n\ -noh - Don't generate the output header file\n\ - -nomodern - Don't use modern python features which are not back compatible \n\ + -nomodern - Don't use modern python features which are not backwards compatible \n\ -nomodernargs - Use classic ParseTuple/CallFunction methods to pack/unpack the function arguments (default) \n"; static const char *usage3 = (char *) "\ -noolddefs - Don't emit the old method definitions even when using fastproxy (default) \n\ @@ -1799,7 +1799,7 @@ public: } while ((sibl = Getattr(sibl, "sym:nextSibling"))); Append(f->code, "fail:\n"); Printf(f->code, "SWIG_SetErrorMsg(PyExc_NotImplementedError," - "\"Wrong number of arguments for overloaded function '%s'.\\n\"" "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); + "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); Append(f->code, "return NULL;\n"); Delete(protoTypes); } @@ -2866,7 +2866,7 @@ public: bool ignore = GetFlag(b.item, "feature:ignore") ? true : false; if (!bname || ignore) { if (!bname && !ignore) { - Swig_warning(WARN_TYPE_UNDEFINED_CLASS, input_file, line_number, + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(n), Getline(n), "Base class '%s' ignored - unknown module name for base. Either import the appropriate module interface file or specify the name of the module in the %%import directive.\n", SwigType_namestr(Getattr(b.item, "name"))); } b = Next(b); diff --git a/Source/Modules/r.cxx b/Source/Modules/r.cxx index 749797c78..64583175b 100644 --- a/Source/Modules/r.cxx +++ b/Source/Modules/r.cxx @@ -300,7 +300,7 @@ public: Printf(stderr, "<memberfunctionHandler> %s %s\n", Getattr(n, "name"), Getattr(n, "type")); - member_name = Getattr(n, "name"); + member_name = Getattr(n, "sym:name"); processing_class_member_function = 1; int status = Language::memberfunctionHandler(n); processing_class_member_function = 0; @@ -1603,6 +1603,16 @@ void R::dispatchFunction(Node *n) { j == 0 ? "" : " && ", j+1); } + else if (DohStrcmp(tm,"integer")==0) { + Printf(f->code, "%s(is.integer(argv[[%d]]) || is.numeric(argv[[%d]]))", + j == 0 ? "" : " && ", + j+1, j+1); + } + else if (DohStrcmp(tm,"character")==0) { + Printf(f->code, "%sis.character(argv[[%d]])", + j == 0 ? "" : " && ", + j+1); + } else { Printf(f->code, "%sextends(argtypes[%d], '%s')", j == 0 ? "" : " && ", @@ -1617,7 +1627,10 @@ void R::dispatchFunction(Node *n) { } } if (cur_args != -1) { - Printv(f->code, "}", NIL); + Printf(f->code, "} else {\n" + "stop(\"cannot find overloaded function for %s with argtypes (\"," + "toString(argtypes),\")\");\n" + "}", sfname); } Printv(f->code, ";\nf(...)", NIL); Printv(f->code, ";\n}", NIL); diff --git a/Source/Modules/ruby.cxx b/Source/Modules/ruby.cxx index bcdfd69d3..8461b8bef 100644 --- a/Source/Modules/ruby.cxx +++ b/Source/Modules/ruby.cxx @@ -2054,8 +2054,15 @@ public: // Construct real method name String* methodName = NewString(""); - if ( isMethod ) - Printv( methodName, Getattr(parentNode(sibl),"sym:name"), ".", NIL ); + if ( isMethod ) { + // Sometimes a method node has no parent (SF#3034054). + // This value is used in an exception message, so just skip the class + // name in this case so at least we don't segfault. This is probably + // just working around a problem elsewhere though. + Node *parent_node = parentNode(sibl); + if (parent_node) + Printv( methodName, Getattr(parent_node,"sym:name"), ".", NIL ); + } Append( methodName, Getattr(sibl,"sym:name" ) ); if ( isCtor ) Append( methodName, ".new" ); @@ -2395,7 +2402,7 @@ public: } String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); - Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, input_file, line_number, + Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Ruby.\n", proxyclassname, baseclassname); base = Next(base); } diff --git a/Source/Modules/swigmain.cxx b/Source/Modules/swigmain.cxx index 844229a96..bcccf7a1b 100644 --- a/Source/Modules/swigmain.cxx +++ b/Source/Modules/swigmain.cxx @@ -53,6 +53,7 @@ extern "C" { Language *swig_uffi(void); Language *swig_r(void); Language *swig_go(void); + Language *swig_d(void); } struct swig_module { @@ -71,6 +72,7 @@ static swig_module modules[] = { {"-clisp", swig_clisp, "CLISP"}, {"-cffi", swig_cffi, "CFFI"}, {"-csharp", swig_csharp, "C#"}, + {"-d", swig_d, "D"}, {"-fortran", swig_fortran, "FORTRAN"}, {"-go", swig_go, "Go"}, {"-guile", swig_guile, "Guile"}, diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h index 693a67071..142130628 100644 --- a/Source/Modules/swigmod.h +++ b/Source/Modules/swigmod.h @@ -213,7 +213,7 @@ public: virtual int addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope = ""); /* Add symbol */ virtual void dumpSymbols(); virtual Node *symbolLookup(String *s, const_String_or_char_ptr scope = ""); /* Symbol lookup */ - virtual Node *classLookup(SwigType *s); /* Class lookup */ + virtual Node *classLookup(const SwigType *s); /* Class lookup */ virtual Node *enumLookup(SwigType *s); /* Enum lookup */ virtual int abstractClassTest(Node *n); /* Is class really abstract? */ virtual int is_assignable(Node *n); /* Is variable assignable? */ @@ -382,9 +382,15 @@ void Wrapper_fast_dispatch_mode_set(int); void Wrapper_cast_dispatch_mode_set(int); void Wrapper_naturalvar_mode_set(int); - void clean_overloaded(Node *n); +extern "C" { + const char *Swig_to_string(DOH *object, int count = -1); + const char *Swig_to_string_with_location(DOH *object, int count = -1); + void Swig_print(DOH *object, int count = -1); + void Swig_print_with_location(DOH *object, int count = -1); +} + /* Contracts */ void Swig_contracts(Node *n); @@ -397,5 +403,4 @@ void Swig_browser(Node *n, int); void Swig_default_allocators(Node *n); void Swig_process_types(Node *n); - #endif diff --git a/Source/Modules/tcl8.cxx b/Source/Modules/tcl8.cxx index b6b4c6965..dfdd71b64 100644 --- a/Source/Modules/tcl8.cxx +++ b/Source/Modules/tcl8.cxx @@ -783,10 +783,7 @@ public: String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); SwigType_remember_clientdata(t, wrap_class); - // t = Copy(Getattr(n,"classtype")); - // SwigType_add_pointer(t); - - String *rt = Copy(Getattr(n, "classtype")); + String *rt = Copy(getClassType()); SwigType_add_pointer(rt); // Register the class structure with the type checker diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index e0e06d54e..3e2c9ca1e 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -175,10 +175,10 @@ class TypePass:private Dispatcher { } } if (Strcmp(nodeType(bcls), "classforward") != 0) { - Swig_error(Getfile(cls), Getline(cls), "'%s' does not have a valid base class.\n", Getattr(cls, "name")); - Swig_error(Getfile(bcls), Getline(bcls), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); + Swig_error(Getfile(bname), Getline(bname), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); + Swig_error(Getfile(bcls), Getline(bcls), "See definition of '%s'.\n", SwigType_namestr(bname)); } else { - Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(cls), Getline(cls), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bname), Getline(bname), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname)); clsforward = 1; } @@ -189,7 +189,7 @@ class TypePass:private Dispatcher { ilist = alist = NewList(); Append(ilist, bcls); } else { - Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Base class '%s' undefined.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' undefined.\n", SwigType_namestr(bname)); Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "'%s' must be defined before it is used as a base class.\n", SwigType_namestr(bname)); } } @@ -202,10 +202,9 @@ class TypePass:private Dispatcher { if (!bcls) { if (!clsforward) { if (ispublic && !Getmeta(bname, "already_warned")) { - Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); if (Strchr(bname, '<')) { - Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Maybe you forgot to instantiate '%s' using %%template.\n", - SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Maybe you forgot to instantiate '%s' using %%template.\n", SwigType_namestr(bname)); } Setmeta(bname, "already_warned", "1"); } @@ -255,12 +254,17 @@ class TypePass:private Dispatcher { Delete(smartnamestr); /* setup inheritance relationship between smart pointer templates */ SwigType_inherit(smart, bsmart, 0, convcode); + if (!GetFlag(bclass, "feature:smartptr")) + Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Base class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(bclass, "name")), SwigType_namestr(Getattr(first, "name"))); Delete(convcode); Delete(bsmart); Delete(smart); } else { - Swig_error(Getfile(first), Getline(first), "Invalid type (%s) in 'smartptr' feature for class %s.\n", smartptr, clsname); + Swig_error(Getfile(first), Getline(first), "Invalid type (%s) in 'smartptr' feature for class %s.\n", SwigType_namestr(smartptr), SwigType_namestr(clsname)); } + } else { + if (GetFlag(bclass, "feature:smartptr")) + Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Derived class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(first, "name")), SwigType_namestr(Getattr(bclass, "name"))); } if (!importmode) { String *btype = Copy(bname); @@ -275,7 +279,7 @@ class TypePass:private Dispatcher { Symtab *st = Getattr(cls, "symtab"); Symtab *bst = Getattr(bclass, "symtab"); if (st == bst) { - Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", Getattr(cls, "name")); + Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", SwigType_namestr(Getattr(cls, "name"))); continue; } Symtab *s = Swig_symbol_current(); @@ -995,6 +999,7 @@ class TypePass:private Dispatcher { } Node *nn = copyNode(c); Delattr(nn, "access"); // access might be different from the method in the base class + Setattr(nn, "access", Getattr(n, "access")); if (!Getattr(nn, "sym:name")) Setattr(nn, "sym:name", symname); diff --git a/Source/Modules/utils.cxx b/Source/Modules/utils.cxx index 3fe7a2709..13a504bcf 100644 --- a/Source/Modules/utils.cxx +++ b/Source/Modules/utils.cxx @@ -100,3 +100,116 @@ void clean_overloaded(Node *n) { Delattr(n, "sym:overloaded"); } } + +/* ----------------------------------------------------------------------------- + * Swig_set_max_hash_expand() + * + * Controls how many Hash objects are displayed when displaying nested Hash objects. + * Makes DohSetMaxHashExpand an externally callable function (for debugger). + * ----------------------------------------------------------------------------- */ + +void Swig_set_max_hash_expand(int count) { + SetMaxHashExpand(count); +} + +extern "C" { + +/* ----------------------------------------------------------------------------- + * Swig_get_max_hash_expand() + * + * Returns how many Hash objects are displayed when displaying nested Hash objects. + * Makes DohGetMaxHashExpand an externally callable function (for debugger). + * ----------------------------------------------------------------------------- */ + +int Swig_get_max_hash_expand() { + return GetMaxHashExpand(); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_doh_string() + * + * DOH version of Swig_to_string() + * ----------------------------------------------------------------------------- */ + +static String *Swig_to_doh_string(DOH *object, int count) { + int old_count = Swig_get_max_hash_expand(); + if (count >= 0) + Swig_set_max_hash_expand(count); + + String *debug_string = object ? NewStringf("%s", object) : NewString("NULL"); + + Swig_set_max_hash_expand(old_count); + return debug_string; +} + +/* ----------------------------------------------------------------------------- + * Swig_to_doh_string_with_location() + * + * DOH version of Swig_to_string_with_location() + * ----------------------------------------------------------------------------- */ + +static String *Swig_to_doh_string_with_location(DOH *object, int count) { + int old_count = Swig_get_max_hash_expand(); + if (count >= 0) + Swig_set_max_hash_expand(count); + + String *debug_string = Swig_stringify_with_location(object); + + Swig_set_max_hash_expand(old_count); + return debug_string; +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string() + * + * Swig debug - return C string representation of any DOH type. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * Note: leaks memory. + * ----------------------------------------------------------------------------- */ + +const char *Swig_to_string(DOH *object, int count) { + return Char(Swig_to_doh_string(object, count)); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string_with_location() + * + * Swig debug - return C string representation of any DOH type, within [] brackets + * for Hash and List types, prefixed by line and file information. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * Note: leaks memory. + * ----------------------------------------------------------------------------- */ + +const char *Swig_to_string_with_location(DOH *object, int count) { + return Char(Swig_to_doh_string_with_location(object, count)); +} + +/* ----------------------------------------------------------------------------- + * Swig_print() + * + * Swig debug - display string representation of any DOH type. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * ----------------------------------------------------------------------------- */ + +void Swig_print(DOH *object, int count) { + String *output = Swig_to_doh_string(object, count); + Printf(stdout, "%s\n", output); + Delete(output); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string_with_location() + * + * Swig debug - display string representation of any DOH type, within [] brackets + * for Hash and List types, prefixed by line and file information. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * ----------------------------------------------------------------------------- */ + +void Swig_print_with_location(DOH *object, int count) { + String *output = Swig_to_doh_string_with_location(object, count); + Printf(stdout, "%s\n", output); + Delete(output); +} + +} // extern "C" + |