blob: 5e82dfda372a2a7cefdcb276e458a7612285eb8c [file] [log] [blame]
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* d.cxx
*
* D language module for SWIG.
* ----------------------------------------------------------------------------- */
#include "swigmod.h"
#include "cparse.h"
#include <ctype.h>
// Hash type used for storing information about director callbacks for a class.
typedef DOH UpcallData;
class D : public Language {
static const char *usage;
const String *empty_string;
const String *public_string;
const String *protected_string;
/*
* Files and file sections containing C/C++ code.
*/
File *f_begin;
File *f_runtime;
File *f_runtime_h;
File *f_header;
File *f_wrappers;
File *f_init;
File *f_directors;
File *f_directors_h;
List *filenames_list;
/*
* Command line-set modes of operation.
*/
// Whether a single proxy D module is generated or classes and enums are
// written to their own files.
bool split_proxy_dmodule;
// The major D version targeted (currently 1 or 2).
unsigned short d_version;
/*
* State variables which indicate what is being wrapped at the moment.
* This is probably not the most elegant way of handling state, but it has
* proven to work in the C# and Java modules.
*/
// Indicates if wrapping a native function.
bool native_function_flag;
// Indicates if wrapping a static functions or member variables
bool static_flag;
// Indicates if wrapping a nonstatic member variable
bool variable_wrapper_flag;
// Indicates if wrapping a member variable/enum/const.
bool wrapping_member_flag;
// Indicates if wrapping a global variable.
bool global_variable_flag;
// Name of a variable being wrapped.
String *variable_name;
/*
* Variables temporarily holding the generated C++ code.
*/
// C++ code for the generated wrapper functions for casts up the C++
// for inheritance hierarchies.
String *upcasts_code;
// Function pointer typedefs for handling director callbacks on the C++ side.
String *director_callback_typedefs;
// Variables for storing the function pointers to the director callbacks on
// the C++ side.
String *director_callback_pointers;
/*
* Names of generated D entities.
*/
// The name of the D module containing the interface to the C wrapper.
String *im_dmodule_name;
// The fully qualified name of the wrap D module (package name included).
String *im_dmodule_fq_name;
// The name of the proxy module which exposes the (SWIG) module contents as a
// D module.
String *proxy_dmodule_name;
// The fully qualified name of the proxy D module.
String *proxy_dmodule_fq_name;
// Optional: Package the D modules are placed in (set via the -package
// command line option).
String *package;
// The directory the generated D module files are written to. Is constructed
// from the package path if a target package is set, points to the general
// output directory otherwise.
String *dmodule_directory;
// The name of the library which contains the C wrapper (used when generating
// the dynamic library loader). Can be overridden via the -wrapperlibrary
// command line flag.
String *wrap_library_name;
/*
* Variables temporarily holding the generated D code.
*/
// Import statements written to the intermediary D module header set via
// %pragma(d) imdmoduleimports.
String *im_dmodule_imports;
// The code for the intermediary D module body.
String *im_dmodule_code;
// Import statements for all proxy modules (the main proxy module and, if in
// split proxy module mode, the proxy class modules) from
// %pragma(d) globalproxyimports.
String *global_proxy_imports;
// 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;
// Contains a D call to the function wrapping C++ the destructor of the
// current class (if there is a public C++ destructor).
String *destructor_call;
// D code for the director callbacks generated for the current class.
String *director_dcallbacks_code;
/*
* Code for dynamically loading the wrapper library on the D side.
*/
// D code which is inserted into the im D module if dynamic linking is used.
String *wrapper_loader_code;
// The D code to bind a function pointer to a library symbol.
String *wrapper_loader_bind_command;
// The cumulated binding commands binding all the functions declared in the
// intermediary D module to the C/C++ library symbols.
String *wrapper_loader_bind_code;
/*
* Director data.
*/
List *dmethods_seq;
Hash *dmethods_table;
int n_dmethods;
int first_class_dmethod;
int curr_class_dmethod;
/*
* SWIG types data.
*/
// Collects information about encountered types SWIG does not know about (e.g.
// incomplete types). This is used later to generate type wrapper proxy
// classes for the unknown types.
Hash *unknown_types;
public:
/* ---------------------------------------------------------------------------
* D::D()
* --------------------------------------------------------------------------- */
D():empty_string(NewString("")),
public_string(NewString("public")),
protected_string(NewString("protected")),
f_begin(NULL),
f_runtime(NULL),
f_runtime_h(NULL),
f_header(NULL),
f_wrappers(NULL),
f_init(NULL),
f_directors(NULL),
f_directors_h(NULL),
filenames_list(NULL),
split_proxy_dmodule(false),
d_version(1),
native_function_flag(false),
static_flag(false),
variable_wrapper_flag(false),
wrapping_member_flag(false),
global_variable_flag(false),
variable_name(NULL),
upcasts_code(NULL),
director_callback_typedefs(NULL),
director_callback_pointers(NULL),
im_dmodule_name(NULL),
im_dmodule_fq_name(NULL),
proxy_dmodule_name(NULL),
proxy_dmodule_fq_name(NULL),
package(NULL),
dmodule_directory(NULL),
wrap_library_name(NULL),
im_dmodule_imports(NULL),
im_dmodule_code(NULL),
global_proxy_imports(NULL),
proxy_dmodule_imports(NULL),
proxy_dmodule_code(NULL),
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),
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;
director_language = 1;
// Not used:
Delete(none_comparison);
none_comparison = NewString("");
}
/* ---------------------------------------------------------------------------
* D::main()
* --------------------------------------------------------------------------- */
virtual void main(int argc, char *argv[]) {
SWIG_library_directory("d");
// Look for certain command line options
for (int i = 1; i < argc; i++) {
if (argv[i]) {
if ((strcmp(argv[i], "-d2") == 0)) {
Swig_mark_arg(i);
d_version = 2;
} else if (strcmp(argv[i], "-wrapperlibrary") == 0) {
if (argv[i + 1]) {
wrap_library_name = NewString("");
Printf(wrap_library_name, argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-package") == 0) {
if (argv[i + 1]) {
package = NewString("");
Printf(package, argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if ((strcmp(argv[i], "-splitproxy") == 0)) {
Swig_mark_arg(i);
split_proxy_dmodule = true;
} else if (strcmp(argv[i], "-help") == 0) {
Printf(stdout, "%s\n", usage);
}
}
}
// Add a symbol to the parser for conditional compilation
Preprocessor_define("SWIGD 1", 0);
// Also make the target D version available as preprocessor symbol for
// use in our library files.
String *version_define = NewStringf("SWIG_D_VERSION %u", d_version);
Preprocessor_define(version_define, 0);
Delete(version_define);
// Add typemap definitions
SWIG_typemap_lang("d");
SWIG_config_file("d.swg");
allow_overloading();
}
/* ---------------------------------------------------------------------------
* D::top()
* --------------------------------------------------------------------------- */
virtual int top(Node *n) {
// Get any options set in the module directive
Node *optionsnode = Getattr(Getattr(n, "module"), "options");
if (optionsnode) {
if (Getattr(optionsnode, "imdmodulename")) {
im_dmodule_name = Copy(Getattr(optionsnode, "imdmodulename"));
}
if (Getattr(optionsnode, "directors")) {
// Check if directors are enabled for this module. Note: This is a
// "master switch", if it is not set, not director code will be emitted
// at all. %feature("director") statements are also required to enable
// directors for individual classes or methods.
//
// Use the »directors« attributte of the %module directive to enable
// director generation (e.g. »%module(directors="1") modulename«).
allow_directors();
}
if (Getattr(optionsnode, "dirprot")) {
allow_dirprot();
}
allow_allprotected(GetFlag(optionsnode, "allprotected"));
}
/* Initialize all of the output files */
String *outfile = Getattr(n, "outfile");
String *outfile_h = Getattr(n, "outfile_h");
if (!outfile) {
Printf(stderr, "Unable to determine outfile\n");
SWIG_exit(EXIT_FAILURE);
}
f_begin = NewFile(outfile, "w", SWIG_output_files());
if (!f_begin) {
FileErrorDisplay(outfile);
SWIG_exit(EXIT_FAILURE);
}
if (directorsEnabled()) {
if (!outfile_h) {
Printf(stderr, "Unable to determine outfile_h\n");
SWIG_exit(EXIT_FAILURE);
}
f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files());
if (!f_runtime_h) {
FileErrorDisplay(outfile_h);
SWIG_exit(EXIT_FAILURE);
}
}
f_runtime = NewString("");
f_init = NewString("");
f_header = NewString("");
f_wrappers = NewString("");
f_directors_h = NewString("");
f_directors = NewString("");
/* Register file targets with the SWIG file handler */
Swig_register_filebyname("header", f_header);
Swig_register_filebyname("wrapper", f_wrappers);
Swig_register_filebyname("begin", f_begin);
Swig_register_filebyname("runtime", f_runtime);
Swig_register_filebyname("init", f_init);
Swig_register_filebyname("director", f_directors);
Swig_register_filebyname("director_h", f_directors_h);
unknown_types = NewHash();
filenames_list = NewList();
// Make the package name and the resulting module output path.
if (package) {
// Append a dot so we can prepend the package variable directly to the
// module names in the rest of the code.
Printv(package, ".", NIL);
} else {
// Write the generated D modules to the »root« package by default.
package = NewString("");
}
dmodule_directory = Copy(SWIG_output_directory());
if (Len(package) > 0) {
String *package_directory = Copy(package);
Replaceall(package_directory, ".", SWIG_FILE_DELIMITER);
Printv(dmodule_directory, package_directory, NIL);
Delete(package_directory);
}
// Make the wrap and proxy D module names.
// The wrap module name can be set in the module directive.
if (!im_dmodule_name) {
im_dmodule_name = NewStringf("%s_im", Getattr(n, "name"));
}
im_dmodule_fq_name = NewStringf("%s%s", package, im_dmodule_name);
proxy_dmodule_name = Copy(Getattr(n, "name"));
proxy_dmodule_fq_name = NewStringf("%s%s", package, proxy_dmodule_name);
im_dmodule_code = NewString("");
proxy_class_imports = NewString("");
proxy_class_enums_code = NewString("");
proxy_class_body_code = NewString("");
proxy_class_epilogue_code = NewString("");
proxy_class_code = NewString("");
destructor_call = NewString("");
proxy_dmodule_code = NewString("");
proxy_dmodule_imports = NewString("");
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);
Printf(f_runtime, "\n\n#ifndef SWIGD\n#define SWIGD\n#endif\n\n");
if (directorsEnabled()) {
Printf(f_runtime, "#define SWIG_DIRECTORS\n");
/* Emit initial director header and director code: */
Swig_banner(f_directors_h);
Printf(f_directors_h, "\n");
Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", proxy_dmodule_name);
Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", proxy_dmodule_name);
Printf(f_directors, "\n\n");
Printf(f_directors, "/* ---------------------------------------------------\n");
Printf(f_directors, " * C++ director class methods\n");
Printf(f_directors, " * --------------------------------------------------- */\n\n");
if (outfile_h) {
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 (directorsEnabled()) {
// 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);
SWIG_exit(EXIT_FAILURE);
}
Append(filenames_list, Copy(filen));
Delete(filen);
filen = NULL;
// Start writing out the intermediary class file.
emitBanner(im_d_file);
Printf(im_d_file, "module %s;\n", im_dmodule_fq_name);
Printv(im_d_file, im_dmodule_imports, "\n", NIL);
Replaceall(wrapper_loader_code, "$wraplibrary", wrap_library_name);
Replaceall(wrapper_loader_code, "$wrapperloaderbindcode", wrapper_loader_bind_code);
Replaceall(wrapper_loader_code, "$module", proxy_dmodule_name);
Printf(im_d_file, "%s\n", wrapper_loader_code);
// Add the wrapper function declarations.
replaceModuleVariables(im_dmodule_code);
Printv(im_d_file, im_dmodule_code, NIL);
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);
SWIG_exit(EXIT_FAILURE);
}
Append(filenames_list, Copy(filen));
Delete(filen);
filen = NULL;
emitBanner(proxy_d_file);
Printf(proxy_d_file, "module %s;\n", proxy_dmodule_fq_name);
Printf(proxy_d_file, "\nstatic import %s;\n", im_dmodule_fq_name);
Printv(proxy_d_file, global_proxy_imports, NIL);
Printv(proxy_d_file, proxy_dmodule_imports, NIL);
Printv(proxy_d_file, "\n", NIL);
// Write a D type wrapper class for each SWIG type to the proxy module code.
for (Iterator swig_type = First(unknown_types); swig_type.key; swig_type = Next(swig_type)) {
writeTypeWrapperClass(swig_type.key, swig_type.item);
}
// Add the proxy functions (and classes, if they are not written to a 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);
SWIG_exit(EXIT_FAILURE);
}
Delete(filename);
emitBanner(file);
Printf(file, "module %s%s.%s;\n", package, it.key, module_name);
Printf(file, "\nstatic import %s;\n", im_dmodule_fq_name);
Printv(file, global_proxy_imports, NIL);
Printv(file, Getattr(it.item, "imports"), NIL);
Printv(file, "\n", NIL);
String *code = Getattr(it.item, "code");
replaceModuleVariables(code);
Printv(file, code, NIL);
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 (directorsEnabled()) {
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) {
const String *enummodifiers = lookupCodeTypemap(n, "dclassmodifiers", typemap_lookup_type, WARN_D_TYPEMAP_CLASSMOD_UNDEF);
Printv(proxy_enum_code, "\n", enummodifiers, " ", symname, " {\n", NIL);
} else {
// Handle anonymous enums.
Printv(proxy_enum_code, "\nenum {\n", NIL);
}
// Emit each enum item.
Language::enumDeclaration(n);
if (GetFlag(n, "nonempty")) {
// 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);
SWIG_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
int swigtype = SwigType_type(Getattr(n, "type"));
if (swigtype == T_BOOL) {
const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0";
Setattr(n, "enumvalue", val);
} else if (swigtype == T_CHAR) {
String *val = NewStringf("'%(escape)s'", Getattr(n, "enumvalue"));
Setattr(n, "enumvalue", val);
Delete(val);
}
// 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);
SWIG_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_imports);
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);
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);
}
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, "value", NIL);
Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:dtype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:dtype:outattributes", NIL);
// Add the stripped quotes back in.
String *old_value = Getattr(n, "value");
SwigType *t = Getattr(n, "type");
if (SwigType_type(t) == T_STRING) {
Setattr(n, "value", NewStringf("\"%s\"", old_value));
Delete(old_value);
} else if (SwigType_type(t) == T_CHAR) {
Setattr(n, "value", NewStringf("\'%s\'", old_value));
Delete(old_value);
}
SetFlag(n, "feature:immutable");
int result = globalvariableHandler(n);
Swig_restore(n);
return result;
}
String *constants_code = NewString("");
SwigType *t = Getattr(n, "type");
SwigType *valuetype = Getattr(n, "valuetype");
ParmList *l = Getattr(n, "parms");
// Attach the non-standard typemaps to the parameter list.
Swig_typemap_attach_parms("dtype", l, NULL);
// Get D return type.
String *return_type = NewString("");
String *tm;
if ((tm = lookupDTypemap(n, "dtype"))) {
String *dtypeout = Getattr(n, "tmap:dtype:out");
if (dtypeout) {
// The type in the out attribute of the typemap overrides the type
// in the dtype typemap.
tm = dtypeout;
replaceClassname(tm, t);
}
Printf(return_type, "%s", tm);
} else {
Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number,
"No dtype typemap defined for %s\n", SwigType_str(t, 0));
}
const String *itemname = wrapping_member_flag ? variable_name : symname;
String *attributes = Getattr(n, "feature:d:methodmodifiers");
if (attributes) {
attributes = Copy(attributes);
} else {
attributes = Copy(is_public(n) ? public_string : protected_string);
}
if (d_version == 1) {
if (static_flag) {
Printv(attributes, " static", NIL);
}
Printf(constants_code, "\n%s const %s %s = ", attributes, return_type, itemname);
} else {
Printf(constants_code, "\n%s enum %s %s = ", attributes, return_type, itemname);
}
Delete(attributes);
// 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")) {
if (SwigType_type(valuetype) == T_CHAR)
Printf(constants_code, "\'%(escape)s\';\n", Getattr(n, "staticmembervariableHandler:value"));
else
Printf(constants_code, "%s;\n", Getattr(n, "staticmembervariableHandler:value"));
} else {
// Add the stripped quotes back in.
String* value = Getattr(n, "value");
if (SwigType_type(t) == T_STRING) {
Printf(constants_code, "\"%s\";\n", value);
} else if (SwigType_type(t) == T_CHAR) {
Printf(constants_code, "\'%s\';\n", value);
} else {
Printf(constants_code, "%s;\n", value);
}
}
}
// Emit the generated code to appropriate place.
if (wrapping_member_flag) {
Printv(proxy_class_body_code, constants_code, NIL);
} else {
Printv(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 *t = Getattr(n, "type");
ParmList *l = Getattr(n, "parms");
String *tm;
Parm *p;
int i;
String *c_return_type = NewString("");
String *im_return_type = NewString("");
String *cleanup = NewString("");
String *outarg = NewString("");
String *body = NewString("");
int num_arguments = 0;
bool is_void_return;
String *overloaded_name = getOverloadedName(n);
if (!Getattr(n, "sym:overloaded")) {
if (!addSymbol(Getattr(n, "sym:name"), n))
return SWIG_ERROR;
}
// A new wrapper function object
Wrapper *f = NewWrapper();
// Make a wrapper name for this function
String *wname = Swig_name_wrapper(overloaded_name);
/* Attach the non-standard typemaps to the parameter list. */
Swig_typemap_attach_parms("ctype", l, f);
Swig_typemap_attach_parms("imtype", l, f);
/* Get return types */
if ((tm = lookupDTypemap(n, "ctype"))) {
String *ctypeout = Getattr(n, "tmap:ctype:out");
if (ctypeout) {
// The type in the ctype typemap's out attribute overrides the type in
// the typemap itself.
tm = ctypeout;
}
Printf(c_return_type, "%s", tm);
} else {
Swig_warning(WARN_D_TYPEMAP_CTYPE_UNDEF, input_file, line_number,
"No ctype typemap defined for %s\n", SwigType_str(t, 0));
}
if ((tm = lookupDTypemap(n, "imtype"))) {
String *imtypeout = Getattr(n, "tmap:imtype:out");
if (imtypeout) {
// The type in the imtype typemap's out attribute overrides the type in
// the typemap itself.
tm = imtypeout;
}
Printf(im_return_type, "%s", tm);
} else {
Swig_warning(WARN_D_TYPEMAP_IMTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(t, 0));
}
is_void_return = (Cmp(c_return_type, "void") == 0);
if (!is_void_return)
Wrapper_add_localv(f, "jresult", c_return_type, "jresult", NIL);
Printv(f->def, " SWIGEXPORT ", c_return_type, " ", wname, "(", NIL);
// Emit all of the local variables for holding arguments.
emit_parameter_variables(l, f);
/* Attach the standard typemaps */
emit_attach_parmmaps(l, f);
// Parameter overloading
Setattr(n, "wrap:parms", l);
Setattr(n, "wrap:name", wname);
// Wrappers not wanted for some methods where the parameters cannot be overloaded in D
if (Getattr(n, "sym:overloaded")) {
// Emit warnings for the few cases that can't be overloaded in D and give up on generating wrapper
Swig_overload_check(n);
if (Getattr(n, "overload:ignore")) {
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(t, 0), Getattr(n, "name"));
}
emit_return_variable(n, t, f);
}
/* Output argument output code */
Printv(f->code, outarg, NIL);
/* Output cleanup code */
Printv(f->code, cleanup, NIL);
/* Look to see if there is any newfree cleanup code */
if (GetFlag(n, "feature:new")) {
if ((tm = Swig_typemap_lookup("newfree", n, 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);
/* Substitute the function name */
Replaceall(f->code, "$symname", symname);
/* Contract macro modification */
if (Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, ") > 0) {
Setattr(n, "d:canthrow", "1");
}
if (!null_attribute)
Replaceall(f->code, "$null", "0");
else
Replaceall(f->code, "$null", null_attribute);
/* Dump the function out */
if (!native_function_flag) {
Wrapper_print(f, f_wrappers);
// Handle %exception which sets the canthrow attribute.
if (Getattr(n, "feature:except:canthrow")) {
Setattr(n, "d:canthrow", "1");
}
// A very simple check (it is not foolproof) to assist typemap writers
// with setting the correct features when the want to throw D exceptions
// from C++ code. It checks for the common methods which set
// a pending D exception and issues a warning if one of them has been found
// in the typemap, but the »canthrow« attribute/feature is not set.
if (!Getattr(n, "d:canthrow")) {
if (Strstr(f->code, "SWIG_exception")) {
Swig_warning(WARN_D_CANTHROW_MISSING, input_file, line_number,
"C code contains a call to SWIG_exception and D code does not handle pending exceptions via the canthrow attribute.\n");
} else if (Strstr(f->code, "SWIG_DSetPendingException")) {
Swig_warning(WARN_D_CANTHROW_MISSING, input_file, line_number,
"C code contains a call to a SWIG_DSetPendingException method and D code does not handle pending exceptions via the canthrow attribute.\n");
}
}
}
// If we are not processing an enum or constant, and we were not generating
// a wrapper function which will be accessed via a proxy class, write a
// function to the proxy D module.
if (!is_wrapping_class()) {
writeProxyDModuleFunction(n);
}
// If we are processing a public member variable, write the property-style
// member function to the proxy class.
if (wrapping_member_flag) {
Setattr(n, "proxyfuncname", variable_name);
Setattr(n, "imfuncname", symname);
writeProxyClassFunction(n);
}
Delete(c_return_type);
Delete(im_return_type);
Delete(cleanup);
Delete(outarg);
Delete(body);
Delete(overloaded_name);
DelWrapper(f);
return SWIG_OK;
}
/* ---------------------------------------------------------------------------
* D::nativeWrapper()
* --------------------------------------------------------------------------- */
virtual int nativeWrapper(Node *n) {
String *wrapname = Getattr(n, "wrap:name");
if (!addSymbol(wrapname, n))
return SWIG_ERROR;
if (Getattr(n, "type")) {
Swig_save("nativeWrapper", n, "name", NIL);
Setattr(n, "name", wrapname);
native_function_flag = true;
functionWrapper(n);
Swig_restore(n);
native_function_flag = false;
} else {
Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name"));
}
return SWIG_OK;
}
/* ---------------------------------------------------------------------------
* D::classDirector()
* --------------------------------------------------------------------------- */
virtual int classDirector(Node *n) {
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 = getOverloadedName(n);
String *storage = Getattr(n, "storage");
String *value = Getattr(n, "value");
String *decl = Getattr(n, "decl");
String *declaration = NewString("");
String *tm;
Parm *p;
int i;
Wrapper *w = NewWrapper();
ParmList *l = Getattr(n, "parms");
bool is_void = !(Cmp(returntype, "void"));
String *qualified_return = 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 *imclass_dmethod;
String *callback_typedef_parms = NewString("");
String *delegate_parms = NewString("");
String *proxy_method_param_list = NewString("");
String *proxy_callback_return_type = NewString("");
String *callback_def = NewString("");
String *callback_code = NewString("");
String *imcall_args = NewString("");
bool ignored_method = GetFlag(n, "feature:ignore") ? true : false;
// Kludge Alert: functionWrapper sets sym:overload properly, but it
// isn't at this point, so we have to manufacture it ourselves. At least
// we're consistent with the sym:overload name in functionWrapper. (?? when
// does the overloaded method name get set?)
imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(getNSpace(), classname, overloaded_name));
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;
}
/* Add to local variables */
Printf(c_decl, "%s %s", c_param_type, arg);
if (!ignored_method)
Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL);
/* Add input marshalling code */
if ((tm = Getattr(p, "tmap:directorin"))) {
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", "");
}
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 = lookupDTypemap(n, "dtype");
if (dp_return_type) {
String *dtypeout = Getattr(n, "tmap:dtype:out");
if (dtypeout) {
// The type in the dtype typemap's out attribute overrides the type
// in the typemap itself.
dp_return_type = dtypeout;
replaceClassname(dp_return_type, returntype);
}
} else {
Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number,
"No dtype typemap defined for %s\n", SwigType_str(returntype, 0));
dp_return_type = NewString("");
}
UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name, dp_return_type, proxy_method_param_list);
Delete(dp_return_type);
// Write the global callback function pointer on the C code.
String *methid = Getattr(udata, "class_methodidx");
Printf(director_callback_typedefs, " typedef %s (* SWIG_Callback%s_t)", c_ret_type, methid);
Printf(director_callback_typedefs, "(void *dobj%s);\n", callback_typedef_parms);
Printf(director_callback_pointers, " SWIG_Callback%s_t swig_callback_%s;\n", methid, overloaded_name);
// Write the type alias for the callback to the intermediary D module.
String *proxy_callback_type = NewString("");
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(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);