swig/Source/Modules/d.cxx

4866 lines
167 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -----------------------------------------------------------------------------
* 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 https://www.swig.org/legal.html.
*
* d.cxx
*
* D language module for SWIG.
* ----------------------------------------------------------------------------- */
#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 *private_string;
const String *protected_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;
/*
* 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;
// The D code for the main proxy modules. nspace_proxy_dmodules is a hash from
// the namespace name as key to an {"imports", "code"}. If the nspace feature
// is not active, only proxy_dmodule_imports and proxy_dmodule_code are used,
// which contain the code for the root proxy module.
//
// These variables should not be accessed directly but rather via the
// proxy{Imports, Code}Buffer)() helper functions which return the right
// buffer for a given namespace. If not in split proxy mode, they contain the
// whole proxy code.
String *proxy_dmodule_imports;
String *proxy_dmodule_code;
Hash *nspace_proxy_dmodules;
// The D code generated for the currently processed enum.
String *proxy_enum_code;
/*
* D data for the current proxy class.
*
* These strings are mainly used to temporarily accumulate code from the
* various member handling functions while a single class is processed and are
* no longer relevant once that class has been finished, i.e. after
* classHandler() has returned.
*/
// The unqualified name of the current proxy class.
String *proxy_class_name;
// The name of the current proxy class, qualified with the name of the
// namespace it is in, if any.
String *proxy_class_qname;
// The import directives for the current proxy class. They are written to the
// same D module the proxy class is written to.
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;
// Code generated at the begin of every D file
String *common_begin_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")),
private_string(NewString("private")),
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),
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),
nspace_proxy_dmodules(NULL),
proxy_enum_code(NULL),
proxy_class_name(NULL),
proxy_class_qname(NULL),
proxy_class_imports(NULL),
proxy_class_enums_code(NULL),
proxy_class_body_code(NULL),
proxy_class_epilogue_code(NULL),
proxy_class_code(NULL),
common_begin_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),
first_class_dmethod(0),
curr_class_dmethod(0),
unknown_types(NULL) {
// For now, multiple inheritance with directors is not possible. It should be
// easy to implement though.
director_multiple_inheritance = 0;
directorLanguage();
// 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)) {
/* Keep for backward compatible only */
Swig_mark_arg(i);
} 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.
Preprocessor_define("SWIG_D_VERSION 2", 0);
SWIG_config_file("d.swg");
allow_overloading();
}
/* ---------------------------------------------------------------------------
* D::top()
* --------------------------------------------------------------------------- */
virtual int top(Node *n) {
// Get any options set in the module directive
Node *module = Getattr(n, "module");
Node *optionsnode = Getattr(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"));
common_begin_code = Getattr(optionsnode, "dbegin");
if (common_begin_code)
Printf(common_begin_code, "\n");
}
/* 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");
Exit(EXIT_FAILURE);
}
f_begin = NewFile(outfile, "w", SWIG_output_files());
if (!f_begin) {
FileErrorDisplay(outfile);
Exit(EXIT_FAILURE);
}
if (Swig_directors_enabled()) {
if (!outfile_h) {
Printf(stderr, "Unable to determine outfile_h\n");
Exit(EXIT_FAILURE);
}
f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files());
if (!f_runtime_h) {
FileErrorDisplay(outfile_h);
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("");
nspace_proxy_dmodules = NewHash();
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);
Swig_obligatory_macros(f_runtime, "D");
if (Swig_directors_enabled()) {
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) {
String *filename = Swig_file_filename(outfile_h);
Printf(f_directors, "#include \"%s\"\n\n", filename);
Delete(filename);
}
}
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 (Swig_directors_enabled()) {
// Insert director runtime into the f_runtime file (before %header section).
Swig_insert_file("director_common.swg", f_runtime);
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);
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);
Delete(im_d_file);
}
// Generate the main D proxy module.
{
String *filen = NewStringf("%s%s.d", dmodule_directory, proxy_dmodule_name);
File *proxy_d_file = NewFile(filen, "w", SWIG_output_files());
if (!proxy_d_file) {
FileErrorDisplay(filen);
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 separate file).
replaceModuleVariables(proxy_dmodule_code);
Printv(proxy_d_file, proxy_dmodule_code, NIL);
Delete(proxy_d_file);
}
// Generate the additional proxy modules for nspace support.
for (Iterator it = First(nspace_proxy_dmodules); it.key; it = Next(it)) {
String *module_name = createLastNamespaceName(it.key);
String *filename = NewStringf("%s%s.d", outputDirectory(it.key), module_name);
File *file = NewFile(filename, "w", SWIG_output_files());
if (!file) {
FileErrorDisplay(filename);
Exit(EXIT_FAILURE);
}
Delete(filename);
emitBanner(file);
Printf(file, "module %s%s.%s;\n", package, it.key, module_name);
Printf(file, "\nstatic import %s;\n", im_dmodule_fq_name);
Printv(file, global_proxy_imports, NIL);
Printv(file, Getattr(it.item, "imports"), NIL);
Printv(file, "\n", NIL);
String *code = Getattr(it.item, "code");
replaceModuleVariables(code);
Printv(file, code, NIL);
Delete(file);
Delete(module_name);
}
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(nspace_proxy_dmodules);
nspace_proxy_dmodules = 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 (Swig_directors_enabled()) {
Dump(f_directors, f_begin);
Dump(f_directors_h, f_runtime_h);
Printf(f_runtime_h, "\n");
Printf(f_runtime_h, "#endif\n");
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);
Delete(f_runtime);
Delete(f_begin);
return SWIG_OK;
}
/* ---------------------------------------------------------------------------
* D::insertDirective()
* --------------------------------------------------------------------------- */
virtual int insertDirective(Node *n) {
int ret = SWIG_OK;
String *code = Getattr(n, "code");
String *section = Getattr(n, "section");
replaceModuleVariables(code);
if (!ImportMode && (Cmp(section, "proxycode") == 0)) {
if (proxy_class_body_code) {
Swig_typemap_replace_embedded_typemap(code, n);
Printv(proxy_class_body_code, code, NIL);
}
} else {
ret = Language::insertDirective(n);
}
return ret;
}
/* ---------------------------------------------------------------------------
* 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(proxyCodeBuffer(0), "%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) {
// Enum base (underlying enum type)
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;
Delete(attributes);
const String *baseclass = NULL;
if (!purebase_replace) {
String *underlying_enum_type = Getattr(n, "enumbase");
if (underlying_enum_type) {
baseclass = lookupCodeTypemap(n, "dtype", underlying_enum_type, WARN_D_TYPEMAP_DTYPE_UNDEF);
}
}
const String *wanted_base = baseclass ? baseclass : pure_baseclass;
if (purebase_replace) {
wanted_base = pure_baseclass;
} else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) {
Swig_warning(WARN_D_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s, enum base %s ignored. Multiple enum bases is not supported in D enums. "
"Perhaps you need the 'replace' attribute in the dbase typemap?\n", typemap_lookup_type, pure_baseclass);
}
const String *enummodifiers = lookupCodeTypemap(n, "dclassmodifiers", typemap_lookup_type, WARN_D_TYPEMAP_CLASSMOD_UNDEF);
Printv(proxy_enum_code, "\n", enummodifiers, " ", symname, *Char(wanted_base) ? " : " : "", wanted_base, " {\n", NIL);
} else {
// Handle anonymous enums.
Printv(proxy_enum_code, "\nenum {\n", NIL);
}
// Emit each enum item.
Language::enumDeclaration(n);
if (GetFlag(n, "nonempty")) {
// 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);
} else {
// D enum declarations must have at least one member to be legal, so emit
// an alias to int instead (their ctype/imtype is always int).
Delete(proxy_enum_code);
proxy_enum_code = NewStringf("\nalias int %s;\n", 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 *nspace = Getattr(n, "sym:nspace");
String *output_directory = outputDirectory(nspace);
String *filename = NewStringf("%s%s.d", output_directory, symname);
Delete(output_directory);
File *class_file = NewFile(filename, "w", SWIG_output_files());
if (!class_file) {
FileErrorDisplay(filename);
Exit(EXIT_FAILURE);
}
Append(filenames_list, Copy(filename));
Delete(filename);
emitBanner(class_file);
if (nspace) {
Printf(class_file, "module %s%s.%s;\n", package, nspace, symname);
} else {
Printf(class_file, "module %s%s;\n", package, symname);
}
Printv(class_file, imports_trimmed, NIL);
Printv(class_file, proxy_enum_code, NIL);
Delete(class_file);
} else {
String *nspace = Getattr(n, "sym:nspace");
Printv(proxyImportsBuffer(nspace), imports, NIL);
Printv(proxyCodeBuffer(nspace), 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);
// Deal with enum values that are not int
{
String *numval = Getattr(n, "enumnumval");
if (numval) Setattr(n, "enumvalue", numval);
}
// Emit the enum item.
{
if (!GetFlag(n, "firstenumitem"))
Printf(proxy_enum_code, ",\n");
Printf(proxy_enum_code, " %s", Getattr(n, "sym: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(getNSpace(), 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.
// TODO: This might occur with nspace as well, augment the check.
Swig_warning(WARN_D_NAME_COLLISION, input_file, line_number,
"%s::%s might collide with the package name, consider using %%rename to resolve the ambiguity.\n",
proxy_class_name, proxy_func_name);
}
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 because
// 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(getNSpace(), 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 overloadedprocess 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(getNSpace(), 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 *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj");
String *construct_tm = Copy(lookupCodeTypemap(n, "dconstructor",
typemap_lookup_type, 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(getNSpace(),symname), "(cast(void*)swigCPtr)", NIL);
const String *methodmods = Getattr(n, "feature:d:methodmodifiers");
if (methodmods)
Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods);
return SWIG_OK;
}
/* ---------------------------------------------------------------------------
* D::classHandler()
* --------------------------------------------------------------------------- */
virtual int classHandler(Node *n) {
String *nspace = getNSpace();
File *class_file = NULL;
proxy_class_name = Copy(Getattr(n, "sym:name"));
if (nspace) {
proxy_class_qname = NewStringf("%s.%s", nspace, proxy_class_name);
} else {
proxy_class_qname = Copy(proxy_class_name);
}
if (!addSymbol(proxy_class_name, n, nspace)) {
return SWIG_ERROR;
}
assertClassNameValidity(proxy_class_name);
if (split_proxy_dmodule) {
String *output_directory = outputDirectory(nspace);
String *filename = NewStringf("%s%s.d", output_directory, proxy_class_name);
class_file = NewFile(filename, "w", SWIG_output_files());
Delete(output_directory);
if (!class_file) {
FileErrorDisplay(filename);
Exit(EXIT_FAILURE);
}
Append(filenames_list, Copy(filename));
Delete(filename);
emitBanner(class_file);
if (nspace) {
Printf(class_file, "module %s%s.%s;\n", package, nspace, proxy_class_name);
} else {
Printf(class_file, "module %s%s;\n", package, proxy_class_name);
}
Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name);
}
Clear(proxy_class_enums_code);
Clear(proxy_class_body_code);
Clear(proxy_class_epilogue_code);
Clear(proxy_class_code);
Clear(destructor_call);
// Traverse the tree for this class, using the *Handler()s to generate code
// to the proxy_class_* variables.
Language::classHandler(n);
// This function write super methods in proxy_class_body_code
writeDirectorSuperFunctions(n);
writeProxyClassAndUpcasts(n);
writeDirectorConnectWrapper(n);
Replaceall(proxy_class_code, "$dclassname", proxy_class_name);
String *dclazzname = Swig_name_member(getNSpace(), proxy_class_name, "");
Replaceall(proxy_class_code, "$dclazzname", dclazzname);
Delete(dclazzname);
if (split_proxy_dmodule) {
Printv(class_file, global_proxy_imports, NIL);
Printv(class_file, proxy_class_imports, NIL);
replaceModuleVariables(proxy_class_code);
Printv(class_file, proxy_class_code, NIL);
Delete(class_file);
} else {
Printv(proxyImportsBuffer(getNSpace()), proxy_class_imports, NIL);
Printv(proxyCodeBuffer(getNSpace()), proxy_class_code, NIL);
}
Clear(proxy_class_imports);
Delete(proxy_class_qname);
proxy_class_qname = NULL;
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 handled in staticmemberfunctionHandler().
Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:dtype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:dtype:outattributes", NIL);
SetFlag(n, "feature:immutable");
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 = getOutDtype(n);
if (!return_type) {
Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number,
"No dtype typemap defined for %s\n", SwigType_str(t, 0));
return_type = NewString("");
}
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);
}
Printf(constants_code, "\n%s enum %s %s = ", attributes, return_type, itemname);
Delete(attributes);
// Retrieve 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.
if (Getattr(n, "wrappedasconstant")) {
Printf(constants_code, "%s;\n", Getattr(n, "staticmembervariableHandler:value"));
} else {
Printf(constants_code, "%s;\n", Getattr(n, "value"));
}
}
// Emit the generated code to appropriate place.
if (wrapping_member_flag) {
Printv(proxy_class_body_code, constants_code, NIL);
} else {
Printv(proxyCodeBuffer(getNSpace()), 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 *returntype = 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("");
int num_arguments = 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(returntype, 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(returntype, 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")) {
DelWrapper(f);
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);
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 (Getattr(p, "tmap:throws")) {
canThrow(n, "throws", p);
}
}
}
String *null_attribute = 0;
// Now write code to make the function call
if (!native_function_flag) {
Swig_director_emit_dynamic_cast(n, f);
String *actioncode = emit_action(n);
/* Return value if necessary */
if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), 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(returntype, 0), Getattr(n, "name"));
}
emit_return_variable(n, returntype, 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, Swig_cresult_name(), 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, Swig_cresult_name(), 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);
Replaceall(f->code, "$isvoid", is_void_return ? "1" : "0");
/* 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(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) {
String *nspace = Getattr(n, "sym:nspace");
proxy_class_name = NewString(Getattr(n, "sym:name"));
if (nspace) {
proxy_class_qname = NewStringf("%s.%s", nspace, proxy_class_name);
} else {
proxy_class_qname = Copy(proxy_class_name);
}
int success = Language::classDirector(n);
Delete(proxy_class_qname);
proxy_class_qname = NULL;
Delete(proxy_class_name);
proxy_class_name = NULL;
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 = directorClassName(n);
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 *classname = Getattr(parent, "sym:name");
String *c_classname = Getattr(parent, "name");
String *name = Getattr(n, "name");
String *symname = Getattr(n, "sym:name");
SwigType *returntype = Getattr(n, "type");
String *overloaded_name = 0;
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 = 0;
bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0")));
int status = SWIG_OK;
bool output_director = true;
String *dirclassname = directorClassName(parent);
String *qualified_name = NewStringf("%s::%s", dirclassname, name);
SwigType *c_ret_type = NULL;
String *dcallback_call_args = NewString("");
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?)
if (!ignored_method)
overloaded_name = getOverloadedName(n);
qualified_return = SwigType_rcaststr(returntype, "c_result");
if (!is_void && (!ignored_method || pure_virtual)) {
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, "abstracts"))) {
/* 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. */
SwigType *noref_type = SwigType_del_reference(Copy(returntype));
String *noref_ltype = SwigType_lstr(noref_type, 0);
String *return_ltype = SwigType_lstr(returntype, 0);
Wrapper_add_localv(w, "result_default", "static", noref_ltype, "result_default", NIL);
Wrapper_add_localv(w, "c_result", return_ltype, "c_result", NIL);
Printf(w->code, "result_default = SwigValueInit< %s >();\n", noref_ltype);
Printf(w->code, "c_result = &result_default;\n");
Delete(return_ltype);
Delete(noref_ltype);
Delete(noref_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 */
tm = lookupDTypemap(n, "imtype");
if (tm) {
String *imtypeout = Getattr(n, "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));
}
if ((c_ret_type = Swig_typemap_lookup("ctype", n, "", 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;
}
Swig_director_parms_fixup(l);
// 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, w);
Swig_typemap_attach_parms("ddirectorin", l, 0);
Swig_typemap_attach_parms("directorargout", l, w);
// 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, "Swig::DirectorPureVirtualException::raise(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name));
if (!is_void)
Printf(w->code, "return %s;", qualified_return);
else if (!ignored_method)
Printf(w->code, "return;\n");
}
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;
}
// ctype default assignment
const String *ctypedef = Getattr(p, "tmap:ctype:default");
String *ctypeassign;
if (ctypedef) {
ctypeassign = Copy(ctypedef);
} else if (SwigType_ispointer(pt) || SwigType_isreference(pt)) {
ctypeassign = NewString("= 0");
} else {
ctypeassign = NewString("");
}
/* Add to local variables */
Printf(c_decl, "%s %s", c_param_type, arg);
if (!ignored_method)
Wrapper_add_localv(w, arg, c_decl, ctypeassign, NIL);
Delete(ctypeassign);
/* Add input marshalling code */
if ((tm = Getattr(p, "tmap:directorin"))) {
Setattr(p, "emit:directorinput", arg);
Replaceall(tm, "$input", arg);
Replaceall(tm, "$owner", "0");
if (Len(tm))
if (!ignored_method)
Printf(w->code, "%s\n", 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 : Getattr(n, "classDirectorMethods:type");
target = Swig_method_decl(rtype, decl, qualified_name, l, 0);
Printf(w->def, "%s", target);
Delete(qualified_name);
Delete(target);
target = Swig_method_decl(rtype, decl, name, l, 1);
Printf(declaration, " virtual %s", target);
Delete(target);
// Add any exception specifications to the methods in the director class
if (Getattr(n, "noexcept")) {
Append(w->def, " noexcept");
Append(declaration, " noexcept");
}
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 (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) {
if ((tm = lookupDTypemap(n, "ddirectorout"))) {
Replaceall(tm, "$dcall", upcall);
Printf(callback_code, " return %s;\n", tm);
}
} 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");
/* Copy jresult into c_result... */
if ((tm = Swig_typemap_lookup("directorout", n, 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(jresult_str);
Delete(result_str);
}
/* Marshal outputs */
for (p = l; p;) {
if ((tm = Getattr(p, "tmap:directorargout"))) {
canThrow(n, "directorargout", p);
Replaceall(tm, "$result", "jresult");
Replaceall(tm, "$input", Getattr(p, "emit:directorinput"));
Printv(w->code, tm, "\n", NIL);
p = Getattr(p, "tmap:directorargout:next");
} else {
p = nextSibling(p);
}
}
/* 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 the director method */
if (status == SWIG_OK && output_director) {
if (!is_void) {
Replaceall(w->code, "$null", qualified_return);
} else {
Replaceall(w->code, "$null", "");
}
Replaceall(w->code, "$isvoid", is_void ? "1" : "0");
if (!ignored_method)
Printv(director_dcallbacks_code, callback_def, callback_code, NIL);
if (!Getattr(n, "defaultargs")) {
Replaceall(w->code, "$symname", symname);
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.
String *dp_return_type = getOutDtype(n);
if (!dp_return_type) {
Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number,
"No dtype typemap defined for %s\n", SwigType_str(returntype, 0));
dp_return_type = NewString("");
}
String *member_name = Swig_name_member(getNSpace(), classname, overloaded_name);
String *imclass_dmethod = NewStringf("SwigDirector_%s", member_name);
UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name, dp_return_type, proxy_method_param_list);
// 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("");
String *dirClassName = directorClassName(parent);
Printf(proxy_callback_type, "%s_Callback%s", dirClassName, methid);
Printf(im_dmodule_code, "alias extern(C) %s function(void*%s) %s;\n", proxy_callback_return_type, delegate_parms, proxy_callback_type);
Delete(imclass_dmethod);
Delete(member_name);
Delete(dp_return_type);
Delete(proxy_callback_type);
Delete(dirClassName);
}
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 *dirclassname = directorClassName(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, dirclassname, parms, 0);
String *call = Swig_csuperclass_call(0, basetype, superparms);
String *classtype = SwigType_namestr(Getattr(n, "name"));
Printf(f_directors, "%s::%s : %s, %s {\n", dirclassname, 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, dirclassname, parms, 1);
Printf(f_directors_h, " %s;\n", target);
Delete(target);
}
}
Delete(sub);
Delete(supername);
Delete(parms);
Delete(dirclassname);
return Language::classDirectorConstructor(n);
}
/* ---------------------------------------------------------------------------
* D::classDirectorDefaultConstructor()
* --------------------------------------------------------------------------- */
virtual int classDirectorDefaultConstructor(Node *n) {
String *dirclassname = directorClassName(n);
String *classtype = SwigType_namestr(Getattr(n, "name"));
Wrapper *w = NewWrapper();
Printf(w->def, "%s::%s() : %s {", dirclassname, dirclassname, Getattr(n, "director:ctor"));
Printf(w->code, "}\n");
Wrapper_print(w, f_directors);
Printf(f_directors_h, " %s();\n", dirclassname);
DelWrapper(w);
Delete(classtype);
Delete(dirclassname);
return Language::classDirectorDefaultConstructor(n);
}
/* ---------------------------------------------------------------------------
* D::classDirectorDestructor()
* --------------------------------------------------------------------------- */
virtual int classDirectorDestructor(Node *n) {
Node *current_class = getCurrentClass();
String *dirclassname = directorClassName(current_class);
Wrapper *w = NewWrapper();
if (Getattr(n, "noexcept")) {
Printf(f_directors_h, " virtual ~%s() noexcept;\n", dirclassname);
Printf(w->def, "%s::~%s() noexcept {\n", dirclassname, dirclassname);
} else if (Getattr(n, "throw")) {
Printf(f_directors_h, " virtual ~%s() throw();\n", dirclassname);
Printf(w->def, "%s::~%s() throw() {\n", dirclassname, dirclassname);
} else {
Printf(f_directors_h, " virtual ~%s();\n", dirclassname);
Printf(w->def, "%s::~%s() {\n", dirclassname, dirclassname);
}
Printv(w->code, "}\n", NIL);
Wrapper_print(w, f_directors);
DelWrapper(w);
Delete(dirclassname);
return SWIG_OK;
}
/* ---------------------------------------------------------------------------
* D::classDirectorEnd()
* --------------------------------------------------------------------------- */
virtual int classDirectorEnd(Node *n) {
int i;
String *director_classname = directorClassName(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_pointers) > 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.
* return type - The return type of the function in the C wrapper.
* parameters - The parameter list of the C wrapper function.
* wrapper_function_name - The name of the exported function in the C wrapper
* (usually d_name prefixed by »D_«).
* --------------------------------------------------------------------------- */
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, "SwigExternC!(%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, bool super = false) {
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 *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.
String *return_type = getOutDtype(n);
if (!return_type) {
Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number,
"No dtype typemap defined for %s\n", SwigType_str(t, 0));
return_type = NewString("");
}
if (wrapping_member_flag) {
// Check if this is a setter method for a public member.
const String *setter_name = Swig_name_set(getNSpace(),
Swig_name_member(0, proxy_class_name, variable_name));
if (Cmp(Getattr(n, "sym:name"), setter_name) == 0) {
setter_flag = true;
}
}
// We move the modifiers after the parameter list
// as we need the D parametes to catch D override of functions
String *param_function_code = NewString("");
if (super) {
Printf(imcall, "super.$funcname(");
} else {
// 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 && !super;
for (i = 0, p = l; p; i++) {
// Ignored varargs.
if (checkAttribute(p, "varargs:ignore", "1")) {
Setattr(p, "d:type", NewString(""));
p = nextSibling(p);
continue;
}
// Ignored parameters.
if (checkAttribute(p, "tmap:in:numinputs", "0")) {
Setattr(p, "d:type", NewString(""));
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);
{
int ln = Len(package);
/* If proxy_type uses the package name, it must be larger */
if (Len(proxy_type) > ln && Strncmp(package, proxy_type, ln) == 0) {
Setattr(p, "d:type", NewString(Char(proxy_type) + ln));
} else {
Setattr(p, "d:type", Copy(proxy_type));
}
}
} 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(param_function_code, ", ");
Printf(proxy_param_types, ", ");
}
gencomma = 2;
Printf(param_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");
}
// Complete the function declaration up to the parameter list.
// Write function modifiers.
{
const String *mods_override = Getattr(n, "feature:d:methodmodifiers");
bool isPrivate = false;
if (mods_override) {
isPrivate = Strcmp(mods_override, private_string) == 0;
} else {
mods_override = is_public(n) ? public_string : protected_string;
}
String *modifiers = Copy(mods_override);
Setattr(n, "dmodify", Copy(mods_override));
/* private function are never override */
if (super || (!isPrivate && isDOverride(n, l))) {
Printf(modifiers, " override");
}
Chop(modifiers);
if (static_flag) {
Printf(modifiers, " static");
}
Printf(function_code, "%s ", modifiers);
Delete(modifiers);
}
Printf(function_code, "%s %s(", return_type, proxy_function_name);
// Add Body the parameter list part after the modifiers
Append(function_code, param_function_code);
Printf(imcall, ")");
Printf(function_code, ") ");
if (wrapping_member_flag) {
Printf(function_code, "@property ");
}
if (wrapMemberFunctionAsDConst(n)) {
Printf(function_code, "const ");
}
if (super) {
Replaceall(imcall, "$funcname", proxy_function_name);
if (!Cmp(return_type, "void")) {
tm = NewString("{\n $imcall;\n}");
} else {
tm = NewString("{\n return $imcall;\n}");
}
Replaceall(tm, "$imcall", imcall);
} else {
// 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 && Swig_directorclass(getCurrentClass())) {
String *ex_overloaded_name = getOverloadedName(explicit_n);
String *ex_intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, ex_overloaded_name);
String *ex_imcall = Copy(imcall);
Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name);
Replaceall(imcall, "$imfuncname", intermediary_function_name);
String *override_use_const = NewString("");
if (wrapMemberFunctionAsDConst(n)) {
Printf(override_use_const, "Const");
}
String *excode = NewString("");
if (!Cmp(return_type, "void"))
Printf(excode, "if (swigIsMethodOverridden%s!(%s delegate(%s), %s function(%s), %s)()) %s; else %s",
override_use_const, return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall);
else
Printf(excode, "((swigIsMethodOverridden%s!(%s delegate(%s), %s function(%s), %s)()) ? %s : %s)",
override_use_const, 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, "$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(tm);
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 *function_code = NewString("");
int num_arguments = 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 */
String *return_type = getOutDtype(n);
if (!return_type) {
Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number,
"No dtype typemap defined for %s\n", SwigType_str(t, 0));
return_type = NewString("");
}
/* 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);
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) {
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, "$imfuncname", overloaded_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));
}
// 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(proxyCodeBuffer(getNSpace()), 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()
*
* Collects all the code fragments generated by the handler function while
* traversing the tree from the proxy_class_* variables and writes the
* class definition (including any epilogue code) to proxy_class_code.
*
* Also writes the upcast function to the wrapper layer when processing a
* derived class.
*
* Inputs:
* n The class node currently processed.
* --------------------------------------------------------------------------- */
void writeProxyClassAndUpcasts(Node *n) {
SwigType *typemap_lookup_type = Getattr(n, "classtypeobj");
/*
* Handle inheriting from D and C++ classes.
*/
String *c_classname = Getattr(n, "name");
String *c_baseclassname = NULL;
Node *basenode = NULL;
String *baseclass = NULL;
SwigType *bsmart = 0;
// 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) {
if (!GetFlag(base.item, "feature:ignore")) {
SwigType *baseclassname = Getattr(base.item, "name");
if (!c_baseclassname) {
basenode = base.item;
String *name = createProxyName(baseclassname);
if (name) {
c_baseclassname = baseclassname;
baseclass = name;
bsmart = Getattr(base.item, "smart");
}
} else {
/* Warn about multiple inheritance for additional base class(es) */
String *proxyclassname = Getattr(n, "classtypeobj");
Swig_warning(WARN_D_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Base %s of class %s ignored: multiple inheritance is not supported in D.\n", SwigType_namestr(baseclassname), SwigType_namestr(proxyclassname));
}
}
base = Next(base);
}
}
}
bool derived = baseclass != NULL;
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;
basenode = NULL;
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, 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, bsmart, proxy_class_name, c_classname, c_baseclassname);
}
/*
* 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(Getattr(basenode, "sym:nspace"), Getattr(basenode, "sym:name"));
}
// 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;
const String *dispose_methodname;
const String *dispose_methodmodifiers;
const String *dispose_parameters;
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");
dispose_parameters = Getattr(attributes, "tmap:ddispose_derived:parameters");
} 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");
dispose_parameters = Getattr(attributes, "tmap:ddispose:parameters");
}
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 (!dispose_parameters)
dispose_parameters = empty_string;
}
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", NIL);
const String *methodmods = Getattr(n, "destructmethodmodifiers");
if (methodmods)
Printv(body, methodmods, NIL);
else
Printv(body, dispose_methodmodifiers, (derived ? " override" : ""), NIL);
Printv(body, " void ", dispose_methodname, "(", dispose_parameters, ") ", 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(n);
}
// 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);
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, SwigType *bsmart, const String *d_class_name, SwigType *c_classname, SwigType *c_baseclassname) {
SwigType *smart = Getattr(n, "smart");
String *upcast_name = Swig_name_member(getNSpace(), d_class_name, (smart != 0 ? "SmartPtrUpcast" : "Upcast"));
String *upcast_wrapper_name = Swig_name_wrapper(upcast_name);
writeImDModuleFunction(upcast_name, "void*", "(void* objectRef)", upcast_wrapper_name);
String *classname = SwigType_namestr(c_classname);
String *baseclassname = SwigType_namestr(c_baseclassname);
if (smart) {
if (bsmart) {
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);
}
} else {
Printv(upcasts_code,
"SWIGEXPORT ", baseclassname, " * ", upcast_wrapper_name,
"(", classname, " *objectRef) {\n",
" return (", baseclassname, " *)objectRef;\n"
"}\n",
"\n", NIL);
}
Replaceall(upcasts_code, "$cclass", classname);
Replaceall(upcasts_code, "$cbaseclass", baseclassname);
Delete(baseclassname);
Delete(classname);
Delete(upcast_wrapper_name);
Delete(upcast_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);
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 = proxyImportsBuffer(0);
code_target = proxyCodeBuffer(0);
}
// 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);
Delete(class_file);
}
Delete(n);
}
/* ---------------------------------------------------------------------------
* D::writeDirectorConnectProxy(Node *classNode)
*
* 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(Node* classNode) {
String *dirClassName = directorClassName(classNode);
String *connect_name = Swig_name_member(getNSpace(),
proxy_class_name, "director_connect");
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.%s_Callback%s callback%s;\n", im_dmodule_fq_name, dirClassName, 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(cast(void*)swigCPtr, cast(void*)this", im_dmodule_fq_name, connect_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)() {\n");
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, "private bool swigIsMethodOverriddenConst(DelegateType, FunctionType, alias fn)() inout {\n");
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;
Delete(dirClassName);
Delete(connect_name);
}
/* ---------------------------------------------------------------------------
* D::writeDirectorSuperFunctions()
*
* Writes super methods for protected methods in virtual table
* which are not implemented in class.
* So the director connect function can call them.
* As function outside the class, can call module protected methods
* but not protected of clases outside this module!
* --------------------------------------------------------------------------- */
// TODO WORK
void writeDirectorSuperFunctions(Node *n) {
if (!Swig_directorclass(n))
return;
Node *vtable = Getattr(n, "vtable");
int len = Len(vtable);
for (int i = 0; i < len; i++) {
Node *item = Getitem(vtable, i);
if (GetFlag(item, "director")) {
Node *method = Getattr(item, "methodNode");
Node *p = parentNode(method);
if (p && p != n && is_protected(method)) {
const String *nodeType = nodeType(method);
if (Strcmp(nodeType, "cdecl") == 0) {
Setattr(method, "proxyfuncname", Getattr(method, "sym:name"));
writeProxyClassFunction(method, true);
}
}
}
}
}
/* ---------------------------------------------------------------------------
* 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 = Swig_name_member(getNSpace(),
proxy_class_name, "director_connect");
String *dirClassName = directorClassName(n);
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, " %s *director = static_cast<%s *>(obj);\n", dirClassName, dirClassName);
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, ", %s::SWIG_Callback%s_t callback%s", dirClassName, methid, methid);
Printf(code_wrap->code, ", callback%s", methid);
Printf(im_dmodule_code, ", %s_Callback%s callback%s", dirClassName, 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");
Wrapper_print(code_wrap, f_wrappers);
DelWrapper(code_wrap);
Delete(connect_name);
Delete(dirClassName);
}
/* ---------------------------------------------------------------------------
* D::requireDType()
*
* If the given type is not already in scope in the current module, adds an
* import statement for it. The name is considered relative to the global root
* package if one is set.
*
* This is only used for dependencies created in generated code, user-
* (i.e. typemap-) specified import statements are handled separately.
* --------------------------------------------------------------------------- */
void requireDType(const String *nspace, const String *symname) {
String *dmodule = createModuleName(nspace, symname);
if (!inProxyModule(dmodule)) {
String *import = createImportStatement(dmodule);
Append(import, "\n");
if (is_wrapping_class()) {
addImportStatement(proxy_class_imports, import);
} else {
addImportStatement(proxyImportsBuffer(getNSpace()), import);
}
Delete(import);
}
Delete(dmodule);
}
/* ---------------------------------------------------------------------------
* 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 occurrence 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.
* --------------------------------------------------------------------------- */
String *createImportStatement(const String *dmodule_name,
bool static_import = true) const {
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 type is declared in the currently
* processed proxy D module.
*
* This function is used to determine if fully qualified type names have to
* be used (package, module and type name). If the split proxy mode is not
* used, this solely depends on whether the type is in the current namespace.
* --------------------------------------------------------------------------- */
bool inProxyModule(const String *type_name) const {
if (!split_proxy_dmodule) {
String *nspace = createOuterNamespaceNames(type_name);
// Check if strings are either both null (no namespace) or are both
// non-null and have the same contents. Cannot use Strcmp for this
// directly because of its strange way of handling the case where only
// one argument is 0 ("<").
bool result = !nspace && !getNSpace();
if (nspace && getNSpace())
result = (Strcmp(nspace, getNSpace()) == 0);
Delete(nspace);
return result;
}
if (!is_wrapping_class()) {
return false;
}
return (Strcmp(proxy_class_qname, 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) {
String *key = NewStringf("%s|%s", imclass_method, decl);
++curr_class_dmethod;
String *class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod);
n_dmethods++;
Hash *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 {
// TODO: With nspace support, there could arise problems also when not in
// split proxy mode, warnings for these should be added.
if (split_proxy_dmodule) {
if (Cmp(class_name, im_dmodule_name) == 0) {
Swig_error(input_file, line_number,
"Class name cannot be equal to intermediary D module name: %s\n",
class_name);
Exit(EXIT_FAILURE);
}
String *nspace = getNSpace();
if (nspace) {
// Check the root package/outermost namespace (a class A in module
// A.B leads to problems if another module A.C is also imported)
if (Len(package) > 0) {
String *dotless_package = NewStringWithSize(package, Len(package) - 1);
if (Cmp(class_name, dotless_package) == 0) {
Swig_error(input_file, line_number,
"Class name cannot be the same as the root package it is in: %s\n",
class_name);
Exit(EXIT_FAILURE);
}
Delete(dotless_package);
} else {
String *outer = createFirstNamespaceName(nspace);
if (Cmp(class_name, outer) == 0) {
Swig_error(input_file, line_number,
"Class name cannot be the same as the outermost namespace it is in: %s\n",
class_name);
Exit(EXIT_FAILURE);
}
Delete(outer);
}
// … and the innermost one (because of the conflict with the main proxy
// module named like the namespace).
String *inner = createLastNamespaceName(nspace);
if (Cmp(class_name, inner) == 0) {
Swig_error(input_file, line_number,
"Class name cannot be the same as the innermost namespace it is in: %s\n",
class_name);
Exit(EXIT_FAILURE);
}
Delete(inner);
} else {
if (Cmp(class_name, proxy_dmodule_name) == 0) {
Swig_error(input_file, line_number,
"Class name cannot be equal to proxy D module name: %s\n",
class_name);
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.SwigExternC!(%s function(%s))", im_dmodule_fq_name,
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 = Copy(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 separate file, which allows
// us to handle imports here.
// When working in split proxy module mode, each generated proxy class/enum
// is written to a separate 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 *type_name;
if (SwigType_isenum(type)) {
// RESEARCH: Make sure that we really cannot get here for anonymous enums.
Node *n = enumLookup(type);
if (n) {
String *enum_name = Getattr(n, "sym:name");
Node *p = parentNode(n);
if (p && !Strcmp(nodeType(p), "class")) {
// This is a nested enum.
String *parent_name = Getattr(p, "sym:name");
String *nspace = Getattr(p, "sym:nspace");
// An enum nested in a class is not written to a separate module (this
// would not even be possible in D), so just import the parent.
requireDType(nspace, parent_name);
String *module = createModuleName(nspace, parent_name);
if (inProxyModule(module)) {
type_name = NewStringf("%s.%s", parent_name, enum_name);
} else {
type_name = NewStringf("%s%s.%s.%s", package, module, parent_name, enum_name);
}
} else {
// A non-nested enum is written to a separate module, import it.
String *nspace = Getattr(n, "sym:nspace");
requireDType(nspace, enum_name);
String *module = createModuleName(nspace, enum_name);
if (inProxyModule(module)) {
type_name = Copy(enum_name);
} else {
type_name = NewStringf("%s%s.%s", package, module, enum_name);
}
}
} else {
type_name = NewStringf("int");
}
} else {
Node *n = classLookup(type);
if (n) {
String *class_name = Getattr(n, "sym:name");
String *nspace = Getattr(n, "sym:nspace");
requireDType(nspace, class_name);
String *module = createModuleName(nspace, class_name);
if (inProxyModule(module)) {
type_name = Copy(class_name);
} else {
type_name = NewStringf("%s%s.%s", package, module, class_name);
}
Delete(module);
} 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));
requireDType(NULL, descriptor);
String *module = createModuleName(NULL, descriptor);
if (inProxyModule(module)) {
type_name = Copy(descriptor);
} else {
type_name = NewStringf("%s%s.%s", package, module, descriptor);
}
Delete(module);
// Add to hash table so that a type wrapper class can be created later.
Setattr(unknown_types, descriptor, type);
Delete(descriptor);
}
}
Replaceall(target, variable, type_name);
Delete(type_name);
}
/* ---------------------------------------------------------------------------
* D::createModuleName()
*
* Returns a string holding the name of the module to import to bring the
* given type in scope.
* --------------------------------------------------------------------------- */
String *createModuleName(const String *nspace, const String *type_name) const {
String *module;
if (nspace) {
module = NewStringf("%s.", nspace);
if (split_proxy_dmodule) {
Printv(module, type_name, NIL);
} else {
String *inner = createLastNamespaceName(nspace);
Printv(module, inner, NIL);
Delete(inner);
}
} else {
if (split_proxy_dmodule) {
module = Copy(type_name);
} else {
module = Copy(proxy_dmodule_name);
}
}
return module;
}
/* ---------------------------------------------------------------------------
* 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, (int)(end - start));
String *current_param = NewStringWithSize(param_start, (int)(param_end - param_start));
if (inProxyModule(current_param)) {
Replace(target, current_macro, "", DOH_REPLACE_ANY);
} else {
String *import = createImportStatement(current_param, false);
Replace(target, current_macro, import, DOH_REPLACE_ANY);
Delete(import);
}
Delete(current_param);
Delete(current_macro);
} else {
String *current_macro = NewStringWithSize(start, (int)(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::createProxyName()
*
* Returns the D class name if a type corresponds to something wrapped with a
* proxy class, NULL otherwise.
* --------------------------------------------------------------------------- */
String *createProxyName(SwigType *t) {
String *proxyname = NULL;
Node *n = classLookup(t);
if (n) {
String *nspace = Getattr(n, "sym:nspace");
String *symname = Getattr(n, "sym:name");
String *module = createModuleName(nspace, symname);
if (inProxyModule(module)) {
proxyname = Copy(symname);
} else {
proxyname = NewStringf("%s%s.%s", package, module, symname);
}
}
return proxyname;
}
String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const {
String *arg = Language::makeParameterName(n, p, arg_num, setter);
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 (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 hierarchy.
* --------------------------------------------------------------------------- */
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 hierarchy even if there have been
// new overloads introduced after the topmost class.
Node *base_function = NULL;
String *symname = Getattr(n, "sym:name");
if (symname) {
for (Node *tmp = firstChild(base_class); tmp; tmp = nextSibling(tmp)) {
String *child_symname = Getattr(tmp, "sym:name");
if (child_symname && (Strcmp(child_symname, symname) == 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 visibility
// 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::checkClassBaseOver()
*
* Search a class for a method that can override the current method.
* --------------------------------------------------------------------------- */
bool checkClassBaseOver(Node *b, const String *name, ParmList *l, const int llen, const String *bname = NULL)
{
if (bname == NULL) {
bname = Getattr(b, "name");
}
for(Node *e = firstChild(b); e; e = nextSibling(e)) {
/* We look for D only fuctions! */
const String *ename = Getattr(e, "name");
const String *etype = nodeType(e);
if (Strcmp(etype, "extend") == 0) {
/* extend of class do not have a name attribute,
* it is the same class. */
if (checkClassBaseOver(e, name, l, llen, bname)) {
return true;
}
} else if (Strcmp(etype, "cdecl") == 0 || Strcmp(etype, "using") == 0) {
/* 'using' is marked in markDOverride() same as 'cdecl' */
if (Strcmp(name, ename) == 0) {
if (GetFlag(e, "d:override_property")) {
return true;
}
/* Do we need a full compare of ParmList? How about in typemaps? */
ParmList *el = Getattr(e, "d:override_parms");
const int ellen = ParmList_len(el);
if (GetFlag(e, "d:can_override") && ellen == llen) {
bool eq = true;
String *detd = NewString("");
if (llen > 0) {
for(ParmList *le = el, *ln = l; eq && le && ln; le = nextSibling(le), ln = nextSibling(ln)) {
const String *ntd = Getattr(ln, "d:type");
const String *etd = Getattr(le, "d:type");
Printf(detd, "%s.%s", etd, etd);
/* Parameter types are equal, or the type is 'class.class' */
eq = etd && ntd && (Strcmp(ntd, etd) == 0 || Strcmp(ntd, detd) == 0);
}
}
Delete(detd);
if (eq) {
return true;
}
}
}
}
}
return false;
}
/* ---------------------------------------------------------------------------
* D::checkBaseOver()
*
* Traverse all base classes and look for a method the current method override.
* --------------------------------------------------------------------------- */
bool checkBaseOver(Node *c, const String *name, ParmList *l, const int llen)
{
// * Member template functions?
if (!c) {
return false;
}
List *bases = Getattr(c, "bases");
if (!bases) {
return false;
}
for (int i = 0; i < Len(bases); i++) {
Node *b = Getitem(bases, i);
if (checkClassBaseOver(b, name, l, llen)) {
return true;
}
if (checkBaseOver(b, name, l, llen)) {
return true;
}
}
return false;
}
/* ---------------------------------------------------------------------------
* D::markDOverride()
*
* Mark current method for methods in derived classes.
* --------------------------------------------------------------------------- */
void markDOverride(Node *n, const String *name, ParmList *l, Node *p, const String *pname, const String *ptype) {
if (!pname && Strcmp(ptype, "extend") == 0) {
Node *pp = parentNode(p);
if (pp) {
pname = Getattr(pp, "name");
}
}
for(Node *e = firstChild(p); e; e = nextSibling(e)) {
/* Am I in my class? */
if (n == e) {
SetFlag(n, "d:can_override");
if (wrapping_member_flag) {
SetFlag(n, "d:override_property");
} else {
Setattr(n, "d:override_parms", CopyParmList(l));
}
return;
}
}
/*
* I am a 'using' method.
* Our method is using a method definition from a different class.
* We need to mark the original 'using' method in our class,
* as this node is not accessibale in derived classes.
*/
for(Node *e = firstChild(p); e; e = nextSibling(e)) {
const String *ename = Getattr(e, "name");
const String *ntype = nodeType(e);
if (ename && Strcmp(ename, name) == 0 && ntype && Strcmp(ntype, "using") == 0) {
SetFlag(e, "d:can_override");
Setattr(e, "d:override_parms", CopyParmList(l));
return;
}
}
}
/* ---------------------------------------------------------------------------
* D::isDOverride()
*
* Override should be used for override D existing method.
* Class D methods, non static and non private.
* Check if current method override,
* anf mark it for derived classes use.
* --------------------------------------------------------------------------- */
bool isDOverride(Node *n, ParmList *l) {
if (is_smart_pointer()) {
/* Smart pointer classes do not mirror the inheritance hierarchy of the
* underlying pointer type, so no override required. */
return false;
}
if (static_flag) { /* Static are never override */
return false;
}
Node *p = parentNode(n);
if (!p) {
return false;
}
const String *name = Getattr(n, "name");
const int llen = ParmList_len(l);
const String *ptype = nodeType(p);
const String *pname = Getattr(p, "name");
markDOverride(n, name, l, p, pname, ptype);
if (Strcmp(ptype, "extend") == 0) {
/* The 'bases' are in the class we extend */
p = parentNode(p);
}
return checkBaseOver(p, name, l, llen);
}
/* ---------------------------------------------------------------------------
* 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");
Printv(f, common_begin_code, NIL);
}
/* ---------------------------------------------------------------------------
* D::getOutDtype()
*
* Returns the return (out) D type and check the Dtype out typemap.
* --------------------------------------------------------------------------- */
String *getOutDtype(Node *n) {
String *result = lookupDTypemap(n, "dtype");
if (result) {
String *dtypeout = Copy(Getattr(n, "tmap:dtype:out"));
if (dtypeout) {
/* The type in the out attribute of the typemap overrides the type
* in the dtype typemap. */
Delete(result);
result = dtypeout;
replaceClassname(result, Getattr(n, "type"));
}
}
return result;
}
/* ---------------------------------------------------------------------------
* D::outputDirectory()
*
* Returns the directory to write the D modules for the given namespace to and
* and creates the subdirectory if it doesn't exist.
* --------------------------------------------------------------------------- */
String *outputDirectory(String *nspace) {
String *output_directory = Copy(dmodule_directory);
if (nspace) {
String *nspace_subdirectory = Copy(nspace);
Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER);
String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory);
if (newdir_error) {
Printf(stderr, "%s\n", newdir_error);
Delete(newdir_error);
Exit(EXIT_FAILURE);
}
Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0);
Delete(nspace_subdirectory);
}
return output_directory;
}
/* ---------------------------------------------------------------------------
* D::proxyCodeBuffer()
*
* Returns the buffer to write proxy code for the given namespace to.
* --------------------------------------------------------------------------- */
String *proxyCodeBuffer(String *nspace) {
if (!nspace) {
return proxy_dmodule_code;
}
Hash *hash = Getattr(nspace_proxy_dmodules, nspace);
if (!hash) {
hash = NewHash();
Setattr(hash, "code", NewString(""));
Setattr(hash, "imports", NewString(""));
Setattr(nspace_proxy_dmodules, nspace, hash);
}
return Getattr(hash, "code");
}
/* ---------------------------------------------------------------------------
* D::proxyCodeBuffer()
*
* Returns the buffer to write imports for the proxy code for the given
* namespace to.
* --------------------------------------------------------------------------- */
String *proxyImportsBuffer(String *nspace) {
if (!nspace) {
return proxy_dmodule_imports;
}
Hash *hash = Getattr(nspace_proxy_dmodules, nspace);
if (!hash) {
hash = NewHash();
Setattr(hash, "code", NewString(""));
Setattr(hash, "imports", NewString(""));
Setattr(nspace_proxy_dmodules, nspace, hash);
}
return Getattr(hash, "imports");
}
/* ---------------------------------------------------------------------------
* D::createFirstNamespaceName()
*
* Returns a new string containing the name of the outermost namespace, e.g.
* »A« for the argument »A.B.C«.
* --------------------------------------------------------------------------- */
String *createFirstNamespaceName(const String *nspace) const {
char *tmp = Char(nspace);
char *c = tmp;
char *co = 0;
if (!strchr(c, '.'))
return 0;
co = c + Len(nspace);
while (*c && (c != co)) {
if (*c == '.') {
break;
}
c++;
}
if (!*c || (c == tmp)) {
return NULL;
}
return NewStringWithSize(tmp, (int)(c - tmp));
}
/* ---------------------------------------------------------------------------
* D::createLastNamespaceName()
*
* Returns a new string containing the name of the innermost namespace, e.g.
* »C« for the argument »A.B.C«.
* --------------------------------------------------------------------------- */
String *createLastNamespaceName(const String *nspace) const {
if (!nspace) return NULL;
char *c = Char(nspace);
char *cc = c;
if (!strchr(c, '.'))
return NewString(nspace);
while (*c) {
if (*c == '.') {
cc = c;
}
++c;
}
return NewString(cc + 1);
}
/* ---------------------------------------------------------------------------
* D::createOuterNamespaceNames()
*
* Returns a new string containing the name of the outer namespace, e.g.
* »A.B« for the argument »A.B.C«.
* --------------------------------------------------------------------------- */
String *createOuterNamespaceNames(const String *nspace) const {
if (!nspace) return NULL;
char *tmp = Char(nspace);
char *c = tmp;
char *cc = c;
if (!strchr(c, '.'))
return NULL;
while (*c) {
if (*c == '.') {
cc = c;
}
++c;
}
if (cc == tmp) {
return NULL;
}
return NewStringWithSize(tmp, (int)(cc - tmp));
}
};
static Language *new_swig_d() {
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 = "\
D Options (available with -d)\n\
-d2 - Generate code for D2/Phobos (The default, left for backward compatibility)\n\
-package <pkg> - Write generated D modules into package <pkg>\n\
-splitproxy - Write each D type to a dedicated file instead of\n\
generating a single proxy D module.\n\
-wrapperlibrary <wl> - Set the name of the wrapper library to <wl>\n\
\n";