diff options
author | say <[email protected]> | 2023-02-14 17:24:43 +0300 |
---|---|---|
committer | say <[email protected]> | 2023-02-14 17:24:43 +0300 |
commit | e0094c4ad6964e11564777bc0d859c68d8aa9de2 (patch) | |
tree | 5d2ad1a4df88da1f74385888891a2a5f9fbbc3ef /contrib/tools/swig/Source/Modules | |
parent | 65a08c9fdece8dba50da8beb4d7c81447211dd45 (diff) |
Migrate black linter on custom_lint pipeline
Diffstat (limited to 'contrib/tools/swig/Source/Modules')
33 files changed, 63957 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/Modules/README b/contrib/tools/swig/Source/Modules/README new file mode 100644 index 00000000000..058779d227d --- /dev/null +++ b/contrib/tools/swig/Source/Modules/README @@ -0,0 +1,9 @@ +06/25/2002 + +This directory contains all of the SWIG language modules. Many of these +modules contain code that dates back to SWIG1.0. The module API has changed +a lot in the development releases so this is fairly messy. We're working on +cleaning it up, but you'll have to bear with us until it's done. + +-- Dave + diff --git a/contrib/tools/swig/Source/Modules/allocate.cxx b/contrib/tools/swig/Source/Modules/allocate.cxx new file mode 100644 index 00000000000..23683c38596 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/allocate.cxx @@ -0,0 +1,965 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * allocate.cxx + * + * This module tries to figure out which classes and structures support + * default constructors and destructors in C++. There are several rules that + * define this behavior including pure abstract methods, private sections, + * and non-default constructors in base classes. See the ARM or + * Doc/Manual/SWIGPlus.html for details. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static int virtual_elimination_mode = 0; /* set to 0 on default */ + +/* Set virtual_elimination_mode */ +void Wrapper_virtual_elimination_mode_set(int flag) { + virtual_elimination_mode = flag; +} + +/* Helper function to assist with abstract class checking. + This is a major hack. Sorry. */ + +extern "C" { + static String *search_decl = 0; /* Declarator being searched */ + static int check_implemented(Node *n) { + String *decl; + if (!n) + return 0; + while (n) { + if (Strcmp(nodeType(n), "cdecl") == 0) { + decl = Getattr(n, "decl"); + if (SwigType_isfunction(decl)) { + SwigType *decl1 = SwigType_typedef_resolve_all(decl); + SwigType *decl2 = SwigType_pop_function(decl1); + if (Strcmp(decl2, search_decl) == 0) { + if (!GetFlag(n, "abstract")) { + Delete(decl1); + Delete(decl2); + return 1; + } + } + Delete(decl1); + Delete(decl2); + } + } + n = Getattr(n, "csym:nextSibling"); + } + return 0; + } +} + +class Allocate:public Dispatcher { + Node *inclass; + int extendmode; + + /* Checks if a function, n, is the same as any in the base class, ie if the method is polymorphic. + * Also checks for methods which will be hidden (ie a base has an identical non-virtual method). + * Both methods must have public access for a match to occur. */ + int function_is_defined_in_bases(Node *n, Node *bases) { + + if (!bases) + return 0; + + String *this_decl = Getattr(n, "decl"); + if (!this_decl) + return 0; + + String *name = Getattr(n, "name"); + String *this_type = Getattr(n, "type"); + String *resolved_decl = SwigType_typedef_resolve_all(this_decl); + + // Search all base classes for methods with same signature + for (int i = 0; i < Len(bases); i++) { + Node *b = Getitem(bases, i); + Node *base = firstChild(b); + while (base) { + if (Strcmp(nodeType(base), "extend") == 0) { + // Loop through all the %extend methods + Node *extend = firstChild(base); + while (extend) { + if (function_is_defined_in_bases_seek(n, b, extend, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + extend = nextSibling(extend); + } + } else if (Strcmp(nodeType(base), "using") == 0) { + // Loop through all the using declaration methods + Node *usingdecl = firstChild(base); + while (usingdecl) { + if (function_is_defined_in_bases_seek(n, b, usingdecl, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + usingdecl = nextSibling(usingdecl); + } + } else { + // normal methods + if (function_is_defined_in_bases_seek(n, b, base, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + } + base = nextSibling(base); + } + } + Delete(resolved_decl); + resolved_decl = 0; + for (int j = 0; j < Len(bases); j++) { + Node *b = Getitem(bases, j); + if (function_is_defined_in_bases(n, Getattr(b, "allbases"))) + return 1; + } + return 0; + } + + /* Helper function for function_is_defined_in_bases */ + int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) { + + String *base_decl = Getattr(base, "decl"); + SwigType *base_type = Getattr(base, "type"); + if (base_decl && base_type) { + if (checkAttribute(base, "name", name) && !GetFlag(b, "feature:ignore") /* whole class is ignored */ ) { + if (SwigType_isfunction(resolved_decl) && SwigType_isfunction(base_decl)) { + // We have found a method that has the same name as one in a base class + bool covariant_returntype = false; + bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false; + bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false; + if (returntype_match && decl_match) { + // Exact match - we have found a method with identical signature + // No typedef resolution was done, but skipping it speeds things up slightly + } else { + // Either we have: + // 1) matching methods but are one of them uses a different typedef (return type or parameter) to the one in base class' method + // 2) matching polymorphic methods with covariant return type + // 3) a non-matching method (ie an overloaded method of some sort) + // 4) a matching method which is not polymorphic, ie it hides the base class' method + + // Check if fully resolved return types match (including + // covariant return types) + if (!returntype_match) { + String *this_returntype = function_return_type(n); + String *base_returntype = function_return_type(base); + returntype_match = Strcmp(this_returntype, base_returntype) == 0 ? true : false; + if (!returntype_match) { + covariant_returntype = SwigType_issubtype(this_returntype, base_returntype) ? true : false; + returntype_match = covariant_returntype; + } + Delete(this_returntype); + Delete(base_returntype); + } + // The return types must match at this point, for the whole method to match + if (returntype_match && !decl_match) { + // Now need to check the parameter list + // First do an inexpensive parameter count + ParmList *this_parms = Getattr(n, "parms"); + ParmList *base_parms = Getattr(base, "parms"); + if (ParmList_len(this_parms) == ParmList_len(base_parms)) { + // Number of parameters are the same, now check that all the parameters match + SwigType *base_fn = NewString(""); + SwigType *this_fn = NewString(""); + SwigType_add_function(base_fn, base_parms); + SwigType_add_function(this_fn, this_parms); + base_fn = SwigType_typedef_resolve_all(base_fn); + this_fn = SwigType_typedef_resolve_all(this_fn); + if (Strcmp(base_fn, this_fn) == 0) { + // Finally check that the qualifiers match + int base_qualifier = SwigType_isqualifier(resolved_decl); + int this_qualifier = SwigType_isqualifier(base_decl); + if (base_qualifier == this_qualifier) { + decl_match = true; + } + } + Delete(base_fn); + Delete(this_fn); + } + } + } + //Printf(stderr,"look %s %s %d %d\n",base_decl, this_decl, returntype_match, decl_match); + + if (decl_match && returntype_match) { + // Found an identical method in the base class + bool this_wrapping_protected_members = is_member_director(n) ? true : false; // This should really check for dirprot rather than just being a director method + bool base_wrapping_protected_members = is_member_director(base) ? true : false; // This should really check for dirprot rather than just being a director method + bool both_have_public_access = is_public(n) && is_public(base); + bool both_have_protected_access = (is_protected(n) && this_wrapping_protected_members) && (is_protected(base) && base_wrapping_protected_members); + bool both_have_private_access = is_private(n) && is_private(base); + if (checkAttribute(base, "storage", "virtual")) { + // Found a polymorphic method. + // Mark the polymorphic method, in case the virtual keyword was not used. + Setattr(n, "storage", "virtual"); + if (!Getattr(b, "feature:interface")) { // interface implementation neither hides nor overrides + if (both_have_public_access || both_have_protected_access) { + if (!is_non_public_base(inclass, b)) + Setattr(n, "override", base); // Note C# definition of override, ie access must be the same + } + else if (!both_have_private_access) { + // Different access + if (this_wrapping_protected_members || base_wrapping_protected_members) + if (!is_non_public_base(inclass, b)) + Setattr(n, "hides", base); // Note C# definition of hiding, ie hidden if access is different + } + } + // Try and find the most base's covariant return type + SwigType *most_base_covariant_type = Getattr(base, "covariant"); + if (!most_base_covariant_type && covariant_returntype) + most_base_covariant_type = function_return_type(base, false); + + if (!most_base_covariant_type) { + // Eliminate the derived virtual method. + if (virtual_elimination_mode && !is_member_director(n)) + if (both_have_public_access) + if (!is_non_public_base(inclass, b)) + if (!Swig_symbol_isoverloaded(n)) { + // Don't eliminate if an overloaded method as this hides the method + // in the scripting languages: the dispatch function will hide the base method if ignored. + SetFlag(n, "feature:ignore"); + } + } else { + // Some languages need to know about covariant return types + Setattr(n, "covariant", most_base_covariant_type); + } + + } else { + // Found an identical method in the base class, but it is not polymorphic. + if (both_have_public_access || both_have_protected_access) + if (!is_non_public_base(inclass, b)) + Setattr(n, "hides", base); + } + if (both_have_public_access || both_have_protected_access) + return 1; + } + } + } + } + return 0; + } + + /* Determines whether the base class, b, is in the list of private + * or protected base classes for class n. */ + bool is_non_public_base(Node *n, Node *b) { + bool non_public_base = false; + Node *bases = Getattr(n, "privatebases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *base = Getitem(bases, i); + if (base == b) + non_public_base = true; + } + } + bases = Getattr(n, "protectedbases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *base = Getitem(bases, i); + if (base == b) + non_public_base = true; + } + } + return non_public_base; + } + + /* Returns the return type for a function. The node n should be a function. + If resolve is true the fully returned type is fully resolved. + Caller is responsible for deleting returned string. */ + String *function_return_type(Node *n, bool resolve = true) { + String *decl = Getattr(n, "decl"); + SwigType *type = Getattr(n, "type"); + String *ty = NewString(type); + SwigType_push(ty, decl); + if (SwigType_isqualifier(ty)) + Delete(SwigType_pop(ty)); + Delete(SwigType_pop_function(ty)); + if (resolve) { + String *unresolved = ty; + ty = SwigType_typedef_resolve_all(unresolved); + Delete(unresolved); + } + return ty; + } + + /* Checks if a class member is the same as inherited from the class bases */ + int class_member_is_defined_in_bases(Node *member, Node *classnode) { + Node *bases; /* bases is the closest ancestors of classnode */ + int defined = 0; + + bases = Getattr(classnode, "allbases"); + if (!bases) + return 0; + + { + int old_mode = virtual_elimination_mode; + if (is_member_director(classnode, member)) + virtual_elimination_mode = 0; + + if (function_is_defined_in_bases(member, bases)) { + defined = 1; + } + + virtual_elimination_mode = old_mode; + } + + if (defined) + return 1; + else + return 0; + } + + /* Checks to see if a class is abstract through inheritance, + and saves the first node that seems to be abstract. + */ + int is_abstract_inherit(Node *n, Node *base = 0, int first = 0) { + if (!first && (base == n)) + return 0; + if (!base) { + /* Root node */ + Symtab *stab = Getattr(n, "symtab"); /* Get symbol table for node */ + Symtab *oldtab = Swig_symbol_setscope(stab); + int ret = is_abstract_inherit(n, n, 1); + Swig_symbol_setscope(oldtab); + return ret; + } + List *abstracts = Getattr(base, "abstracts"); + if (abstracts) { + int dabstract = 0; + int len = Len(abstracts); + for (int i = 0; i < len; i++) { + Node *nn = Getitem(abstracts, i); + String *name = Getattr(nn, "name"); + if (!name) + continue; + if (Strchr(name, '~')) + continue; /* Don't care about destructors */ + String *base_decl = Getattr(nn, "decl"); + if (base_decl) + base_decl = SwigType_typedef_resolve_all(base_decl); + if (SwigType_isfunction(base_decl)) + search_decl = SwigType_pop_function(base_decl); + Node *dn = Swig_symbol_clookup_local_check(name, 0, check_implemented); + Delete(search_decl); + Delete(base_decl); + + if (!dn) { + List *nabstracts = Getattr(n, "abstracts"); + if (!nabstracts) { + nabstracts = NewList(); + Setattr(n, "abstracts", nabstracts); + Delete(nabstracts); + } + Append(nabstracts, nn); + if (!Getattr(n, "abstracts:firstnode")) { + Setattr(n, "abstracts:firstnode", nn); + } + dabstract = base != n; + } + } + if (dabstract) + return 1; + } + List *bases = Getattr(base, "allbases"); + if (!bases) + return 0; + for (int i = 0; i < Len(bases); i++) { + if (is_abstract_inherit(n, Getitem(bases, i))) { + return 1; + } + } + return 0; + } + + + /* Grab methods used by smart pointers */ + + List *smart_pointer_methods(Node *cls, List *methods, int isconst, String *classname = 0) { + if (!methods) { + methods = NewList(); + } + + Node *c = firstChild(cls); + + while (c) { + if (Getattr(c, "error") || GetFlag(c, "feature:ignore")) { + c = nextSibling(c); + continue; + } + if (!isconst && (Strcmp(nodeType(c), "extend") == 0)) { + methods = smart_pointer_methods(c, methods, isconst, Getattr(cls, "name")); + } else if (Strcmp(nodeType(c), "cdecl") == 0) { + if (!GetFlag(c, "feature:ignore")) { + String *storage = Getattr(c, "storage"); + if (!((Cmp(storage, "typedef") == 0)) + && !((Cmp(storage, "friend") == 0))) { + String *name = Getattr(c, "name"); + String *symname = Getattr(c, "sym:name"); + Node *e = Swig_symbol_clookup_local(name, 0); + if (e && is_public(e) && !GetFlag(e, "feature:ignore") && (Cmp(symname, Getattr(e, "sym:name")) == 0)) { + Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(e), Getline(e), "Declaration of '%s' shadows declaration accessible via operator->(),\n", name); + Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(c), Getline(c), "previous declaration of '%s'.\n", name); + } else { + /* Make sure node with same name doesn't already exist */ + int k; + int match = 0; + for (k = 0; k < Len(methods); k++) { + e = Getitem(methods, k); + if (Cmp(symname, Getattr(e, "sym:name")) == 0) { + match = 1; + break; + } + if (!Getattr(e, "sym:name") && (Cmp(name, Getattr(e, "name")) == 0)) { + match = 1; + break; + } + } + if (!match) { + Node *cc = c; + while (cc) { + Node *cp = cc; + if (classname) { + Setattr(cp, "extendsmartclassname", classname); + } + Setattr(cp, "allocate:smartpointeraccess", "1"); + /* If constant, we have to be careful */ + if (isconst) { + SwigType *decl = Getattr(cp, "decl"); + if (decl) { + if (SwigType_isfunction(decl)) { /* If method, we only add if it's a const method */ + if (SwigType_isconst(decl)) { + Append(methods, cp); + } + } else { + Append(methods, cp); + } + } else { + Append(methods, cp); + } + } else { + Append(methods, cp); + } + cc = Getattr(cc, "sym:nextSibling"); + } + } + } + } + } + } + + c = nextSibling(c); + } + /* Look for methods in base classes */ + { + Node *bases = Getattr(cls, "bases"); + int k; + for (k = 0; k < Len(bases); k++) { + smart_pointer_methods(Getitem(bases, k), methods, isconst); + } + } + /* Remove protected/private members */ + { + for (int i = 0; i < Len(methods);) { + Node *n = Getitem(methods, i); + if (!is_public(n)) { + Delitem(methods, i); + continue; + } + i++; + } + } + return methods; + } + + void mark_exception_classes(ParmList *p) { + while (p) { + SwigType *ty = Getattr(p, "type"); + SwigType *t = SwigType_typedef_resolve_all(ty); + if (SwigType_isreference(t) || SwigType_ispointer(t) || SwigType_isarray(t)) { + Delete(SwigType_pop(t)); + } + Node *c = Swig_symbol_clookup(t, 0); + if (c) { + if (!GetFlag(c, "feature:exceptionclass")) { + SetFlag(c, "feature:exceptionclass"); + } + } + p = nextSibling(p); + Delete(t); + } + } + + + void process_exceptions(Node *n) { + ParmList *catchlist = 0; + /* + the "catchlist" attribute is used to emit the block + + try {$action;} + catch <list of catches>; + + in emit.cxx + + and is either constructed from the "feature:catches" feature + or copied from the node "throws" list. + */ + String *scatchlist = Getattr(n, "feature:catches"); + if (scatchlist) { + catchlist = Swig_cparse_parms(scatchlist, n); + if (catchlist) { + Setattr(n, "catchlist", catchlist); + mark_exception_classes(catchlist); + Delete(catchlist); + } + } + ParmList *throws = Getattr(n, "throws"); + if (throws) { + /* if there is no explicit catchlist, we catch everything in the throws list */ + if (!catchlist) { + Setattr(n, "catchlist", throws); + } + mark_exception_classes(throws); + } + } + +public: +Allocate(): + inclass(NULL), extendmode(0) { + } + + virtual int top(Node *n) { + cplus_mode = PUBLIC; + inclass = 0; + extendmode = 0; + emit_children(n); + return SWIG_OK; + } + + virtual int importDirective(Node *n) { + return emit_children(n); + } + virtual int includeDirective(Node *n) { + return emit_children(n); + } + virtual int externDeclaration(Node *n) { + return emit_children(n); + } + virtual int namespaceDeclaration(Node *n) { + return emit_children(n); + } + virtual int extendDirective(Node *n) { + extendmode = 1; + emit_children(n); + extendmode = 0; + return SWIG_OK; + } + + virtual int classDeclaration(Node *n) { + Symtab *symtab = Swig_symbol_current(); + Swig_symbol_setscope(Getattr(n, "symtab")); + save_value<Node*> oldInclass(inclass); + save_value<AccessMode> oldAcessMode(cplus_mode); + save_value<int> oldExtendMode(extendmode); + if (Getattr(n, "template")) + extendmode = 0; + if (!CPlusPlus) { + /* Always have default constructors/destructors in C */ + Setattr(n, "allocate:default_constructor", "1"); + Setattr(n, "allocate:default_destructor", "1"); + } + + if (Getattr(n, "allocate:visit")) + return SWIG_OK; + Setattr(n, "allocate:visit", "1"); + + /* Always visit base classes first */ + { + List *bases = Getattr(n, "bases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *b = Getitem(bases, i); + classDeclaration(b); + } + } + } + inclass = n; + String *kind = Getattr(n, "kind"); + if (Strcmp(kind, "class") == 0) { + cplus_mode = PRIVATE; + } else { + cplus_mode = PUBLIC; + } + + emit_children(n); + + /* Check if the class is abstract via inheritance. This might occur if a class didn't have + any pure virtual methods of its own, but it didn't implement all of the pure methods in + a base class */ + if (!Getattr(n, "abstracts") && is_abstract_inherit(n)) { + if (((Getattr(n, "allocate:public_constructor") || (!GetFlag(n, "feature:nodefault") && !Getattr(n, "allocate:has_constructor"))))) { + if (!GetFlag(n, "feature:notabstract")) { + Node *na = Getattr(n, "abstracts:firstnode"); + if (na) { + Swig_warning(WARN_TYPE_ABSTRACT, Getfile(n), Getline(n), + "Class '%s' might be abstract, " "no constructors generated,\n", SwigType_namestr(Getattr(n, "name"))); + Swig_warning(WARN_TYPE_ABSTRACT, Getfile(na), Getline(na), "Method %s might not be implemented.\n", Swig_name_decl(na)); + if (!Getattr(n, "abstracts")) { + List *abstracts = NewList(); + Append(abstracts, na); + Setattr(n, "abstracts", abstracts); + Delete(abstracts); + } + } + } + } + } + + if (!Getattr(n, "allocate:has_constructor")) { + /* No constructor is defined. We need to check a few things */ + /* If class is abstract. No default constructor. Sorry */ + if (Getattr(n, "abstracts")) { + Delattr(n, "allocate:default_constructor"); + } + if (!Getattr(n, "allocate:default_constructor")) { + /* Check base classes */ + List *bases = Getattr(n, "allbases"); + int allows_default = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow default constructor, we don't allow it either */ + if (!Getattr(n, "allocate:default_constructor") && (!Getattr(n, "allocate:default_base_constructor"))) { + allows_default = 0; + } + } + if (allows_default) { + Setattr(n, "allocate:default_constructor", "1"); + } + } + } + if (!Getattr(n, "allocate:has_copy_constructor")) { + if (Getattr(n, "abstracts")) { + Delattr(n, "allocate:copy_constructor"); + } + if (!Getattr(n, "allocate:copy_constructor")) { + /* Check base classes */ + List *bases = Getattr(n, "allbases"); + int allows_copy = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow copy constructor, we don't allow it either */ + if (!Getattr(n, "allocate:copy_constructor") && (!Getattr(n, "allocate:copy_base_constructor"))) { + allows_copy = 0; + } + } + if (allows_copy) { + Setattr(n, "allocate:copy_constructor", "1"); + } + } + } + + if (!Getattr(n, "allocate:has_destructor")) { + /* No destructor was defined */ + List *bases = Getattr(n, "allbases"); + int allows_destruct = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow default destructor, we don't allow it either */ + if (!Getattr(n, "allocate:default_destructor") && (!Getattr(n, "allocate:default_base_destructor"))) { + allows_destruct = 0; + } + } + if (allows_destruct) { + Setattr(n, "allocate:default_destructor", "1"); + } + } + + if (!Getattr(n, "allocate:has_assign")) { + /* No assignment operator was defined */ + List *bases = Getattr(n, "allbases"); + int allows_assign = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow assignment, we don't allow it either */ + if (Getattr(n, "allocate:has_assign")) { + allows_assign = !Getattr(n, "allocate:noassign"); + } + } + if (!allows_assign) { + Setattr(n, "allocate:noassign", "1"); + } + } + + if (!Getattr(n, "allocate:has_new")) { + /* No new operator was defined */ + List *bases = Getattr(n, "allbases"); + int allows_new = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow new operator, we don't allow it either */ + if (Getattr(n, "allocate:has_new")) { + allows_new = !Getattr(n, "allocate:nonew"); + } + } + if (!allows_new) { + Setattr(n, "allocate:nonew", "1"); + } + } + + /* Check if base classes allow smart pointers, but might be hidden */ + if (!Getattr(n, "allocate:smartpointer")) { + Node *sp = Swig_symbol_clookup("operator ->", 0); + if (sp) { + /* Look for parent */ + Node *p = parentNode(sp); + if (Strcmp(nodeType(p), "extend") == 0) { + p = parentNode(p); + } + if (Strcmp(nodeType(p), "class") == 0) { + if (GetFlag(p, "feature:ignore")) { + Setattr(n, "allocate:smartpointer", Getattr(p, "allocate:smartpointer")); + } + } + } + } + + Swig_interface_propagate_methods(n); + + /* Only care about default behavior. Remove temporary values */ + Setattr(n, "allocate:visit", "1"); + Swig_symbol_setscope(symtab); + return SWIG_OK; + } + + virtual int accessDeclaration(Node *n) { + String *kind = Getattr(n, "kind"); + if (Cmp(kind, "public") == 0) { + cplus_mode = PUBLIC; + } else if (Cmp(kind, "private") == 0) { + cplus_mode = PRIVATE; + } else if (Cmp(kind, "protected") == 0) { + cplus_mode = PROTECTED; + } + return SWIG_OK; + } + + virtual int usingDeclaration(Node *n) { + + Node *c = 0; + for (c = firstChild(n); c; c = nextSibling(c)) { + if (Strcmp(nodeType(c), "cdecl") == 0) { + process_exceptions(c); + + if (inclass) + class_member_is_defined_in_bases(c, inclass); + } + } + + return SWIG_OK; + } + + virtual int cDeclaration(Node *n) { + + process_exceptions(n); + + if (inclass) { + /* check whether the member node n is defined in class node in class's bases */ + class_member_is_defined_in_bases(n, inclass); + + /* Check to see if this is a static member or not. If so, we add an attribute + cplus:staticbase that saves the current class */ + + if (Swig_storage_isstatic(n)) { + Setattr(n, "cplus:staticbase", inclass); + } + + String *name = Getattr(n, "name"); + if (cplus_mode != PUBLIC) { + if (Strcmp(name, "operator =") == 0) { + /* Look for a private assignment operator */ + if (!GetFlag(n, "deleted")) + Setattr(inclass, "allocate:has_assign", "1"); + Setattr(inclass, "allocate:noassign", "1"); + } else if (Strcmp(name, "operator new") == 0) { + /* Look for a private new operator */ + if (!GetFlag(n, "deleted")) + Setattr(inclass, "allocate:has_new", "1"); + Setattr(inclass, "allocate:nonew", "1"); + } + } else { + if (Strcmp(name, "operator =") == 0) { + if (!GetFlag(n, "deleted")) + Setattr(inclass, "allocate:has_assign", "1"); + else + Setattr(inclass, "allocate:noassign", "1"); + } else if (Strcmp(name, "operator new") == 0) { + if (!GetFlag(n, "deleted")) + Setattr(inclass, "allocate:has_new", "1"); + else + Setattr(inclass, "allocate:nonew", "1"); + } + /* Look for smart pointer operator */ + if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) { + /* Look for version with no parameters */ + Node *sn = n; + while (sn) { + if (!Getattr(sn, "parms")) { + SwigType *type = SwigType_typedef_resolve_all(Getattr(sn, "type")); + SwigType_push(type, Getattr(sn, "decl")); + Delete(SwigType_pop_function(type)); + SwigType *base = SwigType_base(type); + Node *sc = Swig_symbol_clookup(base, 0); + if ((sc) && (Strcmp(nodeType(sc), "class") == 0)) { + if (SwigType_check_decl(type, "p.")) { + /* Need to check if type is a const pointer */ + int isconst = 0; + Delete(SwigType_pop(type)); + if (SwigType_isconst(type)) { + isconst = !Getattr(inclass, "allocate:smartpointermutable"); + Setattr(inclass, "allocate:smartpointerconst", "1"); + } + else { + Setattr(inclass, "allocate:smartpointermutable", "1"); + } + List *methods = smart_pointer_methods(sc, 0, isconst); + Setattr(inclass, "allocate:smartpointer", methods); + Setattr(inclass, "allocate:smartpointerpointeeclassname", Getattr(sc, "name")); + } else { + /* Hmmm. The return value is not a pointer. If the type is a value + or reference. We're going to chase it to see if another operator->() + can be found */ + if ((SwigType_check_decl(type, "")) || (SwigType_check_decl(type, "r."))) { + Node *nn = Swig_symbol_clookup("operator ->", Getattr(sc, "symtab")); + if (nn) { + Delete(base); + Delete(type); + sn = nn; + continue; + } + } + } + } + Delete(base); + Delete(type); + break; + } + } + } + } + } + return SWIG_OK; + } + + virtual int constructorDeclaration(Node *n) { + if (!inclass) + return SWIG_OK; + Parm *parms = Getattr(n, "parms"); + + process_exceptions(n); + if (!extendmode) { + if (!ParmList_numrequired(parms)) { + /* Class does define a default constructor */ + /* However, we had better see where it is defined */ + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:default_constructor", "1"); + } else if (cplus_mode == PROTECTED) { + Setattr(inclass, "allocate:default_base_constructor", "1"); + } + } + /* Class defines some kind of constructor. May or may not be public */ + Setattr(inclass, "allocate:has_constructor", "1"); + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:public_constructor", "1"); + } + } else { + Setattr(inclass, "allocate:has_constructor", "1"); + Setattr(inclass, "allocate:public_constructor", "1"); + } + + + /* See if this is a copy constructor */ + if (parms && (ParmList_numrequired(parms) == 1)) { + /* Look for a few cases. X(const X &), X(X &), X(X *) */ + int copy_constructor = 0; + SwigType *type = Getattr(inclass, "name"); + String *tn = NewStringf("r.q(const).%s", type); + String *cc = SwigType_typedef_resolve_all(tn); + SwigType *rt = SwigType_typedef_resolve_all(Getattr(parms, "type")); + if (SwigType_istemplate(type)) { + String *tmp = Swig_symbol_template_deftype(cc, 0); + Delete(cc); + cc = tmp; + tmp = Swig_symbol_template_deftype(rt, 0); + Delete(rt); + rt = tmp; + } + if (Strcmp(cc, rt) == 0) { + copy_constructor = 1; + } else { + Delete(cc); + cc = NewStringf("r.%s", Getattr(inclass, "name")); + if (Strcmp(cc, Getattr(parms, "type")) == 0) { + copy_constructor = 1; + } else { + Delete(cc); + cc = NewStringf("p.%s", Getattr(inclass, "name")); + String *ty = SwigType_strip_qualifiers(Getattr(parms, "type")); + if (Strcmp(cc, ty) == 0) { + copy_constructor = 1; + } + Delete(ty); + } + } + Delete(cc); + Delete(rt); + Delete(tn); + + if (copy_constructor) { + Setattr(n, "copy_constructor", "1"); + Setattr(inclass, "allocate:has_copy_constructor", "1"); + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:copy_constructor", "1"); + } else if (cplus_mode == PROTECTED) { + Setattr(inclass, "allocate:copy_base_constructor", "1"); + } + } + } + return SWIG_OK; + } + + virtual int destructorDeclaration(Node *n) { + (void) n; + if (!inclass) + return SWIG_OK; + if (!extendmode) { + Setattr(inclass, "allocate:has_destructor", "1"); + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:default_destructor", "1"); + } else if (cplus_mode == PROTECTED) { + Setattr(inclass, "allocate:default_base_destructor", "1"); + } else if (cplus_mode == PRIVATE) { + Setattr(inclass, "allocate:private_destructor", "1"); + } + } else { + Setattr(inclass, "allocate:has_destructor", "1"); + Setattr(inclass, "allocate:default_destructor", "1"); + } + return SWIG_OK; + } +}; + +void Swig_default_allocators(Node *n) { + if (!n) + return; + Allocate *a = new Allocate; + a->top(n); + delete a; +} diff --git a/contrib/tools/swig/Source/Modules/browser.cxx b/contrib/tools/swig/Source/Modules/browser.cxx new file mode 100644 index 00000000000..217b40a7ec0 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/browser.cxx @@ -0,0 +1,421 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * browser.cxx + * + * A web-base parse tree browser using SWILL. This is an optional + * feature that's normally disabled. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +#ifdef SWIG_SWILL +extern "C" { +#include "swill.h" +} static FILE *out = 0; +static Node *view_top = 0; + +class Browser:public Dispatcher { + void show_checkbox(Node *t, Node *n) { + int v = 0; + if (Getmeta(n, "visible")) { + v = 1; + } + if (v) { + Printf(out, "<a name=\"n%p\"></a>[<a href=\"hide.html?node=%p&hn=%p#n%p\">-</a>] ", n, t, n, n); + } else { + Printf(out, "<a name=\"n%p\"></a>[<a href=\"show.html?node=%p&hn=%p#n%p\">+</a>] ", n, t, n, n); + } + } + void show_attributes(Node *obj) { + if (!Getmeta(obj, "visible")) + return; + String *os = NewString(""); + String *k; + Iterator ki; + ki = First(obj); + while (ki.key) { + k = ki.key; + if ((Cmp(k, "nodeType") == 0) || (Cmp(k, "firstChild") == 0) || (Cmp(k, "lastChild") == 0) || + (Cmp(k, "parentNode") == 0) || (Cmp(k, "nextSibling") == 0) || (Cmp(k, "previousSibling") == 0) || (*(Char(k)) == '$')) { + /* Do nothing */ + } else if (Cmp(k, "parms") == 0) { + String *o = NewString(""); + Printf(o, "%s", ParmList_protostr(Getattr(obj, k))); + Replaceall(o, "&", "&"); + Replaceall(o, "<", "<"); + Replaceall(o, ">", ">"); + Printf(os, "<a href=\"data.html?n=%p\">?</a> %-12s - %s\n", Getattr(obj, k), k, o); + Delete(o); + } else { + DOH *o; + char *trunc = ""; + if (DohIsString(Getattr(obj, k))) { + o = Str(Getattr(obj, k)); + if (Len(o) > 70) { + trunc = "..."; + } + Replaceall(o, "&", "&"); + Replaceall(o, "<", "<"); + Printf(os, "<a href=\"data.html?n=%p\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj, k), k, o, trunc); + Delete(o); + } else { + Printf(os, "<a href=\"data.html?n=%p\">?</a> %-12s - %p\n", Getattr(obj, k), k, Getattr(obj, k)); + } + } + ki = Next(ki); + } + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os)); + Delete(os); + } + +public: + virtual int emit_one(Node *n) { + char *tag = Char(nodeType(n)); + char *file = Char(Getfile(n)); + int line = Getline(n); + char *name = GetChar(n, "name"); + + show_checkbox(view_top, n); + Printf(out, "<b><a href=\"index.html?node=%p\">%s</a></b>", n, tag); + if (name) { + Printf(out, " (%s)", name); + } + Printf(out, ". %s:%d\n", file, line); + Printf(out, "<br>"); + Dispatcher::emit_one(n); + return SWIG_OK; + } + virtual int emit_children(Node *n) { + if (Getmeta(n, "visible")) { + Printf(out, "<blockquote>\n"); + Dispatcher::emit_children(n); + Printf(out, "</blockquote>\n"); + } + return SWIG_OK; + } + virtual int defaultHandler(Node *n) { + show_attributes(n); + return SWIG_OK; + } + virtual int top(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int includeDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int importDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int extendDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int classDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int templateDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int lambdaDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int enumDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int typemapDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int namespaceDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int usingDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + +}; + +static int browser_exit = 0; +static Node *tree_top = 0; +static Browser *browse = 0; + +/* ---------------------------------------------------------------------- + * exit_handler() - Force the browser to exit + * ---------------------------------------------------------------------- */ + +void exit_handler(FILE *f) { + browser_exit = 1; + Printf(f, "Terminated.\n"); +} + +/* ---------------------------------------------------------------------- + * node_handler() - Generate information about a specific node + * ---------------------------------------------------------------------- */ + +static void display(FILE *f, Node *n) { + /* Print standard HTML header */ + + Printf(f, "<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", Swig_package_version()); + Printf(f, "<b>SWIG-%s</b><br>\n", Swig_package_version()); + Printf(f, "[ <a href=\"exit.html\">Exit</a> ]"); + Printf(f, " [ <a href=\"index.html?node=%p\">Top</a> ]", tree_top); + if (n != tree_top) { + Printf(f, " [ <a href=\"index.html?node=%p\">Up</a> ]", parentNode(n)); + } + Printf(f, " [ <a href=\"symbol.html\">Symbols</a> ]"); + Printf(f, "<br><hr><p>\n"); + + out = f; + + browse->emit_one(n); + + /* Print standard footer */ + Printf(f, "<br><hr></BODY></HTML>\n"); + +} + +void node_handler(FILE *f) { + Node *n = 0; + if (!swill_getargs("p(node)", &n)) { + n = tree_top; + } + view_top = n; + display(f, n); +} + + +/* ---------------------------------------------------------------------- + * hide_handler() - Hide a node + * ---------------------------------------------------------------------- */ + +void hide_handler(FILE *f) { + Node *n = 0; + if (!swill_getargs("p(hn)", &n)) { + n = 0; + } + if (n) { + Delmeta(n, "visible"); + } + node_handler(f); +} + +void show_handler(FILE *f) { + Node *n = 0; + if (!swill_getargs("p(hn)", &n)) { + n = 0; + } + if (n) { + Setmeta(n, "visible", "1"); + } + node_handler(f); +} + +void raw_data(FILE *out, Node *obj) { + if (!obj) + return; + if (DohIsMapping(obj)) { + String *k; + Iterator ki; + String *os = NewString(""); + Printf(os, "Hash {\n"); + ki = First(obj); + while (ki.key) { + k = ki.key; + DOH *o; + const char *trunc = ""; + if (DohIsString(Getattr(obj, k))) { + o = Str(Getattr(obj, k)); + if (Len(o) > 70) { + trunc = "..."; + } + Replaceall(o, "<", "<"); + Printf(os, " <a href=\"data.html?n=%p\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj, k), k, o, trunc); + Delete(o); + } else { + Printf(os, " <a href=\"data.html?n=%p\">?</a> %-12s - %p\n", Getattr(obj, k), k, Getattr(obj, k)); + } + ki = Next(ki); + } + Printf(os, "}\n"); + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os)); + Delete(os); + } else if (DohIsString(obj)) { + String *o = Str(obj); + Replaceall(o, "<", "<"); + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(o)); + Delete(o); + } else if (DohIsSequence(obj)) { + int i; + String *os = NewString(""); + Printf(os, "List [\n"); + for (i = 0; i < Len(obj); i++) { + DOH *o = Getitem(obj, i); + const char *trunc = ""; + if (DohIsString(o)) { + String *s = Str(o); + if (Len(s) > 70) { + trunc = "..."; + } + Replaceall(o, "<", "<"); + Printf(os, " <a href=\"data.html?n=%p\">?</a> [%d] - \"%(escape)-0.70s%s\"\n", o, i, s, trunc); + Delete(s); + } else { + Printf(os, " <a href=\"data.html?n=%p\">?</a> [%d] - %p\n", o, i, o); + } + } + Printf(os, "\n]\n"); + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os)); + Delete(os); + } +} + +void data_handler(FILE *f) { + DOH *n = 0; + if (!swill_getargs("p(n)", &n)) { + n = 0; + } + Printf(f, "<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", Swig_package_version()); + Printf(f, "<b>SWIG-%s</b><br>\n", Swig_package_version()); + Printf(f, "[ <a href=\"exit.html\">Exit</a> ]"); + Printf(f, " [ <a href=\"index.html?node=%p\">Top</a> ]", tree_top); + Printf(f, "<br><hr><p>\n"); + if (n) { + raw_data(f, n); + } + /* Print standard footer */ + Printf(f, "<br><hr></BODY></HTML>\n"); +} + +void symbol_handler(FILE *f) { + Symtab *sym; + char *name = 0; + + Printf(f, "<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", Swig_package_version()); + Printf(f, "<b>SWIG-%s</b><br>\n", Swig_package_version()); + Printf(f, "[ <a href=\"exit.html\">Exit</a> ]"); + Printf(f, " [ <a href=\"index.html?node=%p\">Top</a> ]", tree_top); + Printf(f, " [ <a href=\"symbol.html\">Symbols</a> ]"); + Printf(f, "<br><hr><p>\n"); + + if (!swill_getargs("p(sym)|s(name)", &sym, &name)) { + sym = Swig_symbol_getscope(""); + name = 0; + } + if (!sym) { + Printf(f, "No symbol table specified!\n"); + return; + } + { + String *q = Swig_symbol_qualifiedscopename(sym); + if (!Len(q)) { + Printf(f, "<b>Symbol table: :: (global)</b><br>\n"); + } else { + Printf(f, "<b>Symbol table: %s</b><br>\n", q); + } + Delete(q); + } + + fprintf(f, "<p><form action=\"symbol.html\" method=GET>\n"); + fprintf(f, "Symbol lookup: <input type=text name=name size=40></input><br>\n"); + fprintf(f, "<input type=hidden name=sym value=\"%p\">\n", sym); + fprintf(f, "Submit : <input type=submit></input>\n"); + fprintf(f, "</form>"); + + if (name) { + Node *n = Swig_symbol_clookup(name, sym); + Printf(f, "Symbol '%s':\n", name); + Printf(f, "<blockquote>\n"); + if (!n) { + Printf(f, "Not defined!\n"); + } else { + raw_data(f, n); + } + Printf(f, "</blockquote>\n"); + } + + Printf(f, "<p><b>Nested scopes</b><br>\n"); + Printf(f, "<blockquote><pre>\n"); + { + Hash *h; + h = firstChild(sym); + while (h) { + Printf(f, "<a href=\"symbol.html?sym=%p\">%s</a>\n", h, Getattr(h, "name")); + h = nextSibling(h); + } + } + Printf(f, "</pre></blockquote>\n"); + + Printf(f, "<p><b>Symbol table contents</b></br>\n"); + raw_data(f, Getattr(sym, "symtab")); + Printf(f, "<br><hr></BODY></HTML>\n"); + +} +#endif + +void Swig_browser(Node *top, int port) { +#ifdef SWIG_SWILL + int sport; + browser_exit = 0; + + /* Initialize the server */ + sport = swill_init(port); + if (sport < 0) { + Printf(stderr, "Couldn't open socket on port %d. Sorry.\n", port); + return; + } + browse = new Browser(); + Setmeta(top, "visible", "1"); + tree_top = top; + + Printf(stderr, "SWIG: Tree browser listening on port %d\n", sport); + + swill_handle("exit.html", exit_handler, 0); + swill_handle("index.html", node_handler, 0); + swill_handle("hide.html", hide_handler, 0); + swill_handle("show.html", show_handler, 0); + swill_handle("data.html", data_handler, 0); + swill_handle("symbol.html", symbol_handler, 0); + swill_netscape("index.html"); + + while (!browser_exit) { + swill_serve(); + } + Printf(stderr, "Browser terminated.\n"); + swill_close(); + delete browse; + return; +#else + (void) top; + (void) port; +#endif +} diff --git a/contrib/tools/swig/Source/Modules/contract.cxx b/contrib/tools/swig/Source/Modules/contract.cxx new file mode 100644 index 00000000000..7e0eaf9e074 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/contract.cxx @@ -0,0 +1,358 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * contract.cxx + * + * Support for Wrap by Contract in SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +/* Contract structure. This holds rules about the different kinds of contract sections + and their combination rules */ + +struct contract { + const char *section; + const char *combiner; +}; +/* Contract rules. This table defines what contract sections are recognized as well as + how contracts are to combined via inheritance */ + +static contract Rules[] = { + {"require:", "&&"}, + {"ensure:", "||"}, + {NULL, NULL} +}; + +/* ---------------------------------------------------------------------------- + * class Contracts: + * + * This class defines the functions that need to be used in + * "wrap by contract" module. + * ------------------------------------------------------------------------- */ + +class Contracts:public Dispatcher { + String *make_expression(String *s, Node *n); + void substitute_parms(String *s, ParmList *p, int method); +public: + Hash *ContractSplit(Node *n); + int emit_contract(Node *n, int method); + int cDeclaration(Node *n); + int constructorDeclaration(Node *n); + int externDeclaration(Node *n); + int extendDirective(Node *n); + int importDirective(Node *n); + int includeDirective(Node *n); + int namespaceDeclaration(Node *n); + int classDeclaration(Node *n); + virtual int top(Node *n); +}; + +static int Contract_Mode = 0; /* contract option */ +static int InClass = 0; /* Parsing C++ or not */ +static int InConstructor = 0; +static Node *CurrentClass = 0; + +/* Set the contract mode, default is 0 (not open) */ +/* Normally set in main.cxx, when get the "-contracts" option */ +void Swig_contract_mode_set(int flag) { + Contract_Mode = flag; +} + +/* Get the contract mode */ +int Swig_contract_mode_get() { + return Contract_Mode; +} + +/* Apply contracts */ +void Swig_contracts(Node *n) { + + Contracts *a = new Contracts; + a->top(n); + delete a; +} + +/* Split the whole contract into preassertion, postassertion and others */ +Hash *Contracts::ContractSplit(Node *n) { + + String *contract = Getattr(n, "feature:contract"); + Hash *result; + if (!contract) + return NULL; + + result = NewHash(); + String *current_section = NewString(""); + const char *current_section_name = Rules[0].section; + List *l = SplitLines(contract); + + Iterator i; + for (i = First(l); i.item; i = Next(i)) { + int found = 0; + if (Strchr(i.item, '{')) + continue; + if (Strchr(i.item, '}')) + continue; + for (int j = 0; Rules[j].section; j++) { + if (Strstr(i.item, Rules[j].section)) { + if (Len(current_section)) { + Setattr(result, current_section_name, current_section); + current_section = Getattr(result, Rules[j].section); + if (!current_section) + current_section = NewString(""); + } + current_section_name = Rules[j].section; + found = 1; + break; + } + } + if (!found) + Append(current_section, i.item); + } + if (Len(current_section)) + Setattr(result, current_section_name, current_section); + return result; +} + +/* This function looks in base classes and collects contracts found */ +void inherit_contracts(Node *c, Node *n, Hash *contracts, Hash *messages) { + + Node *b, *temp; + String *name, *type, *local_decl, *base_decl; + List *bases; + int found = 0; + + bases = Getattr(c, "bases"); + if (!bases) + return; + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + local_decl = Getattr(n, "decl"); + if (local_decl) { + local_decl = SwigType_typedef_resolve_all(local_decl); + } else { + return; + } + /* Width first search */ + for (int i = 0; i < Len(bases); i++) { + b = Getitem(bases, i); + temp = firstChild(b); + while (temp) { + base_decl = Getattr(temp, "decl"); + if (base_decl) { + base_decl = SwigType_typedef_resolve_all(base_decl); + if ((checkAttribute(temp, "storage", "virtual")) && + (checkAttribute(temp, "name", name)) && (checkAttribute(temp, "type", type)) && (!Strcmp(local_decl, base_decl))) { + /* Yes, match found. */ + Hash *icontracts = Getattr(temp, "contract:rules"); + Hash *imessages = Getattr(temp, "contract:messages"); + found = 1; + if (icontracts && imessages) { + /* Add inherited contracts and messages to the contract rules above */ + int j = 0; + for (j = 0; Rules[j].section; j++) { + String *t = Getattr(contracts, Rules[j].section); + String *s = Getattr(icontracts, Rules[j].section); + if (s) { + if (t) { + Insert(t, 0, "("); + Printf(t, ") %s (%s)", Rules[j].combiner, s); + String *m = Getattr(messages, Rules[j].section); + Printf(m, " %s [%s from %s]", Rules[j].combiner, Getattr(imessages, Rules[j].section), Getattr(b, "name")); + } else { + Setattr(contracts, Rules[j].section, NewString(s)); + Setattr(messages, Rules[j].section, NewStringf("[%s from %s]", Getattr(imessages, Rules[j].section), Getattr(b, "name"))); + } + } + } + } + } + Delete(base_decl); + } + temp = nextSibling(temp); + } + } + Delete(local_decl); + if (!found) { + for (int j = 0; j < Len(bases); j++) { + b = Getitem(bases, j); + inherit_contracts(b, n, contracts, messages); + } + } +} + +/* This function cleans up the assertion string by removing some extraneous characters. + Splitting the assertion into pieces */ + +String *Contracts::make_expression(String *s, Node *n) { + String *str_assert, *expr = 0; + List *list_assert; + + str_assert = NewString(s); + /* Omit all useless characters and split by ; */ + Replaceall(str_assert, "\n", ""); + Replaceall(str_assert, "{", ""); + Replaceall(str_assert, "}", ""); + Replace(str_assert, " ", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE); + Replace(str_assert, "\t", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE); + + list_assert = Split(str_assert, ';', -1); + Delete(str_assert); + + /* build up new assertion */ + str_assert = NewString(""); + Iterator ei; + + for (ei = First(list_assert); ei.item; ei = Next(ei)) { + expr = ei.item; + if (Len(expr)) { + Replaceid(expr, Getattr(n, "name"), Swig_cresult_name()); + if (Len(str_assert)) + Append(str_assert, "&&"); + Printf(str_assert, "(%s)", expr); + } + } + Delete(list_assert); + return str_assert; +} + +/* This function substitutes parameter names for argument names in the + contract specification. Note: it is assumed that the wrapper code + uses arg1 for self and arg2..argn for arguments. */ + +void Contracts::substitute_parms(String *s, ParmList *p, int method) { + int argnum = 1; + char argname[32]; + + if (method) { + Replaceid(s, "$self", "arg1"); + argnum++; + } + while (p) { + sprintf(argname, "arg%d", argnum); + String *name = Getattr(p, "name"); + if (name) { + Replaceid(s, name, argname); + } + argnum++; + p = nextSibling(p); + } +} + +int Contracts::emit_contract(Node *n, int method) { + Hash *contracts; + Hash *messages; + String *c; + + ParmList *cparms; + + if (!Getattr(n, "feature:contract")) + return SWIG_ERROR; + + /* Get contract parameters */ + cparms = Getmeta(Getattr(n, "feature:contract"), "parms"); + + /* Split contract into preassert & postassert */ + contracts = ContractSplit(n); + if (!contracts) + return SWIG_ERROR; + + /* This messages hash is used to hold the error messages that will be displayed on + failed contract. */ + + messages = NewHash(); + + /* Take the different contract expressions and clean them up a bit */ + Iterator i; + for (i = First(contracts); i.item; i = Next(i)) { + String *e = make_expression(i.item, n); + substitute_parms(e, cparms, method); + Setattr(contracts, i.key, e); + + /* Make a string containing error messages */ + Setattr(messages, i.key, NewString(e)); + } + + /* If we're in a class. We need to inherit other assertions. */ + if (InClass) { + inherit_contracts(CurrentClass, n, contracts, messages); + } + + /* Save information */ + Setattr(n, "contract:rules", contracts); + Setattr(n, "contract:messages", messages); + + /* Okay. Generate the contract runtime code. */ + + if ((c = Getattr(contracts, "require:"))) { + Setattr(n, "contract:preassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: require: %s\");\n", c, Getattr(messages, "require:"))); + } + if ((c = Getattr(contracts, "ensure:"))) { + Setattr(n, "contract:postassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: ensure: %s\");\n", c, Getattr(messages, "ensure:"))); + } + return SWIG_OK; +} + +int Contracts::cDeclaration(Node *n) { + int ret = SWIG_OK; + String *decl = Getattr(n, "decl"); + + /* Not a function. Don't even bother with it (for now) */ + if (!SwigType_isfunction(decl)) + return SWIG_OK; + + if (Getattr(n, "feature:contract")) + ret = emit_contract(n, InClass && !Swig_storage_isstatic(n)); + return ret; +} + +int Contracts::constructorDeclaration(Node *n) { + int ret = SWIG_OK; + InConstructor = 1; + if (Getattr(n, "feature:contract")) + ret = emit_contract(n, 0); + InConstructor = 0; + return ret; +} + +int Contracts::externDeclaration(Node *n) { + return emit_children(n); +} + +int Contracts::extendDirective(Node *n) { + return emit_children(n); +} + +int Contracts::importDirective(Node *n) { + return emit_children(n); +} + +int Contracts::includeDirective(Node *n) { + return emit_children(n); +} + +int Contracts::namespaceDeclaration(Node *n) { + return emit_children(n); +} + +int Contracts::classDeclaration(Node *n) { + int ret = SWIG_OK; + int oldInClass = InClass; + Node *oldClass = CurrentClass; + InClass = 1; + CurrentClass = n; + emit_children(n); + InClass = oldInClass; + CurrentClass = oldClass; + return ret; +} + +int Contracts::top(Node *n) { + emit_children(n); + return SWIG_OK; +} diff --git a/contrib/tools/swig/Source/Modules/csharp.cxx b/contrib/tools/swig/Source/Modules/csharp.cxx new file mode 100644 index 00000000000..27cc65b3245 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/csharp.cxx @@ -0,0 +1,4598 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * csharp.cxx + * + * C# language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <limits.h> // for INT_MAX +#include "cparse.h" +#include <ctype.h> + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class CSHARP:public Language { + static const char *usage; + const String *empty_string; + const String *public_string; + const String *protected_string; + + Hash *swig_types_hash; + 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; + File *f_single_out; + List *filenames_list; + + bool proxy_flag; // Flag for generating proxy classes + bool native_function_flag; // Flag for when wrapping a native function + bool enum_constant_flag; // Flag for when wrapping an enum or constant + bool static_flag; // Flag for when wrapping a static functions or member variables + bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable + bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const + bool global_variable_flag; // Flag for when wrapping a global variable + bool old_variable_names; // Flag for old style variable names in the intermediary class + bool generate_property_declaration_flag; // Flag for generating properties + + String *imclass_name; // intermediary class name + String *module_class_name; // module class name + String *imclass_class_code; // intermediary class code + String *proxy_class_def; + String *proxy_class_code; + String *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration + String *module_class_code; + String *proxy_class_name; // proxy class name + String *full_imclass_name; // fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name + String *variable_name; //Name of a variable being wrapped + String *proxy_class_constants_code; + String *module_class_constants_code; + String *enum_code; + String *dllimport; // DllImport attribute name + String *namespce; // Optional namespace name + String *imclass_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *imclass_baseclass; //inheritance for intermediary class class from %pragma + String *module_baseclass; //inheritance for module class from %pragma + String *imclass_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *imclass_class_modifiers; //class modifiers for intermediary class overridden by %pragma + String *module_class_modifiers; //class modifiers for module class overridden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *imclass_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *director_callback_typedefs; // Director function pointer typedefs for callbacks + String *director_callbacks; // Director callback function pointer member variables + String *director_delegate_callback; // Director callback method that delegates are set to call + String *director_delegate_definitions; // Director delegates definitions in proxy class + String *director_delegate_instances; // Director delegates member variables in proxy class + String *director_method_types; // Director method types + String *director_connect_parms; // Director delegates parameter list for director connect call + String *destructor_call; //C++ destructor call if any + String *output_file; // File name for single file mode. If set all generated code will be written to this file + + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + int first_class_dmethod; + int curr_class_dmethod; + int nesting_depth; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + +public: + + /* ----------------------------------------------------------------------------- + * CSHARP() + * ----------------------------------------------------------------------------- */ + + CSHARP():empty_string(NewString("")), + public_string(NewString("public")), + protected_string(NewString("protected")), + swig_types_hash(NULL), + 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), + f_single_out(NULL), + filenames_list(NULL), + proxy_flag(true), + native_function_flag(false), + enum_constant_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + old_variable_names(false), + generate_property_declaration_flag(false), + imclass_name(NULL), + module_class_name(NULL), + imclass_class_code(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + interface_class_code(NULL), + module_class_code(NULL), + proxy_class_name(NULL), + full_imclass_name(NULL), + variable_name(NULL), + proxy_class_constants_code(NULL), + module_class_constants_code(NULL), + enum_code(NULL), + dllimport(NULL), + namespce(NULL), + imclass_imports(NULL), + module_imports(NULL), + imclass_baseclass(NULL), + module_baseclass(NULL), + imclass_interfaces(NULL), + module_interfaces(NULL), + imclass_class_modifiers(NULL), + module_class_modifiers(NULL), + upcasts_code(NULL), + imclass_cppcasts_code(NULL), + director_callback_typedefs(NULL), + director_callbacks(NULL), + director_delegate_callback(NULL), + director_delegate_definitions(NULL), + director_delegate_instances(NULL), + director_method_types(NULL), + director_connect_parms(NULL), + destructor_call(NULL), + output_file(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(0), + first_class_dmethod(0), + curr_class_dmethod(0), + nesting_depth(0){ + /* for now, multiple inheritance in directors is disabled, this + should be easy to implement though */ + director_multiple_inheritance = 0; + director_language = 1; + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class. + * Return NULL if not otherwise the proxy class name, fully qualified with + * a namespace if the nspace feature is used. + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + String *proxyname = NULL; + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + proxyname = Getattr(n, "proxyname"); + if (!proxyname) { + String *nspace = Getattr(n, "sym:nspace"); + String *symname = Copy(Getattr(n, "sym:name")); + if (symname && !GetFlag(n, "feature:flatnested")) { + for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + if (String* name = Getattr(outer_class, "sym:name")) { + Push(symname, "."); + Push(symname, name); + } + else + return NULL; + } + } + if (nspace) { + if (namespce) + proxyname = NewStringf("%s.%s.%s", namespce, nspace, symname); + else + proxyname = NewStringf("%s.%s", nspace, symname); + } else { + proxyname = Copy(symname); + } + Setattr(n, "proxyname", proxyname); + Delete(proxyname); + Delete(symname); + } + } + } + return proxyname; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("csharp"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-dllimport") == 0) { + if (argv[i + 1]) { + dllimport = NewString(""); + Printf(dllimport, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-namespace") == 0) { + if (argv[i + 1]) { + namespce = NewString(""); + Printf(namespce, argv[i + 1]); + if (Len(namespce) == 0) { + Delete(namespce); + namespce = 0; + } + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + Swig_mark_arg(i); + proxy_flag = false; + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } else if (strcmp(argv[i], "-outfile") == 0) { + if (argv[i + 1]) { + output_file = NewString(""); + Printf(output_file, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGCSHARP 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("csharp"); + SWIG_config_file("csharp.swg"); + + allow_overloading(); + Swig_interface_feature_enable(); + } + + /* --------------------------------------------------------------------- + * 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, "imclassname")) + imclass_name = Copy(Getattr(optionsnode, "imclassname")); + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + if (Getattr(optionsnode, "directors")) { + 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); + + swig_types_hash = NewHash(); + filenames_list = NewList(); + + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + if (!imclass_name) { + imclass_name = NewStringf("%sPINVOKE", Getattr(n, "name")); + module_class_name = Copy(Getattr(n, "name")); + } else { + // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution + if (Cmp(imclass_name, Getattr(n, "name")) == 0) + module_class_name = NewStringf("%sModule", Getattr(n, "name")); + else + module_class_name = Copy(Getattr(n, "name")); + } + + // module class and intermediary classes are always created + if (!addSymbol(imclass_name, n)) + return SWIG_ERROR; + if (!addSymbol(module_class_name, n)) + return SWIG_ERROR; + + imclass_class_code = NewString(""); + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + module_class_constants_code = NewString(""); + imclass_baseclass = NewString(""); + imclass_interfaces = NewString(""); + imclass_class_modifiers = NewString(""); + module_class_code = NewString(""); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + module_class_modifiers = NewString(""); + imclass_imports = NewString(""); + imclass_cppcasts_code = NewString(""); + director_connect_parms = NewString(""); + upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + if (!dllimport) + dllimport = Copy(module_class_name); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGCSHARP\n#define SWIGCSHARP\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", module_class_name); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_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"); + if (namespce) { + String *wrapper_name = NewStringf(""); + Printf(wrapper_name, "CSharp_%s_%%f", namespce); + Swig_name_register("wrapper", wrapper_name); + Delete(wrapper_name); + } + else { + Swig_name_register("wrapper", "CSharp_%f"); + } + + if (old_variable_names) { + Swig_name_register("set", "set_%n%v"); + Swig_name_register("get", "get_%n%v"); + } + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + /* Emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + // Generate the intermediary class + { + File *f_im = getOutputFile(SWIG_output_directory(), imclass_name); + + addOpenNamespace(0, f_im); + + if (imclass_imports) + Printf(f_im, "%s\n", imclass_imports); + + if (Len(imclass_class_modifiers) > 0) + Printf(f_im, "%s ", imclass_class_modifiers); + Printf(f_im, "%s ", imclass_name); + + if (imclass_baseclass && *Char(imclass_baseclass)) + Printf(f_im, ": %s ", imclass_baseclass); + if (Len(imclass_interfaces) > 0) + Printv(f_im, "implements ", imclass_interfaces, " ", NIL); + Printf(f_im, "{\n"); + + // Add the intermediary class methods + Replaceall(imclass_class_code, "$module", module_class_name); + Replaceall(imclass_class_code, "$imclassname", imclass_name); + Replaceall(imclass_class_code, "$dllimport", dllimport); + Printv(f_im, imclass_class_code, NIL); + Printv(f_im, imclass_cppcasts_code, NIL); + + // Finish off the class + Printf(f_im, "}\n"); + addCloseNamespace(0, f_im); + + if (f_im != f_single_out) + Delete(f_im); + f_im = NULL; + } + + // Generate the C# module class + { + File *f_module = getOutputFile(SWIG_output_directory(), module_class_name); + + addOpenNamespace(0, f_module); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + if (Len(module_class_modifiers) > 0) + Printf(f_module, "%s ", module_class_modifiers); + Printf(f_module, "%s ", module_class_name); + + if (module_baseclass && *Char(module_baseclass)) + Printf(f_module, ": %s ", module_baseclass); + if (Len(module_interfaces) > 0) + Printv(f_module, "implements ", module_interfaces, " ", NIL); + Printf(f_module, "{\n"); + + Replaceall(module_class_code, "$module", module_class_name); + Replaceall(module_class_constants_code, "$module", module_class_name); + + Replaceall(module_class_code, "$imclassname", imclass_name); + Replaceall(module_class_constants_code, "$imclassname", imclass_name); + + Replaceall(module_class_code, "$dllimport", dllimport); + Replaceall(module_class_constants_code, "$dllimport", dllimport); + + // Add the wrapper methods + Printv(f_module, module_class_code, NIL); + + // Write out all the global constants + Printv(f_module, module_class_constants_code, NIL); + + // Finish off the class + Printf(f_module, "}\n"); + addCloseNamespace(0, f_module); + + if (f_module != f_single_out) + Delete(f_module); + f_module = NULL; + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a C# type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + // 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(swig_types_hash); + swig_types_hash = NULL; + Delete(filenames_list); + filenames_list = NULL; + Delete(imclass_name); + imclass_name = NULL; + Delete(imclass_class_code); + imclass_class_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(module_class_constants_code); + module_class_constants_code = NULL; + Delete(imclass_baseclass); + imclass_baseclass = NULL; + Delete(imclass_interfaces); + imclass_interfaces = NULL; + Delete(imclass_class_modifiers); + imclass_class_modifiers = NULL; + Delete(module_class_name); + module_class_name = NULL; + Delete(module_class_code); + module_class_code = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(module_class_modifiers); + module_class_modifiers = NULL; + Delete(imclass_imports); + imclass_imports = NULL; + Delete(imclass_cppcasts_code); + imclass_cppcasts_code = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(dmethods_seq); + dmethods_seq = NULL; + Delete(dmethods_table); + dmethods_table = NULL; + Delete(namespce); + namespce = NULL; + n_dmethods = 0; + + /* Close all of the 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; + } + + if (f_single_out) { + Dump(f_single_out, f_begin); + Delete(f_single_out); + f_single_out = 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; + } + + /* ----------------------------------------------------------------------------- + * emitBanner() + * ----------------------------------------------------------------------------- */ + + void emitBanner(File *f) { + Printf(f, "//------------------------------------------------------------------------------\n"); + Printf(f, "// <auto-generated />\n"); + Printf(f, "//\n"); + Swig_banner_target_lang(f, "//"); + Printf(f, "//------------------------------------------------------------------------------\n\n"); + } + + /* ----------------------------------------------------------------------------- + * getOutputFile() + * + * Prepares a File object by creating the file in the file system and + * writing the banner for auto-generated files to it (emitBanner). + * If '-outfile' is provided (single file mode) the supplied parameters will + * be ignored and the returned file will always be: + * <outdir>/<outfile> + * Otherwise the file will be: + * <dir>/<name>.cs + * ----------------------------------------------------------------------------- */ + + File *getOutputFile(const String *dir, const String *name) { + if (output_file) { + if (!f_single_out) { + String *filen = NewStringf("%s%s", SWIG_output_directory(), output_file); + f_single_out = NewFile(filen, "w", SWIG_output_files()); + if (!f_single_out) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + emitBanner(f_single_out); + } + return f_single_out; + } else { + String *filen = NewStringf("%s%s.cs", dir, name); + File *f = NewFile(filen, "w", SWIG_output_files()); + if (!f) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + emitBanner(f); + return f; + } + } + + /*----------------------------------------------------------------------- + * Add new director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *decl, String *overloaded_name) { + 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)); + + Delete(key); + return new_udata; + } + + /*----------------------------------------------------------------------- + * Get director upcall signature + *----------------------------------------------------------------------*/ + + /* + UpcallData * getUpcallMethodData(String *director_class, String *decl) { + String *key = NewStringf("%s|%s", director_class, decl); + UpcallData *udata = Getattr(dmethods_table, key); + + Delete(key); + return udata; + } + */ + + /* ---------------------------------------------------------------------- + * nativeWrapper() + * ---------------------------------------------------------------------- */ + + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n, imclass_name)) + 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; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + 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(""); + String *im_outattributes = 0; + int num_arguments = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(symname, n, imclass_name)) + return SWIG_ERROR; + } + + /* + The rest of this function deals with generating the intermediary class wrapper function (that wraps + a c/c++ function) and generating the PInvoke c code. Each C# wrapper function has a + matching PInvoke c function call. + */ + + // 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 = Swig_typemap_lookup("ctype", n, "", 0))) { + String *ctypeout = Getattr(n, "tmap:ctype:out"); // the type in the ctype typemap's out attribute overrides the type in the typemap + if (ctypeout) + tm = ctypeout; + Printf(c_return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if ((tm = Swig_typemap_lookup("imtype", n, "", 0))) { + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + Printf(im_return_type, "%s", tm); + im_outattributes = Getattr(n, "tmap:imtype:outattributes"); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_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, " SWIGSTDCALL ", 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 C# + if (Getattr(n, "sym:overloaded")) { + // Emit warnings for the few cases that can't be overloaded in C# and give up on generating wrapper + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) { + DelWrapper(f); + return SWIG_OK; + } + } + + Printv(imclass_class_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); + + if (im_outattributes) + Printf(imclass_class_code, " %s\n", im_outattributes); + + Printf(imclass_class_code, " public static extern %s %s(", im_return_type, overloaded_name); + + + /* 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 = Getattr(p, "tmap:ctype"))) { + Printv(c_param_type, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_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 = Getattr(p, "tmap:imtype"))) { + const String *inattributes = Getattr(p, "tmap:imtype:inattributes"); + Printf(im_param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_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(imclass_class_code, ", "); + Printf(imclass_class_code, "%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, "$source", arg); /* deprecated */ + Replaceall(tm, "$target", ln); /* deprecated */ + Replaceall(tm, "$arg", arg); /* deprecated? */ + 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, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + 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, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + 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, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + 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, "$source", Swig_cresult_name()); /* deprecated */ + Replaceall(tm, "$target", "jresult"); /* deprecated */ + 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); + Replaceall(tm, "$source", Swig_cresult_name()); /* deprecated */ + 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); + Replaceall(tm, "$source", Swig_cresult_name()); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C function and intermediary class function definitions */ + Printf(imclass_class_code, ")"); + Printf(imclass_class_code, ";\n"); + + 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, "csharp: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 %csexception which sets the canthrow attribute + if (Getattr(n, "feature:except:canthrow")) + Setattr(n, "csharp:canthrow", "1"); + + // A very simple check (it is not foolproof) to help typemap/feature writers for + // throwing C# exceptions from unmanaged code. It checks for the common methods which + // set a pending C# exception... the 'canthrow' typemap/feature attribute must be set + // so that code which checks for pending exceptions is added in the C# proxy method. + if (!Getattr(n, "csharp:canthrow")) { + if (Strstr(f->code, "SWIG_exception")) { + Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, + "Unmanaged code contains a call to SWIG_exception and C# code does not handle pending exceptions via the canthrow attribute.\n"); + } else if (Strstr(f->code, "SWIG_CSharpSetPendingException")) { + Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, + "Unmanaged code contains a call to a SWIG_CSharpSetPendingException method and C# code does not handle pending exceptions via the canthrow attribute.\n"); + } + } + } + + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + moduleClassFunctionHandler(n); + } + + /* + * Generate the proxy class properties for public member variables. + * Not for enums and constants. + */ + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Capitalize the first letter in the variable in the getter/setter function name + bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) != 0; + + String *getter_setter_name = NewString(""); + if (!getter_flag) + Printf(getter_setter_name, "set"); + else + Printf(getter_setter_name, "get"); + Putc(toupper((int) *Char(variable_name)), getter_setter_name); + Printf(getter_setter_name, "%s", Char(variable_name) + 1); + + Setattr(n, "proxyfuncname", getter_setter_name); + Setattr(n, "imfuncname", symname); + + proxyClassFunctionHandler(n); + Delete(getter_setter_name); + } + + Delete(c_return_type); + Delete(im_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(overloaded_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + Language::variableWrapper(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * globalvariableHandler() + * ------------------------------------------------------------------------ */ + + virtual int globalvariableHandler(Node *n) { + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + generate_property_declaration_flag = false; + + if (proxy_flag) { + Printf(module_class_code, "\n }\n\n"); + } + + return ret; + } + + String *getCurrentScopeName(String *nspace) { + String *scope = 0; + if (nspace || getCurrentClass()) { + scope = NewString(""); + if (nspace) + Printf(scope, "%s", nspace); + if (Node *cls = getCurrentClass()) { + if (Node *outer = Getattr(cls, "nested:outer")) { + String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); + for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { + Push(outerClassesPrefix, "."); + Push(outerClassesPrefix, Getattr(outer, "sym:name")); + } + Printv(scope, nspace ? "." : "", outerClassesPrefix, ".", proxy_class_name, NIL); + Delete(outerClassesPrefix); + } else + Printv(scope, nspace ? "." : "", proxy_class_name, NIL); + } + } + return scope; + } + + /* ---------------------------------------------------------------------- + * enumDeclaration() + * + * C/C++ enums can be mapped in one of 4 ways, depending on the cs:enum feature specified: + * 1) Simple enums - simple constant within the proxy class or module class + * 2) Typeunsafe enums - simple constant in a C# class (class named after the c++ enum name) + * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) + * 4) Proper enums - proper C# enum + * Anonymous enums always default to 1) + * ---------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call + if (proxy_flag && !is_wrapping_class()) { + // Global enums / enums in a namespace + assert(!full_imclass_name); + + if (!nspace) { + full_imclass_name = NewStringf("%s", imclass_name); + } else { + if (namespce) { + full_imclass_name = NewStringf("%s.%s", namespce, imclass_name); + } else { + full_imclass_name = NewStringf("%s", imclass_name); + } + } + } + + enum_code = NewString(""); + String *symname = Getattr(n, "sym:name"); + String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; + EnumFeature enum_feature = decodeEnumFeature(n); + String *typemap_lookup_type = Getattr(n, "name"); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + + String *scope = getCurrentScopeName(nspace); + if (!addSymbol(symname, n, scope)) + return SWIG_ERROR; + + // Pure C# baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "csinterfaces", typemap_lookup_type, WARN_NONE); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(enum_code, "%s\n", csattributes); + + // Emit the enum + Printv(enum_code, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers (enum modifiers really) + " ", symname, (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {\n", NIL); + Delete(scope); + } else { + // Wrap C++ enum with integers - just indicate start of enum with a comment, no comment for anonymous enums of any sort + if (symname && !Getattr(n, "unnamedinstance")) + Printf(constants_code, " // %s \n", symname); + } + + // Emit each enum item + Language::enumDeclaration(n); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + // Finish the enum declaration + // Typemaps are used to generate the enum definition in a similar manner to proxy classes. + Printv(enum_code, (enum_feature == ProperEnum) ? "\n" : typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "}", NIL); + + Replaceall(enum_code, "$csclassname", symname); + + // Substitute $enumvalues - intended usage is for typesafe enums + if (Getattr(n, "enumvalues")) + Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); + else + Replaceall(enum_code, "$enumvalues", ""); + + if (proxy_flag && is_wrapping_class()) { + // Enums defined within the C++ class are defined within the proxy class + + // Add extra indentation + Replaceall(enum_code, "\n", "\n "); + Replaceall(enum_code, " \n", "\n"); + + Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL); + } else { + // Global enums are defined in their own file + String *output_directory = outputDirectory(nspace); + File *f_enum = getOutputFile(output_directory, symname); + + addOpenNamespace(nspace, f_enum); + + Printv(f_enum, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + addCloseNamespace(nspace, f_enum); + if (f_enum != f_single_out) + Delete(f_enum); + f_enum = NULL; + Delete(output_directory); + } + } else { + // Wrap C++ enum with simple constant + Printf(enum_code, "\n"); + if (proxy_flag && is_wrapping_class()) + Printv(proxy_class_constants_code, enum_code, NIL); + else + Printv(module_class_constants_code, enum_code, NIL); + } + + Delete(enum_code); + enum_code = NULL; + + if (proxy_flag && !is_wrapping_class()) { + Delete(full_imclass_name); + full_imclass_name = 0; + } + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + Node *parent = parentNode(n); + int unnamedinstance = GetFlag(parent, "unnamedinstance"); + String *parent_name = Getattr(parent, "name"); + String *nspace = getNSpace(); + String *newsymname = 0; + String *tmpValue; + + // Strange hack from parent method + 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("'%(hexescape)s'", Getattr(n, "enumvalue")); + Setattr(n, "enumvalue", val); + Delete(val); + } + + { + EnumFeature enum_feature = decodeEnumFeature(parent); + + if ((enum_feature == SimpleEnum) && GetFlag(parent, "scopedenum")) { + newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + symname = newsymname; + } + + // Add to language symbol table + String *scope = 0; + if (unnamedinstance || !parent_name || enum_feature == SimpleEnum) { + String *enumClassPrefix = getEnumClassPrefix(); + if (enumClassPrefix) { + scope = NewString(""); + if (nspace) + Printf(scope, "%s.", nspace); + Printf(scope, "%s", enumClassPrefix); + } else { + scope = Copy(module_class_name); + } + } else { + scope = getCurrentScopeName(nspace); + if (!scope) + scope = Copy(Getattr(parent, "sym:name")); + else + Printf(scope, ".%s", Getattr(parent, "sym:name")); + } + if (!addSymbol(symname, n, scope)) + return SWIG_ERROR; + + const String *csattributes = Getattr(n, "feature:cs:attributes"); + + if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) { + // Wrap (non-anonymous) C/C++ enum with a proper C# enum + // Emit the enum item. + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + + if (csattributes) + Printf(enum_code, " %s\n", csattributes); + + Printf(enum_code, " %s", symname); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + // Note that the enum value must be a true constant and cannot be set from a PINVOKE call, thus no support for %csconst(0) + value = value ? value : Getattr(n, "enumvalue"); + if (value) { + Printf(enum_code, " = %s", value); + } + } else { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); + Setattr(n, "type", typemap_lookup_type); + const String *tm = typemapLookup(n, "cstype", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF); + + String *return_type = Copy(tm); + substituteClassname(typemap_lookup_type, return_type); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if (csattributes) + Printf(enum_code, " %s\n", csattributes); + + if ((enum_feature == TypesafeEnum) && parent_name && !unnamedinstance) { + // Wrap (non-anonymous) enum using the typesafe enum pattern + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, " %s static readonly %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); + Delete(value); + } else { + Printf(enum_code, " %s static readonly %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); + } + } else { + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + const char *const_readonly = const_feature_flag ? "const" : "static readonly"; + String *value = enumValue(n); + Printf(enum_code, " %s %s %s %s = %s;\n", methodmods, const_readonly, return_type, symname, value); + Delete(value); + } + Delete(return_type); + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parent, "enumvalues"); + if (!enumvalues) + Setattr(parent, "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + Delete(scope); + } + + Delete(newsymname); + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * Used for wrapping constants - #define or %constant. + * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). + * C# static const variables are generated for these. + * If the %csconst(1) feature is used then the C constant value is used to initialise the C# const variable. + * If not, a PINVOKE method is generated to get the C constant value for initialisation of the C# const variable. + * However, if the %csconstvalue feature is used, it overrides all other ways to generate the initialisation. + * Also note that this method might be called for wrapping enum items (when the enum is using %csconst(0)). + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + SwigType *valuetype = Getattr(n, "valuetype"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + Swig_save("constantWrapper", n, "value", NIL); + Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:cstype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:cstype:outattributes", NIL); + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + if (!is_enum_item) { + String *scope = 0; + if (proxy_class_name) { + String *nspace = getNSpace(); + scope = NewString(""); + if (nspace) + Printf(scope, "%s.", nspace); + Printf(scope, "%s", proxy_class_name); + } else { + scope = Copy(module_class_name); + } + if (!addSymbol(itemname, n, scope)) + return SWIG_ERROR; + Delete(scope); + } + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + /* Adjust the enum type for the Swig_typemap_lookup. + * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ + if (is_enum_item) { + t = Getattr(parentNode(n), "enumtype"); + Setattr(n, "type", t); + } + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("cstype", l, NULL); + + /* Get C# return types */ + bool classname_substituted_flag = false; + + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + classname_substituted_flag = substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + // Default (octal) escaping is no good - change to hex escaped value + String *hexescaped_value = Getattr(n, "rawvalue") ? NewStringf("%(hexescape)s", Getattr(n, "rawvalue")) : 0; + // Add the stripped quotes back in + String *new_value = NewString(""); + if (SwigType_type(t) == T_STRING) { + Printf(new_value, "\"%s\"", hexescaped_value ? hexescaped_value : Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } else if (SwigType_type(t) == T_CHAR) { + Printf(new_value, "\'%s\'", hexescaped_value ? hexescaped_value : Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } + + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(constants_code, " %s\n", outattributes); + + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + Printf(constants_code, " %s %s %s %s = ", methodmods, (const_feature_flag ? "const" : "static readonly"), return_type, itemname); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + if (value) { + Printf(constants_code, "%s;\n", value); + } else if (!const_feature_flag) { + // Default enum and constant handling will work with any type of C constant and initialises the C# variable from C through a PINVOKE call. + + if (classname_substituted_flag) { + if (SwigType_isenum(t)) { + // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) + Printf(constants_code, "(%s)%s.%s();\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } + } else { + Printf(constants_code, "%s.%s();\n", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } + + // Each constant and enum value is wrapped with a separate PInvoke function call + SetFlag(n, "feature:immutable"); + enum_constant_flag = true; + variableWrapper(n); + enum_constant_flag = false; + } else { + // Alternative constant handling will use the C syntax to make a true C# constant and hope that it compiles as C# code + if (Getattr(n, "wrappedasconstant")) { + if (SwigType_type(t) == T_CHAR) { + if (SwigType_type(valuetype) == T_CHAR) + Printf(constants_code, "\'%(hexescape)s\';\n", Getattr(n, "staticmembervariableHandler:value")); + else + Printf(constants_code, "(char)%s;\n", Getattr(n, "staticmembervariableHandler:value")); + } else { + 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 + // Enums only emit the intermediate and PINVOKE methods, so no proxy or module class wrapper methods needed + if (!is_enum_item) { + if (proxy_flag && wrapping_member_flag) + Printv(proxy_class_constants_code, constants_code, NIL); + else + Printv(module_class_constants_code, constants_code, NIL); + } + // Cleanup + Swig_restore(n); + Delete(new_value); + Delete(return_type); + Delete(constants_code); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * insertDirective() + * ----------------------------------------------------------------------------- */ + + virtual int insertDirective(Node *n) { + int ret = SWIG_OK; + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + Replaceall(code, "$dllimport", dllimport); + + if (!ImportMode && (Cmp(section, "proxycode") == 0)) { + if (proxy_class_code) { + Swig_typemap_replace_embedded_typemap(code, n); + int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0; + Printv(proxy_class_code, Char(code) + offset, "\n", NIL); + } + } else { + ret = Language::insertDirective(n); + } + return ret; + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * imclassbase - base (extends) for the intermediary class + * imclassclassmodifiers - class modifiers for the intermediary class + * imclasscode - text (C# code) is copied verbatim to the intermediary class + * imclassimports - import statements for the intermediary class + * imclassinterfaces - interface (implements) for the intermediary class + * + * modulebase - base (extends) for the module class + * moduleclassmodifiers - class modifiers for the module class + * modulecode - text (C# code) is copied verbatim to the module class + * moduleimports - import statements for the module class + * moduleinterfaces - interface (implements) for the module class + * + * ----------------------------------------------------------------------------- */ + + 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, "csharp") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); + + if (Strcmp(code, "imclassbase") == 0) { + Delete(imclass_baseclass); + imclass_baseclass = Copy(strvalue); + } else if (Strcmp(code, "imclassclassmodifiers") == 0) { + Delete(imclass_class_modifiers); + imclass_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "imclasscode") == 0) { + Printf(imclass_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "imclassimports") == 0) { + Delete(imclass_imports); + imclass_imports = Copy(strvalue); + } else if (Strcmp(code, "imclassinterfaces") == 0) { + Delete(imclass_interfaces); + imclass_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(module_class_modifiers); + module_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(module_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "moduleimports") == 0) { + Delete(module_imports); + module_imports = Copy(strvalue); + } else if (Strcmp(code, "moduleinterfaces") == 0) { + Delete(module_interfaces); + module_interfaces = Copy(strvalue); + } else { + Swig_error(input_file, line_number, "Unrecognized pragma.\n"); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * getQualifiedInterfaceName() + * ----------------------------------------------------------------------------- */ + + String *getQualifiedInterfaceName(Node *n) { + String *ret = Getattr(n, "interface:qname"); + if (!ret) { + String *nspace = Getattr(n, "sym:nspace"); + String *interface_name = Getattr(n, "interface:name"); + if (nspace) { + if (namespce) + ret = NewStringf("%s.%s.%s", namespce, nspace, interface_name); + else + ret = NewStringf("%s.%s", nspace, interface_name); + } else { + ret = Copy(interface_name); + } + Setattr(n, "interface:qname", ret); + } + return ret; + } + + /* ----------------------------------------------------------------------------- + * getInterfaceName() + * ----------------------------------------------------------------------------- */ + + String *getInterfaceName(SwigType *t, bool qualified) { + String *interface_name = NULL; + if (proxy_flag) { + Node *n = classLookup(t); + if (n && Getattr(n, "interface:name")) + interface_name = qualified ? getQualifiedInterfaceName(n) : Getattr(n, "interface:name"); + } + return interface_name; + } + + /* ----------------------------------------------------------------------------- + * addInterfaceNameAndUpcasts() + * ----------------------------------------------------------------------------- */ + + void addInterfaceNameAndUpcasts(SwigType *smart, String *interface_list, String *interface_upcasts, Hash *base_list, SwigType *c_classname) { + List *keys = Keys(base_list); + for (Iterator it = First(keys); it.item; it = Next(it)) { + Node *base = Getattr(base_list, it.item); + SwigType *c_baseclassname = Getattr(base, "name"); + String *interface_name = Getattr(base, "interface:name"); + if (Len(interface_list)) + Append(interface_list, ", "); + Append(interface_list, interface_name); + + Node *attributes = NewHash(); + String *interface_code = Copy(typemapLookup(base, "csinterfacecode", Getattr(base, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACECODE_UNDEF, attributes)); + String *cptr_method_name = 0; + if (interface_code) { + Replaceall(interface_code, "$interfacename", interface_name); + Printv(interface_upcasts, interface_code, NIL); + cptr_method_name = Copy(Getattr(attributes, "tmap:csinterfacecode:cptrmethod")); + } + if (!cptr_method_name) + cptr_method_name = NewStringf("%s_GetInterfaceCPtr", interface_name); + Replaceall(cptr_method_name, ".", "_"); + Replaceall(cptr_method_name, "$interfacename", interface_name); + + String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), cptr_method_name); + upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); + + Delete(upcast_method_name); + Delete(cptr_method_name); + Delete(interface_code); + } + Delete(keys); + } + + /* ----------------------------------------------------------------------------- + * upcastsCode() + * + * Add code for C++ casting to base class + * ----------------------------------------------------------------------------- */ + + void upcastsCode(SwigType *smart, String *upcast_method_name, SwigType *c_classname, SwigType *c_baseclassname) { + String *wname = Swig_name_wrapper(upcast_method_name); + + Printv(imclass_cppcasts_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); + Printf(imclass_cppcasts_code, " public static extern global::System.IntPtr %s(global::System.IntPtr jarg1);\n", upcast_method_name); + + Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name); + + String *classname = SwigType_namestr(c_classname); + String *baseclassname = SwigType_namestr(c_baseclassname); + if (smart) { + String *smartnamestr = SwigType_namestr(smart); + String *bsmartnamestr = SwigType_namestr(smart); + + // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates + SwigType *rclassname = SwigType_typedef_resolve_all(classname); + SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname); + Replaceall(bsmartnamestr, rclassname, rbaseclassname); + + Printv(upcasts_code, + "SWIGEXPORT ", bsmartnamestr, " * SWIGSTDCALL ", wname, "(", smartnamestr, " *jarg1) {\n", + " return jarg1 ? new ", bsmartnamestr, "(*jarg1) : 0;\n" + "}\n", "\n", NIL); + + Delete(rbaseclassname); + Delete(rclassname); + Delete(bsmartnamestr); + Delete(smartnamestr); + } else { + Printv(upcasts_code, + "SWIGEXPORT ", baseclassname, " * SWIGSTDCALL ", wname, "(", classname, " *jarg1) {\n", + " return (", baseclassname, " *)jarg1;\n" + "}\n", "\n", NIL); + } + + Delete(baseclassname); + Delete(classname); + Delete(wname); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + SwigType *c_classname = Getattr(n, "name"); + SwigType *c_baseclassname = NULL; + String *baseclass = NULL; + String *interface_list = NewStringEmpty(); + String *interface_upcasts = NewStringEmpty(); + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); + SwigType *smart = Swig_cparse_smartptr(n); + + // Inheritance from pure C# classes + Node *attributes = NewHash(); + const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE, attributes); + bool purebase_replace = GetFlag(attributes, "tmap:csbase:replace") ? true : false; + bool purebase_notderived = GetFlag(attributes, "tmap:csbase: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") || Getattr(base.item, "feature:interface"))) { + SwigType *baseclassname = Getattr(base.item, "name"); + if (!c_baseclassname) { + String *name = getProxyName(baseclassname); + if (name) { + c_baseclassname = baseclassname; + baseclass = name; + } + } else { + /* Warn about multiple inheritance for additional base class(es) */ + String *proxyclassname = Getattr(n, "classtypeobj"); + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s, base %s ignored. Multiple inheritance is not supported in C#.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname)); + } + } + base = Next(base); + } + } + } + Hash *interface_bases = Getattr(n, "interface:bases"); + if (interface_bases) + addInterfaceNameAndUpcasts(smart, interface_list, interface_upcasts, interface_bases, c_classname); + + bool derived = baseclass != 0; + 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; + baseclass = NULL; + if (purebase_notderived) + Swig_error(Getfile(n), Getline(n), "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s, base %s ignored. Multiple inheritance is not supported in C#. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure C# interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE); + if (*Char(interface_list) && *Char(pure_interfaces)) + Append(interface_list, ", "); + Append(interface_list, pure_interfaces); + // Start writing the proxy class + if (!has_outerclass) + Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", NIL); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(proxy_class_def, "%s\n", csattributes); + + Printv(proxy_class_def, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $csclassname", // Class name and base class + (*Char(wanted_base) || *Char(interface_list)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(interface_list)) ? // Interfaces + ", " : "", interface_list, " {", derived ? typemapLookup(n, "csbody_derived", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF) : // main body of class + typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + NIL); + + // C++ destructor is wrapped by the Finalize and Dispose methods + + const char *tmap_method = derived ? "csdestruct_derived" : "csdestruct"; + const String *tm = typemapExists(n, tmap_method, typemap_lookup_type); + if (tm) { + Swig_error(Getfile(tm), Getline(tm), + "A deprecated %s typemap was found for %s, please remove it and replace all csdestruct, csdestruct_derived and csfinalize typemaps by the csdispose, csdispose_derived, csdisposing and csdisposing_derived typemaps.\n", + tmap_method, proxy_class_name); + } + tmap_method = "csfinalize"; + tm = typemapExists(n, tmap_method, typemap_lookup_type); + if (tm) { + Swig_error(Getfile(tm), Getline(tm), + "A deprecated %s typemap was found for %s, please remove it and replace all csdestruct, csdestruct_derived and csfinalize typemaps by the csdispose, csdispose_derived, csdisposing and csdisposing_derived typemaps.\n", + tmap_method, proxy_class_name); + } + + tmap_method = derived ? "csdisposing_derived" : "csdisposing"; + String *destruct = NewString(""); + attributes = NewHash(); + const String *destruct_methodname = NULL; + const String *destruct_methodmodifiers = NULL; + const String *destruct_parameters = NULL; + if (derived) { + tm = typemapLookup(n, "csdisposing_derived", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdisposing_derived:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdisposing_derived:methodmodifiers"); + destruct_parameters = Getattr(attributes, "tmap:csdisposing_derived:parameters"); + } else { + tm = typemapLookup(n, "csdisposing", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdisposing:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdisposing:methodmodifiers"); + destruct_parameters = Getattr(attributes, "tmap:csdisposing:parameters"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in %s typemap for %s\n", tmap_method, proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(Getfile(n), Getline(n), + "No methodmodifiers attribute defined in %s typemap for %s.\n", tmap_method, proxy_class_name); + } + if (!destruct_parameters) + destruct_parameters = empty_string; + } + // Emit the Finalize and Dispose methods + if (tm) { + // Finalize and Dispose methods + Printv(proxy_class_def, typemapLookup(n, derived ? "csdispose_derived" : "csdispose", typemap_lookup_type, WARN_NONE), NIL); + // Dispose(bool disposing) method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$imcall", destructor_call); + else + Replaceall(destruct, "$imcall", "throw new global::System.MethodAccessException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) { + Printv(proxy_class_def, "\n ", NIL); + const String *methodmods = Getattr(n, "destructmethodmodifiers"); + if (methodmods) + Printv(proxy_class_def, methodmods, NIL); + else + Printv(proxy_class_def, destruct_methodmodifiers, " ", derived ? "override" : "virtual", NIL); + Printv(proxy_class_def, " void ", destruct_methodname, "(", destruct_parameters, ") ", destruct, "\n", NIL); + } + } + if (*Char(interface_upcasts)) + Printv(proxy_class_def, interface_upcasts, NIL); + + if (feature_director) { + // Generate director connect method + // put this in classDirectorEnd ??? + Printf(proxy_class_code, " private 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 *methid = Getattr(udata, "class_methodidx"); + String *overname = Getattr(udata, "overname"); + Printf(proxy_class_code, " if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s))\n", method, methid); + Printf(proxy_class_code, " swigDelegate%s = new SwigDelegate%s_%s(SwigDirectorMethod%s);\n", methid, proxy_class_name, methid, overname); + } + String *director_connect_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); + Printf(proxy_class_code, " %s.%s(swigCPtr", imclass_name, director_connect_method_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_code, ", swigDelegate%s", methid); + } + Printf(proxy_class_code, ");\n"); + Printf(proxy_class_code, " }\n"); + + if (first_class_dmethod < curr_class_dmethod) { + // Only emit if there is at least one director method + Printf(proxy_class_code, "\n"); + Printf(proxy_class_code, " private bool SwigDerivedClassHasMethod(string methodName, global::System.Type[] methodTypes) {\n"); + Printf(proxy_class_code, + " global::System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, methodTypes, null);\n"); + Printf(proxy_class_code, " bool hasDerivedMethod = methodInfo.DeclaringType.IsSubclassOf(typeof(%s));\n", proxy_class_name); + /* Could add this code to cover corner case where the GetMethod() returns a method which allows type + * promotion, eg it will return foo(double), if looking for foo(int). + if (hasDerivedMethod) { + hasDerivedMethod = false; + if (methodInfo != null) + { + hasDerivedMethod = true; + ParameterInfo[] parameterArray1 = methodInfo.GetParameters(); + for (int i=0; i<methodTypes.Length; i++) + { + if (parameterArray1[0].ParameterType != methodTypes[0]) + { + hasDerivedMethod = false; + break; + } + } + } + } + */ + Printf(proxy_class_code, " return hasDerivedMethod;\n"); + Printf(proxy_class_code, " }\n"); + } + + if (Len(director_delegate_callback) > 0) + Printv(proxy_class_code, director_delegate_callback, NIL); + if (Len(director_delegate_definitions) > 0) + Printv(proxy_class_code, "\n", director_delegate_definitions, NIL); + if (Len(director_delegate_instances) > 0) + Printv(proxy_class_code, "\n", director_delegate_instances, NIL); + if (Len(director_method_types) > 0) + Printv(proxy_class_code, "\n", director_method_types, NIL); + + Delete(director_callback_typedefs); + director_callback_typedefs = NULL; + Delete(director_callbacks); + director_callbacks = NULL; + Delete(director_delegate_callback); + director_delegate_callback = NULL; + Delete(director_delegate_definitions); + director_delegate_definitions = NULL; + Delete(director_delegate_instances); + director_delegate_instances = NULL; + Delete(director_method_types); + director_method_types = NULL; + Delete(director_connect_parms); + director_connect_parms = NULL; + Delete(director_connect_method_name); + } + + Delete(interface_upcasts); + Delete(interface_list); + Delete(attributes); + Delete(destruct); + + // Emit extra user code + Printv(proxy_class_def, typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "\n", NIL); + + if (derived) { + String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), smart != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); + upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); + Delete(upcast_method_name); + } + + Delete(smart); + } + + /* ---------------------------------------------------------------------- + * emitInterfaceDeclaration() + * ---------------------------------------------------------------------- */ + + void emitInterfaceDeclaration(Node *n, String *interface_name, File *f_interface) { + Printv(f_interface, typemapLookup(n, "csimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL); + Printf(f_interface, "public interface %s", interface_name); + if (List *baselist = Getattr(n, "bases")) { + String *bases = 0; + for (Iterator base = First(baselist); base.item; base = Next(base)) { + if (GetFlag(base.item, "feature:ignore") || !Getattr(base.item, "feature:interface")) + continue; // TODO: warn about skipped non-interface bases + String *base_iname = Getattr(base.item, "interface:name"); + if (!bases) + bases = NewStringf(" : %s", base_iname); + else { + Append(bases, ", "); + Append(bases, base_iname); + } + } + if (bases) { + Printv(f_interface, bases, NIL); + Delete(bases); + } + } + Printf(f_interface, " {\n"); + + Node *attributes = NewHash(); + String *interface_code = Copy(typemapLookup(n, "csinterfacecode", Getattr(n, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACECODE_UNDEF, attributes)); + if (interface_code) { + String *interface_declaration = Copy(Getattr(attributes, "tmap:csinterfacecode:declaration")); + if (interface_declaration) { + Replaceall(interface_declaration, "$interfacename", interface_name); + Printv(f_interface, interface_declaration, NIL); + Delete(interface_declaration); + } + Delete(interface_code); + } + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + String *nspace = getNSpace(); + File *f_proxy = NULL; + File *f_interface = NULL; + // save class local variables + String *old_proxy_class_name = proxy_class_name; + String *old_full_imclass_name = full_imclass_name; + String *old_destructor_call = destructor_call; + String *old_proxy_class_constants_code = proxy_class_constants_code; + String *old_proxy_class_def = proxy_class_def; + String *old_proxy_class_code = proxy_class_code; + bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested"); + String *old_interface_class_code = interface_class_code; + interface_class_code = 0; + + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + String *interface_name = Getattr(n, "feature:interface") ? Getattr(n, "interface:name") : 0; + if (Node *outer = Getattr(n, "nested:outer")) { + String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); + for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { + Push(outerClassesPrefix, "."); + Push(outerClassesPrefix, Getattr(outer, "sym:name")); + } + String *fnspace = nspace ? NewStringf("%s.%s", nspace, outerClassesPrefix) : outerClassesPrefix; + if (!addSymbol(proxy_class_name, n, fnspace)) + return SWIG_ERROR; + if (interface_name && !addInterfaceSymbol(interface_name, n, fnspace)) + return SWIG_ERROR; + if (nspace) + Delete(fnspace); + Delete(outerClassesPrefix); + } else { + if (!addSymbol(proxy_class_name, n, nspace)) + return SWIG_ERROR; + if (interface_name && !addInterfaceSymbol(interface_name, n, nspace)) + return SWIG_ERROR; + } + + if (!nspace) { + full_imclass_name = NewStringf("%s", imclass_name); + if (Cmp(proxy_class_name, imclass_name) == 0) { + Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + if (Cmp(proxy_class_name, module_class_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + } else { + if (namespce) { + full_imclass_name = NewStringf("%s.%s", namespce, imclass_name); + } else { + full_imclass_name = NewStringf("%s", imclass_name); + } + } + + if (!has_outerclass) { + String *output_directory = outputDirectory(nspace); + f_proxy = getOutputFile(output_directory, proxy_class_name); + + addOpenNamespace(nspace, f_proxy); + Delete(output_directory); + } + else + ++nesting_depth; + + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + destructor_call = NewString(""); + proxy_class_constants_code = NewString(""); + + if (Getattr(n, "feature:interface")) { + interface_class_code = NewString(""); + String *output_directory = outputDirectory(nspace); + f_interface = getOutputFile(output_directory, interface_name); + addOpenNamespace(nspace, f_interface); + emitInterfaceDeclaration(n, interface_name, interface_class_code); + Delete(output_directory); + } + } + + Language::classHandler(n); + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + String *csclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name + + Replaceall(proxy_class_def, "$csclassname", proxy_class_name); + Replaceall(proxy_class_code, "$csclassname", proxy_class_name); + Replaceall(proxy_class_constants_code, "$csclassname", proxy_class_name); + Replaceall(interface_class_code, "$csclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$csclazzname", csclazzname); + Replaceall(proxy_class_code, "$csclazzname", csclazzname); + Replaceall(proxy_class_constants_code, "$csclazzname", csclazzname); + Replaceall(interface_class_code, "$csclazzname", csclazzname); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + Replaceall(proxy_class_constants_code, "$module", module_class_name); + Replaceall(interface_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", full_imclass_name); + Replaceall(proxy_class_code, "$imclassname", full_imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name); + Replaceall(interface_class_code, "$imclassname", full_imclass_name); + + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + Replaceall(proxy_class_constants_code, "$dllimport", dllimport); + Replaceall(interface_class_code, "$dllimport", dllimport); + + if (!has_outerclass) + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + else { + Swig_offset_string(proxy_class_def, nesting_depth); + Append(old_proxy_class_code, proxy_class_def); + Swig_offset_string(proxy_class_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_code); + } + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) { + if (!has_outerclass) + Printv(f_proxy, proxy_class_constants_code, NIL); + else { + Swig_offset_string(proxy_class_constants_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_constants_code); + } + } + if (!has_outerclass) { + Printf(f_proxy, "}\n"); + addCloseNamespace(nspace, f_proxy); + if (f_proxy != f_single_out) + Delete(f_proxy); + f_proxy = NULL; + } else { + for (int i = 0; i < nesting_depth; ++i) + Append(old_proxy_class_code, " "); + Append(old_proxy_class_code, "}\n\n"); + --nesting_depth; + } + + if (f_interface) { + Printv(f_interface, interface_class_code, "}\n", NIL); + addCloseNamespace(nspace, f_interface); + if (f_interface != f_single_out) + Delete(f_interface); + f_interface = 0; + } + + emitDirectorExtraMethods(n); + + Delete(interface_class_code); + interface_class_code = old_interface_class_code; + Delete(csclazzname); + Delete(proxy_class_name); + proxy_class_name = old_proxy_class_name; + Delete(full_imclass_name); + full_imclass_name = old_full_imclass_name; + Delete(destructor_call); + destructor_call = old_destructor_call; + Delete(proxy_class_constants_code); + proxy_class_constants_code = old_proxy_class_constants_code; + Delete(proxy_class_def); + proxy_class_def = old_proxy_class_def; + Delete(proxy_class_code); + proxy_class_code = old_proxy_class_code; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + Language::memberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + + return SWIG_OK; + } + + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a C# wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to C# static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the C# class proxy function, which in turn will call "imfuncname" - + * the intermediary (PInvoke) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + Parm *last_parm = 0; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + bool is_interface = Getattr(parentNode(n), "feature:interface") != 0 + && !static_flag && Getattr(n, "interface:owner") == 0; + + if (!proxy_flag) + return; + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in directors + if (GetFlag(n, "explicitcall")) + return; + + 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("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type + SwigType *covariant = Getattr(n, "covariant"); + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(covariant ? covariant : t, tm); + Printf(return_type, "%s", tm); + if (covariant) + Swig_warning(WARN_CSHARP_COVARIANT_RET, input_file, line_number, + "Covariant return types not supported in C#. Proxy method will return %s.\n", SwigType_str(covariant, 0)); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // Properties + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0); + if (setter_flag) + Swig_typemap_attach_parms("csvarin", l, NULL); + } + + /* Start generating the proxy function */ + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(function_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (methodmods) { + if (is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. + String *mmods = Copy(methodmods); + Replaceall(mmods, "override", ""); + Replaceall(mmods, "virtual", ""); + Replaceall(mmods, "new", ""); + Chop(mmods); // remove trailing whitespace + Printf(function_code, " %s ", mmods); + Delete(mmods); + } else { + Printf(function_code, " %s ", methodmods); + } + } else { + methodmods = (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s ", methodmods); + if (!is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. + if (Getattr(n, "override")) + Printf(function_code, "override "); + else if (checkAttribute(n, "storage", "virtual")) + Printf(function_code, "virtual "); + if (Getattr(n, "hides")) + Printf(function_code, "new "); + } + } + if (static_flag) + Printf(function_code, "static "); + Printf(function_code, "%s %s(", return_type, proxy_function_name); + if (is_interface) + Printf(interface_class_code, " %s %s(", return_type, proxy_function_name); + + + Printv(imcall, full_imclass_name, ".$imfuncname(", NIL); + if (!static_flag) + Printf(imcall, "swigCPtr"); + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0)) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + if (setter_flag) + last_parm = p; + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, setter_flag); + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) { + Printf(function_code, ", "); + if (is_interface) + Printf(interface_class_code, ", "); + } + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + if (is_interface) + Printf(interface_class_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + if (is_interface) + Printf(interface_class_code, ");\n"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class) + if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { + excodeSubstitute(n, tm, "csout", 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) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + 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"); + substituteClassname(t, tm); + + // For director methods: generate code to selectively make a normal polymorphic call or + // an explicit method call - needed to prevent infinite recursion calls in director methods. + Node *explicit_n = Getattr(n, "explicitcallnode"); + if (explicit_n) { + String *ex_overloaded_name = getOverloadedName(explicit_n); + String *ex_intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), ex_overloaded_name); + + String *ex_imcall = Copy(imcall); + Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); + Replaceall(imcall, "$imfuncname", intermediary_function_name); + String *excode = NewString(""); + Node *directorNode = Getattr(n, "directorNode"); + if (directorNode) { + UpcallData *udata = Getattr(directorNode, "upcalldata"); + String *methid = Getattr(udata, "class_methodidx"); + + if (!Cmp(return_type, "void")) + Printf(excode, "if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s)) %s; else %s", proxy_function_name, methid, ex_imcall, imcall); + else + Printf(excode, "(SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s) ? %s : %s)", proxy_function_name, methid, ex_imcall, imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + } else { + // probably an ignored method or nodirector + } + Delete(excode); + Delete(ex_overloaded_name); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // Properties + if (generate_property_declaration_flag) { // Ensure the declaration is generated just once should the property contain both a set and get + // Get the C# variable type - obtained differently depending on whether a setter is required. + String *variable_type = return_type; + if (setter_flag) { + assert(last_parm); // (last parameter is the only parameter for properties) + /* Get variable type - ensure the variable name is fully resolved during typemap lookup via the symbol table set in NewParmNode */ + SwigType *cvariable_type = Getattr(last_parm, "type"); + Parm *variable_parm = NewParmNode(cvariable_type, n); + if ((tm = Swig_typemap_lookup("cstype", variable_parm, "", 0))) { + String *cstypeout = Getattr(variable_parm, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(cvariable_type, tm); + variable_type = tm; + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(cvariable_type, 0)); + } + } + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(proxy_class_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (!methodmods) + methodmods = (is_public(n) ? public_string : protected_string); + Printf(proxy_class_code, " %s %s%s %s {", methodmods, static_flag ? "static " : "", variable_type, variable_name); + } + generate_property_declaration_flag = false; + + if (setter_flag) { + // Setter method + assert(last_parm); // (last parameter is the only parameter for properties) + SwigType *cvariable_type = Getattr(last_parm, "type"); + Parm *variable_parm = NewParmNode(cvariable_type, n); + if ((tm = Swig_typemap_lookup("csvarin", variable_parm, "", 0))) { + substituteClassname(cvariable_type, tm); + Replaceall(tm, "$csinput", "value"); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", variable_parm); + Printf(proxy_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(cvariable_type, 0)); + } + } else { + // Getter method + if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarout", n); + Printf(proxy_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); + } + } + } else { + // Normal function call + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(proxy_class_code, function_code, NIL); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *function_code = NewString(""); + String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the csin typemap has code in the pre or post attributes + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + String *im_return_type = NewString(""); + bool feature_director = (parentNode(n) && Swig_directorclass(n)); + + Language::constructorHandler(n); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name); + String *imcall = NewString(""); + + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) { + Printf(function_code, " %s\n", csattributes); + Printf(helper_code, " %s\n", csattributes); + } + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + tm = Getattr(n, "tmap:imtype"); // typemaps were attached earlier to the node + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + Printf(im_return_type, "%s", tm); + + Printf(function_code, " %s %s(", methodmods, proxy_class_name); + Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + + Printv(imcall, full_imclass_name, ".", mangled_overname, "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, false); + String *cshin = 0; + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + cshin = Getattr(p, "tmap:csin:cshin"); + if (cshin) + Replaceall(cshin, "$csinput", arg); + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma) { + Printf(function_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } + Printf(function_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", cshin ? cshin : arg); + ++gencomma; + + Delete(cshin); + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + + Printf(function_code, ")"); + Printf(helper_code, ")"); + + /* Insert the csconstruct typemap, doing the replacement for $directorconnect, as needed */ + Hash *attributes = NewHash(); + String *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj"); + String *construct_tm = Copy(typemapLookup(n, "csconstruct", typemap_lookup_type, + WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF, attributes)); + if (construct_tm) { + if (!feature_director) { + Replaceall(construct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(attributes, "tmap:csconstruct:directorconnect"); + + if (connect_attr) { + Replaceall(construct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_CSHARP_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"csconstruct\" typemap.\n", + Getattr(n, "name")); + Replaceall(construct_tm, "$directorconnect", ""); + } + } + + Printv(function_code, " ", construct_tm, NIL); + } + + excodeSubstitute(n, function_code, "csconstruct", 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); + String *im_outattributes = Getattr(n, "tmap:imtype:outattributes"); + if (im_outattributes) + Printf(proxy_class_code, " %s\n", im_outattributes); + Printv(proxy_class_code, helper_code, "\n", NIL); + Replaceall(function_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(function_code, "$imcall", imcall); + } + + Printv(proxy_class_code, function_code, "\n", NIL); + + Delete(helper_args); + Delete(im_return_type); + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(construct_tm); + Delete(attributes); + Delete(overloaded_name); + Delete(imcall); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (methodmods) + Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + + generate_property_declaration_flag = true; + 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; + generate_property_declaration_flag = false; + + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + + bool static_const_member_flag = (Getattr(n, "value") == 0); + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + generate_property_declaration_flag = false; + + if (static_const_member_flag) + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * 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; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + + /* A C# HandleRef is used for all classes in the SWIG intermediary class. + * The intermediary class methods are thus mangled when overloaded to give + * a unique name. */ + String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * moduleClassFunctionHandler() + * ----------------------------------------------------------------------------- */ + + void moduleClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + Parm *last_parm = 0; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + 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("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (proxy_flag && global_variable_flag) { + // Capitalize the first letter in the variable to create the getter/setter function name + func_name = NewString(""); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), variable_name)) == 0); + if (setter_flag) + Printf(func_name, "set"); + else + Printf(func_name, "get"); + Putc(toupper((int) *Char(variable_name)), func_name); + Printf(func_name, "%s", Char(variable_name) + 1); + if (setter_flag) + Swig_typemap_attach_parms("csvarin", l, NULL); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(function_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name); + Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + + bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); + 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(""); + last_parm = p; + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, global_or_member_variable); + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin 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, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in module class) + if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { + excodeSubstitute(n, tm, "csout", 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) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + 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"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (proxy_flag && global_variable_flag) { + // Properties + if (generate_property_declaration_flag) { // Ensure the declaration is generated just once should the property contain both a set and get + // Get the C# variable type - obtained differently depending on whether a setter is required. + String *variable_type = return_type; + if (setter_flag) { + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + String *cstypeout = Getattr(p, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + variable_type = cstypeout ? cstypeout : tm; + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(module_class_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (!methodmods) + methodmods = (is_public(n) ? public_string : protected_string); + Printf(module_class_code, " %s static %s %s {", methodmods, variable_type, variable_name); + } + generate_property_declaration_flag = false; + + if (setter_flag) { + // Setter method + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:csvarin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", "value"); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", p); + Printf(module_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + // Getter method + if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarout", n); + Printf(module_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); + } + } + } else { + // Normal function call + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(module_class_code, function_code, NIL); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(func_name); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /*---------------------------------------------------------------------- + * decodeEnumFeature() + * Decode the possible enum features, which are one of: + * %csenum(simple) + * %csenum(typeunsafe) - default + * %csenum(typesafe) + * %csenum(proper) + *--------------------------------------------------------------------*/ + + EnumFeature decodeEnumFeature(Node *n) { + EnumFeature enum_feature = TypeunsafeEnum; + String *feature = Getattr(n, "feature:cs:enum"); + if (feature) { + if (Cmp(feature, "simple") == 0) + enum_feature = SimpleEnum; + else if (Cmp(feature, "typesafe") == 0) + enum_feature = TypesafeEnum; + else if (Cmp(feature, "proper") == 0) + enum_feature = ProperEnum; + } + return enum_feature; + } + + /* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in C# generated + * code. If the %csconst feature is not used, the string will contain the intermediary + * class call to obtain the enum value. The intermediary class and PINVOKE methods to obtain + * the enum value will be generated. Otherwise the C/C++ enum value will be used if there + * is one and hopefully it will compile as C# code - e.g. 20 as in: enum E{e=20}; + * The %csconstvalue feature overrides all other ways to generate the constant value. + * The caller must delete memory allocated for the returned string. + * ------------------------------------------------------------------------ */ + + String *enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + if (!value) { + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + if (const_feature_flag) { + // Use the C syntax to make a true C# constant and hope that it compiles as C# code + value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); + } else { + String *newsymname = 0; + if (!getCurrentClass() || !proxy_flag) { + String *enumClassPrefix = getEnumClassPrefix(); + if (enumClassPrefix) { + // A global scoped enum + newsymname = Swig_name_member(0, enumClassPrefix, symname); + symname = newsymname; + } + } + + // Get the enumvalue from a PINVOKE call + if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), Swig_name_member(0, getEnumClassPrefix(), symname))); + } + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t) { + Node *enumname = NULL; + Node *n = enumLookup(t); + if (n) { + enumname = Getattr(n, "enumname"); + if (!enumname) { + String *symname = Getattr(n, "sym:name"); + if (symname) { + // Add in class scope when referencing enum if not a global enum + String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); + String *proxyname = 0; + if (scopename_prefix) { + proxyname = getProxyName(scopename_prefix); + } + if (proxyname) { + enumname = NewStringf("%s.%s", proxyname, symname); + } else { + // global enum or enum in a namespace + String *nspace = Getattr(n, "sym:nspace"); + if (nspace) { + if (namespce) + enumname = NewStringf("%s.%s.%s", namespce, nspace, symname); + else + enumname = NewStringf("%s.%s", nspace, symname); + } else { + enumname = Copy(symname); + } + } + Setattr(n, "enumname", enumname); + Delete(enumname); + Delete(scopename_prefix); + } + } + } + + return enumname; + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $csclassname with the proxy class name for classes/structs/unions + * that SWIG knows about. Also substitutes enums with enum name. + * Otherwise use the $descriptor name for the C# class name. Note that the $&csclassname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm) { + bool substitution_performed = false; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + SwigType *strippedtype = SwigType_strip_qualifiers(type); + + if (Strstr(tm, "$csclassname")) { + SwigType *classnametype = Copy(strippedtype); + substituteClassnameSpecialVariable(classnametype, tm, "$csclassname"); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$*csclassname")) { + SwigType *classnametype = Copy(strippedtype); + Delete(SwigType_pop(classnametype)); + if (Len(classnametype) > 0) { + substituteClassnameSpecialVariable(classnametype, tm, "$*csclassname"); + substitution_performed = true; + } + Delete(classnametype); + } + if (Strstr(tm, "$&csclassname")) { + SwigType *classnametype = Copy(strippedtype); + SwigType_add_pointer(classnametype); + substituteClassnameSpecialVariable(classnametype, tm, "$&csclassname"); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$csinterfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$csinterfacename", true); + substitution_performed = true; + Delete(interfacenametype); + } + if (Strstr(tm, "$*csinterfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + Delete(SwigType_pop(interfacenametype)); + if (Len(interfacenametype) > 0) { + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*csinterfacename", true); + substitution_performed = true; + } + Delete(interfacenametype); + } + if (Strstr(tm, "$&csinterfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + SwigType_add_pointer(interfacenametype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&csinterfacename", true); + substitution_performed = true; + Delete(interfacenametype); + } + if (Strstr(tm, "$interfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$interfacename", false); + substitution_performed = true; + Delete(interfacenametype); + } + if (Strstr(tm, "$*interfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + Delete(SwigType_pop(interfacenametype)); + if (Len(interfacenametype) > 0) { + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*interfacename", false); + substitution_performed = true; + } + Delete(interfacenametype); + } + if (Strstr(tm, "$&interfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + SwigType_add_pointer(interfacenametype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&interfacename", false); + substitution_performed = true; + Delete(interfacenametype); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) { + String *replacementname; + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype); + if (enumname) { + replacementname = Copy(enumname); + } else { + bool anonymous_enum = (Cmp(classnametype, "enum ") == 0); + if (anonymous_enum) { + replacementname = NewString("int"); + } else { + // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum + replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replace(replacementname, "enum ", "", DOH_REPLACE_ANY); + Setattr(swig_types_hash, replacementname, classnametype); + } + } + } else { + String *classname = getProxyName(classnametype); // getProxyName() works for pointers to classes too + if (classname) { + replacementname = Copy(classname); + } else { + // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, replacementname, classnametype); + } + } + Replaceall(tm, classnamespecialvariable, replacementname); + + Delete(replacementname); + } + + /* ----------------------------------------------------------------------------- + * substituteInterfacenameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteInterfacenameSpecialVariable(SwigType *interfacenametype, String *tm, const char *interfacenamespecialvariable, bool qualified) { + + String *interfacename = getInterfaceName(interfacenametype, qualified); + if (interfacename) { + String *replacementname = Copy(interfacename); + Replaceall(tm, interfacenamespecialvariable, replacementname); + Delete(replacementname); + } + } + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *swigtype = NewString(""); + File *f_swigtype = getOutputFile(SWIG_output_directory(), classname); + + addOpenNamespace(0, f_swigtype); + + // Pure C# baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "csbase", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "csinterfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "csimports", type, WARN_NONE), // Import statements + "\n", NIL); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(swigtype, "%s\n", csattributes); + + Printv(swigtype, typemapLookup(n, "csclassmodifiers", type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $csclassname", // Class name and base class + (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {", typemapLookup(n, "csbody", type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + typemapLookup(n, "cscode", type, WARN_NONE), // extra C# code + "}\n", NIL); + + Replaceall(swigtype, "$csclassname", classname); + Replaceall(swigtype, "$module", module_class_name); + Replaceall(swigtype, "$imclassname", imclass_name); + Replaceall(swigtype, "$dllimport", dllimport); + + // For unknown enums + Replaceall(swigtype, "$enumvalues", ""); + + Printv(f_swigtype, swigtype, NIL); + + addCloseNamespace(0, f_swigtype); + if (f_swigtype != f_single_out) + Delete(f_swigtype); + f_swigtype = NULL; + Delete(swigtype); + Delete(n); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * 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 *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + 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; + } + + /* ----------------------------------------------------------------------------- + * typemapExists() + * 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 + * returns found typemap or NULL if not found + * ----------------------------------------------------------------------------- */ + + const String *typemapExists(Node *n, const_String_or_char_ptr tmap_method, SwigType *type) { + Node *node = NewHash(); + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + Delete(node); + return tm; + } + + /* ----------------------------------------------------------------------------- + * canThrow() + * Determine whether the code in the typemap can throw a C# exception. + * If so, note it for later when excodeSubstitute() is called. + * ----------------------------------------------------------------------------- */ + + void canThrow(Node *n, const String *typemap, Node *parameter) { + String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap); + String *canthrow = Getattr(parameter, canthrow_attribute); + if (canthrow) + Setattr(n, "csharp:canthrow", "1"); + Delete(canthrow_attribute); + } + + /* ----------------------------------------------------------------------------- + * excodeSubstitute() + * If a method can throw a C# exception, additional exception code is added to + * check for the pending exception so that it can then throw the exception. The + * $excode special variable is replaced by the exception code in the excode + * typemap attribute. + * ----------------------------------------------------------------------------- */ + + void excodeSubstitute(Node *n, String *code, const String *typemap, Node *parameter) { + String *excode_attribute = NewStringf("tmap:%s:excode", typemap); + String *excode = Getattr(parameter, excode_attribute); + if (Getattr(n, "csharp:canthrow")) { + int count = Replaceall(code, "$excode", excode); + if (count < 1 || !excode) { + Swig_warning(WARN_CSHARP_EXCODE, input_file, line_number, + "C# exception may not be thrown - no $excode or excode attribute in '%s' typemap.\n", typemap); + } + } else { + Replaceall(code, "$excode", empty_string); + } + Delete(excode_attribute); + } + + /* ----------------------------------------------------------------------------- + * addOpenNamespace() + * ----------------------------------------------------------------------------- */ + + void addOpenNamespace(const String *nspace, File *file) { + if (namespce || nspace) { + Printf(file, "namespace "); + if (namespce) + Printv(file, namespce, nspace ? "." : "", NIL); + if (nspace) + Printv(file, nspace, NIL); + Printf(file, " {\n"); + } + } + + /* ----------------------------------------------------------------------------- + * addCloseNamespace() + * ----------------------------------------------------------------------------- */ + + void addCloseNamespace(const String *nspace, File *file) { + if (namespce || nspace) + Printf(file, "\n}\n"); + } + + /* ----------------------------------------------------------------------------- + * outputDirectory() + * + * Return the directory to use for generating C# classes/enums and create the + * subdirectory (does not create if language specific outdir does not exist). + * ----------------------------------------------------------------------------- */ + + String *outputDirectory(String *nspace) { + String *output_directory = Copy(SWIG_output_directory()); + if (nspace) { + String *nspace_subdirectory = Copy(nspace); + Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); + String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); + if (newdir_error) { + Printf(stderr, "%s\n", newdir_error); + Delete(newdir_error); + SWIG_exit(EXIT_FAILURE); + } + Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); + Delete(nspace_subdirectory); + } + return output_directory; + } + + /*---------------------------------------------------------------------- + * Start of director methods + *--------------------------------------------------------------------*/ + +#if 0 + /*---------------------------------------------------------------------- + * emitDirectorUpcalls() + *--------------------------------------------------------------------*/ + + void emitDirectorUpcalls() { + if (n_dmethods) { + Wrapper *w = NewWrapper(); + String *dmethod_data = NewString(""); + int n_methods = 0; + Iterator udata_iter; + + udata_iter = First(dmethods_seq); + while (udata_iter.item) { + UpcallData *udata = udata_iter.item; + Printf(dmethod_data, " { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); + ++n_methods; + + udata_iter = Next(udata_iter); + + if (udata_iter.item) + Putc(',', dmethod_data); + Putc('\n', dmethod_data); + } + + + Wrapper_print(w, f_wrappers); + Delete(dmethod_data); + Delete(swig_module_init); + DelWrapper(w); + } + } +#endif + + /*---------------------------------------------------------------------- + * emitDirectorExtraMethods() + * + * This is where the director connect method is generated. + *--------------------------------------------------------------------*/ + void emitDirectorExtraMethods(Node *n) { + if (!Swig_directorclass(n)) + return; + + // Output the director connect method: + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *dirclassname = directorClassName(n); + String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); + String *wname = Swig_name_wrapper(swig_director_connect); + String *sym_name = Getattr(n, "sym:name"); + String *qualified_classname = Copy(sym_name); + String *nspace = getNSpace(); + String *dirClassName = directorClassName(n); + String *smartptr = Getattr(n, "feature:smartptr"); + if (!GetFlag(n, "feature:flatnested")) { + for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + + Push(qualified_classname, "."); + Push(qualified_classname, Getattr(outer_class, "sym:name")); + } + } + if (nspace) + Insert(qualified_classname, 0, NewStringf("%s.", nspace)); + + Printv(imclass_class_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); + Printf(imclass_class_code, " public static extern void %s(global::System.Runtime.InteropServices.HandleRef jarg1", swig_director_connect); + + Wrapper *code_wrap = NewWrapper(); + Printf(code_wrap->def, "SWIGEXPORT void SWIGSTDCALL %s(void *objarg", wname); + + if (smartptr) { + Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", smartptr, smartptr); + Printf(code_wrap->code, " // Keep a local instance of the smart pointer around while we are using the raw pointer\n"); + Printf(code_wrap->code, " // Avoids using smart pointer specific API.\n"); + Printf(code_wrap->code, " %s *director = static_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName); + } else { + 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("); + + 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, ", "); + if (i != first_class_dmethod) + Printf(code_wrap->code, ", "); + Printf(code_wrap->def, "%s::SWIG_Callback%s_t callback%s", dirclassname, methid, methid); + Printf(code_wrap->code, "callback%s", methid); + Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", qualified_classname, sym_name, methid, methid); + } + + Printf(code_wrap->def, ") {\n"); + Printf(code_wrap->code, ");\n"); + Printf(imclass_class_code, ");\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(wname); + Delete(swig_director_connect); + Delete(qualified_classname); + Delete(dirclassname); + } + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying C# object. + * + * --------------------------------------------------------------- */ + + 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 *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = 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 *jupcall_args = NewString(""); + String *imclass_dmethod; + String *callback_typedef_parms = NewString(""); + String *delegate_parms = NewString(""); + String *proxy_method_types = 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(), getClassPrefix(), 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 C# 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 = Swig_typemap_lookup("imtype", n, "", 0); + if (tm) { + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + const String *im_directoroutattributes = Getattr(n, "tmap:imtype:directoroutattributes"); + if (im_directoroutattributes) { + Printf(callback_def, " %s\n", im_directoroutattributes); + if (!ignored_method) + Printf(director_delegate_definitions, " %s\n", im_directoroutattributes); + } + + Printf(callback_def, " private %s SwigDirectorMethod%s(", tm, overloaded_name); + if (!ignored_method) { + const String *csdirectordelegatemodifiers = Getattr(n, "feature:csdirectordelegatemodifiers"); + String *modifiers = (csdirectordelegatemodifiers ? NewStringf("%s%s", csdirectordelegatemodifiers, Len(csdirectordelegatemodifiers) > 0 ? " " : "") : NewStringf("public ")); + Printf(director_delegate_definitions, " %sdelegate %s", modifiers, tm); + Delete(modifiers); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_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_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(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("cstype", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("csdirectorin", 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, convert from native to C# */ + 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); + + /* And add to the upcall args */ + if (i > 0) + Printf(jupcall_args, ", "); + Printf(jupcall_args, "%s", arg); + + /* Get parameter's intermediary C type */ + if ((c_param_type = Getattr(p, "tmap:ctype"))) { + String *ctypeout = Getattr(p, "tmap:ctype:out"); // the type in the ctype typemap's out attribute overrides the type in the typemap + if (ctypeout) + 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 C type to callback typedef */ + if (i > 0) + Printf(callback_typedef_parms, ", "); + Printf(callback_typedef_parms, "%s", c_param_type); + + /* Add parameter to the intermediate class code if generating the + * intermediate's upcall code */ + if ((tm = Getattr(p, "tmap:imtype"))) { + + String *imtypeout = Getattr(p, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + const String *im_directorinattributes = Getattr(p, "tmap:imtype:directorinattributes"); + + String *din = Copy(Getattr(p, "tmap:csdirectorin")); + + if (din) { + Replaceall(din, "$module", module_class_name); + Replaceall(din, "$imclassname", imclass_name); + substituteClassname(pt, din); + Replaceall(din, "$iminput", ln); + + // pre and post attribute support + String *pre = Getattr(p, "tmap:csdirectorin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$iminput", ln); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csdirectorin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$iminput", ln); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csdirectorin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$iminput", ln); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + + if (i > 0) { + Printf(delegate_parms, ", "); + Printf(proxy_method_types, ", "); + 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); + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + int flags = DOH_REPLACE_FIRST | DOH_REPLACE_ID_BEGIN | DOH_REPLACE_NOCOMMENT; + if (Replace(tm, "ref ", "", flags) || Replace(tm, "ref\t", "", flags)) { + Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm); + } else if (Replace(tm, "out ", "", flags) || Replace(tm, "out\t", "", flags)) { + Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm); + } else { + Printf(proxy_method_types, "typeof(%s)", tm); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, "No csdirectorin 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_CSHARP_TYPEMAP_CSTYPE_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_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + output_director = false; + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + Delete(ln); + Delete(arg); + Delete(c_decl); + } + + /* 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 off the inherited upcall's definition */ + + Printf(callback_def, "%s)", delegate_parms); + Printf(callback_def, " {\n"); + + /* Emit the intermediate class's upcall to the actual class */ + + String *upcall = NewStringf("%s(%s)", symname, imcall_args); + + if ((tm = Swig_typemap_lookup("csdirectorout", n, "", 0))) { + substituteClassname(returntype, tm); + Replaceall(tm, "$cscall", upcall); + if (!is_void) + Insert(tm, 0, "return "); + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + + // pre and post attribute support + 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) + Printf(callback_code, "%s\n try {\n %s;\n } finally {\n%s\n }\n", pre_code, tm, post_code); + else if (is_pre_code) + Printf(callback_code, "%s\n %s;\n", pre_code, tm); + else if (is_post_code) + Printf(callback_code, " try {\n %s;\n } finally {\n%s\n }\n", tm, post_code); + else + Printf(callback_code, " %s;\n", tm); + if (is_terminator_code) + Printv(callback_code, "\n", terminator_code, NIL); + } + + 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(%s);\n", overloaded_name, jupcall_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_delegate_callback, "\n", 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) { + /* Emit the actual upcall through */ + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name); + String *methid = Getattr(udata, "class_methodidx"); + Setattr(n, "upcalldata", udata); + /* + Printf(stdout, "setting upcalldata, nodeType: %s %s::%s %p\n", nodeType(n), classname, Getattr(n, "name"), n); + */ + + Printf(director_callback_typedefs, " typedef %s (SWIGSTDCALL* SWIG_Callback%s_t)(", c_ret_type, methid); + Printf(director_callback_typedefs, "%s);\n", callback_typedef_parms); + Printf(director_callbacks, " SWIG_Callback%s_t swig_callback%s;\n", methid, overloaded_name); + + Printf(director_delegate_definitions, " SwigDelegate%s_%s(%s);\n", classname, methid, delegate_parms); + Printf(director_delegate_instances, " private SwigDelegate%s_%s swigDelegate%s;\n", classname, methid, methid); + Printf(director_method_types, " private static global::System.Type[] swigMethodTypes%s = new global::System.Type[] { %s };\n", methid, proxy_method_types); + Printf(director_connect_parms, "SwigDirector%s%s delegate%s", classname, methid, methid); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(qualified_return); + Delete(declaration); + Delete(callback_typedef_parms); + Delete(delegate_parms); + Delete(proxy_method_types); + Delete(callback_def); + Delete(callback_code); + Delete(dirclassname); + DelWrapper(w); + + return status; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + 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); + + 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(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); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + 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); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + directorDeclaration(n); + + Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); + Printf(f_directors_h, "\npublic:\n"); + + /* Keep track of the director methods for this class */ + first_class_dmethod = curr_class_dmethod = n_dmethods; + + director_callback_typedefs = NewString(""); + director_callbacks = NewString(""); + director_delegate_callback = NewString(""); + director_delegate_definitions = NewString(""); + director_delegate_instances = NewString(""); + director_method_types = NewString(""); + director_connect_parms = NewString(""); + + return Language::classDirectorInit(n); + } + + int classDeclaration(Node *n) { + String *old_director_callback_typedefs = director_callback_typedefs; + String *old_director_callbacks = director_callbacks; + String *old_director_delegate_callback = director_delegate_callback; + String *old_director_delegate_definitions = director_delegate_definitions; + String *old_director_delegate_instances = director_delegate_instances; + String *old_director_method_types = director_method_types; + String *old_director_connect_parms = director_connect_parms; + + int ret = Language::classDeclaration(n); + + // these variables are deleted in emitProxyClassDefAndCPPCasts, hence no Delete here + director_callback_typedefs = old_director_callback_typedefs; + director_callbacks = old_director_callbacks; + director_delegate_callback = old_director_delegate_callback; + director_delegate_definitions = old_director_delegate_definitions; + director_delegate_instances = old_director_delegate_instances; + director_method_types = old_director_method_types; + director_connect_parms = old_director_connect_parms; + + return ret; + } + + /* ---------------------------------------------------------------------- + * classDirectorDestructor() + * ---------------------------------------------------------------------- */ + + 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; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + int i; + String *dirclassname = 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("); + + Printf(w->def, "void %s::swig_connect_director(", dirclassname); + + 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); + if (i != curr_class_dmethod - 1) { + Printf(f_directors_h, ", "); + Printf(w->def, ", "); + } + } + + Printf(f_directors_h, ");\n"); + Printf(w->def, ") {"); + + + if (Len(director_callbacks) > 0) { + Printf(f_directors_h, "\nprivate:\n%s", director_callbacks); + } + Printf(f_directors_h, " void swig_init_callbacks();\n"); + Printf(f_directors_h, "};\n\n"); + Printf(w->code, "}\n\n"); + + Printf(w->code, "void %s::swig_init_callbacks() {\n", dirclassname); + 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); + Delete(dirclassname); + + return Language::classDirectorEnd(n); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + *--------------------------------------------------------------------*/ + + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * directorDeclaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void directorDeclaration(Node *n) { + + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director()"); + + String *dirclassname = directorClassName(n); + String *declaration = Swig_class_declaration(n, dirclassname); + + Printf(declaration, " : public %s, public Swig::Director", base); + + // Stash stuff for later. + Setattr(n, "director:decl", declaration); + Setattr(n, "director:ctor", class_ctor); + + Delete(dirclassname); + } + + /*---------------------------------------------------------------------- + * nestedClassesSupport() + *--------------------------------------------------------------------*/ + + NestedClassSupport nestedClassesSupport() const { + return NCS_Full; + } +}; /* class CSHARP */ + +/* ----------------------------------------------------------------------------- + * swig_csharp() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_csharp() { + return new CSHARP(); +} +extern "C" Language *swig_csharp(void) { + return new_swig_csharp(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *CSHARP::usage = "\ +C# Options (available with -csharp)\n\ + -dllimport <dl> - Override DllImport attribute name to <dl>\n\ + -namespace <nm> - Generate wrappers into C# namespace <nm>\n\ + -noproxy - Generate the low-level functional interface instead\n\ + of proxy classes\n\ + -oldvarnames - Old intermediary method names for variable wrappers\n\ + -outfile <file> - Write all C# into a single <file> located in the output directory\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/d.cxx b/contrib/tools/swig/Source/Modules/d.cxx new file mode 100644 index 00000000000..b7283eac221 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/d.cxx @@ -0,0 +1,4647 @@ +/* ----------------------------------------------------------------------------- + * 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); + 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) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + // Wrappers not wanted for some methods where the parameters cannot be + // overloaded in D. + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in + // directors. + if (GetFlag(n, "explicitcall")) + return; + + // RESEARCH: What is this good for? + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("dtype", l, NULL); + Swig_typemap_attach_parms("din", l, NULL); + + // Get return types. + if ((tm = lookupDTypemap(n, "dtype"))) { + String *dtypeout = Getattr(n, "tmap:dtype:out"); + if (dtypeout) { + // The type in the dtype typemap's out attribute overrides the type in + // the typemap. + tm = dtypeout; + replaceClassname(tm, t); + } + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag) { + // Check if this is a setter method for a public member. + const String *setter_name = Swig_name_set(getNSpace(), + Swig_name_member(0, proxy_class_name, variable_name)); + + if (Cmp(Getattr(n, "sym:name"), setter_name) == 0) { + setter_flag = true; + } + } + + // Write function modifiers. + { + String *modifiers; + + const String *mods_override = Getattr(n, "feature:d:methodmodifiers"); + if (mods_override) { + modifiers = Copy(mods_override); + } else { + modifiers = Copy(is_public(n) ? public_string : protected_string); + + if (Getattr(n, "override")) { + Printf(modifiers, " override"); + } + } + + if (is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the + // underlying pointer type, so no override required. + Replaceall(modifiers, "override", ""); + } + + Chop(modifiers); + + if (static_flag) { + Printf(modifiers, " static"); + } + + Printf(function_code, "%s ", modifiers); + Delete(modifiers); + } + + // Complete the function declaration up to the parameter list. + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + // Write the wrapper function call up to the parameter list. + Printv(imcall, im_dmodule_fq_name, ".$imfuncname(", NIL); + if (!static_flag) { + Printf(imcall, "cast(void*)swigCPtr"); + } + + String *proxy_param_types = NewString(""); + + // Write the parameter list for the proxy function declaration and the + // wrapper function call. + emit_mark_varargs(l); + int gencomma = !static_flag; + for (i = 0, p = l; p; i++) { + // Ignored varargs. + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + // Ignored parameters. + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + // Ignore the 'this' argument for variable wrappers. + if (!(variable_wrapper_flag && i == 0)) { + String *param_name = makeParameterName(n, p, i, setter_flag); + SwigType *pt = Getattr(p, "type"); + + // Write the wrapper function call argument. + { + if (gencomma) { + Printf(imcall, ", "); + } + + if ((tm = lookupDTypemap(p, "din", true))) { + Replaceall(tm, "$dinput", param_name); + String *pre = Getattr(p, "tmap:din:pre"); + if (pre) { + replaceClassname(pre, pt); + Replaceall(pre, "$dinput", param_name); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:din:post"); + if (post) { + replaceClassname(post, pt); + Replaceall(post, "$dinput", param_name); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:din:terminator"); + if (terminator) { + replaceClassname(terminator, pt); + Replaceall(terminator, "$dinput", param_name); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, + "No din typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + + // Write the D proxy function parameter. + { + String *proxy_type = NewString(""); + + if ((tm = lookupDTypemap(p, "dtype"))) { + const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); + Printf(proxy_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma >= 2) { + Printf(function_code, ", "); + Printf(proxy_param_types, ", "); + } + gencomma = 2; + Printf(function_code, "%s %s", proxy_type, param_name); + Append(proxy_param_types, proxy_type); + + Delete(proxy_type); + } + + Delete(param_name); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ") "); + + if (d_version > 1 && wrapping_member_flag) { + Printf(function_code, "@property "); + } + + if (wrapMemberFunctionAsDConst(n)) { + Printf(function_code, "const "); + } + + // Lookup the code used to convert the wrapper return value to the proxy + // function return type. + if ((tm = lookupDTypemap(n, "dout"))) { + replaceExcode(n, tm, "dout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, "{"); + Printv(tm, "}", NIL); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + replaceClassname(tm, t); + + // For director methods: generate code to selectively make a normal + // polymorphic call or an explicit method call. Needed to prevent infinite + // recursion when calling director methods. + Node *explicit_n = Getattr(n, "explicitcallnode"); + if (explicit_n && 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 *excode = NewString(""); + if (!Cmp(return_type, "void")) + Printf(excode, "if (swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) %s; else %s", + return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall); + else + Printf(excode, "((swigIsMethodOverridden!(%s delegate(%s), %s function(%s), %s)()) ? %s : %s)", + return_type, proxy_param_types, return_type, proxy_param_types, proxy_function_name, ex_imcall, imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + Delete(ex_overloaded_name); + Delete(excode); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_D_TYPEMAP_DOUT_UNDEF, input_file, line_number, + "No dout typemap defined for %s\n", SwigType_str(t, 0)); + } + + Delete(proxy_param_types); + + // The whole function body is now in stored tm (if there was a matching type + // map, of course), so simply append it to the code buffer. The braces are + // included in the typemap. + Printv(function_code, tm, NIL); + + // Write function code buffer to the class code. + Printv(proxy_class_body_code, "\n", function_code, "\n", NIL); + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* --------------------------------------------------------------------------- + * D::writeProxyDModuleFunction() + * --------------------------------------------------------------------------- */ + void writeProxyDModuleFunction(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + // RESEARCH: What is this good for? + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("dtype", l, NULL); + Swig_typemap_attach_parms("din", l, NULL); + + /* Get return types */ + if ((tm = lookupDTypemap(n, "dtype"))) { + String *dtypeout = Getattr(n, "tmap:dtype:out"); + if (dtypeout) { + // The type in the dtype typemap's out attribute overrides the type in + // the typemap. + tm = dtypeout; + replaceClassname(tm, t); + } + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (global_variable_flag) { + // RESEARCH: Is the Copy() needed here? + func_name = Copy(variable_name); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *outattributes = Getattr(n, "tmap:dtype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + + const String *methodmods = Getattr(n, "feature:d:methodmodifiers"); + // TODO: Check if is_public(n) could possibly make any sense here + // (private global functions would be useless anyway?). + methodmods = methodmods ? methodmods : empty_string; + + Printf(function_code, "\n%s%s %s(", methodmods, return_type, func_name); + Printv(imcall, im_dmodule_fq_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; i < num_arguments; i++) { + + /* Ignored parameters */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + // Get the D parameter type. + if ((tm = lookupDTypemap(p, "dtype", true))) { + const String *inattributes = Getattr(p, "tmap:dtype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_D_TYPEMAP_DTYPE_UNDEF, input_file, line_number, + "No dtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + const bool generating_setter = global_variable_flag || wrapping_member_flag; + String *arg = makeParameterName(n, p, i, generating_setter); + + // Get the D code to convert the parameter value to the type used in the + // wrapper D module. + if ((tm = lookupDTypemap(p, "din", true))) { + Replaceall(tm, "$dinput", arg); + String *pre = Getattr(p, "tmap:din:pre"); + if (pre) { + replaceClassname(pre, pt); + Replaceall(pre, "$dinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:din:post"); + if (post) { + replaceClassname(post, pt); + Replaceall(post, "$dinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:din:terminator"); + if (terminator) { + replaceClassname(terminator, pt); + Replaceall(terminator, "$dinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_D_TYPEMAP_DIN_UNDEF, input_file, line_number, + "No din typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to module class function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + p = Getattr(p, "tmap:in:next"); + Delete(arg); + Delete(param_type); + } + + Printf(imcall, ")"); + Printf(function_code, ") "); + + if (global_variable_flag && (d_version > 1)) { + Printf(function_code, "@property "); + } + + // Lookup the code used to convert the wrapper return value to the proxy + // function return type. + if ((tm = lookupDTypemap(n, "dout"))) { + replaceExcode(n, tm, "dout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, " {"); + Printf(tm, "\n}"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + replaceClassname(tm, t); + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_D_TYPEMAP_DOUT_UNDEF, input_file, line_number, + "No dout typemap defined for %s\n", SwigType_str(t, 0)); + } + + // The whole function code is now stored in tm (if there was a matching + // type map, of course), so simply append it to the code buffer. + Printf(function_code, "%s\n", tm ? (const String *) tm : empty_string); + Printv(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; + + // 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; + } + } 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, 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, const String* d_class_name, SwigType* c_classname, SwigType* c_baseclassname) { + + SwigType *smart = Swig_cparse_smartptr(n); + 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) { + String *smartnamestr = SwigType_namestr(smart); + String *bsmartnamestr = SwigType_namestr(smart); + + // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates + SwigType *rclassname = SwigType_typedef_resolve_all(classname); + SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname); + Replaceall(bsmartnamestr, rclassname, rbaseclassname); + + Printv(upcasts_code, + "SWIGEXPORT ", bsmartnamestr, " * ", upcast_wrapper_name, + "(", smartnamestr, " *objectRef) {\n", + " return objectRef ? new ", bsmartnamestr, "(*objectRef) : 0;\n" + "}\n", + "\n", NIL); + + Delete(rbaseclassname); + Delete(rclassname); + Delete(bsmartnamestr); + Delete(smartnamestr); + } else { + Printv(upcasts_code, + "SWIGEXPORT ", baseclassname, " * ", upcast_wrapper_name, + "(", baseclassname, " *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_name); + Delete(upcast_wrapper_name); + Delete(smart); + } + + /* --------------------------------------------------------------------------- + * D::writeTypeWrapperClass() + * --------------------------------------------------------------------------- */ + void writeTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + assertClassNameValidity(classname); + + String* imports_target; + String* code_target; + File *class_file = NULL; + if (split_proxy_dmodule) { + String *filename = NewStringf("%s%s.d", dmodule_directory, classname); + class_file = NewFile(filename, "w", SWIG_output_files()); + if (!class_file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filename)); + Delete(filename); + + emitBanner(class_file); + Printf(class_file, "module %s%s;\n", package, classname); + Printf(class_file, "\nstatic import %s;\n", im_dmodule_fq_name); + + imports_target = NewString(""); + code_target = NewString(""); + } else { + imports_target = 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)() %s{\n", (d_version > 1) ? "const " : ""); + Printf(proxy_class_body_code, " DelegateType dg = &fn;\n"); + Printf(proxy_class_body_code, " return dg.funcptr != SwigNonVirtualAddressOf!(FunctionType, fn);\n"); + Printf(proxy_class_body_code, "}\n"); + Printf(proxy_class_body_code, "\n"); + Printf(proxy_class_body_code, "private static Function SwigNonVirtualAddressOf(Function, alias fn)() {\n"); + Printf(proxy_class_body_code, " return cast(Function) &fn;\n"); + Printf(proxy_class_body_code, "}\n"); + } + + if (Len(director_dcallbacks_code) > 0) { + Printv(proxy_class_epilogue_code, director_dcallbacks_code, NIL); + } + + Delete(director_callback_typedefs); + director_callback_typedefs = NULL; + Delete(director_callback_pointers); + director_callback_pointers = NULL; + Delete(director_dcallbacks_code); + director_dcallbacks_code = NULL; + Delete(dirClassName); + Delete(connect_name); + } + + /* --------------------------------------------------------------------------- + * 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); + SWIG_exit(EXIT_FAILURE); + } + + String *nspace = getNSpace(); + if (nspace) { + // Check the root package/outermost namespace (a class A in module + // A.B leads to problems if another module A.C is also imported) + if (Len(package) > 0) { + String *dotless_package = NewStringWithSize(package, Len(package) - 1); + if (Cmp(class_name, dotless_package) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be the same as the root package it is in: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + Delete(dotless_package); + } else { + String *outer = createFirstNamespaceName(nspace); + if (Cmp(class_name, outer) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be the same as the outermost namespace it is in: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + Delete(outer); + } + + // … and the innermost one (because of the conflict with the main proxy + // module named like the namespace). + String *inner = createLastNamespaceName(nspace); + if (Cmp(class_name, inner) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be the same as the innermost namespace it is in: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + Delete(inner); + } else { + if (Cmp(class_name, proxy_dmodule_name) == 0) { + Swig_error(input_file, line_number, + "Class name cannot be equal to proxy D module name: %s\n", + class_name); + SWIG_exit(EXIT_FAILURE); + } + } + } + } + + /* --------------------------------------------------------------------------- + * 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 (d_version == 1) return false; + if (static_flag) return false; // Never emit »const« for static member functions. + return GetFlag(n, "memberget") || SwigType_isconst(Getattr(n, "decl")); + } + + /* --------------------------------------------------------------------------- + * D::areAllOverloadsOverridden() + * + * Determines whether the class the passed function node belongs to overrides + * all the overlaods for the passed function node defined somewhere up the + * inheritance 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::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"); + } + + /* --------------------------------------------------------------------------- + * D::outputDirectory() + * + * Returns the directory to write the D modules for the given namespace to and + * and creates the subdirectory if it doesn't exist. + * --------------------------------------------------------------------------- */ + String *outputDirectory(String *nspace) { + String *output_directory = Copy(dmodule_directory); + if (nspace) { + String *nspace_subdirectory = Copy(nspace); + Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); + String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); + if (newdir_error) { + Printf(stderr, "%s\n", newdir_error); + Delete(newdir_error); + SWIG_exit(EXIT_FAILURE); + } + Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); + Delete(nspace_subdirectory); + } + return output_directory; + } + + /* --------------------------------------------------------------------------- + * D::proxyCodeBuffer() + * + * Returns the buffer to write proxy code for the given namespace to. + * --------------------------------------------------------------------------- */ + String *proxyCodeBuffer(String *nspace) { + if (!nspace) { + return proxy_dmodule_code; + } + + Hash *hash = Getattr(nspace_proxy_dmodules, nspace); + if (!hash) { + hash = NewHash(); + Setattr(hash, "code", NewString("")); + Setattr(hash, "imports", NewString("")); + Setattr(nspace_proxy_dmodules, nspace, hash); + } + return Getattr(hash, "code"); + } + + /* --------------------------------------------------------------------------- + * D::proxyCodeBuffer() + * + * Returns the buffer to write imports for the proxy code for the given + * namespace to. + * --------------------------------------------------------------------------- */ + String *proxyImportsBuffer(String *nspace) { + if (!nspace) { + return proxy_dmodule_imports; + } + + Hash *hash = Getattr(nspace_proxy_dmodules, nspace); + if (!hash) { + hash = NewHash(); + Setattr(hash, "code", NewString("")); + Setattr(hash, "imports", NewString("")); + Setattr(nspace_proxy_dmodules, nspace, hash); + } + return Getattr(hash, "imports"); + } + + /* --------------------------------------------------------------------------- + * D::createFirstNamespaceName() + * + * Returns a new string containing the name of the outermost namespace, e.g. + * »A« for the argument »A.B.C«. + * --------------------------------------------------------------------------- */ + String *createFirstNamespaceName(const String *nspace) const { + char *tmp = Char(nspace); + char *c = tmp; + char *co = 0; + if (!strstr(c, ".")) + return 0; + + co = c + Len(nspace); + + while (*c && (c != co)) { + if (*c == '.') { + break; + } + c++; + } + if (!*c || (c == tmp)) { + return NULL; + } + return NewStringWithSize(tmp, (int)(c - tmp)); + } + + /* --------------------------------------------------------------------------- + * D::createLastNamespaceName() + * + * Returns a new string containing the name of the innermost namespace, e.g. + * »C« for the argument »A.B.C«. + * --------------------------------------------------------------------------- */ + String *createLastNamespaceName(const String *nspace) const { + if (!nspace) return NULL; + char *c = Char(nspace); + char *cc = c; + if (!strstr(c, ".")) + return NewString(nspace); + + while (*c) { + if (*c == '.') { + cc = c; + } + ++c; + } + return NewString(cc + 1); + } + + /* --------------------------------------------------------------------------- + * D::createOuterNamespaceNames() + * + * Returns a new string containing the name of the outer namespace, e.g. + * »A.B« for the argument »A.B.C«. + * --------------------------------------------------------------------------- */ + String *createOuterNamespaceNames(const String *nspace) const { + if (!nspace) return NULL; + char *tmp = Char(nspace); + char *c = tmp; + char *cc = c; + if (!strstr(c, ".")) + return NULL; + + while (*c) { + if (*c == '.') { + cc = c; + } + ++c; + } + if (cc == tmp) { + return NULL; + } + return NewStringWithSize(tmp, (int)(cc - tmp)); + } +}; + +static Language *new_swig_d() { + 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 (default: D1/Tango)\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"; diff --git a/contrib/tools/swig/Source/Modules/directors.cxx b/contrib/tools/swig/Source/Modules/directors.cxx new file mode 100644 index 00000000000..a91d5fd9a32 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/directors.cxx @@ -0,0 +1,241 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * directors.cxx + * + * Director support functions. + * Not all of these may be necessary, and some may duplicate existing functionality + * in SWIG. --MR + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +/* ----------------------------------------------------------------------------- + * Swig_csuperclass_call() + * + * Generates a fully qualified method call, including the full parameter list. + * e.g. "base::method(i, j)" + * ----------------------------------------------------------------------------- */ + +String *Swig_csuperclass_call(String *base, String *method, ParmList *l) { + String *call = NewString(""); + int arg_idx = 0; + Parm *p; + if (base) { + Printf(call, "%s::", base); + } + Printf(call, "%s(", method); + for (p = l; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + if (!pname && Cmp(Getattr(p, "type"), "void")) { + pname = NewString(""); + Printf(pname, "arg%d", arg_idx++); + } + if (p != l) + Printf(call, ", "); + Printv(call, pname, NIL); + } + Printf(call, ")"); + return call; +} + +/* ----------------------------------------------------------------------------- + * Swig_class_declaration() + * + * Generate the start of a class/struct declaration. + * e.g. "class myclass" + * ----------------------------------------------------------------------------- */ + +String *Swig_class_declaration(Node *n, String *name) { + if (!name) { + name = Getattr(n, "sym:name"); + } + String *result = NewString(""); + String *kind = Getattr(n, "kind"); + Printf(result, "%s %s", kind, name); + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_class_name() + * ----------------------------------------------------------------------------- */ + +String *Swig_class_name(Node *n) { + String *name; + name = Copy(Getattr(n, "sym:name")); + return name; +} + +/* ----------------------------------------------------------------------------- + * Swig_director_declaration() + * + * Generate the full director class declaration, complete with base classes. + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + * ----------------------------------------------------------------------------- */ + +String *Swig_director_declaration(Node *n) { + String *classname = Swig_class_name(n); + String *directorname = Language::instance()->directorClassName(n); + String *base = Getattr(n, "classtype"); + String *declaration = Swig_class_declaration(n, directorname); + + Printf(declaration, " : public %s, public Swig::Director {\n", base); + Delete(classname); + Delete(directorname); + return declaration; +} + + +/* ----------------------------------------------------------------------------- + * Swig_method_call() + * ----------------------------------------------------------------------------- */ + +String *Swig_method_call(const_String_or_char_ptr name, ParmList *parms) { + String *func; + int i = 0; + int comma = 0; + Parm *p = parms; + SwigType *pt; + String *nname; + + func = NewString(""); + nname = SwigType_namestr(name); + Printf(func, "%s(", nname); + while (p) { + String *pname; + pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + if (comma) + Printf(func, ","); + pname = Getattr(p, "name"); + Printf(func, "%s", pname); + comma = 1; + i++; + } + p = nextSibling(p); + } + Printf(func, ")"); + return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_method_decl() + * + * Return a stringified version of a C/C++ declaration. + * ----------------------------------------------------------------------------- */ + +String *Swig_method_decl(SwigType *return_base_type, SwigType *decl, const_String_or_char_ptr id, List *args, int default_args) { + String *result = NewString(""); + bool conversion_operator = Strstr(id, "operator ") != 0 && !return_base_type; + + Parm *parm = args; + int arg_idx = 0; + while (parm) { + String *type = Getattr(parm, "type"); + String *name = Getattr(parm, "name"); + if (!name && Cmp(type, "void")) { + name = NewString(""); + Printf(name, "arg%d", arg_idx++); + Setattr(parm, "name", name); + } + parm = nextSibling(parm); + } + + String *rettype = Copy(decl); + String *quals = SwigType_pop_function_qualifiers(rettype); + String *qualifiers = 0; + if (quals) + qualifiers = SwigType_str(quals, 0); + + String *popped_decl = SwigType_pop_function(rettype); + if (return_base_type) + Append(rettype, return_base_type); + + if (!conversion_operator) { + SwigType *rettype_stripped = SwigType_strip_qualifiers(rettype); + String *rtype = SwigType_str(rettype, 0); + Append(result, rtype); + if (SwigType_issimple(rettype_stripped) && return_base_type) + Append(result, " "); + Delete(rtype); + Delete(rettype_stripped); + } + + if (id) + Append(result, id); + + String *args_string = default_args ? ParmList_str_defaultargs(args) : ParmList_str(args); + Printv(result, "(", args_string, ")", NIL); + + if (qualifiers) + Printv(result, " ", qualifiers, NIL); + + // Reformat result to how it has been historically + Replaceall(result, ",", ", "); + Replaceall(result, "=", " = "); + + Delete(args_string); + Delete(popped_decl); + Delete(qualifiers); + Delete(quals); + Delete(rettype); + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_director_emit_dynamic_cast() + * + * In order to call protected virtual director methods from the target language, we need + * to add an extra dynamic_cast to call the public C++ wrapper in the director class. + * Also for non-static protected members when the allprotected option is on. + * ----------------------------------------------------------------------------- */ + +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f) { + // TODO: why is the storage element removed in staticmemberfunctionHandler ?? + if ((!is_public(n) && (is_member_director(n) || GetFlag(n, "explicitcall"))) || + (is_non_virtual_protected_access(n) && !(Swig_storage_isstatic_custom(n, "staticmemberfunctionHandler:storage") || + Swig_storage_isstatic(n)) + && !Equal(nodeType(n), "constructor"))) { + Node *parent = Getattr(n, "parentNode"); + String *dirname; + String *dirdecl; + dirname = Language::instance()->directorClassName(parent); + dirdecl = NewStringf("%s *darg = 0", dirname); + Wrapper_add_local(f, "darg", dirdecl); + Printf(f->code, "darg = dynamic_cast<%s *>(arg1);\n", dirname); + Delete(dirname); + Delete(dirdecl); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_director_parms_fixup() + * + * For each parameter in the C++ member function, copy the parameter name + * to its "lname"; this ensures that Swig_typemap_attach_parms() will do + * the right thing when it sees strings like "$1" in "directorin" typemaps. + * ----------------------------------------------------------------------------- */ + +void Swig_director_parms_fixup(ParmList *parms) { + Parm *p; + int i; + for (i = 0, p = parms; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = 0; + + if (!arg && !Equal(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = Copy(arg); + + Setattr(p, "lname", lname); + Delete(lname); + } +} + diff --git a/contrib/tools/swig/Source/Modules/emit.cxx b/contrib/tools/swig/Source/Modules/emit.cxx new file mode 100644 index 00000000000..7a4c2dcfb12 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/emit.cxx @@ -0,0 +1,559 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * emit.cxx + * + * Useful functions for emitting various pieces of code. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +/* ----------------------------------------------------------------------------- + * emit_return_variable() + * + * Emits a variable declaration for a function return value. + * The variable name is always called result. + * n => Node of the method being wrapped + * rt => the return type + * f => the wrapper to generate code into + * ----------------------------------------------------------------------------- */ + +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f) { + + if (!GetFlag(n, "tmap:out:optimal")) { + if (rt && (SwigType_type(rt) != T_VOID)) { + SwigType *vt = cplus_value_type(rt); + SwigType *tt = vt ? vt : rt; + SwigType *lt = SwigType_ltype(tt); + String *lstr = SwigType_str(lt, Swig_cresult_name()); + if (SwigType_ispointer(lt)) { + Wrapper_add_localv(f, Swig_cresult_name(), lstr, "= 0", NULL); + } else { + Wrapper_add_local(f, Swig_cresult_name(), lstr); + } + if (vt) { + Delete(vt); + } + Delete(lt); + Delete(lstr); + } + } +} + +/* ----------------------------------------------------------------------------- + * emit_parameter_variables() + * + * Emits a list of variable declarations for function parameters. + * The variable names are always called arg1, arg2, etc... + * l => the parameter list + * f => the wrapper to generate code into + * ----------------------------------------------------------------------------- */ + +void emit_parameter_variables(ParmList *l, Wrapper *f) { + + Parm *p; + String *tm; + + /* Emit function arguments */ + Swig_cargs(f, l); + + /* Attach typemaps to parameters */ + /* Swig_typemap_attach_parms("ignore",l,f); */ + + Swig_typemap_attach_parms("default", l, f); + Swig_typemap_attach_parms("arginit", l, f); + + /* Apply the arginit and default */ + p = l; + while (p) { + tm = Getattr(p, "tmap:arginit"); + if (tm) { + Replace(tm, "$target", Getattr(p, "lname"), DOH_REPLACE_ANY); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:arginit:next"); + } else { + p = nextSibling(p); + } + } + + /* Apply the default typemap */ + p = l; + while (p) { + tm = Getattr(p, "tmap:default"); + if (tm) { + Replace(tm, "$target", Getattr(p, "lname"), DOH_REPLACE_ANY); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:default:next"); + } else { + p = nextSibling(p); + } + } +} + +/* ----------------------------------------------------------------------------- + * emit_attach_parmmaps() + * + * Attach the standard parameter related typemaps. + * ----------------------------------------------------------------------------- */ + +void emit_attach_parmmaps(ParmList *l, Wrapper *f) { + Swig_typemap_attach_parms("in", l, f); + Swig_typemap_attach_parms("typecheck", l, 0); + Swig_typemap_attach_parms("argout", l, f); + Swig_typemap_attach_parms("check", l, f); + Swig_typemap_attach_parms("freearg", l, f); + + { + /* This is compatibility code to deal with the deprecated "ignore" typemap */ + Parm *p = l; + Parm *np; + while (p) { + String *tm = Getattr(p, "tmap:in"); + if (tm && checkAttribute(p, "tmap:in:numinputs", "0")) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + np = Getattr(p, "tmap:in:next"); + while (p && (p != np)) { + /* Setattr(p,"ignore","1"); Deprecate */ + p = nextSibling(p); + } + } else if (tm) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Perform a sanity check on "in" and "freearg" typemaps. These + must exactly match to avoid chaos. If a mismatch occurs, we + nuke the freearg typemap */ + { + Parm *p = l; + Parm *npin, *npfreearg; + while (p) { + npin = Getattr(p, "tmap:in:next"); + + /* + if (Getattr(p,"tmap:ignore")) { + npin = Getattr(p,"tmap:ignore:next"); + } else if (Getattr(p,"tmap:in")) { + npin = Getattr(p,"tmap:in:next"); + } + */ + + if (Getattr(p, "tmap:freearg")) { + npfreearg = Getattr(p, "tmap:freearg:next"); + if (npin != npfreearg) { + while (p != npin) { + Delattr(p, "tmap:freearg"); + Delattr(p, "tmap:freearg:next"); + p = nextSibling(p); + } + } + } + p = npin; + } + } + + /* Check for variable length arguments with no input typemap. + If no input is defined, we set this to ignore and print a + message. + */ + { + Parm *p = l; + Parm *lp = 0; + while (p) { + if (!checkAttribute(p, "tmap:in:numinputs", "0")) { + lp = p; + p = Getattr(p, "tmap:in:next"); + continue; + } + if (SwigType_isvarargs(Getattr(p, "type"))) { + Swig_warning(WARN_LANG_VARARGS, input_file, line_number, "Variable length arguments discarded.\n"); + Setattr(p, "tmap:in", ""); + } + lp = 0; + p = nextSibling(p); + } + + /* Check if last input argument is variable length argument */ + if (lp) { + p = lp; + while (p) { + if (SwigType_isvarargs(Getattr(p, "type"))) { + // Mark the head of the ParmList that it has varargs + Setattr(l, "emit:varargs", lp); +//Printf(stdout, "setting emit:varargs %s ... %s +++ %s\n", Getattr(l, "emit:varargs"), Getattr(l, "type"), Getattr(p, "type")); + break; + } + p = nextSibling(p); + } + } + } + + /* + * An equivalent type can be used in the typecheck typemap for SWIG to detect the overloading of equivalent + * target language types. This is primarily for the smartptr feature, where a pointer and a smart pointer + * are seen as equivalent types in the target language. + */ + { + Parm *p = l; + while (p) { + String *tm = Getattr(p, "tmap:typecheck"); + if (tm) { + String *equivalent = Getattr(p, "tmap:typecheck:equivalent"); + if (equivalent) { + String *precedence = Getattr(p, "tmap:typecheck:precedence"); + if (precedence && Strcmp(precedence, "0") != 0) + Swig_error(Getfile(tm), Getline(tm), "The 'typecheck' typemap for %s contains an 'equivalent' attribute for a 'precedence' that is not set to SWIG_TYPECHECK_POINTER or 0.\n", SwigType_str(Getattr(p, "type"), 0)); + SwigType *cpt = Swig_cparse_type(equivalent); + if (cpt) { + Setattr(p, "equivtype", cpt); + Delete(cpt); + } else { + Swig_error(Getfile(tm), Getline(tm), "Invalid type (%s) in 'equivalent' attribute in 'typecheck' typemap for type %s.\n", equivalent, SwigType_str(Getattr(p, "type"), 0)); + } + } + p = Getattr(p, "tmap:typecheck:next"); + } else { + p = nextSibling(p); + } + } + } +} + +/* ----------------------------------------------------------------------------- + * emit_num_arguments() + * + * Calculate the total number of arguments. This function is safe for use + * with multi-argument typemaps which may change the number of arguments in + * strange ways. + * ----------------------------------------------------------------------------- */ + +int emit_num_arguments(ParmList *parms) { + Parm *p = parms; + int nargs = 0; + + while (p) { + if (Getattr(p, "tmap:in")) { + nargs += GetInt(p, "tmap:in:numinputs"); + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + + /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ + /* + if (parms && (p = Getattr(parms,"emit:varargs"))) { + if (!nextSibling(p)) { + nargs--; + } + } + */ + return nargs; +} + +/* ----------------------------------------------------------------------------- + * emit_num_required() + * + * Computes the number of required arguments. This function is safe for + * use with multi-argument typemaps and knows how to skip over everything + * properly. Note that parameters with default values are counted unless + * the compact default args option is on. + * ----------------------------------------------------------------------------- */ + +int emit_num_required(ParmList *parms) { + Parm *p = parms; + int nargs = 0; + Parm *first_default_arg = 0; + int compactdefargs = ParmList_is_compactdefargs(p); + + while (p) { + if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } else { + if (Getattr(p, "tmap:default")) + break; + if (Getattr(p, "value")) { + if (!first_default_arg) + first_default_arg = p; + if (compactdefargs) + break; + } + nargs += GetInt(p, "tmap:in:numinputs"); + if (Getattr(p, "tmap:in")) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Print error message for non-default arguments following default arguments */ + /* The error message is printed more than once with most language modules, this ought to be fixed */ + if (first_default_arg) { + p = first_default_arg; + while (p) { + if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } else { + if (!Getattr(p, "value") && (!Getattr(p, "tmap:default"))) { + Swig_error(Getfile(p), Getline(p), "Non-optional argument '%s' follows an optional argument.\n", Getattr(p, "name")); + } + if (Getattr(p, "tmap:in")) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + } + + /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ + /* + if (parms && (p = Getattr(parms,"emit:varargs"))) { + if (!nextSibling(p)) { + nargs--; + } + } + */ + return nargs; +} + +/* ----------------------------------------------------------------------------- + * emit_isvarargs() + * + * Checks if a ParmList is a parameter list containing varargs. + * This function requires emit_attach_parmmaps to have been called beforehand. + * ----------------------------------------------------------------------------- */ + +int emit_isvarargs(ParmList *p) { + if (!p) + return 0; + if (Getattr(p, "emit:varargs")) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * emit_isvarargs_function() + * + * Checks for varargs in a function/constructor (can be overloaded) + * ----------------------------------------------------------------------------- */ + +bool emit_isvarargs_function(Node *n) { + bool has_varargs = false; + Node *over = Getattr(n, "sym:overloaded"); + if (over) { + for (Node *sibling = over; sibling; sibling = Getattr(sibling, "sym:nextSibling")) { + if (ParmList_has_varargs(Getattr(sibling, "parms"))) { + has_varargs = true; + break; + } + } + } else { + has_varargs = ParmList_has_varargs(Getattr(n, "parms")) ? true : false; + } + return has_varargs; +} + +/* ----------------------------------------------------------------------------- + * void emit_mark_vararg_parms() + * + * Marks the vararg parameters which are to be ignored. + * Vararg parameters are marked as ignored if there is no 'in' varargs (...) + * typemap. + * ----------------------------------------------------------------------------- */ + +void emit_mark_varargs(ParmList *l) { + Parm *p = l; + while (p) { + if (SwigType_isvarargs(Getattr(p, "type"))) + if (!Getattr(p, "tmap:in")) + Setattr(p, "varargs:ignore", "1"); + p = nextSibling(p); + } +} + +#if 0 +/* replace_contract_args. This function replaces argument names in contract + specifications. Used in conjunction with the %contract directive. */ + +static void replace_contract_args(Parm *cp, Parm *rp, String *s) { + while (cp && rp) { + String *n = Getattr(cp, "name"); + if (n) { + Replace(s, n, Getattr(rp, "lname"), DOH_REPLACE_ID); + } + cp = nextSibling(cp); + rp = nextSibling(rp); + } +} +#endif + +/* ----------------------------------------------------------------------------- + * int emit_action_code() + * + * Emits action code for a wrapper. Adds in exception handling code (%exception). + * eaction -> the action code to emit + * wrappercode -> the emitted code (output) + * ----------------------------------------------------------------------------- */ +int emit_action_code(Node *n, String *wrappercode, String *eaction) { + assert(Getattr(n, "wrap:name")); + + /* Look for except feature (%exception) */ + String *tm = GetFlagAttr(n, "feature:except"); + if (tm) + tm = Copy(tm); + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + if (Strstr(tm, "$")) { + Swig_replace_special_variables(n, parentNode(n), tm); + Replaceall(tm, "$function", eaction); // deprecated + Replaceall(tm, "$action", eaction); + } + Printv(wrappercode, tm, "\n", NIL); + Delete(tm); + return 1; + } else { + Printv(wrappercode, eaction, "\n", NIL); + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * int emit_action() + * + * Emits the call to the wrapped function. + * Adds in exception specification exception handling and %exception code. + * ----------------------------------------------------------------------------- */ +String *emit_action(Node *n) { + String *actioncode = NewStringEmpty(); + String *tm; + String *action; + String *wrap; + ParmList *catchlist = Getattr(n, "catchlist"); + + /* Look for fragments */ + { + String *fragment = Getattr(n, "feature:fragment"); + if (fragment) { + char *c, *tok; + String *t = Copy(fragment); + c = Char(t); + tok = strtok(c, ","); + while (tok) { + String *fname = NewString(tok); + Setfile(fname, Getfile(n)); + Setline(fname, Getline(n)); + Swig_fragment_emit(fname); + Delete(fname); + tok = strtok(NULL, ","); + } + Delete(t); + } + } + + /* Emit wrapper code (if any) */ + wrap = Getattr(n, "wrap:code"); + if (wrap && Swig_filebyname("header") != Getattr(n, "wrap:code:done")) { + File *f_code = Swig_filebyname("header"); + if (f_code) { + Printv(f_code, wrap, NIL); + } + Setattr(n, "wrap:code:done", f_code); + } + + action = Getattr(n, "feature:action"); + if (!action) + action = Getattr(n, "wrap:action"); + assert(action != 0); + + /* Emit contract code (if any) */ + if (Swig_contract_mode_get()) { + /* Preassertion */ + tm = Getattr(n, "contract:preassert"); + if (Len(tm)) { + Printv(actioncode, tm, "\n", NIL); + } + } + /* Exception handling code */ + + /* saves action -> eaction for postcatching exception */ + String *eaction = NewString(""); + + /* If we are in C++ mode and there is an exception specification. We're going to + enclose the block in a try block */ + if (catchlist) { + Printf(eaction, "try {\n"); + } + + String *preaction = Getattr(n, "wrap:preaction"); + if (preaction) + Printv(eaction, preaction, NIL); + + Printv(eaction, action, NIL); + + String *postaction = Getattr(n, "wrap:postaction"); + if (postaction) + Printv(eaction, postaction, NIL); + + if (catchlist) { + int unknown_catch = 0; + int has_varargs = 0; + Printf(eaction, "}"); + for (Parm *ep = catchlist; ep; ep = nextSibling(ep)) { + String *em = Swig_typemap_lookup("throws", ep, "_e", 0); + if (em) { + SwigType *et = Getattr(ep, "type"); + SwigType *etr = SwigType_typedef_resolve_all(et); + if (SwigType_isreference(etr) || SwigType_ispointer(etr) || SwigType_isarray(etr)) { + Printf(eaction, " catch(%s) {", SwigType_str(et, "_e")); + } else if (SwigType_isvarargs(etr)) { + Printf(eaction, " catch(...) {"); + has_varargs = 1; + } else { + Printf(eaction, " catch(%s) {", SwigType_str(et, "&_e")); + } + Printv(eaction, em, "\n", NIL); + Printf(eaction, "}"); + } else { + Swig_warning(WARN_TYPEMAP_THROW, Getfile(n), Getline(n), "No 'throws' typemap defined for exception type '%s'\n", SwigType_str(Getattr(ep, "type"), 0)); + unknown_catch = 1; + } + } + if (unknown_catch && !has_varargs) { + Printf(eaction, " catch(...) {\nthrow;\n}"); + } + } + + /* Look for except typemap (Deprecated) */ + tm = Swig_typemap_lookup("except", n, Swig_cresult_name(), 0); + if (tm) { + Setattr(n, "feature:except", tm); + tm = 0; + } + + /* emit the except feature code */ + emit_action_code(n, actioncode, eaction); + + Delete(eaction); + + /* Emit contract code (if any) */ + if (Swig_contract_mode_get()) { + /* Postassertion */ + tm = Getattr(n, "contract:postassert"); + if (Len(tm)) { + Printv(actioncode, tm, "\n", NIL); + } + } + + return actioncode; +} diff --git a/contrib/tools/swig/Source/Modules/go.cxx b/contrib/tools/swig/Source/Modules/go.cxx new file mode 100644 index 00000000000..0163f71df0a --- /dev/null +++ b/contrib/tools/swig/Source/Modules/go.cxx @@ -0,0 +1,7010 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * go.cxx + * + * Go language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +/* ---------------------------------------------------------------------- + * siphash() + * + * 64-bit SipHash-2-4 to generate unique id for each module + * ---------------------------------------------------------------------- */ + +// An unsigned 64-bit integer that works on a 32-bit host. +typedef struct { + // Assume unsigned long is at least 32 bits. + unsigned long hi; + unsigned long lo; +} swig_uint64; + +// Rotate v left by bits, which must be <= 32. +static inline void _rotl(swig_uint64 *v, int bits) { + assert(bits <= 32); + unsigned long tmp = v->hi; + if (bits == 32) { + v->hi = v->lo; + v->lo = tmp; + } else { + v->hi = (tmp << bits) | ((0xfffffffful & v->lo) >> (32 - bits)); + v->lo = (v->lo << bits) | ((0xfffffffful & tmp) >> (32 - bits)); + } +} + +// dst ^= src +static inline void _xor(swig_uint64 *dst, swig_uint64 *src) { + dst->lo ^= src->lo; + dst->hi ^= src->hi; +} + +// dst += src +static inline void _add(swig_uint64 *dst, swig_uint64 *src) { + dst->lo += src->lo; + dst->hi += src->hi + ((dst->lo & 0xfffffffful) < (src->lo&0xfffffffful) ? 1 : 0); +} +#define SIPROUND \ + do { \ + _add(&v0, &v1); _rotl(&v1, 13); _xor(&v1, &v0); _rotl(&v0, 32); \ + _add(&v2, &v3); _rotl(&v3, 16); _xor(&v3, &v2); \ + _add(&v0, &v3); _rotl(&v3, 21); _xor(&v3, &v0); \ + _add(&v2, &v1); _rotl(&v1, 17); _xor(&v1, &v2); _rotl(&v2, 32); \ + } while(0) + +// Set out to the hash of inc/inlen. +static void siphash(swig_uint64 *out, const char *inc, unsigned long inlen) { + /* "somepseudorandomlygeneratedbytes" */ + swig_uint64 v0 = {0x736f6d65UL, 0x70736575UL}; + swig_uint64 v1 = {0x646f7261UL, 0x6e646f6dUL}; + swig_uint64 v2 = {0x6c796765UL, 0x6e657261UL}; + swig_uint64 v3 = {0x74656462UL, 0x79746573UL}; + swig_uint64 b; + /* hard-coded k. */ + swig_uint64 k0 = {0x07060504UL, 0x03020100UL}; + swig_uint64 k1 = {0x0F0E0D0CUL, 0x0B0A0908UL}; + int i; + const int cROUNDS = 2, dROUNDS = 4; + const unsigned char *in = (const unsigned char *)inc; + const unsigned char *end = in + inlen - (inlen % 8); + int left = inlen & 7; + _xor(&v3, &k1); _xor(&v2, &k0); _xor(&v1, &k1); _xor(&v0, &k0); + for (; in != end; in += 8) { + b.hi = 0; b.lo = 0; + for (i = 0; i < 4; i++) { + b.lo |= ((unsigned long)in[i]) << (8*i); + } + for (i = 0; i < 4; i++) { + b.hi |= ((unsigned long)in[i+4]) << (8*i); + } + _xor(&v3, &b); + for (i = 0; i < cROUNDS; i++) { + SIPROUND; + } + _xor(&v0, &b); + } + b.hi = (inlen & 0xff)<<24; b.lo = 0; + for (; left; left--) { + if (left > 4) { + b.hi |= ((unsigned long)in[left-1]) << (8*left-8-32); + } else { + b.lo |= ((unsigned long)in[left-1]) << (8*left-8); + } + } + _xor(&v3, &b); + for(i=0; i<cROUNDS; i++) { + SIPROUND; + } + _xor(&v0, &b); v2.lo ^= 0xff; + for(i=0; i<dROUNDS; i++) { + SIPROUND; + } + out->lo = 0; out->hi = 0; + _xor(out, &v0); _xor(out, &v1); _xor(out, &v2); _xor(out, &v3); +} +#undef SIPROUND + +class GO:public Language { + static const char *const usage; + + // Go package name. + String *package; + // SWIG module name. + String *module; + // Flag for generating cgo input files. + bool cgo_flag; + // Flag for generating gccgo output. + bool gccgo_flag; + // Prefix to use with gccgo. + String *go_prefix; + // -fgo-prefix option. + String *prefix_option; + // -fgo-pkgpath option. + String *pkgpath_option; + // Prefix for translating %import directive to import statements. + String *import_prefix; + // Whether to use a shared library. + bool use_shlib; + // Name of shared library to import. + String *soname; + // Size in bits of the Go type "int". 0 if not specified. + int intgo_type_size; + + /* Output files */ + File *f_c_begin; + File *f_go_begin; + File *f_gc_begin; + + /* Output fragments */ + File *f_c_runtime; + File *f_c_header; + File *f_c_wrappers; + File *f_c_init; + File *f_c_directors; + File *f_c_directors_h; + File *f_go_imports; + File *f_go_runtime; + File *f_go_header; + File *f_go_wrappers; + File *f_go_directors; + File *f_gc_runtime; + File *f_gc_header; + File *f_gc_wrappers; + File *f_cgo_comment; + File *f_cgo_comment_typedefs; + + // True if we imported a module. + bool saw_import; + // If not NULL, name of import package being processed. + String *imported_package; + // Build interface methods while handling a class. This is only + // non-NULL when we are handling methods. + String *interfaces; + // The class node while handling a class. This is only non-NULL + // when we are handling methods. + Node *class_node; + // The class name while handling a class. This is only non-NULL + // when we are handling methods. This is the name of the class as + // SWIG sees it. + String *class_name; + // The receiver name while handling a class. This is only non-NULL + // when we are handling methods. This is the name of the class + // as run through goCPointerType. + String *class_receiver; + // A hash table of method names that we have seen when processing a + // class. This lets us detect base class methods that we don't want + // to use. + Hash *class_methods; + // True when we are generating the wrapper functions for a variable. + bool making_variable_wrappers; + // True when working with a static member function. + bool is_static_member_function; + // A hash table of enum types that we have seen but which may not have + // been defined. The index is a SwigType. + Hash *undefined_enum_types; + // A hash table of types that we have seen but which may not have + // been defined. The index is a SwigType. + Hash *undefined_types; + // A hash table of classes which were defined. The index is a Go + // type name. + Hash *defined_types; + // A hash table of all the go_imports already imported. The index is a full + // import name e.g. '"runtime"' or '_ "runtime/cgo"' or 'sc "syscall"'. + Hash *go_imports; + // A unique ID used to make public symbols unique. + String *unique_id; + +public: + GO():package(NULL), + module(NULL), + cgo_flag(true), + gccgo_flag(false), + go_prefix(NULL), + prefix_option(NULL), + pkgpath_option(NULL), + import_prefix(NULL), + use_shlib(false), + soname(NULL), + intgo_type_size(0), + f_c_begin(NULL), + f_go_begin(NULL), + f_gc_begin(NULL), + f_c_runtime(NULL), + f_c_header(NULL), + f_c_wrappers(NULL), + f_c_init(NULL), + f_c_directors(NULL), + f_c_directors_h(NULL), + f_go_imports(NULL), + f_go_runtime(NULL), + f_go_header(NULL), + f_go_wrappers(NULL), + f_go_directors(NULL), + f_gc_runtime(NULL), + f_gc_header(NULL), + f_gc_wrappers(NULL), + f_cgo_comment(NULL), + f_cgo_comment_typedefs(NULL), + saw_import(false), + imported_package(NULL), + interfaces(NULL), + class_node(NULL), + class_name(NULL), + class_receiver(NULL), + class_methods(NULL), + making_variable_wrappers(false), + is_static_member_function(false), + undefined_enum_types(NULL), + undefined_types(NULL), + defined_types(NULL), + go_imports(NULL), + unique_id(NULL) { + director_multiple_inheritance = 1; + director_language = 1; + director_prot_ctor_code = NewString("_swig_gopanic(\"accessing abstract class or protected constructor\");"); + } + +private: + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("go"); + bool display_help = false; + + // Process command line options. + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-package") == 0) { + if (argv[i + 1]) { + package = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-cgo") == 0) { + Swig_mark_arg(i); + cgo_flag = true; + } else if (strcmp(argv[i], "-no-cgo") == 0) { + Swig_mark_arg(i); + cgo_flag = false; + } else if (strcmp(argv[i], "-gccgo") == 0) { + Swig_mark_arg(i); + gccgo_flag = true; + } else if (strcmp(argv[i], "-go-prefix") == 0) { + if (argv[i + 1]) { + prefix_option = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-go-pkgpath") == 0) { + if (argv[i + 1]) { + pkgpath_option = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-import-prefix") == 0) { + if (argv[i + 1]) { + import_prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-use-shlib") == 0) { + Swig_mark_arg(i); + use_shlib = true; + } else if (strcmp(argv[i], "-soname") == 0) { + if (argv[i + 1]) { + soname = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-longsize") == 0) { + // Ignore for backward compatibility. + if (argv[i + 1]) { + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + ++i; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-intgosize") == 0) { + if (argv[i + 1]) { + intgo_type_size = atoi(argv[i + 1]); + if (intgo_type_size != 32 && intgo_type_size != 64) { + Printf(stderr, "-intgosize not 32 or 64\n"); + Swig_arg_error(); + } + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + ++i; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-help") == 0) { + display_help = true; + Printf(stdout, "%s\n", usage); + } + } + } + + if (gccgo_flag && !pkgpath_option && !prefix_option) { + prefix_option = NewString("go"); + } + + // Add preprocessor symbol to parser. + Preprocessor_define("SWIGGO 1", 0); + + if (cgo_flag) { + Preprocessor_define("SWIGGO_CGO 1", 0); + } + + if (gccgo_flag) { + Preprocessor_define("SWIGGO_GCCGO 1", 0); + } + + // This test may be removed in the future, when we can assume that + // everybody has upgraded to Go 1.1. The code below is prepared + // for this test to simply be taken out. + if (intgo_type_size == 0 && !display_help) { + Printf(stderr, "SWIG -go: -intgosize option required but not specified\n"); + SWIG_exit(EXIT_FAILURE); + } + + if (intgo_type_size == 32) { + Preprocessor_define("SWIGGO_INTGO_SIZE 32", 0); + } else if (intgo_type_size == 64) { + Preprocessor_define("SWIGGO_INTGO_SIZE 64", 0); + } else { + Preprocessor_define("SWIGGO_INTGO_SIZE 0", 0); + } + + // Add typemap definitions. + SWIG_typemap_lang("go"); + SWIG_config_file("go.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * + * For 6g/8g, we are going to create the following files: + * + * 1) A .c or .cxx file compiled with gcc. This file will contain + * function wrappers. Each wrapper will take a pointer to a + * struct holding the arguments, unpack them, and call the real + * function. + * + * 2) A .go file which defines the Go form of all types, and which + * defines Go function wrappers. Each wrapper will call the C + * function wrapper in the second file. + * + * 3) A .c file compiled with 6c/8c. This file will define + * Go-callable C function wrappers. Each wrapper will use + * cgocall to call the function wrappers in the first file. + * + * When generating code for gccgo, we don't need the third file, and + * the function wrappers in the first file have a different form. + * + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + if (optionsnode) { + if (Getattr(optionsnode, "directors")) { + allow_directors(); + } + if (Getattr(optionsnode, "dirprot")) { + allow_dirprot(); + } + allow_allprotected(GetFlag(optionsnode, "allprotected")); + } + + module = Getattr(n, "name"); + if (!package) { + package = Copy(module); + } + if (!soname && use_shlib) { + soname = Copy(package); + Append(soname, ".so"); + } + + if (gccgo_flag) { + String *pref; + if (pkgpath_option) { + pref = pkgpath_option; + } else { + pref = prefix_option; + } + go_prefix = NewString(""); + for (char *p = Char(pref); *p != '\0'; p++) { + if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '.' || *p == '$') { + Putc(*p, go_prefix); + } else { + Putc('_', go_prefix); + } + } + if (!pkgpath_option) { + Append(go_prefix, "."); + Append(go_prefix, getModuleName(package)); + } + } + + // Get filenames. + + String *swig_filename = Getattr(n, "infile"); + String *c_filename = Getattr(n, "outfile"); + String *c_filename_h = Getattr(n, "outfile_h"); + + String *go_filename = NewString(""); + Printf(go_filename, "%s%s.go", SWIG_output_directory(), module); + + String *gc_filename = NULL; + if (!gccgo_flag) { + gc_filename = NewString(""); + Printf(gc_filename, "%s%s_gc.c", SWIG_output_directory(), module); + } + + // Generate a unique ID based on a hash of the SWIG input. + swig_uint64 hash = {0, 0}; + FILE *swig_input = Swig_open(swig_filename); + if (swig_input == NULL) { + FileErrorDisplay(swig_filename); + SWIG_exit(EXIT_FAILURE); + } + String *swig_input_content = Swig_read_file(swig_input); + siphash(&hash, Char(swig_input_content), Len(swig_input_content)); + Delete(swig_input_content); + fclose(swig_input); + unique_id = NewString(""); + Printf(unique_id, "_%s_%08x%08x", getModuleName(package), hash.hi, hash.lo); + + // Open files. + + f_c_begin = NewFile(c_filename, "w", SWIG_output_files()); + if (!f_c_begin) { + FileErrorDisplay(c_filename); + SWIG_exit(EXIT_FAILURE); + } + + if (directorsEnabled()) { + if (!c_filename_h) { + Printf(stderr, "Unable to determine outfile_h\n"); + SWIG_exit(EXIT_FAILURE); + } + f_c_directors_h = NewFile(c_filename_h, "w", SWIG_output_files()); + if (!f_c_directors_h) { + FileErrorDisplay(c_filename_h); + SWIG_exit(EXIT_FAILURE); + } + } + + f_go_begin = NewFile(go_filename, "w", SWIG_output_files()); + if (!f_go_begin) { + FileErrorDisplay(go_filename); + SWIG_exit(EXIT_FAILURE); + } + + if (!gccgo_flag && !cgo_flag) { + f_gc_begin = NewFile(gc_filename, "w", SWIG_output_files()); + if (!f_gc_begin) { + FileErrorDisplay(gc_filename); + SWIG_exit(EXIT_FAILURE); + } + } + + f_c_runtime = NewString(""); + f_c_header = NewString(""); + f_c_wrappers = NewString(""); + f_c_init = NewString(""); + f_c_directors = NewString(""); + f_go_imports = NewString(""); + f_go_runtime = NewString(""); + f_go_header = NewString(""); + f_go_wrappers = NewString(""); + f_go_directors = NewString(""); + if (!gccgo_flag && !cgo_flag) { + f_gc_runtime = NewString(""); + f_gc_header = NewString(""); + f_gc_wrappers = NewString(""); + } + if (cgo_flag) { + f_cgo_comment = NewString(""); + f_cgo_comment_typedefs = NewString(""); + } + + Swig_register_filebyname("begin", f_c_begin); + Swig_register_filebyname("runtime", f_c_runtime); + Swig_register_filebyname("header", f_c_header); + Swig_register_filebyname("wrapper", f_c_wrappers); + Swig_register_filebyname("init", f_c_init); + Swig_register_filebyname("director", f_c_directors); + Swig_register_filebyname("director_h", f_c_directors_h); + Swig_register_filebyname("go_begin", f_go_begin); + Swig_register_filebyname("go_imports", f_go_imports); + Swig_register_filebyname("go_runtime", f_go_runtime); + Swig_register_filebyname("go_header", f_go_header); + Swig_register_filebyname("go_wrapper", f_go_wrappers); + Swig_register_filebyname("go_director", f_go_directors); + if (!gccgo_flag && !cgo_flag) { + Swig_register_filebyname("gc_begin", f_gc_begin); + Swig_register_filebyname("gc_runtime", f_gc_runtime); + Swig_register_filebyname("gc_header", f_gc_header); + Swig_register_filebyname("gc_wrapper", f_gc_wrappers); + } + if (cgo_flag) { + Swig_register_filebyname("cgo_comment", f_cgo_comment); + Swig_register_filebyname("cgo_comment_typedefs", f_cgo_comment_typedefs); + } + + Swig_banner(f_c_begin); + if (CPlusPlus) { + Printf(f_c_begin, "\n// source: %s\n\n", swig_filename); + } else { + Printf(f_c_begin, "\n/* source: %s */\n\n", swig_filename); + } + + Printf(f_c_runtime, "#define SWIGMODULE %s\n", module); + if (gccgo_flag) { + Printf(f_c_runtime, "#define SWIGGO_PREFIX %s\n", go_prefix); + } + + if (directorsEnabled()) { + Printf(f_c_runtime, "#define SWIG_DIRECTORS\n"); + + Swig_banner(f_c_directors_h); + Printf(f_c_directors_h, "\n// source: %s\n\n", swig_filename); + + Printf(f_c_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); + Printf(f_c_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module); + Printf(f_c_directors_h, "class Swig_memory;\n\n"); + + Printf(f_c_directors, "\n// C++ director class methods.\n"); + String *filename = Swig_file_filename(c_filename_h); + Printf(f_c_directors, "#include \"%s\"\n\n", filename); + Delete(filename); + } + + Swig_banner(f_go_begin); + Printf(f_go_begin, "\n// source: %s\n", swig_filename); + + if (!gccgo_flag && !cgo_flag && soname) { + Swig_banner(f_gc_begin); + Printf(f_gc_begin, "\n/* source: %s */\n\n", swig_filename); + Printf(f_gc_begin, "\n/* This file should be compiled with 6c/8c. */\n"); + Printf(f_gc_begin, "#pragma dynimport _ _ \"%s\"\n", soname); + } + + if (cgo_flag) { + Printv(f_cgo_comment_typedefs, "/*\n", NULL); + + // The cgo program defines the intgo type after our function + // definitions, but we want those definitions to be able to use + // intgo also. + Printv(f_cgo_comment_typedefs, "#define intgo swig_intgo\n", NULL); + Printv(f_cgo_comment_typedefs, "typedef void *swig_voidp;\n", NULL); + } + + // Output module initialization code. + + Printf(f_go_begin, "\npackage %s\n\n", getModuleName(package)); + + if (gccgo_flag && !cgo_flag) { + Printf(f_go_runtime, "func SwigCgocall()\n"); + Printf(f_go_runtime, "func SwigCgocallDone()\n"); + Printf(f_go_runtime, "func SwigCgocallBack()\n"); + Printf(f_go_runtime, "func SwigCgocallBackDone()\n\n"); + } + + // All the C++ wrappers should be extern "C". + + Printv(f_c_wrappers, "#ifdef __cplusplus\n", "extern \"C\" {\n", "#endif\n\n", NULL); + + // Set up the hash table for types not defined by SWIG. + + undefined_enum_types = NewHash(); + undefined_types = NewHash(); + defined_types = NewHash(); + go_imports = NewHash(); + + // Emit code. + + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_c_runtime); + Swig_insert_file("director.swg", f_c_runtime); + } + + Delete(go_imports); + + // Write out definitions for the types not defined by SWIG. + + if (Len(undefined_enum_types) > 0) + Printv(f_go_wrappers, "\n", NULL); + for (Iterator p = First(undefined_enum_types); p.key; p = Next(p)) { + String *name = p.item; + Printv(f_go_wrappers, "type ", name, " int\n", NULL); + } + + Printv(f_go_wrappers, "\n", NULL); + for (Iterator p = First(undefined_types); p.key; p = Next(p)) { + String *ty = goType(NULL, p.key); + if (!Getattr(defined_types, ty)) { + String *cp = goCPointerType(p.key, false); + if (!Getattr(defined_types, cp)) { + Printv(f_go_wrappers, "type ", cp, " uintptr\n", NULL); + Printv(f_go_wrappers, "type ", ty, " interface {\n", NULL); + Printv(f_go_wrappers, "\tSwigcptr() uintptr;\n", NULL); + Printv(f_go_wrappers, "}\n", NULL); + Printv(f_go_wrappers, "func (p ", cp, ") Swigcptr() uintptr {\n", NULL); + Printv(f_go_wrappers, "\treturn uintptr(p)\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + } + Delete(cp); + } + Delete(ty); + } + Delete(undefined_enum_types); + Delete(undefined_types); + Delete(defined_types); + + /* Write and cleanup */ + + Dump(f_c_header, f_c_runtime); + + if (directorsEnabled()) { + Printf(f_c_directors_h, "#endif\n"); + Delete(f_c_directors_h); + f_c_directors_h = NULL; + + Dump(f_c_directors, f_c_runtime); + Delete(f_c_directors); + f_c_directors = NULL; + } + + // End the extern "C". + Printv(f_c_wrappers, "#ifdef __cplusplus\n", "}\n", "#endif\n\n", NULL); + + if (cgo_flag) { + // End the cgo comment. + Printv(f_cgo_comment, "#undef intgo\n", NULL); + Printv(f_cgo_comment, "*/\n", NULL); + Printv(f_cgo_comment, "import \"C\"\n", NULL); + Printv(f_cgo_comment, "\n", NULL); + } + + Dump(f_c_runtime, f_c_begin); + Dump(f_c_wrappers, f_c_begin); + Dump(f_c_init, f_c_begin); + if (cgo_flag) { + Dump(f_cgo_comment_typedefs, f_go_begin); + Dump(f_cgo_comment, f_go_begin); + } + Dump(f_go_imports, f_go_begin); + Dump(f_go_header, f_go_begin); + Dump(f_go_runtime, f_go_begin); + Dump(f_go_wrappers, f_go_begin); + if (directorsEnabled()) { + Dump(f_go_directors, f_go_begin); + } + if (!gccgo_flag && !cgo_flag) { + Dump(f_gc_header, f_gc_begin); + Dump(f_gc_runtime, f_gc_begin); + Dump(f_gc_wrappers, f_gc_begin); + } + + Delete(f_c_runtime); + Delete(f_c_header); + Delete(f_c_wrappers); + Delete(f_c_init); + Delete(f_go_imports); + Delete(f_go_runtime); + Delete(f_go_header); + Delete(f_go_wrappers); + Delete(f_go_directors); + if (!gccgo_flag && !cgo_flag) { + Delete(f_gc_runtime); + Delete(f_gc_header); + Delete(f_gc_wrappers); + } + if (cgo_flag) { + Delete(f_cgo_comment); + Delete(f_cgo_comment_typedefs); + } + + Delete(f_c_begin); + Delete(f_go_begin); + if (!gccgo_flag && !cgo_flag) { + Delete(f_gc_begin); + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * + * Handle a SWIG import statement by generating a Go import + * statement. + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + String *hold_import = imported_package; + String *modname = Getattr(n, "module"); + if (modname) { + if (!Getattr(go_imports, modname)) { + Setattr(go_imports, modname, modname); + Printv(f_go_imports, "import \"", NULL); + if (import_prefix) { + Printv(f_go_imports, import_prefix, "/", NULL); + } + Printv(f_go_imports, modname, "\"\n", NULL); + } + imported_package = modname; + saw_import = true; + } + int r = Language::importDirective(n); + imported_package = hold_import; + return r; + } + + /* ---------------------------------------------------------------------- + * Language::insertDirective() + * + * If the section is go_imports, store them for later. + * ---------------------------------------------------------------------- */ + virtual int insertDirective(Node *n) { + char *section = Char(Getattr(n, "section")); + if ((ImportMode && !Getattr(n, "generated")) || + !section || (strcmp(section, "go_imports") != 0)) { + return Language::insertDirective(n); + } + + char *code = Char(Getattr(n, "code")); + char *pch = strtok(code, ","); + while (pch != NULL) { + // Do not import same thing more than once. + if (!Getattr(go_imports, pch)) { + Setattr(go_imports, pch, pch); + Printv(f_go_imports, "import ", pch, "\n", NULL); + } + pch = strtok(NULL, ","); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * + * Implement a function. + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + if (GetFlag(n, "feature:ignore")) { + return SWIG_OK; + } + + // We don't need explicit calls. + if (GetFlag(n, "explicitcall")) { + return SWIG_OK; + } + + // Don't emit constructors for abstract director classes. They + // will never succeed anyhow. + if (Swig_methodclass(n) && Swig_directorclass(n) + && Strcmp(Char(Getattr(n, "wrap:action")), director_prot_ctor_code) == 0) { + return SWIG_OK; + } + + String *name = Getattr(n, "sym:name"); + String *nodetype = Getattr(n, "nodeType"); + bool is_static = is_static_member_function || isStatic(n); + bool is_friend = isFriend(n); + bool is_ctor_dtor = false; + + SwigType *result = Getattr(n, "type"); + + // For some reason SWIG changs the "type" value during the call to + // functionWrapper. We need to remember the type for possible + // overload processing. + Setattr(n, "go:type", Copy(result)); + + String *go_name; + + String *r1 = NULL; + if (making_variable_wrappers) { + // Change the name of the variable setter and getter functions + // to be more Go like. + + bool is_set = Strcmp(Char(name) + Len(name) - 4, "_set") == 0; + assert(is_set || Strcmp(Char(name) + Len(name) - 4, "_get") == 0); + + // Start with Set or Get. + go_name = NewString(is_set ? "Set" : "Get"); + + // If this is a static variable, put in the class name, + // capitalized. + if (is_static && class_name) { + String *ccn = exportedName(class_name); + Append(go_name, ccn); + Delete(ccn); + } + + // Add the rest of the name, capitalized, dropping the _set or + // _get. + String *c1 = removeClassname(name); + String *c2 = exportedName(c1); + char *p = Char(c2); + int len = Len(p); + for (int i = 0; i < len - 4; ++i) { + Putc(p[i], go_name); + } + Delete(c2); + Delete(c1); + + if (!checkIgnoredParameters(n, go_name)) { + Delete(go_name); + return SWIG_NOWRAP; + } + } else if (Cmp(nodetype, "constructor") == 0) { + is_ctor_dtor = true; + + // Change the name of a constructor to be more Go like. Change + // new_ to New, and capitalize the class name. + assert(Strncmp(name, "new_", 4) == 0); + String *c1 = NewString(Char(name) + 4); + String *c2 = exportedName(c1); + go_name = NewString("New"); + Append(go_name, c2); + Delete(c2); + Delete(c1); + + if (Swig_methodclass(n) && Swig_directorclass(n)) { + // The core SWIG code skips the first parameter when + // generating the $nondirector_new string. Recreate the + // action in this case. But don't it if we are using the + // special code for an abstract class. + String *call = Swig_cppconstructor_call(getClassType(), + Getattr(n, "parms")); + SwigType *type = Copy(getClassType()); + SwigType_add_pointer(type); + String *cres = Swig_cresult(type, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + } + } else if (Cmp(nodetype, "destructor") == 0) { + // No need to emit protected destructors. + if (!is_public(n)) { + return SWIG_OK; + } + + is_ctor_dtor = true; + + // Change the name of a destructor to be more Go like. Change + // delete_ to Delete and capitalize the class name. + assert(Strncmp(name, "delete_", 7) == 0); + String *c1 = NewString(Char(name) + 7); + String *c2 = exportedName(c1); + go_name = NewString("Delete"); + Append(go_name, c2); + Delete(c2); + Delete(c1); + + result = NewString("void"); + r1 = result; + } else { + if (!checkFunctionVisibility(n, NULL)) { + return SWIG_OK; + } + + go_name = buildGoName(name, is_static, is_friend); + + if (!checkIgnoredParameters(n, go_name)) { + Delete(go_name); + return SWIG_NOWRAP; + } + } + + String *overname = NULL; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + String *scope; + if (!class_name || is_static || is_ctor_dtor) { + scope = NULL; + } else { + scope = NewString("swiggoscope."); + Append(scope, class_name); + } + if (!checkNameConflict(go_name, n, scope)) { + Delete(go_name); + return SWIG_NOWRAP; + } + } + + String *wname = Swig_name_wrapper(name); + if (overname) { + Append(wname, overname); + } + Append(wname, unique_id); + Setattr(n, "wrap:name", wname); + + ParmList *parms = Getattr(n, "parms"); + Setattr(n, "wrap:parms", parms); + + int r = makeWrappers(n, name, go_name, overname, wname, NULL, parms, result, is_static); + if (r != SWIG_OK) { + return r; + } + + if (Getattr(n, "sym:overloaded") && !Getattr(n, "sym:nextSibling")) { + String *scope ; + if (!class_name || is_static || is_ctor_dtor) { + scope = NULL; + } else { + scope = NewString("swiggoscope."); + Append(scope, class_name); + } + if (!checkNameConflict(go_name, n, scope)) { + Delete(go_name); + return SWIG_NOWRAP; + } + + String *receiver = class_receiver; + if (is_static || is_ctor_dtor) { + receiver = NULL; + } + r = makeDispatchFunction(n, go_name, receiver, is_static, NULL, false); + if (r != SWIG_OK) { + return r; + } + } + + Delete(wname); + Delete(go_name); + Delete(r1); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * For some reason the language code removes the "storage" attribute + * for a static function before calling functionWrapper, which means + * that we have no way of knowing whether a function is static or + * not. That makes no sense in the Go context. Here we note that a + * function is static. + * ---------------------------------------------------------------------- */ + + int staticmemberfunctionHandler(Node *n) { + assert(!is_static_member_function); + is_static_member_function = true; + int r = Language::staticmemberfunctionHandler(n); + is_static_member_function = false; + return r; + } + + /* ---------------------------------------------------------------------- + * makeWrappers() + * + * Write out the various function wrappers. + * n: The function we are emitting. + * name: The function name. + * go_name: The name of the function in Go. + * overname: The overload string for overloaded function. + * wname: The SWIG wrapped name--the name of the C function. + * base: A list of the names of base classes, in the case where this + * is a virtual method not defined in the current class. + * parms: The parameters. + * result: The result type. + * is_static: Whether this is a static method or member. + * ---------------------------------------------------------------------- */ + + int makeWrappers(Node *n, String *name, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { + + assert(result); + + int ret = SWIG_OK; + + if (cgo_flag) { + int r = makeCgoWrappers(n, go_name, overname, wname, base, parms, result, is_static); + if (r != SWIG_OK) { + ret = r; + } + } else { + int r = goFunctionWrapper(n, name, go_name, overname, wname, base, parms, result, is_static); + if (r != SWIG_OK) { + ret = r; + } + + if (!gccgo_flag) { + r = gcFunctionWrapper(wname); + if (r != SWIG_OK) { + ret = r; + } + r = gccFunctionWrapper(n, base, wname, parms, result); + if (r != SWIG_OK) { + ret = r; + } + } else { + r = gccgoFunctionWrapper(n, base, wname, parms, result); + if (r != SWIG_OK) { + ret = r; + } + } + } + + if (class_methods) { + Setattr(class_methods, Getattr(n, "name"), NewString("")); + } + + return ret; + } + + /* ---------------------------------------------------------------------- + * struct cgoWrapperInfo + * + * Information needed by the CGO wrapper functions. + * ---------------------------------------------------------------------- */ + + struct cgoWrapperInfo { + // The function we are generating code for. + Node *n; + // The name of the Go function. + String *go_name; + // The overload string for an overloaded function. + String *overname; + // The name of the C wrapper function. + String *wname; + // The base classes. + List *base; + // The parameters. + ParmList *parms; + // The result type. + SwigType *result; + // Whether this is a static function, not a class method. + bool is_static; + // The Go receiver type. + String *receiver; + // Whether this is a class constructor. + bool is_constructor; + // Whether this is a class destructor. + bool is_destructor; + }; + + /* ---------------------------------------------------------------------- + * makeCgoWrappers() + * + * Write out the wrappers for a function when producing cgo input + * files. + * ---------------------------------------------------------------------- */ + + int makeCgoWrappers(Node *n, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { + Swig_save("makeCgoWrappers", n, "emit:cgotype", "emit:cgotypestruct", NULL); + + cgoWrapperInfo info; + + info.n = n; + info.go_name = go_name; + info.overname = overname; + info.wname = wname; + info.base = base; + info.parms = parms; + info.result = result; + info.is_static = is_static; + + info.receiver = class_receiver; + if (is_static) { + info.receiver = NULL; + } + + String *nodetype = Getattr(n, "nodeType"); + info.is_constructor = Cmp(nodetype, "constructor") == 0; + info.is_destructor = Cmp(nodetype, "destructor") == 0; + if (info.is_constructor || info.is_destructor) { + assert(class_receiver); + assert(!base); + info.receiver = NULL; + } + + int ret = SWIG_OK; + + int r = cgoGoWrapper(&info); + if (r != SWIG_OK) { + ret = r; + } + + r = cgoCommentWrapper(&info); + if (r != SWIG_OK) { + ret = r; + } + + r = cgoGccWrapper(&info); + if (r != SWIG_OK) { + ret = r; + } + + Swig_restore(n); + + return ret; + } + + /* ---------------------------------------------------------------------- + * cgoGoWrapper() + * + * Write out Go code to call a cgo function. This code will go into + * the generated Go output file. + * ---------------------------------------------------------------------- */ + int cgoGoWrapper(const cgoWrapperInfo *info) { + + Wrapper *dummy = initGoTypemaps(info->parms); + + bool add_to_interface = interfaces && !info->is_constructor && !info->is_destructor && !info->is_static && !info->overname && checkFunctionVisibility(info->n, NULL); + + Printv(f_go_wrappers, "func ", NULL); + + Parm *p = info->parms; + int pi = 0; + + // Add the receiver first if this is a method. + if (info->receiver) { + Printv(f_go_wrappers, "(", NULL); + if (info->base && info->receiver) { + Printv(f_go_wrappers, "_swig_base", NULL); + } else { + Printv(f_go_wrappers, Getattr(p, "lname"), NULL); + p = nextParm(p); + ++pi; + } + Printv(f_go_wrappers, " ", info->receiver, ") ", NULL); + } + + Printv(f_go_wrappers, info->go_name, NULL); + if (info->overname) { + Printv(f_go_wrappers, info->overname, NULL); + } + Printv(f_go_wrappers, "(", NULL); + + // If we are doing methods, add this method to the interface. + if (add_to_interface) { + Printv(interfaces, "\t", info->go_name, "(", NULL); + } + + // Write out the parameters to both the function definition and + // the interface. + + String *parm_print = NewString(""); + + int parm_count = emit_num_arguments(info->parms); + int required_count = emit_num_required(info->parms); + int args = 0; + + for (; pi < parm_count; ++pi) { + p = getParm(p); + if (pi == 0 && info->is_destructor) { + String *cl = exportedName(class_name); + Printv(parm_print, Getattr(p, "lname"), " ", cl, NULL); + Delete(cl); + ++args; + } else { + if (args > 0) { + Printv(parm_print, ", ", NULL); + } + ++args; + if (pi >= required_count) { + Printv(parm_print, "_swig_args ...interface{}", NULL); + break; + } + Printv(parm_print, Getattr(p, "lname"), " ", NULL); + String *tm = goType(p, Getattr(p, "type")); + Printv(parm_print, tm, NULL); + Delete(tm); + } + p = nextParm(p); + } + + Printv(parm_print, ")", NULL); + + // Write out the result type. + if (info->is_constructor) { + String *cl = exportedName(class_name); + Printv(parm_print, " (_swig_ret ", cl, ")", NULL); + Delete(cl); + } else { + if (SwigType_type(info->result) != T_VOID) { + String *tm = goType(info->n, info->result); + Printv(parm_print, " (_swig_ret ", tm, ")", NULL); + Delete(tm); + } + } + + Printv(f_go_wrappers, parm_print, NULL); + if (add_to_interface) { + Printv(interfaces, parm_print, "\n", NULL); + } + + // Write out the function body. + + Printv(f_go_wrappers, " {\n", NULL); + + if (parm_count > required_count) { + Parm *p = info->parms; + int i; + for (i = 0; i < required_count; ++i) { + p = getParm(p); + p = nextParm(p); + } + for (; i < parm_count; ++i) { + p = getParm(p); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, "\tvar ", Getattr(p, "lname"), " ", tm, "\n", NULL); + Printf(f_go_wrappers, "\tif len(_swig_args) > %d {\n", i - required_count); + Printf(f_go_wrappers, "\t\t%s = _swig_args[%d].(%s)\n", Getattr(p, "lname"), i - required_count, tm); + Printv(f_go_wrappers, "\t}\n", NULL); + Delete(tm); + p = nextParm(p); + } + } + + String *call = NewString("\t"); + + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; + if (SwigType_type(info->result) != T_VOID) { + if (info->is_constructor) { + ret_type = exportedName(class_name); + } else { + ret_type = goImType(info->n, info->result); + } + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); + + bool c_struct_type; + Delete(cgoTypeForGoValue(info->n, info->result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = (", ret_type, ")(", NULL); + } + + if (info->is_constructor || goTypeIsInterface(info->n, info->result)) { + if (info->is_constructor) { + wt = Copy(class_receiver); + } else { + wt = goWrapperType(info->n, info->result, true); + } + Printv(call, wt, "(", NULL); + } + } + + Printv(call, "C.", info->wname, "(", NULL); + + args = 0; + + if (parm_count > required_count) { + Printv(call, "C.swig_intgo(len(_swig_args))", NULL); + ++args; + } + + if (info->base && info->receiver) { + if (args > 0) { + Printv(call, ", ", NULL); + } + ++args; + Printv(call, "C.uintptr_t(_swig_base)", NULL); + } + + p = info->parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (args > 0) { + Printv(call, ", ", NULL); + } + ++args; + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + String *ivar = NewStringf("_swig_i_%d", i); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if ((i == 0 && info->is_destructor) || ((i > 0 || !info->receiver || info->base || info->is_constructor) && goTypeIsInterface(p, pt))) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + Setattr(p, "emit:goinput", ln); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, "\n", NULL); + Delete(goin); + Setattr(p, "emit:goinput", ivar); + } + + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + Delete(ct); + + p = nextParm(p); + } + + Printv(f_go_wrappers, call, ")", NULL); + Delete(call); + + if (wt) { + // Close the type conversion to the wrapper type. + Printv(f_go_wrappers, ")", NULL); + } + if (SwigType_type(info->result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(f_go_wrappers, ")", NULL); + } + + Printv(f_go_wrappers, "\n", NULL); + + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + if (ret_type) { + Delete(ret_type); + } + + goargout(info->parms); + + if (SwigType_type(info->result) != T_VOID) { + + Swig_save("cgoGoWrapper", info->n, "type", "tmap:goout", NULL); + Setattr(info->n, "type", info->result); + + String *goout = goTypemapLookup("goout", info->n, "swig_r"); + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goType(info->n, info->result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + goout = Copy(goout); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + + Swig_restore(info->n); + } + + Printv(f_go_wrappers, "}\n\n", NULL); + + DelWrapper(dummy); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * cgoCommentWrapper() + * + * Write out a cgo function to call a C/C++ function. This code + * will go into the cgo comment in the generated Go output file. + * ---------------------------------------------------------------------- */ + int cgoCommentWrapper(const cgoWrapperInfo *info) { + String *ret_type; + if (SwigType_type(info->result) == T_VOID) { + ret_type = NewString("void"); + } else { + bool c_struct_type; + ret_type = cgoTypeForGoValue(info->n, info->result, &c_struct_type); + } + + Printv(f_cgo_comment, "extern ", ret_type, " ", info->wname, "(", NULL); + + Delete(ret_type); + + int parm_count = emit_num_arguments(info->parms); + int required_count = emit_num_required(info->parms); + int args = 0; + + if (parm_count > required_count) { + Printv(f_cgo_comment, "intgo _swig_args", NULL); + ++args; + } + + if (info->base && info->receiver) { + if (args > 0) { + Printv(f_cgo_comment, ", ", NULL); + } + ++args; + Printv(f_cgo_comment, "uintptr_t _swig_base", NULL); + } + + Parm *p = info->parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (args > 0) { + Printv(f_cgo_comment, ", ", NULL); + } + ++args; + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + Printv(f_cgo_comment, ct, " ", ln, NULL); + Delete(ct); + + p = nextParm(p); + } + + if (args == 0) { + Printv(f_cgo_comment, "void", NULL); + } + + Printv(f_cgo_comment, ");\n", NULL); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * cgoGccWrapper() + * + * Write out code to the C/C++ wrapper file. This code will be + * called by the code generated by cgoCommentWrapper. + * ---------------------------------------------------------------------- */ + int cgoGccWrapper(const cgoWrapperInfo *info) { + Wrapper *f = NewWrapper(); + + Swig_save("cgoGccWrapper", info->n, "parms", NULL); + + ParmList *parms = info->parms; + + Parm *base_parm = NULL; + if (info->base && !isStatic(info->n)) { + SwigType *base_type = Copy(getClassType()); + SwigType_add_pointer(base_type); + base_parm = NewParm(base_type, NewString("arg1"), info->n); + set_nextSibling(base_parm, parms); + parms = base_parm; + } + + emit_parameter_variables(parms, f); + emit_attach_parmmaps(parms, f); + int parm_count = emit_num_arguments(parms); + int required_count = emit_num_required(parms); + + emit_return_variable(info->n, info->result, f); + + // Start the function definition. + + String *fnname = NewString(""); + Printv(fnname, info->wname, "(", NULL); + + int args = 0; + + if (parm_count > required_count) { + Printv(fnname, "intgo _swig_optargc", NULL); + ++args; + } + + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + if (args > 0) { + Printv(fnname, ", ", NULL); + } + ++args; + + p = getParm(p); + + SwigType *pt = Copy(Getattr(p, "type")); + if (SwigType_isarray(pt)) { + SwigType_del_array(pt); + SwigType_add_pointer(pt); + } + String *pn = NewStringf("_swig_go_%d", i); + String *ct = gcCTypeForGoValue(p, pt, pn); + Printv(fnname, ct, NULL); + Delete(ct); + Delete(pn); + Delete(pt); + + p = nextParm(p); + } + + Printv(fnname, ")", NULL); + + if (SwigType_type(info->result) == T_VOID) { + Printv(f->def, "void ", fnname, NULL); + } else { + String *ct = gcCTypeForGoValue(info->n, info->result, fnname); + Printv(f->def, ct, NULL); + Delete(ct); + + String *ln = NewString("_swig_go_result"); + ct = gcCTypeForGoValue(info->n, info->result, ln); + Wrapper_add_local(f, "_swig_go_result", ct); + Delete(ct); + Delete(ln); + } + + Delete(fnname); + + Printv(f->def, " {\n", NULL); + + // Apply the in typemaps. + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = Getattr(p, "tmap:in"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + String *pn = NewStringf("_swig_go_%d", i); + Replaceall(tm, "$input", pn); + if (i < required_count) { + Printv(f->code, "\t", tm, "\n", NULL); + } else { + Printf(f->code, "\tif (_swig_optargc > %d) {\n", i - required_count); + Printv(f->code, "\t\t", tm, "\n", NULL); + Printv(f->code, "\t}\n", NULL); + } + Delete(tm); + Setattr(p, "emit:input", pn); + } + p = nextParm(p); + } + + Printv(f->code, "\n", NULL); + + // Do the real work of the function. + + checkConstraints(parms, f); + + emitGoAction(info->n, info->base, parms, info->result, f); + + argout(parms, f); + + cleanupFunction(info->n, f, parms); + + if (SwigType_type(info->result) != T_VOID) { + Printv(f->code, "\treturn _swig_go_result;\n", NULL); + } + + Printv(f->code, "}\n", NULL); + + Wrapper_print(f, f_c_wrappers); + + Swig_restore(info->n); + + DelWrapper(f); + if (base_parm) { + Delete(base_parm); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * goFunctionWrapper() + * + * Write out a function wrapper in Go. When not implementing a + * method, the actual code is all in C; here we just declare the C + * function. When implementing a method, we have to call the C + * function, because it will have a different name. If base is not + * NULL, then we are being called to forward a virtual method to a + * base class. + * ---------------------------------------------------------------------- */ + + int goFunctionWrapper(Node *n, String *name, String *go_name, String *overname, String *wname, List *base, ParmList *parms, SwigType *result, bool is_static) { + Wrapper *dummy = initGoTypemaps(parms); + + int parm_count = emit_num_arguments(parms); + int required_count = emit_num_required(parms); + + String *receiver = class_receiver; + if (receiver && is_static) { + receiver = NULL; + } + + String *nodetype = Getattr(n, "nodeType"); + bool is_constructor = Cmp(nodetype, "constructor") == 0; + bool is_destructor = Cmp(nodetype, "destructor") == 0; + if (is_constructor || is_destructor) { + assert(class_receiver); + assert(!base); + receiver = NULL; + } + + Swig_save("cgoGoWrapper", n, "type", "tmap:goout", NULL); + Setattr(n, "type", result); + + String *goout = goTypemapLookup("goout", n, "swig_r"); + + Swig_restore(n); + + bool add_to_interface = (interfaces && !is_constructor && !is_destructor && !is_static && !overname && checkFunctionVisibility(n, NULL)); + + bool needs_wrapper = (gccgo_flag || receiver || is_constructor || is_destructor || parm_count > required_count); + + bool has_goout = false; + if (goout) { + has_goout = true; + } + + // See whether any of the function parameters are represented by + // interface values. When calling the C++ code, we need to convert + // back to a uintptr. + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *ty = Getattr(p, "type"); + if (goGetattr(p, "tmap:goargout")) { + has_goout = true; + needs_wrapper = true; + } else if (goTypeIsInterface(p, ty) || goGetattr(p, "tmap:goin")) { + needs_wrapper = true; + } + + if (paramNeedsEscape(p)) { + needs_wrapper = true; + } + + p = nextParm(p); + } + if (goTypeIsInterface(n, result) || goout != NULL) { + needs_wrapper = true; + } + + if (!gccgo_flag) { + Printv(f_go_wrappers, "var ", wname, " unsafe.Pointer\n\n", NULL); + } + + // If this is a method, first declare the C function we will call. + // If we do not need a wrapper, then we will only be writing a + // declaration. + String *wrapper_name = NULL; + if (needs_wrapper) { + wrapper_name = buildGoWrapperName(name, overname); + + if (gccgo_flag) { + Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL); + } + + bool arg = false; + Printv(f_go_wrappers, "func ", wrapper_name, "(", NULL); + if (parm_count > required_count) { + Printv(f_go_wrappers, argName(&arg), " int", NULL); + } + Parm *p = getParm(parms); + int i = 0; + if (is_destructor) { + if (parm_count > required_count) { + Printv(f_go_wrappers, ", ", NULL); + } + Printv(f_go_wrappers, argName(&arg), " uintptr", NULL); + ++i; + p = nextParm(p); + } else if (receiver && (base || !is_constructor)) { + if (parm_count > required_count) { + Printv(f_go_wrappers, ", ", NULL); + } + Printv(f_go_wrappers, argName(&arg), " ", receiver, NULL); + if (!base) { + ++i; + p = nextParm(p); + } + } + for (; i < parm_count; ++i) { + p = getParm(p); + if (i > 0 || (base && receiver) || parm_count > required_count) { + Printv(f_go_wrappers, ", ", NULL); + } + String *tm = goWrapperType(p, Getattr(p, "type"), false); + Printv(f_go_wrappers, argName(&arg), " ", tm, NULL); + Delete(tm); + p = nextParm(p); + } + Printv(f_go_wrappers, ")", NULL); + if (is_constructor) { + Printv(f_go_wrappers, " (", argName(&arg), " ", class_receiver, ")", NULL); + } else { + if (SwigType_type(result) != T_VOID) { + String *tm = goWrapperType(n, result, true); + Printv(f_go_wrappers, " (", argName(&arg), " ", tm, ")", NULL); + Delete(tm); + } + } + + if (!gccgo_flag) { + Printv(f_go_wrappers, " {\n", NULL); + if (arg) { + Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&base))\n", NULL); + } else { + Printv(f_go_wrappers, "\tvar _swig_p uintptr\n", NULL); + } + Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", wname, ", _swig_p)\n", NULL); + Printv(f_go_wrappers, "\treturn\n", NULL); + Printv(f_go_wrappers, "}", NULL); + } + + Printv(f_go_wrappers, "\n\n", NULL); + } + + // Start defining the Go function. + + if (!needs_wrapper && gccgo_flag) { + Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL); + } + + Printv(f_go_wrappers, "func ", NULL); + + p = parms; + int pi = 0; + + // Add the receiver if this is a method. + String *first = NULL; + if (receiver) { + Printv(f_go_wrappers, "(", NULL); + if (base && receiver) { + Printv(f_go_wrappers, "_swig_base", NULL); + if (first == NULL) { + first = NewString("_swig_base"); + } + } else { + Printv(f_go_wrappers, Getattr(p, "lname"), NULL); + if (first == NULL) { + first = Copy(Getattr(p, "lname")); + } + p = nextParm(p); + ++pi; + } + Printv(f_go_wrappers, " ", receiver, ") ", NULL); + } + + Printv(f_go_wrappers, go_name, NULL); + if (overname) { + Printv(f_go_wrappers, overname, NULL); + } + Printv(f_go_wrappers, "(", NULL); + + // If we are doing methods, add this function to the interface. + if (add_to_interface) { + Printv(interfaces, "\t", go_name, "(", NULL); + } + + // Write out the parameters to both the function definition and + // the interface. + + String *parm_print = NewString(""); + + for (; pi < parm_count; ++pi) { + p = getParm(p); + if (pi == 0 && is_destructor) { + String *cl = exportedName(class_name); + Printv(parm_print, Getattr(p, "lname"), " ", cl, NULL); + if (first == NULL) { + first = Copy(Getattr(p, "lname")); + } + Delete(cl); + } else { + if (pi > (receiver && !base ? 1 : 0)) { + Printv(parm_print, ", ", NULL); + } + if (pi >= required_count) { + Printv(parm_print, "_swig_args ...interface{}", NULL); + if (first == NULL) { + first = NewString("_swig_args"); + } + break; + } + Printv(parm_print, Getattr(p, "lname"), " ", NULL); + if (first == NULL) { + first = Copy(Getattr(p, "lname")); + } + String *tm = goType(p, Getattr(p, "type")); + Printv(parm_print, tm, NULL); + Delete(tm); + } + p = nextParm(p); + } + + Printv(parm_print, ")", NULL); + + // Write out the result type. + if (is_constructor) { + String *cl = exportedName(class_name); + Printv(parm_print, " (_swig_ret ", cl, ")", NULL); + if (first == NULL) { + first = NewString("_swig_ret"); + } + Delete(cl); + } else { + if (SwigType_type(result) != T_VOID) { + String *tm = goType(n, result); + Printv(parm_print, " (_swig_ret ", tm, ")", NULL); + if (first == NULL) { + first = NewString("_swig_ret"); + } + Delete(tm); + } + } + + Printv(f_go_wrappers, parm_print, NULL); + if (add_to_interface) { + Printv(interfaces, parm_print, "\n", NULL); + } + + // If this is a wrapper, we need to actually call the C function. + if (needs_wrapper) { + Printv(f_go_wrappers, " {\n", NULL); + + if (parm_count > required_count) { + Parm *p = parms; + int i; + for (i = 0; i < required_count; ++i) { + p = getParm(p); + p = nextParm(p); + } + for (; i < parm_count; ++i) { + p = getParm(p); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, "\tvar ", Getattr(p, "lname"), " ", tm, "\n", NULL); + Printf(f_go_wrappers, "\tif len(_swig_args) > %d {\n", i - required_count); + Printf(f_go_wrappers, "\t\t%s = _swig_args[%d].(%s)\n", Getattr(p, "lname"), i - required_count, tm); + Printv(f_go_wrappers, "\t}\n", NULL); + Delete(tm); + p = nextParm(p); + } + } + + String *call = NewString(""); + + bool need_return_var = SwigType_type(result) != T_VOID && ((gccgo_flag && is_constructor) || has_goout); + if (need_return_var) { + Printv(f_go_wrappers, "\tvar swig_r ", NULL); + if (is_constructor) { + String *cl = exportedName(class_name); + Printv(f_go_wrappers, cl, NULL); + Delete(cl); + } else { + Printv(f_go_wrappers, goImType(n, result), NULL); + } + Printv(f_go_wrappers, "\n", NULL); + } + + if (gccgo_flag) { + if (has_goout || is_constructor) { + Printv(call, "\tfunc() {\n", NULL); + } + Printv(call, "\tdefer SwigCgocallDone()\n", NULL); + Printv(call, "\tSwigCgocall()\n", NULL); + } + + Printv(call, "\t", NULL); + if (SwigType_type(result) != T_VOID) { + if (need_return_var) { + Printv(call, "swig_r = ", NULL); + } else { + Printv(call, "return ", NULL); + } + } + + Printv(call, wrapper_name, "(", NULL); + + if (parm_count > required_count) { + Printv(call, "len(_swig_args)", NULL); + } + + if (base && receiver) { + if (parm_count > required_count) { + Printv(call, ", ", NULL); + } + Printv(call, "_swig_base", NULL); + } + + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (i > 0 || (base && receiver) + || parm_count > required_count) { + Printv(call, ", ", NULL); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(call, ln, NULL); + if ((i == 0 && is_destructor) || ((i > 0 || !receiver || base || is_constructor) && goTypeIsInterface(p, pt))) { + Printv(call, ".Swigcptr()", NULL); + } + Setattr(p, "emit:goinput", ln); + } else { + String *ivar = NewString(""); + Printf(ivar, "_swig_i_%d", i); + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, "\n", NULL); + Delete(goin); + Printv(call, ivar, NULL); + Setattr(p, "emit:goinput", ivar); + } + + // If the parameter has an argout or freearg typemap, make + // sure that it escapes. + if (paramNeedsEscape(p)) { + Printv(f_go_wrappers, "\tif Swig_escape_always_false {\n", NULL); + Printv(f_go_wrappers, "\t\tSwig_escape_val = ", Getattr(p, "emit:goinput"), "\n", NULL); + Printv(f_go_wrappers, "\t}\n", NULL); + } + + p = nextParm(p); + } + Printv(call, ")\n", NULL); + + if (gccgo_flag && (has_goout || is_constructor)) { + Printv(call, "\t}()\n", NULL); + } + + Printv(f_go_wrappers, call, NULL); + Delete(call); + + goargout(parms); + + if (need_return_var) { + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goType(n, result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + } + + Printv(f_go_wrappers, "}\n", NULL); + } else if (!gccgo_flag) { + // We don't need a wrapper. If we're using gccgo, the function + // declaration is all we need--it has a //extern comment to + // GCC-compiled wrapper. If we're not using gccgo, we need to + // call the GCC-compiled wrapper here. + Printv(f_go_wrappers, " {\n", NULL); + if (first == NULL) { + Printv(f_go_wrappers, "\tvar _swig_p uintptr\n", NULL); + } else { + Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&", first, "))\n", NULL); + } + Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", wname, ", _swig_p)\n", NULL); + Printv(f_go_wrappers, "\treturn\n", NULL); + Printv(f_go_wrappers, "}", NULL); + } + + Printv(f_go_wrappers, "\n", NULL); + + Delete(wrapper_name); + DelWrapper(dummy); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * initGoTypemaps() + * + * Initialize the typenames for a Go wrapper, returning a dummy + * Wrapper*. Also set consistent names for the parameters. + * ---------------------------------------------------------------------- */ + + Wrapper* initGoTypemaps(ParmList *parms) { + Wrapper *dummy = NewWrapper(); + emit_attach_parmmaps(parms, dummy); + + Parm *p = parms; + int parm_count = emit_num_arguments(parms); + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + Swig_cparm_name(p, i); + p = nextParm(p); + } + + Swig_typemap_attach_parms("default", parms, dummy); + Swig_typemap_attach_parms("gotype", parms, dummy); + Swig_typemap_attach_parms("goin", parms, dummy); + Swig_typemap_attach_parms("goargout", parms, dummy); + Swig_typemap_attach_parms("imtype", parms, dummy); + + return dummy; + } + + /* ---------------------------------------------------------------------- + * argName() + * + * A helper for goFunctionWrapper to output the first argument name + * as "base" and all others as "_". + * ---------------------------------------------------------------------- */ + + const char *argName(bool *arg) { + if (*arg) { + return "_"; + } + *arg = true; + return "base"; + } + + /* ---------------------------------------------------------------------- + * paramNeedsEscape() + * + * A helper for goFunctionWrapper that returns whether a parameter + * needs to explicitly escape. This is true if the parameter has a + * non-empty argout or freearg typemap, because in those cases the + * Go argument might be or contain a pointer. We need to ensure + * that that pointer does not point into the stack, which means that + * it needs to escape. + * ---------------------------------------------------------------------- */ + bool paramNeedsEscape(Parm *p) { + String *argout = Getattr(p, "tmap:argout"); + String *freearg = Getattr(p, "tmap:freearg"); + if ((!argout || Len(argout) == 0) && (!freearg || Len(freearg) == 0)) { + return false; + } + // If a C++ type is represented as an interface type in Go, then + // we don't care whether it escapes, because we know that the + // pointer is a C++ pointer. + if (goTypeIsInterface(p, Getattr(p, "type"))) { + return false; + } + return true; + } + + /* ---------------------------------------------------------------------- + * gcFunctionWrapper() + * + * This is used for 6g/8g, not for gccgo. Write out the function + * redirector that will be compiled with 6c/8c. This used to write + * out a real function wrapper, but that has moved into Go code. + * ---------------------------------------------------------------------- */ + + int gcFunctionWrapper(String *wname) { + Wrapper *f = NewWrapper(); + + Printv(f->def, "#pragma dynimport ", wname, " ", wname, " \"\"\n", NULL); + Printv(f->def, "#pragma cgo_import_static ", wname, "\n", NULL); + Printv(f->def, "extern void ", wname, "(void*);\n", NULL); + // Declare this as a uintptr, since it is not a pointer into the + // Go heap. + // \xc2\xb7 is UTF-8 for U+00B7 which is Unicode 'Middle Dot' + Printv(f->def, "uintptr \xc2\xb7", wname, " = (uintptr)", wname, ";\n", NULL); + + Wrapper_print(f, f_gc_wrappers); + + DelWrapper(f); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * gccFunctionWrapper() + * + * This is used for 6g/8g, not for gccgo. Write out the function + * wrapper which will be compiled with gcc. If the base parameter + * is not NULL, this is calls the base class method rather than + * executing the SWIG wrapper code. + * ---------------------------------------------------------------------- */ + + int gccFunctionWrapper(Node *n, List *base, String *wname, ParmList *parms, SwigType *result) { + Wrapper *f = NewWrapper(); + + Swig_save("gccFunctionWrapper", n, "parms", NULL); + + Parm *base_parm = NULL; + if (base && !isStatic(n)) { + SwigType *base_type = Copy(getClassType()); + SwigType_add_pointer(base_type); + base_parm = NewParm(base_type, NewString("arg1"), n); + set_nextSibling(base_parm, parms); + parms = base_parm; + } + + emit_parameter_variables(parms, f); + emit_attach_parmmaps(parms, f); + int parm_count = emit_num_arguments(parms); + int required_count = emit_num_required(parms); + bool needs_swigargs = false; + + emit_return_variable(n, result, f); + + // Start the function definition. + + Printv(f->def, "void\n", wname, "(void *swig_v)\n", "{\n", NULL); + + // The single function parameter is a pointer to the real argument + // values. Define the structure that it points to. + + String *swigargs = NewString("\tstruct swigargs {\n"); + + if (parm_count > required_count) { + needs_swigargs = true; + Printv(swigargs, "\t\tintgo _swig_optargc;\n", NULL); + } + + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + + String *ln = Getattr(p, "lname"); + SwigType *pt = Getattr(p, "type"); + String *ct = gcCTypeForGoValue(p, pt, ln); + Printv(swigargs, "\t\t\t", ct, ";\n", NULL); + needs_swigargs = true; + Delete(ct); + + String *gn = NewStringf("_swig_go_%d", i); + ct = gcCTypeForGoValue(p, pt, gn); + Setattr(p, "emit:input", gn); + Wrapper_add_local(f, gn, ct); + Delete(ct); + + p = nextParm(p); + } + if (SwigType_type(result) != T_VOID) { + Printv(swigargs, "\t\tlong : 0;\n", NULL); + String *ln = NewString(Swig_cresult_name()); + String *ct = gcCTypeForGoValue(n, result, ln); + Delete(ln); + Printv(swigargs, "\t\t", ct, ";\n", NULL); + needs_swigargs = true; + Delete(ct); + + ln = NewString("_swig_go_result"); + ct = gcCTypeForGoValue(n, result, ln); + Wrapper_add_local(f, "_swig_go_result", ct); + Delete(ct); + Delete(ln); + } + Printv(swigargs, "\t} SWIGSTRUCTPACKED *swig_a = (struct swigargs *) swig_v;\n", NULL); + + // Copy the input arguments out of the structure into the Go local + // variables. + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *ln = Getattr(p, "lname"); + String *gn = Getattr(p, "emit:input"); + Printv(f->code, "\t", gn, " = swig_a->", ln, ";\n", NULL); + p = nextParm(p); + } + + // Apply the in typemaps. + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = Getattr(p, "tmap:in"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + String *gn = Getattr(p, "emit:input"); + Replaceall(tm, "$input", gn); + if (i < required_count) { + Printv(f->code, "\t", tm, "\n", NULL); + } else { + Printf(f->code, "\tif (swig_a->_swig_optargc > %d) {\n", i - required_count); + Printv(f->code, "\t\t", tm, "\n", NULL); + Printv(f->code, "\t}\n", NULL); + } + Delete(tm); + } + p = nextParm(p); + } + + Printv(f->code, "\n", NULL); + + // Do the real work of the function. + + checkConstraints(parms, f); + + emitGoAction(n, base, parms, result, f); + + argout(parms, f); + + cleanupFunction(n, f, parms); + + if (needs_swigargs) + { + Printv(f->locals, swigargs, NULL); + } + + Printv(f->code, "}\n", NULL); + + Wrapper_print(f, f_c_wrappers); + + Swig_restore(n); + + Delete(swigargs); + DelWrapper(f); + Delete(base_parm); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * gccgoFunctionWrapper() + * + * This is used for gccgo, not 6g/8g. Write out the function + * wrapper which will be compiled with gcc. If the base parameter + * is not NULL, this is calls the base class method rather than + * executing the SWIG wrapper code. + * ---------------------------------------------------------------------- */ + + int gccgoFunctionWrapper(Node *n, List *base, String *wname, ParmList *parms, SwigType *result) { + Wrapper *f = NewWrapper(); + + Swig_save("gccgoFunctionWrapper", n, "parms", NULL); + + Parm *base_parm = NULL; + if (base && !isStatic(n)) { + SwigType *base_type = Copy(getClassType()); + SwigType_add_pointer(base_type); + base_parm = NewParm(base_type, NewString("arg1"), n); + set_nextSibling(base_parm, parms); + parms = base_parm; + } + + emit_parameter_variables(parms, f); + emit_attach_parmmaps(parms, f); + int parm_count = emit_num_arguments(parms); + int required_count = emit_num_required(parms); + + emit_return_variable(n, result, f); + + // Start the function definition. + + String *fnname = NewString(""); + Printv(fnname, "go_", wname, "(", NULL); + + if (parm_count > required_count) { + Printv(fnname, "intgo _swig_optargc", NULL); + } + + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + SwigType *pt = Copy(Getattr(p, "type")); + if (SwigType_isarray(pt)) { + SwigType_del_array(pt); + SwigType_add_pointer(pt); + } + String *pn = NewString("g"); + Append(pn, Getattr(p, "lname")); + String *ct = gccgoCTypeForGoValue(p, pt, pn); + if (i > 0 || parm_count > required_count) { + Printv(fnname, ", ", NULL); + } + Printv(fnname, ct, NULL); + Delete(ct); + Delete(pn); + Delete(pt); + p = nextParm(p); + } + + Printv(fnname, ")", NULL); + + String *fndef = NewString(""); + if (SwigType_type(result) == T_VOID) { + Printv(fndef, "void ", fnname, NULL); + } else { + String *ct = gccgoCTypeForGoValue(n, result, fnname); + Printv(fndef, ct, NULL); + Delete(ct); + } + + Printv(f->def, fndef, " __asm__(\"", go_prefix, "_", wname, "\");\n", NULL); + + Printv(f->def, fndef, " {\n", NULL); + + Delete(fnname); + Delete(fndef); + + if (SwigType_type(result) != T_VOID) { + String *ln = NewString("_swig_go_result"); + String *ct = gccgoCTypeForGoValue(n, result, ln); + Wrapper_add_local(f, "_swig_go_result", ct); + Delete(ct); + Delete(ln); + } + + // Copy the parameters into the variables which hold their values, + // applying appropriate transformations. + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + + String *tm = Getattr(p, "tmap:in"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + String *ln = Getattr(p, "lname"); + String *pn = NewString("g"); + Append(pn, ln); + tm = Copy(tm); + Replaceall(tm, "$input", pn); + Setattr(p, "emit:input", pn); + if (i < required_count) { + Printv(f->code, " ", tm, "\n", NULL); + } else { + Printf(f->code, " if (_swig_optargc > %d) {\n", i - required_count); + Printv(f->code, " ", tm, "\n", NULL); + Printv(f->code, " }\n", NULL); + } + Delete(tm); + } + + p = nextParm(p); + } + + Printv(f->code, "\n", NULL); + + // Do the real work of the function. + + checkConstraints(parms, f); + + emitGoAction(n, base, parms, result, f); + + argout(parms, f); + + cleanupFunction(n, f, parms); + + if (SwigType_type(result) != T_VOID) { + Printv(f->code, " return _swig_go_result;\n", NULL); + } + + Printv(f->code, "}\n", NULL); + + Wrapper_print(f, f_c_wrappers); + + Swig_restore(n); + + DelWrapper(f); + Delete(base_parm); + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * checkConstraints() + * + * Check parameter constraints if any. This is used for the C/C++ + * function. This assumes that each parameter has an "emit:input" + * property with the name to use to refer to that parameter. + * ----------------------------------------------------------------------- */ + + void checkConstraints(ParmList *parms, Wrapper *f) { + Parm *p = parms; + while (p) { + String *tm = Getattr(p, "tmap:check"); + if (!tm) { + p = nextSibling(p); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n\n", NULL); + Delete(tm); + p = Getattr(p, "tmap:check:next"); + } + } + } + + /* ----------------------------------------------------------------------- + * emitGoAction() + * + * Emit the action of the function. This is used for the C/C++ function. + * ----------------------------------------------------------------------- */ + + void emitGoAction(Node *n, List *base, ParmList *parms, SwigType *result, Wrapper *f) { + if (!gccgo_flag && !cgo_flag && SwigType_type(result) != T_VOID) { + Wrapper_add_local(f, "swig_stktop", "char *swig_stktop"); + Printv(f->code, "\tswig_stktop = _swig_topofstack();\n", NULL); + } + String *actioncode; + if (!base || isStatic(n)) { + Swig_director_emit_dynamic_cast(n, f); + actioncode = emit_action(n); + } else { + // Call the base class method. + actioncode = NewString(""); + + String *current = NewString(""); + if (!gccgo_flag && !cgo_flag) { + Printv(current, "swig_a->", NULL); + } + Printv(current, Getattr(parms, "lname"), NULL); + + int vc = 0; + for (Iterator bi = First(base); bi.item; bi = Next(bi)) { + Printf(actioncode, " %s *swig_b%d = (%s *)%s;\n", bi.item, vc, bi.item, current); + Delete(current); + current = NewString(""); + Printf(current, "swig_b%d", vc); + ++vc; + } + + String *code = Copy(Getattr(n, "wrap:action")); + Replace(code, Getattr(parms, "lname"), current, DOH_REPLACE_ANY | DOH_REPLACE_ID); + Delete(current); + Printv(actioncode, code, "\n", NULL); + } + + Swig_save("emitGoAction", n, "type", "tmap:out", NULL); + + Setattr(n, "type", result); + + String *tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode); + if (!tm) { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s\n", SwigType_str(result, 0)); + } else { + Replaceall(tm, "$result", "_swig_go_result"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printv(f->code, tm, "\n", NULL); + Delete(tm); + } + + if (!gccgo_flag && !cgo_flag && SwigType_type(result) != T_VOID) { + // If the function called back into the Go code, the stack might + // have been copied. We need to adjust swig_a accordingly here. + // This is what cgo does. + Printv(f->code, "\tswig_a = (struct swigargs*)((char*)swig_a + (_swig_topofstack() - swig_stktop));\n", NULL); + Printv(f->code, "\tswig_a->", Swig_cresult_name(), " = ", "_swig_go_result;\n", NULL); + } + + Swig_restore(n); + } + + /* ----------------------------------------------------------------------- + * argout() + * + * Handle argument output code if any. This is used for the C/C++ + * function. This assumes that each parameter has an "emit:input" + * property with the name to use to refer to that parameter. + * ----------------------------------------------------------------------- */ + + void argout(ParmList *parms, Wrapper *f) { + Parm *p = parms; + while (p) { + String *tm = Getattr(p, "tmap:argout"); + if (!tm) { + p = nextSibling(p); + } else { + tm = Copy(tm); + Replaceall(tm, "$result", Swig_cresult_name()); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n", NULL); + Delete(tm); + p = Getattr(p, "tmap:argout:next"); + } + } + } + + /* ----------------------------------------------------------------------- + * goargout() + * + * Handle Go argument output code if any. This is used for the Go + * function. This assumes that each parameter has an "emit:goinput" + * property with the name to use to refer to that parameter. + * ----------------------------------------------------------------------- */ + + void goargout(ParmList *parms) { + Parm *p = parms; + while (p) { + String *tm = Getattr(p, "tmap:goargout"); + if (!tm) { + p = nextSibling(p); + } else { + tm = Copy(tm); + Replaceall(tm, "$result", "swig_r"); + Replaceall(tm, "$input", Getattr(p, "emit:goinput")); + Printv(f_go_wrappers, tm, "\n", NULL); + Delete(tm); + p = Getattr(p, "tmap:goargout:next"); + } + } + + // When using cgo, if we need to memcpy a parameter to pass it to + // the C code, the compiler may think that the parameter is not + // live during the function call. If the garbage collector runs + // while the C/C++ function is running, the parameter may be + // freed. Force the compiler to see the parameter as live across + // the C/C++ function. + if (cgo_flag) { + int parm_count = emit_num_arguments(parms); + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + bool c_struct_type; + Delete(cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type)); + if (c_struct_type) { + Printv(f_go_wrappers, "\tif Swig_escape_always_false {\n", NULL); + Printv(f_go_wrappers, "\t\tSwig_escape_val = ", Getattr(p, "emit:goinput"), "\n", NULL); + Printv(f_go_wrappers, "\t}\n", NULL); + } + p = nextParm(p); + } + } + } + + /* ----------------------------------------------------------------------- + * freearg() + * + * Handle argument cleanup code if any. This is used for the C/C++ + * function. This assumes that each parameter has an "emit:input" + * property with the name to use to refer to that parameter. + * ----------------------------------------------------------------------- */ + + String *freearg(ParmList *parms) { + String *ret = NewString(""); + Parm *p = parms; + while (p) { + String *tm = Getattr(p, "tmap:freearg"); + if (!tm) { + p = nextSibling(p); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(ret, tm, "\n", NULL); + Delete(tm); + p = Getattr(p, "tmap:freearg:next"); + } + } + return ret; + } + + /* ----------------------------------------------------------------------- + * cleanupFunction() + * + * Final function cleanup code. + * ----------------------------------------------------------------------- */ + + void cleanupFunction(Node *n, Wrapper *f, ParmList *parms) { + String *cleanup = freearg(parms); + Printv(f->code, cleanup, NULL); + + if (GetFlag(n, "feature:new")) { + String *tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0); + if (tm) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NULL); + Delete(tm); + } + } + + Replaceall(f->code, "$cleanup", cleanup); + Delete(cleanup); + + /* See if there is any return cleanup code */ + String *tm; + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Replaceall(f->code, "$symname", Getattr(n, "sym:name")); + } + + /* ----------------------------------------------------------------------- + * variableHandler() + * + * This exists just to set the making_variable_wrappers flag. + * ----------------------------------------------------------------------- */ + + virtual int variableHandler(Node *n) { + assert(!making_variable_wrappers); + making_variable_wrappers = true; + int r = Language::variableHandler(n); + making_variable_wrappers = false; + return r; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * + * Product a const declaration. + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + SwigType *type = Getattr(n, "type"); + + if (!SwigType_issimple(type) && SwigType_type(type) != T_STRING) { + return goComplexConstant(n, type); + } + + if (Swig_storage_isstatic(n)) { + return goComplexConstant(n, type); + } + + String *go_name = buildGoName(Getattr(n, "sym:name"), false, false); + + String *tm = goType(n, type); + String *value = Getattr(n, "value"); + + String *copy = NULL; + if (SwigType_type(type) == T_BOOL) { + if (Cmp(value, "true") != 0 && Cmp(value, "false") != 0) { + return goComplexConstant(n, type); + } + } else if (SwigType_type(type) == T_STRING || SwigType_type(type) == T_CHAR) { + // Backslash sequences are somewhat different in Go and C/C++. + if (Strchr(value, '\\') != 0) { + return goComplexConstant(n, type); + } + } else { + // Accept a 0x prefix, and strip combinations of u and l + // suffixes. Otherwise accept digits, decimal point, and + // exponentiation. Treat anything else as too complicated to + // handle as a Go constant. + char *p = Char(value); + int len = (int)strlen(p); + bool need_copy = false; + while (len > 0) { + char c = p[len - 1]; + if (c != 'l' && c != 'L' && c != 'u' && c != 'U') { + break; + } + --len; + need_copy = true; + } + bool is_hex = false; + int i = 0; + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + i = 2; + is_hex = true; + } + for (; i < len; ++i) { + switch (p[i]) { + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + break; + case 'a': case 'b': case 'c': case 'd': case 'f': case 'A': case 'B': case 'C': case 'D': case 'F': + if (!is_hex) { + return goComplexConstant(n, type); + } + break; + case '.': case 'e': case 'E': case '+': case '-': + break; + default: + return goComplexConstant(n, type); + } + } + if (need_copy) { + copy = Copy(value); + Replaceall(copy, p + len, ""); + value = copy; + } + } + + if (!checkNameConflict(go_name, n, NULL)) { + Delete(tm); + Delete(go_name); + Delete(copy); + return SWIG_NOWRAP; + } + + Printv(f_go_wrappers, "const ", go_name, " ", tm, " = ", NULL); + if (SwigType_type(type) == T_STRING) { + Printv(f_go_wrappers, "\"", value, "\"", NULL); + } else if (SwigType_type(type) == T_CHAR) { + Printv(f_go_wrappers, "'", value, "'", NULL); + } else { + Printv(f_go_wrappers, value, NULL); + } + + Printv(f_go_wrappers, "\n", NULL); + + Delete(tm); + Delete(go_name); + Delete(copy); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * enumDeclaration() + * + * A C++ enum type turns into a Named go int type. + * ---------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *name = goEnumName(n); + if (Strcmp(name, "int") != 0) { + if (!ImportMode || !imported_package) { + if (!checkNameConflict(name, n, NULL)) { + Delete(name); + return SWIG_NOWRAP; + } + Printv(f_go_wrappers, "type ", name, " int\n", NULL); + } else { + String *nw = NewString(""); + Printv(nw, getModuleName(imported_package), ".", name, NULL); + Setattr(n, "go:enumname", nw); + } + } + Delete(name); + + return Language::enumDeclaration(n); + } + + /* ----------------------------------------------------------------------- + * enumvalueDeclaration() + * + * Declare a single value of an enum type. We fetch the value by + * calling a C/C++ function. + * ------------------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + if (!is_public(n)) { + return SWIG_OK; + } + + Swig_require("enumvalueDeclaration", n, "*sym:name", NIL); + Node *parent = parentNode(n); + + if (Getattr(parent, "unnamed")) { + Setattr(n, "type", NewString("int")); + } else { + Setattr(n, "type", Getattr(parent, "enumtype")); + } + + if (GetFlag(parent, "scopedenum")) { + String *symname = Getattr(n, "sym:name"); + symname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + Setattr(n, "sym:name", symname); + Delete(symname); + } + + int ret = goComplexConstant(n, Getattr(n, "type")); + Swig_restore(n); + return ret; + } + + /* ----------------------------------------------------------------------- + * goComplexConstant() + * + * Handle a const declaration for something which is not a Go constant. + * ------------------------------------------------------------------------ */ + + int goComplexConstant(Node *n, SwigType *type) { + String *symname = Getattr(n, "sym:name"); + if (!symname) { + symname = Getattr(n, "name"); + } + + String *varname = buildGoName(symname, true, false); + + if (!checkNameConflict(varname, n, NULL)) { + Delete(varname); + return SWIG_NOWRAP; + } + + String *rawval = Getattr(n, "rawval"); + if (rawval && Len(rawval)) { + // Based on Swig_VargetToFunction + String *nname = NewStringf("(%s)", rawval); + String *call; + if (SwigType_isclass(type)) { + call = NewStringf("%s", nname); + } else { + call = SwigType_lcaststr(type, nname); + } + String *cres = Swig_cresult(type, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(nname); + Delete(call); + Delete(cres); + } else { + String *get = NewString(""); + Printv(get, Swig_cresult_name(), " = ", NULL); + + char quote; + if (Getattr(n, "wrappedasconstant")) { + quote = '\0'; + } else if (SwigType_type(type) == T_CHAR) { + quote = '\''; + } else if (SwigType_type(type) == T_STRING) { + Printv(get, "(char *)", NULL); + quote = '"'; + } else { + quote = '\0'; + } + + if (quote != '\0') { + Printf(get, "%c", quote); + } + + Printv(get, Getattr(n, "value"), NULL); + + if (quote != '\0') { + Printf(get, "%c", quote); + } + + Printv(get, ";\n", NULL); + + Setattr(n, "wrap:action", get); + Delete(get); + } + + String *sname = Copy(symname); + if (class_name) { + Append(sname, "_"); + Append(sname, class_name); + } + + String *go_name = NewString("_swig_get"); + if (class_name) { + Append(go_name, class_name); + Append(go_name, "_"); + } + Append(go_name, sname); + + String *wname = Swig_name_wrapper(sname); + Append(wname, unique_id); + Setattr(n, "wrap:name", wname); + + int r = makeWrappers(n, sname, go_name, NULL, wname, NULL, NULL, type, true); + + if (r != SWIG_OK) { + return r; + } + + String *t = goType(n, type); + Printv(f_go_wrappers, "var ", varname, " ", t, " = ", go_name, "()\n", NULL); + + Delete(varname); + Delete(t); + Delete(go_name); + Delete(sname); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classHandler() + * + * For a C++ class, in Go we generate both a struct and an + * interface. The interface will declare all the class public + * methods. We will define all the methods on the struct, so that + * the struct meets the interface. We then expect users of the + * class to use the interface. + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + class_node = n; + + List *baselist = Getattr(n, "bases"); + bool has_base_classes = baselist && Len(baselist) > 0; + + String *name = Getattr(n, "sym:name"); + + String *go_name = exportedName(name); + + if (!checkNameConflict(go_name, n, NULL)) { + Delete(go_name); + SetFlag(n, "go:conflict"); + return SWIG_NOWRAP; + } + + String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + + class_name = name; + class_receiver = go_type_name; + class_methods = NewHash(); + + int isdir = GetFlag(n, "feature:director"); + int isnodir = GetFlag(n, "feature:nodirector"); + bool is_director = isdir && !isnodir; + + Printv(f_go_wrappers, "type ", go_type_name, " uintptr\n\n", NULL); + + // A method to return the pointer to the C++ class. This is used + // by generated code to convert between the interface and the C++ + // value. + Printv(f_go_wrappers, "func (p ", go_type_name, ") Swigcptr() uintptr {\n", NULL); + Printv(f_go_wrappers, "\treturn (uintptr)(p)\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + // A method used as a marker for the class, to avoid invalid + // interface conversions when using multiple inheritance. + Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigIs", go_name, "() {\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + if (is_director) { + // Return the interface passed to the NewDirector function. + Printv(f_go_wrappers, "func (p ", go_type_name, ") DirectorInterface() interface{} {\n", NULL); + Printv(f_go_wrappers, "\treturn nil\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + } + + // We have seen a definition for this type. + Setattr(defined_types, go_name, go_name); + Setattr(defined_types, go_type_name, go_type_name); + + interfaces = NewString(""); + + int r = Language::classHandler(n); + if (r != SWIG_OK) { + return r; + } + + if (has_base_classes) { + // For each method defined in a base class but not defined in + // this class, we need to define the method in this class. We + // can't use anonymous field inheritance because it works + // differently in Go and in C++. + + Hash *local = NewHash(); + for (Node *ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + + if (!is_public(ni)) { + continue; + } + + String *type = Getattr(ni, "nodeType"); + if (Cmp(type, "constructor") == 0 || Cmp(type, "destructor") == 0) { + continue; + } + + String *cname = Getattr(ni, "sym:name"); + if (!cname) { + cname = Getattr(ni, "name"); + } + if (cname) { + Setattr(local, cname, NewString("")); + } + } + + for (Iterator b = First(baselist); b.item; b = Next(b)) { + List *bases = NewList(); + Append(bases, Getattr(b.item, "classtype")); + int r = addBase(n, b.item, bases, local); + if (r != SWIG_OK) { + return r; + } + Delete(bases); + } + + Delete(local); + + Hash *parents = NewHash(); + addFirstBaseInterface(n, parents, baselist); + int r = addExtraBaseInterfaces(n, parents, baselist); + Delete(parents); + if (r != SWIG_OK) { + return r; + } + } + + Printv(f_go_wrappers, "type ", go_name, " interface {\n", NULL); + Printv(f_go_wrappers, "\tSwigcptr() uintptr\n", NULL); + Printv(f_go_wrappers, "\tSwigIs", go_name, "()\n", NULL); + + if (is_director) { + Printv(f_go_wrappers, "\tDirectorInterface() interface{}\n", NULL); + } + + Append(f_go_wrappers, interfaces); + Printv(f_go_wrappers, "}\n\n", NULL); + Delete(interfaces); + + interfaces = NULL; + class_name = NULL; + class_receiver = NULL; + class_node = NULL; + Delete(class_methods); + class_methods = NULL; + + Delete(go_type_name); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * addBase() + * + * Implement methods and members defined in a parent class for a + * child class. + * ------------------------------------------------------------ */ + + int addBase(Node *n, Node *base, List *bases, Hash *local) { + if (GetFlag(base, "feature:ignore")) { + return SWIG_OK; + } + + for (Node *ni = Getattr(base, "firstChild"); ni; ni = nextSibling(ni)) { + + if (GetFlag(ni, "feature:ignore")) { + continue; + } + + if (!is_public(ni)) { + continue; + } + + String *type = Getattr(ni, "nodeType"); + if (Strcmp(type, "constructor") == 0 || Strcmp(type, "destructor") == 0 || Strcmp(type, "enum") == 0 || Strcmp(type, "using") == 0 || Strcmp(type, "classforward") == 0 || Strcmp(type, "template") == 0) { + continue; + } + String *storage = Getattr(ni, "storage"); + if (storage && (Strcmp(storage, "typedef") == 0 || Strcmp(storage, "friend") == 0)) { + continue; + } + + String *mname = Getattr(ni, "sym:name"); + if (!mname) { + continue; + } + + String *lname = Getattr(ni, "name"); + if (Getattr(class_methods, lname)) { + continue; + } + if (Getattr(local, lname)) { + continue; + } + Setattr(local, lname, NewString("")); + + String *ty = NewString(Getattr(ni, "type")); + SwigType_push(ty, Getattr(ni, "decl")); + String *fullty = SwigType_typedef_resolve_all(ty); + bool is_function = SwigType_isfunction(fullty) ? true : false; + Delete(ty); + Delete(fullty); + + if (is_function) { + int r = goBaseMethod(n, bases, ni); + if (r != SWIG_OK) { + return r; + } + + if (Getattr(ni, "sym:overloaded")) { + for (Node *on = Getattr(ni, "sym:nextSibling"); on; on = Getattr(on, "sym:nextSibling")) { + r = goBaseMethod(n, bases, on); + if (r != SWIG_OK) { + return r; + } + } + + String *receiver = class_receiver; + bool is_static = isStatic(ni); + if (is_static) { + receiver = NULL; + } + String *go_name = buildGoName(Getattr(ni, "sym:name"), is_static, false); + r = makeDispatchFunction(ni, go_name, receiver, is_static, NULL, false); + Delete(go_name); + if (r != SWIG_OK) { + return r; + } + } + } else { + int r = goBaseVariable(n, bases, ni); + if (r != SWIG_OK) { + return r; + } + } + } + + List *baselist = Getattr(base, "bases"); + if (baselist && Len(baselist) > 0) { + for (Iterator b = First(baselist); b.item; b = Next(b)) { + List *nb = Copy(bases); + Append(nb, Getattr(b.item, "classtype")); + int r = addBase(n, b.item, nb, local); + Delete(nb); + if (r != SWIG_OK) { + return r; + } + } + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * goBaseMethod() + * + * Implement a method defined in a parent class for a child class. + * ------------------------------------------------------------ */ + + int goBaseMethod(Node *method_class, List *bases, Node *method) { + String *symname = Getattr(method, "sym:name"); + if (!validIdentifier(symname)) { + return SWIG_OK; + } + + String *name = NewString(""); + Printv(name, Getattr(method_class, "sym:name"), "_", symname, NULL); + + bool is_static = isStatic(method); + + String *go_name = buildGoName(name, is_static, false); + + String *overname = NULL; + if (Getattr(method, "sym:overloaded")) { + overname = Getattr(method, "sym:overname"); + } + String *wname = Swig_name_wrapper(name); + if (overname) { + Append(wname, overname); + } + Append(wname, unique_id); + + String *result = NewString(Getattr(method, "type")); + SwigType_push(result, Getattr(method, "decl")); + if (SwigType_isqualifier(result)) { + Delete(SwigType_pop(result)); + } + Delete(SwigType_pop_function(result)); + + // If the base method is imported, wrap:action may not be set. + Swig_save("goBaseMethod", method, "wrap:name", "wrap:action", "parms", NULL); + Setattr(method, "wrap:name", wname); + if (!Getattr(method, "wrap:action")) { + if (!is_static) { + Swig_MethodToFunction(method, getNSpace(), getClassType(), (Getattr(method, "template") ? SmartPointer : Extend | SmartPointer), NULL, false); + // Remove any self parameter that was just added. + ParmList *parms = Getattr(method, "parms"); + if (parms && Getattr(parms, "self")) { + parms = CopyParmList(nextSibling(parms)); + Setattr(method, "parms", parms); + } + } else { + String *call = Swig_cfunction_call(Getattr(method, "name"), Getattr(method, "parms")); + Setattr(method, "wrap:action", Swig_cresult(Getattr(method, "type"), Swig_cresult_name(), call)); + } + } + + int r = makeWrappers(method, name, go_name, overname, wname, bases, Getattr(method, "parms"), result, is_static); + + Swig_restore(method); + + Delete(result); + Delete(go_name); + Delete(name); + + return r; + } + + /* ------------------------------------------------------------ + * goBaseVariable() + * + * Add accessors for a member variable defined in a parent class for + * a child class. + * ------------------------------------------------------------ */ + + int goBaseVariable(Node *var_class, List *bases, Node *var) { + if (isStatic(var)) { + return SWIG_OK; + } + + String *var_name = buildGoName(Getattr(var, "sym:name"), false, false); + + Swig_save("goBaseVariable", var, "type", "wrap:action", NULL); + + // For a pointer type we apparently have to wrap in the decl. + SwigType *var_type = NewString(Getattr(var, "type")); + SwigType_push(var_type, Getattr(var, "decl")); + Setattr(var, "type", var_type); + + SwigType *vt = Copy(var_type); + + int flags = Extend | SmartPointer | use_naturalvar_mode(var); + if (isNonVirtualProtectedAccess(var)) { + flags |= CWRAP_ALL_PROTECTED_ACCESS; + } + + // Copied from Swig_wrapped_member_var_type. + if (SwigType_isclass(vt)) { + if (flags & CWRAP_NATURAL_VAR) { + if (CPlusPlus) { + if (!SwigType_isconst(vt)) { + SwigType_add_qualifier(vt, "const"); + } + SwigType_add_reference(vt); + } + } else { + SwigType_add_pointer(vt); + } + } + + String *mname = Swig_name_member(getNSpace(), Getattr(var_class, "sym:name"), var_name); + + if (is_assignable(var)) { + for (Iterator ki = First(var); ki.key; ki = Next(ki)) { + if (Strncmp(ki.key, "tmap:", 5) == 0) { + Delattr(var, ki.key); + } + } + Swig_save("goBaseVariableSet", var, "name", "sym:name", "type", NULL); + + String *mname_set = NewString("Set"); + Append(mname_set, mname); + + String *go_name = NewString("Set"); + Append(go_name, var_name); + + Swig_MembersetToFunction(var, class_name, flags); + + String *wname = Swig_name_wrapper(mname_set); + Append(wname, unique_id); + ParmList *parms = NewParm(vt, var_name, var); + String *result = NewString("void"); + int r = makeWrappers(var, mname_set, go_name, NULL, wname, bases, parms, result, false); + if (r != SWIG_OK) { + return r; + } + Delete(wname); + Delete(parms); + Delete(result); + Delete(go_name); + Delete(mname_set); + + Swig_restore(var); + for (Iterator ki = First(var); ki.key; ki = Next(ki)) { + if (Strncmp(ki.key, "tmap:", 5) == 0) { + Delattr(var, ki.key); + } + } + } + + Swig_MembergetToFunction(var, class_name, flags); + + String *mname_get = NewString("Get"); + Append(mname_get, mname); + + String *go_name = NewString("Get"); + Append(go_name, var_name); + + String *wname = Swig_name_wrapper(mname_get); + Append(wname, unique_id); + + int r = makeWrappers(var, mname_get, go_name, NULL, wname, bases, NULL, vt, false); + if (r != SWIG_OK) { + return r; + } + + Delete(wname); + Delete(mname_get); + Delete(go_name); + Delete(mname); + Delete(var_name); + Delete(var_type); + Delete(vt); + + Swig_restore(var); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * addFirstBaseInterface() + * + * When a C++ class uses multiple inheritance, we can use the C++ + * pointer for the first base class but not for any subsequent base + * classes. However, the Go interface will match the interface for + * all the base classes. To avoid accidentally treating a class as + * a pointer to a base class other than the first one, we use an + * isClassname method. This function adds those methods as + * required. + * + * For convenience when using multiple inheritance, we also add + * functions to retrieve the base class pointers. + * ------------------------------------------------------------ */ + + void addFirstBaseInterface(Node *n, Hash *parents, List *bases) { + if (!bases || Len(bases) == 0) { + return; + } + Iterator b = First(bases); + if (!GetFlag(b.item, "feature:ignore")) { + String *go_name = buildGoName(Getattr(n, "sym:name"), false, false); + String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + String *go_base_name = exportedName(Getattr(b.item, "sym:name")); + String *go_base_type = goType(n, Getattr(b.item, "classtypeobj")); + String *go_base_type_name = goCPointerType(Getattr(b.item, "classtypeobj"), true); + + Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigIs", go_base_name, "() {\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(interfaces, "\tSwigIs", go_base_name, "()\n", NULL); + + Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigGet", go_base_name, "() ", go_base_type, " {\n", NULL); + Printv(f_go_wrappers, "\treturn ", go_base_type_name, "(p.Swigcptr())\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(interfaces, "\tSwigGet", go_base_name, "() ", go_base_type, "\n", NULL); + + Setattr(parents, go_base_name, NewString("")); + + Delete(go_name); + Delete(go_type_name); + Delete(go_base_type); + Delete(go_base_type_name); + } + + addFirstBaseInterface(n, parents, Getattr(b.item, "bases")); + } + + /* ------------------------------------------------------------ + * addExtraBaseInterfaces() + * + * Add functions to retrieve the base class pointers for all base + * classes other than the first. + * ------------------------------------------------------------ */ + + int addExtraBaseInterfaces(Node *n, Hash *parents, List *bases) { + Iterator b = First(bases); + + Node *fb = b.item; + + for (b = Next(b); b.item; b = Next(b)) { + if (GetFlag(b.item, "feature:ignore")) { + continue; + } + + String *go_base_name = exportedName(Getattr(b.item, "sym:name")); + + Swig_save("addExtraBaseInterface", n, "wrap:action", "wrap:name", "wrap:parms", NULL); + + SwigType *type = Copy(Getattr(n, "classtypeobj")); + SwigType_add_pointer(type); + Parm *parm = NewParm(type, "self", n); + Setattr(n, "wrap:parms", parm); + + String *pn = Swig_cparm_name(parm, 0); + String *action = NewString(""); + Printv(action, Swig_cresult_name(), " = (", Getattr(b.item, "classtype"), "*)", pn, ";", NULL); + Delete(pn); + + Setattr(n, "wrap:action", action); + + String *name = Copy(class_name); + Append(name, "_SwigGet"); + Append(name, go_base_name); + + String *go_name = NewString("SwigGet"); + String *c1 = exportedName(go_base_name); + Append(go_name, c1); + Delete(c1); + + String *wname = Swig_name_wrapper(name); + Append(wname, unique_id); + Setattr(n, "wrap:name", wname); + + SwigType *result = Copy(Getattr(b.item, "classtypeobj")); + SwigType_add_pointer(result); + + int r = makeWrappers(n, name, go_name, NULL, wname, NULL, parm, result, + false); + if (r != SWIG_OK) { + return r; + } + + Swig_restore(n); + + Setattr(parents, go_base_name, NewString("")); + + Delete(go_name); + Delete(type); + Delete(parm); + Delete(action); + Delete(result); + + String *ns = NewString(""); + addParentExtraBaseInterfaces(n, parents, b.item, false, ns); + Delete(ns); + } + + if (!GetFlag(fb, "feature:ignore")) { + String *ns = NewString(""); + addParentExtraBaseInterfaces(n, parents, fb, true, ns); + Delete(ns); + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * addParentExtraBaseInterfaces() + * + * Add functions to retrieve the base class pointers for all base + * classes of parents other than the first base class at each level. + * ------------------------------------------------------------ */ + + void addParentExtraBaseInterfaces(Node *n, Hash *parents, Node *base, bool is_base_first, String *sofar) { + List *baselist = Getattr(base, "bases"); + if (!baselist || Len(baselist) == 0) { + return; + } + + String *go_this_base_name = exportedName(Getattr(base, "sym:name")); + + String *sf = NewString(""); + Printv(sf, sofar, ".SwigGet", go_this_base_name, "()", NULL); + + Iterator b = First(baselist); + + if (is_base_first) { + if (!b.item) { + return; + } + if (!GetFlag(b.item, "feature:ignore")) { + addParentExtraBaseInterfaces(n, parents, b.item, true, sf); + } + + b = Next(b); + } + + String *go_name = buildGoName(Getattr(n, "sym:name"), false, false); + String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + + for (; b.item; b = Next(b)) { + if (GetFlag(b.item, "feature:ignore")) { + continue; + } + + String *go_base_name = exportedName(Getattr(b.item, "sym:name")); + + if (!Getattr(parents, go_base_name)) { + Printv(f_go_wrappers, "func (p ", go_type_name, ") SwigGet", go_base_name, "() ", go_base_name, " {\n", NULL); + Printv(f_go_wrappers, "\treturn p", sf, ".SwigGet", go_base_name, "()\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(interfaces, "\tSwigGet", go_base_name, "() ", go_base_name, "\n", NULL); + + addParentExtraBaseInterfaces(n, parents, b.item, false, sf); + + Setattr(parents, go_base_name, NewString("")); + } + } + + Delete(go_name); + Delete(go_type_name); + Delete(go_this_base_name); + Delete(sf); + } + + /* ------------------------------------------------------------ + * classDirectorInit + * + * Add support for a director class. + * + * Virtual inheritance is different in Go and C++. We implement + * director classes by defining a new function in Go, + * NewDirectorClassname, which takes a empty interface value and + * creates an instance of a new child class. The new child class + * refers all methods back to Go. The Go code checks whether the + * value passed to NewDirectorClassname implements that method; if + * it does, it calls it, otherwise it calls back into C++. + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + // Because we use a different function to handle inheritance in + // Go, ordinary creations of the object should not create a + // director object. + Delete(director_ctor_code); + director_ctor_code = NewString("$nondirector_new"); + + class_node = n; + + String *name = Getattr(n, "sym:name"); + + assert(!class_name); + class_name = name; + + String *go_name = exportedName(name); + + String *go_type_name = goCPointerType(Getattr(n, "classtypeobj"), true); + + assert(!class_receiver); + class_receiver = go_type_name; + + String *director_struct_name = NewString("_swig_Director"); + Append(director_struct_name, go_name); + + String *cxx_director_name = NewString("SwigDirector_"); + Append(cxx_director_name, name); + + // The Go type of the director class. + Printv(f_go_wrappers, "type ", director_struct_name, " struct {\n", NULL); + Printv(f_go_wrappers, "\t", go_type_name, "\n", NULL); + Printv(f_go_wrappers, "\tv interface{}\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(f_go_wrappers, "func (p *", director_struct_name, ") Swigcptr() uintptr {\n", NULL); + Printv(f_go_wrappers, "\treturn p.", go_type_name, ".Swigcptr()\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(f_go_wrappers, "func (p *", director_struct_name, ") SwigIs", go_name, "() {\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(f_go_wrappers, "func (p *", director_struct_name, ") DirectorInterface() interface{} {\n", NULL); + Printv(f_go_wrappers, "\treturn p.v\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + // Start defining the director class. + Printv(f_c_directors_h, "class ", cxx_director_name, " : public ", Getattr(n, "classtype"), "\n", NULL); + Printv(f_c_directors_h, "{\n", NULL); + Printv(f_c_directors_h, " public:\n", NULL); + + Delete(director_struct_name); + Delete(cxx_director_name); + + class_methods = NewHash(); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor + * + * Emit a constructor for a director class. + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + + String *name = Getattr(n, "sym:name"); + if (!name) { + assert(is_ignored); + name = Getattr(n, "name"); + } + + String *overname = NULL; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } + + String *go_name = exportedName(name); + + ParmList *parms = Getattr(n, "parms"); + Setattr(n, "wrap:parms", parms); + + String *cn = exportedName(Getattr(parentNode(n), "sym:name")); + + String *go_type_name = goCPointerType(Getattr(parentNode(n), "classtypeobj"), true); + + String *director_struct_name = NewString("_swig_Director"); + Append(director_struct_name, cn); + + String *fn_name = NewString("_swig_NewDirector"); + Append(fn_name, cn); + Append(fn_name, go_name); + + if (!overname && !is_ignored) { + if (!checkNameConflict(fn_name, n, NULL)) { + return SWIG_NOWRAP; + } + } + + String *fn_with_over_name = Copy(fn_name); + if (overname) { + Append(fn_with_over_name, overname); + } + + String *wname = Swig_name_wrapper(fn_name); + + if (overname) { + Append(wname, overname); + } + Append(wname, unique_id); + Setattr(n, "wrap:name", wname); + + bool is_static = isStatic(n); + + Wrapper *dummy = NewWrapper(); + emit_attach_parmmaps(parms, dummy); + DelWrapper(dummy); + + Swig_typemap_attach_parms("gotype", parms, NULL); + Swig_typemap_attach_parms("goin", parms, NULL); + Swig_typemap_attach_parms("goargout", parms, NULL); + Swig_typemap_attach_parms("imtype", parms, NULL); + int parm_count = emit_num_arguments(parms); + + String *func_name = NewString("NewDirector"); + Append(func_name, go_name); + + String *func_with_over_name = Copy(func_name); + if (overname) { + Append(func_with_over_name, overname); + } + + SwigType *first_type = NewString("int"); + Parm *first_parm = NewParm(first_type, "swig_p", n); + set_nextSibling(first_parm, parms); + Setattr(first_parm, "lname", "p"); + + Parm *p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + Swig_cparm_name(p, i); + p = nextParm(p); + } + + if (!is_ignored) { + if (cgo_flag) { + Printv(f_cgo_comment, "extern uintptr_t ", wname, "(int", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type); + Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL); + p = nextParm(p); + } + Printv(f_cgo_comment, ");\n", NULL); + } else { + // Declare the C++ wrapper. + + if (!gccgo_flag) { + Printv(f_go_wrappers, "var ", wname, " unsafe.Pointer\n\n", NULL); + } else { + Printv(f_go_wrappers, "//extern ", go_prefix, "_", wname, "\n", NULL); + } + + Printv(f_go_wrappers, "func ", fn_with_over_name, "(_swig_director int", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = goWrapperType(p, Getattr(p, "type"), false); + Printv(f_go_wrappers, ", _ ", tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ") (_swig_ret ", go_type_name, ")", NULL); + + if (!gccgo_flag) { + Printv(f_go_wrappers, " {\n", NULL); + Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&_swig_director))\n", NULL); + Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", wname, ", _swig_p)\n", NULL); + Printv(f_go_wrappers, "\treturn\n", NULL); + Printv(f_go_wrappers, "}", NULL); + } + + Printv(f_go_wrappers, "\n\n", NULL); + } + + // Write out the Go function that calls the wrapper. + + Printv(f_go_wrappers, "func ", func_with_over_name, "(v interface{}", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ") ", cn, " {\n", NULL); + + Printv(f_go_wrappers, "\tp := &", director_struct_name, "{0, v}\n", NULL); + + if (gccgo_flag && !cgo_flag) { + Printv(f_go_wrappers, "\tdefer SwigCgocallDone()\n", NULL); + Printv(f_go_wrappers, "\tSwigCgocall()\n", NULL); + } + + String *call = NewString(""); + + Printv(call, "\tp.", class_receiver, " = ", NULL); + if (cgo_flag) { + Printv(call, go_type_name, "(C.", wname, "(C.int(swigDirectorAdd(p))", NULL); + } else { + Printv(call, fn_with_over_name, "(swigDirectorAdd(p)", NULL); + } + + p = parms; + for (int i = 0; i < parm_count; ++i) { + Printv(call, ", ", NULL); + + p = getParm(p); + String *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + String *ivar = NewStringf("_swig_i_%d", i); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if (goTypeIsInterface(p, pt)) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, "\n", NULL); + Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + if (cgo_flag) { + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + Delete(ct); + } else { + Printv(call, ivar, NULL); + } + p = nextParm(p); + } + + Printv(call, ")", NULL); + if (cgo_flag) { + Printv(call, ")", NULL); + } + + Printv(f_go_wrappers, call, "\n", NULL); + + goargout(parms); + + Printv(f_go_wrappers, "\treturn p\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + SwigType *result = Copy(Getattr(parentNode(n), "classtypeobj")); + SwigType_add_pointer(result); + + Swig_save("classDirectorConstructor", n, "wrap:name", "wrap:action", NULL); + + String *dwname = Swig_name_wrapper(name); + Append(dwname, unique_id); + Setattr(n, "wrap:name", dwname); + + String *action = NewString(""); + Printv(action, Swig_cresult_name(), " = new SwigDirector_", class_name, "(", NULL); + String *pname = Swig_cparm_name(NULL, 0); + Printv(action, pname, NULL); + Delete(pname); + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *pname = Swig_cparm_name(NULL, i + 1); + Printv(action, ", ", NULL); + if (SwigType_isreference(Getattr(p, "type"))) { + Printv(action, "*", NULL); + } + Printv(action, pname, NULL); + Delete(pname); + p = nextParm(p); + } + Printv(action, ");", NULL); + Setattr(n, "wrap:action", action); + + if (cgo_flag) { + cgoWrapperInfo info; + + info.n = n; + info.go_name = func_name; + info.overname = overname; + info.wname = wname; + info.base = NULL; + info.parms = first_parm; + info.result = result; + info.is_static = false; + info.receiver = NULL; + info.is_constructor = true; + info.is_destructor = false; + + int r = cgoGccWrapper(&info); + if (r != SWIG_OK) { + return r; + } + } else if (!gccgo_flag) { + int r = gcFunctionWrapper(wname); + if (r != SWIG_OK) { + return r; + } + r = gccFunctionWrapper(n, NULL, wname, first_parm, result); + if (r != SWIG_OK) { + return r; + } + } else { + int r = gccgoFunctionWrapper(n, NULL, wname, first_parm, result); + if (r != SWIG_OK) { + return r; + } + } + + Swig_restore(n); + + Delete(result); + } + + String *cxx_director_name = NewString("SwigDirector_"); + Append(cxx_director_name, class_name); + + String *decl = Swig_method_decl(NULL, Getattr(n, "decl"), cxx_director_name, first_parm, 0); + Printv(f_c_directors_h, " ", decl, ";\n", NULL); + Delete(decl); + + decl = Swig_method_decl(NULL, Getattr(n, "decl"), cxx_director_name, first_parm, 0); + Printv(f_c_directors, cxx_director_name, "::", decl, "\n", NULL); + Delete(decl); + + Printv(f_c_directors, " : ", Getattr(parentNode(n), "classtype"), "(", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (i > 0) { + Printv(f_c_directors, ", ", NULL); + } + String *pn = Getattr(p, "name"); + assert(pn); + Printv(f_c_directors, pn, NULL); + p = nextParm(p); + } + Printv(f_c_directors, "),\n", NULL); + Printv(f_c_directors, " go_val(swig_p), swig_mem(0)\n", NULL); + Printv(f_c_directors, "{ }\n\n", NULL); + + if (Getattr(n, "sym:overloaded") && !Getattr(n, "sym:nextSibling")) { + int r = makeDispatchFunction(n, func_name, cn, is_static, Getattr(parentNode(n), "classtypeobj"), false); + if (r != SWIG_OK) { + return r; + } + } + + Delete(cxx_director_name); + Delete(go_name); + Delete(cn); + Delete(go_type_name); + Delete(director_struct_name); + Delete(fn_name); + Delete(fn_with_over_name); + Delete(func_name); + Delete(func_with_over_name); + Delete(wname); + Delete(first_type); + Delete(first_parm); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorDestructor + * + * Emit a destructor for a director class. + * ------------------------------------------------------------ */ + + int classDirectorDestructor(Node *n) { + if (!is_public(n)) { + return SWIG_OK; + } + + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + + if (!is_ignored) { + String *fnname = NewString("DeleteDirector"); + String *c1 = exportedName(class_name); + Append(fnname, c1); + Delete(c1); + + String *wname = Swig_name_wrapper(fnname); + Append(wname, unique_id); + + Setattr(n, "wrap:name", fnname); + + Swig_DestructorToFunction(n, getNSpace(), getClassType(), CPlusPlus, Extend); + + ParmList *parms = Getattr(n, "parms"); + Setattr(n, "wrap:parms", parms); + + String *result = NewString("void"); + int r = makeWrappers(n, fnname, fnname, NULL, wname, NULL, parms, result, isStatic(n)); + if (r != SWIG_OK) { + return r; + } + + Delete(result); + Delete(fnname); + Delete(wname); + } + + // Generate the destructor for the C++ director class. Since the + // Go code is keeping a pointer to the C++ object, we need to call + // back to the Go code to let it know that the C++ object is gone. + + String *go_name = NewString("Swiggo_DeleteDirector_"); + Append(go_name, class_name); + + String *cn = exportedName(class_name); + + String *director_struct_name = NewString("_swig_Director"); + Append(director_struct_name, cn); + + Printv(f_c_directors_h, " virtual ~SwigDirector_", class_name, "()", NULL); + + String *throws = buildThrow(n); + if (throws) { + Printv(f_c_directors_h, " ", throws, NULL); + } + + Printv(f_c_directors_h, ";\n", NULL); + + String *director_sig = NewString(""); + + Printv(director_sig, "SwigDirector_", class_name, "::~SwigDirector_", class_name, "()", NULL); + + if (throws) { + Printv(director_sig, " ", throws, NULL); + Delete(throws); + } + + Printv(director_sig, "\n", NULL); + Printv(director_sig, "{\n", NULL); + + if (is_ignored) { + Printv(f_c_directors, director_sig, NULL); + } else { + makeDirectorDestructorWrapper(go_name, director_struct_name, director_sig); + } + + Printv(f_c_directors, " delete swig_mem;\n", NULL); + + Printv(f_c_directors, "}\n\n", NULL); + + Delete(director_sig); + Delete(go_name); + Delete(cn); + Delete(director_struct_name); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * makeDirectorDestructorWrapper + * + * Emit the function wrapper for the destructor of a director class. + * This writes director_sig to f_c_directors and leaves the function + * unfinished. + * ------------------------------------------------------------ */ + + void makeDirectorDestructorWrapper(String *go_name, String *director_struct_name, String *director_sig) { + if (cgo_flag) { + makeCgoDirectorDestructorWrapper(go_name, director_struct_name, director_sig); + return; + } + + Printv(f_go_wrappers, "func ", go_name, "(c int) {\n", NULL); + if (gccgo_flag) { + Printv(f_go_wrappers, "\tSwigCgocallBack()\n", NULL); + Printv(f_go_wrappers, "\tdefer SwigCgocallBackDone()\n", NULL); + } + Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL); + Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + String *wname = NewString("_swiggo_wrap_DeleteDirector_"); + Append(wname, class_name); + + if (!gccgo_flag) { + Printv(f_c_directors, "extern \"C\" void ", wname, "(void*, int);\n", NULL); + } else { + Printv(f_c_directors, "extern \"C\" void ", wname, "(intgo) __asm__(\"", go_prefix, ".", go_name, "\");\n", NULL); + } + + Printv(f_c_directors, director_sig, NULL); + + if (!gccgo_flag) { + Printv(f_c_directors, " struct { intgo p; } SWIGSTRUCTPACKED a;\n", NULL); + Printv(f_c_directors, " a.p = go_val;\n", NULL); + Printv(f_c_directors, " crosscall2(", wname, ", &a, (int) sizeof a);\n", NULL); + + Printv(f_gc_wrappers, "#pragma dynexport ", wname, " ", wname, "\n", NULL); + Printv(f_gc_wrappers, "#pragma cgo_export_static ", wname, " ", wname, "\n", NULL); + Printv(f_gc_wrappers, "#pragma textflag 7\n", NULL); + Printv(f_gc_wrappers, "extern void \xc2\xb7", go_name, "();\n", NULL); + Printv(f_gc_wrappers, "void\n", NULL); + Printv(f_gc_wrappers, wname, "(void *a, int32 n)\n", NULL); + Printv(f_gc_wrappers, "{\n", NULL); + Printv(f_gc_wrappers, "\truntime\xc2\xb7" "cgocallback(\xc2\xb7", go_name, ", a, n);\n", NULL); + Printv(f_gc_wrappers, "}\n\n", NULL); + } else { + Printv(f_c_directors, " ", wname, "(go_val);\n", NULL); + } + + Delete(wname); + } + + /* ------------------------------------------------------------ + * makeCgoDirectorDestructorWrapper + * + * When using cgo, emit the function wrapper for the destructor of a + * director class. + * ------------------------------------------------------------ */ + + void makeCgoDirectorDestructorWrapper(String *go_name, String *director_struct_name, String *director_sig) { + String *wname = Copy(go_name); + Append(wname, unique_id); + + Printv(f_go_wrappers, "//export ", wname, "\n", NULL); + Printv(f_go_wrappers, "func ", wname, "(c int) {\n", NULL); + Printv(f_go_wrappers, "\tswigDirectorLookup(c).(*", director_struct_name, ").", class_receiver, " = 0\n", NULL); + Printv(f_go_wrappers, "\tswigDirectorDelete(c)\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Printv(f_c_directors, "extern \"C\" void ", wname, "(intgo);\n", NULL); + Printv(f_c_directors, director_sig, NULL); + Printv(f_c_directors, " ", wname, "(go_val);\n", NULL); + } + + /* ------------------------------------------------------------ + * classDirectorMethod + * + * Emit a method for a director class, plus its overloads. + * ------------------------------------------------------------ */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + + // We don't need explicit calls. + if (GetFlag(n, "explicitcall")) { + return SWIG_OK; + } + + String *name = Getattr(n, "sym:name"); + if (!name) { + assert(is_ignored); + name = Getattr(n, "name"); + } + + bool overloaded = Getattr(n, "sym:overloaded") && !Getattr(n, "explicitcallnode"); + if (!overloaded) { + int r = oneClassDirectorMethod(n, parent, super); + if (r != SWIG_OK) { + return r; + } + } else { + // Handle overloaded methods here, because otherwise we will + // reject them in the class_methods hash table. We need to use + // class_methods so that we correctly handle cases where a + // function in one class hides a function of the same name in a + // parent class. + if (!Getattr(class_methods, name)) { + for (Node *on = Getattr(n, "sym:overloaded"); on; on = Getattr(on, "sym:nextSibling")) { + // Swig_overload_rank expects wrap:name and wrap:parms to be + // set. + String *wn = Swig_name_wrapper(Getattr(on, "sym:name")); + Append(wn, Getattr(on, "sym:overname")); + Append(wn, unique_id); + Setattr(on, "wrap:name", wn); + Delete(wn); + Setattr(on, "wrap:parms", Getattr(on, "parms")); + } + } + + int r = oneClassDirectorMethod(n, parent, super); + if (r != SWIG_OK) { + return r; + } + + if (!Getattr(n, "sym:nextSibling")) + { + // Last overloaded function + Node *on = Getattr(n, "sym:overloaded"); + bool is_static = isStatic(on); + + String *cn = exportedName(Getattr(parent, "sym:name")); + String *go_name = buildGoName(name, is_static, false); + + String *director_struct_name = NewString("_swig_Director"); + Append(director_struct_name, cn); + + int r = makeDispatchFunction(on, go_name, director_struct_name, is_static, director_struct_name, false); + if (r != SWIG_OK) { + return r; + } + + if (!GetFlag(n, "abstract")) { + String *go_upcall = NewString("Director"); + Append(go_upcall, cn); + Append(go_upcall, go_name); + r = makeDispatchFunction(on, go_upcall, director_struct_name, is_static, director_struct_name, true); + if (r != SWIG_OK) { + return r; + } + Delete(go_upcall); + } + + Delete(director_struct_name); + Delete(go_name); + Delete(cn); + } + } + Setattr(class_methods, name, NewString("")); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * oneClassDirectorMethod + * + * Emit a method for a director class. + * ------------------------------------------------------------ */ + + int oneClassDirectorMethod(Node *n, Node *parent, String *super) { + String *symname = Getattr(n, "sym:name"); + if (!checkFunctionVisibility(n, parent)) { + return SWIG_OK; + } + + bool is_ignored = GetFlag(n, "feature:ignore") ? true : false; + bool is_pure_virtual = (Cmp(Getattr(n, "storage"), "virtual") == 0 && Cmp(Getattr(n, "value"), "0") == 0); + + String *name = Getattr(n, "sym:name"); + if (!name) { + assert(is_ignored); + name = Getattr(n, "name"); + } + + String *overname = NULL; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } + + String *cn = exportedName(Getattr(parent, "sym:name")); + + String *go_type_name = goCPointerType(Getattr(parent, "classtypeobj"), true); + + String *director_struct_name = NewString("_swig_Director"); + Append(director_struct_name, cn); + + bool is_static = isStatic(n); + + String *go_name = buildGoName(name, is_static, false); + + ParmList *parms = Getattr(n, "parms"); + Setattr(n, "wrap:parms", parms); + + Wrapper *dummy = NewWrapper(); + emit_attach_parmmaps(parms, dummy); + + Swig_typemap_attach_parms("gotype", parms, NULL); + Swig_typemap_attach_parms("imtype", parms, NULL); + int parm_count = emit_num_arguments(parms); + + SwigType *result = Getattr(n, "type"); + + // Save the type for overload processing. + Setattr(n, "go:type", result); + + String *interface_name = NewString("_swig_DirectorInterface"); + Append(interface_name, cn); + Append(interface_name, go_name); + if (overname) { + Append(interface_name, overname); + } + + String *callback_name = Copy(director_struct_name); + Append(callback_name, "_callback_"); + Append(callback_name, name); + Replace(callback_name, "_swig", "Swig", DOH_REPLACE_FIRST); + if (overname) { + Append(callback_name, overname); + } + if (cgo_flag) { + Append(callback_name, unique_id); + } + + String *upcall_name = Copy(director_struct_name); + Append(upcall_name, "_upcall_"); + Append(upcall_name, go_name); + + String *upcall_wname = Swig_name_wrapper(upcall_name); + if (overname) { + Append(upcall_wname, overname); + } + Append(upcall_wname, unique_id); + + String *upcall_gc_name = buildGoWrapperName(upcall_name, overname); + + String *go_with_over_name = Copy(go_name); + if (overname) { + Append(go_with_over_name, overname); + } + + Parm *p = 0; + Wrapper *w = NewWrapper(); + + Swig_director_parms_fixup(parms); + + Swig_typemap_attach_parms("directorin", parms, w); + Swig_typemap_attach_parms("directorargout", parms, w); + Swig_typemap_attach_parms("godirectorin", parms, w); + Swig_typemap_attach_parms("goin", parms, dummy); + Swig_typemap_attach_parms("goargout", parms, dummy); + + DelWrapper(dummy); + + if (!is_ignored) { + // We use an interface to see if this method is defined in Go. + Printv(f_go_wrappers, "type ", interface_name, " interface {\n", NULL); + Printv(f_go_wrappers, "\t", go_with_over_name, "(", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (i > 0) { + Printv(f_go_wrappers, ", ", NULL); + } + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")", NULL); + + if (SwigType_type(result) != T_VOID) { + String *tm = goType(n, result); + Printv(f_go_wrappers, " ", tm, NULL); + Delete(tm); + } + + Printv(f_go_wrappers, "\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + if (!GetFlag(n, "abstract")) { + if (cgo_flag) { + Printv(f_cgo_comment, "extern ", NULL); + + if (SwigType_type(result) == T_VOID) { + Printv(f_cgo_comment, "void", NULL); + } else { + bool c_struct_type; + String *ret_type = cgoTypeForGoValue(n, result, &c_struct_type); + Printv(f_cgo_comment, ret_type, NULL); + Delete(ret_type); + } + + Printv(f_cgo_comment, " ", upcall_wname, "(uintptr_t", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, Getattr(p, "type"), &c_struct_type); + Printv(f_cgo_comment, ", ", ct, " ", Getattr(p, "lname"), NULL); + p = nextParm(p); + } + Printv(f_cgo_comment, ");\n", NULL); + } else { + // Declare the upcall function, which calls the method on + // the parent class. + + if (!gccgo_flag) { + Printv(f_go_wrappers, "var ", upcall_wname, " unsafe.Pointer\n\n", NULL); + } else { + Printv(f_go_wrappers, "//extern ", go_prefix, "_", upcall_wname, "\n", NULL); + } + + Printv(f_go_wrappers, "func ", upcall_gc_name, "(_swig_ptr ", go_type_name, NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = goWrapperType(p, Getattr(p, "type"), false); + Printv(f_go_wrappers, ", _ ", tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")", NULL); + + if (SwigType_type(result) != T_VOID) { + String *tm = goWrapperType(n, result, true); + Printv(f_go_wrappers, " (_swig_ret ", tm, ")", NULL); + Delete(tm); + } + + if (!gccgo_flag) { + Printv(f_go_wrappers, " {\n", NULL); + Printv(f_go_wrappers, "\t_swig_p := uintptr(unsafe.Pointer(&_swig_ptr))\n", NULL); + Printv(f_go_wrappers, "\t_cgo_runtime_cgocall(", upcall_wname, ", _swig_p)\n", NULL); + Printv(f_go_wrappers, "\treturn\n", NULL); + Printv(f_go_wrappers, "}", NULL); + } + + Printv(f_go_wrappers, "\n\n", NULL); + } + } + + // Define the method on the director class in Go. + + Printv(f_go_wrappers, "func (swig_p *", director_struct_name, ") ", go_with_over_name, "(", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (i > 0) { + Printv(f_go_wrappers, ", ", NULL); + } + Printv(f_go_wrappers, Getattr(p, "lname"), " ", NULL); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")", NULL); + + if (SwigType_type(result) != T_VOID) { + String *tm = goType(n, result); + Printv(f_go_wrappers, " ", tm, NULL); + Delete(tm); + } + + Printv(f_go_wrappers, " {\n", NULL); + + Printv(f_go_wrappers, "\tif swig_g, swig_ok := swig_p.v.(", interface_name, "); swig_ok {\n", NULL); + Printv(f_go_wrappers, "\t\t", NULL); + if (SwigType_type(result) != T_VOID) { + Printv(f_go_wrappers, "return ", NULL); + } + Printv(f_go_wrappers, "swig_g.", go_with_over_name, "(", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (i > 0) { + Printv(f_go_wrappers, ", ", NULL); + } + Printv(f_go_wrappers, Getattr(p, "lname"), NULL); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")\n", NULL); + if (SwigType_type(result) == T_VOID) { + Printv(f_go_wrappers, "\t\treturn\n", NULL); + } + Printv(f_go_wrappers, "\t}\n", NULL); + + if (GetFlag(n, "abstract")) { + Printv(f_go_wrappers, "\tpanic(\"call to pure virtual method\")\n", NULL); + } else { + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; + bool has_goout = false; + String *goout = NULL; + if (SwigType_type(result) != T_VOID) { + ret_type = goImType(n, result); + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); + goout = goTypemapLookup("goout", n, "swig_r"); + if (goout) { + has_goout = true; + } + + if (cgo_flag) { + bool c_struct_type; + Delete(cgoTypeForGoValue(n, result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + } + } + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (goGetattr(p, "tmap:goargout")) { + has_goout = true; + } + p = nextParm(p); + } + + String *call = NewString(""); + + if (gccgo_flag && !cgo_flag) { + if (has_goout) { + Printv(call, "\tfunc() {\n", NULL); + } + Printv(call, "\tdefer SwigCgocallDone()\n", NULL); + Printv(call, "\tSwigCgocall()\n", NULL); + } + + Printv(call, "\t", NULL); + if (SwigType_type(result) != T_VOID) { + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = ", NULL); + if (cgo_flag) { + Printv(call, "(", ret_type, ")(", NULL); + } + } + if (cgo_flag && goTypeIsInterface(n, result)) { + wt = goWrapperType(n, result, true); + Printv(call, "(", wt, ")(", NULL); + } + } + + if (cgo_flag) { + Printv(call, "C.", upcall_wname, NULL); + } else { + Printv(call, upcall_gc_name, NULL); + } + Printv(call, "(", NULL); + if (cgo_flag) { + Printv(call, "C.uintptr_t(", NULL); + } + Printv(call, "swig_p.", go_type_name, NULL); + if (cgo_flag) { + Printv(call, ")", NULL); + } + + p = parms; + for (int i = 0; i < parm_count; ++i) { + Printv(call, ", ", NULL); + p = getParm(p); + SwigType *pt = Getattr(p, "type"); + + String *ln = Getattr(p, "lname"); + + String *ivar = NewStringf("_swig_i_%d", i); + + // This is an ordinary call from Go to C++, so adjust using + // the goin typemap. + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if (goTypeIsInterface(p, pt)) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, NULL); + Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + if (cgo_flag) { + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + } else { + Printv(call, ivar, NULL); + } + + p = nextParm(p); + } + + Printv(call, ")", NULL); + + if (gccgo_flag && !cgo_flag && has_goout) { + Printv(call, "\n\t}()", NULL); + } + + if (cgo_flag) { + if (wt) { + // Close the type conversion to the wrapper type. + Printv(call, ")", NULL); + } + if (SwigType_type(result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(call, ")", NULL); + } + } + + Printv(call, "\n", NULL); + + Printv(f_go_wrappers, call, NULL); + Delete(call); + + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + + goargout(parms); + + if (SwigType_type(result) != T_VOID) { + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goType(n, result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + } + + if (ret_type) { + Delete(ret_type); + } + if (wt) { + Delete(wt); + } + } + + Printv(f_go_wrappers, "}\n\n", NULL); + + // Define a method in the C++ director class that the C++ upcall + // function can call. This permits an upcall to a protected + // method. + + if (!GetFlag(n, "abstract")) { + String *upcall_method_name = NewString("_swig_upcall_"); + Append(upcall_method_name, name); + if (overname) { + Append(upcall_method_name, overname); + } + SwigType *rtype = Getattr(n, "classDirectorMethods:type"); + String *upcall_decl = Swig_method_decl(rtype, Getattr(n, "decl"), upcall_method_name, parms, 0); + Printv(f_c_directors_h, " ", upcall_decl, " {\n", NULL); + Delete(upcall_decl); + + Printv(f_c_directors_h, " ", NULL); + if (SwigType_type(result) != T_VOID) { + Printv(f_c_directors_h, "return ", NULL); + } + + String *super_call = Swig_method_call(super, parms); + Printv(f_c_directors_h, super_call, ";\n", NULL); + Delete(super_call); + + Printv(f_c_directors_h, " }\n", NULL); + + // Define the C++ function that the Go function calls. + + SwigType *first_type = NULL; + Parm *first_parm = parms; + if (!is_static) { + first_type = NewString("SwigDirector_"); + Append(first_type, class_name); + SwigType_add_pointer(first_type); + first_parm = NewParm(first_type, "p", n); + set_nextSibling(first_parm, parms); + } + + Swig_save("classDirectorMethod", n, "wrap:name", "wrap:action", NULL); + + Setattr(n, "wrap:name", upcall_wname); + + String *action = NewString(""); + if (SwigType_type(result) != T_VOID) { + Printv(action, Swig_cresult_name(), " = (", SwigType_lstr(result, 0), ")", NULL); + if (SwigType_isreference(result)) { + Printv(action, "&", NULL); + } + } + Printv(action, Swig_cparm_name(NULL, 0), "->", upcall_method_name, "(", NULL); + + p = parms; + int i = 0; + while (p != NULL) { + if (SwigType_type(Getattr(p, "type")) != T_VOID) { + String *pname = Swig_cparm_name(NULL, i + 1); + if (i > 0) { + Printv(action, ", ", NULL); + } + + // A parameter whose type is a reference is converted into a + // pointer type by gcCTypeForGoValue. We are calling a + // function which expects a reference so we need to convert + // back. + if (SwigType_isreference(Getattr(p, "type"))) { + Printv(action, "*", NULL); + } + + Printv(action, pname, NULL); + Delete(pname); + i++; + } + p = nextSibling(p); + } + Printv(action, ");", NULL); + Setattr(n, "wrap:action", action); + + if (cgo_flag) { + cgoWrapperInfo info; + + info.n = n; + info.go_name = go_name; + info.overname = overname; + info.wname = upcall_wname; + info.base = NULL; + info.parms = first_parm; + info.result = result; + info.is_static = is_static; + info.receiver = NULL; + info.is_constructor = false; + info.is_destructor = false; + + int r = cgoGccWrapper(&info); + if (r != SWIG_OK) { + return r; + } + } else if (!gccgo_flag) { + // Write the upcall wrapper function. This is compiled by gc + // and calls the C++ function. + int r = gcFunctionWrapper(upcall_wname); + if (r != SWIG_OK) { + return r; + } + r = gccFunctionWrapper(n, NULL, upcall_wname, first_parm, result); + if (r != SWIG_OK) { + return r; + } + } else { + int r = gccgoFunctionWrapper(n, NULL, upcall_wname, first_parm, result); + if (r != SWIG_OK) { + return r; + } + } + + Delete(first_type); + if (first_parm != parms) { + Delete(first_parm); + } + + Swig_restore(n); + Delete(upcall_method_name); + + // Define a function that uses the Go director type that other + // methods in the Go type can call to get parent methods. + + Printv(f_go_wrappers, "func Director", cn, go_with_over_name, "(p ", cn, NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", NULL); + String *tm = goType(p, Getattr(p, "type")); + Printv(f_go_wrappers, tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ")", NULL); + + if (SwigType_type(result) != T_VOID) { + String *tm = goType(n, result); + Printv(f_go_wrappers, " ", tm, NULL); + Delete(tm); + } + + Printv(f_go_wrappers, " {\n", NULL); + + String *ret_type = NULL; + bool memcpy_ret = false; + String *wt = NULL; + String *goout = NULL; + if (SwigType_type(result) != T_VOID) { + ret_type = goImType(n, result); + Printv(f_go_wrappers, "\tvar swig_r ", ret_type, "\n", NULL); + goout = goTypemapLookup("goout", n, "swig_r"); + + if (cgo_flag) { + bool c_struct_type; + Delete(cgoTypeForGoValue(n, result, &c_struct_type)); + if (c_struct_type) { + memcpy_ret = true; + } + } + } + + String *call = NewString(""); + + if (gccgo_flag && !cgo_flag) { + if (goout != NULL) { + Printv(call, "\tfunc() {\n", NULL); + } + Printv(call, "\tdefer SwigCgocallDone()\n", NULL); + Printv(call, "\tSwigCgocall()\n", NULL); + } + + Printv(call, "\t", NULL); + if (SwigType_type(result) != T_VOID) { + if (memcpy_ret) { + Printv(call, "swig_r_p := ", NULL); + } else { + Printv(call, "swig_r = ", NULL); + if (cgo_flag) { + Printv(call, "(", ret_type, ")(", NULL); + } + } + if (cgo_flag && goTypeIsInterface(n, result)) { + wt = goWrapperType(n, result, true); + Printv(call, "(", wt, ")(", NULL); + } + } + + if (cgo_flag) { + Printv(call, "C.", upcall_wname, NULL); + } else { + Printv(call, upcall_gc_name, NULL); + } + Printv(call, "(", NULL); + if (cgo_flag) { + Printv(call, "C.uintptr_t(", NULL); + } + Printv(call, "p.(*", director_struct_name, ").", go_type_name, NULL); + if (cgo_flag) { + Printv(call, ")", NULL); + } + + p = parms; + for (int i = 0; i < parm_count; ++i) { + Printv(call, ", ", NULL); + p = getParm(p); + SwigType *pt = Getattr(p, "type"); + + String *ivar = NewStringf("_swig_i_%d", i); + + String *ln = Copy(Getattr(p, "lname")); + + String *goin = goGetattr(p, "tmap:goin"); + if (goin == NULL) { + Printv(f_go_wrappers, "\t", ivar, " := ", ln, NULL); + if (goTypeIsInterface(p, pt)) { + Printv(f_go_wrappers, ".Swigcptr()", NULL); + } + Printv(f_go_wrappers, "\n", NULL); + } else { + String *itm = goImType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(f_go_wrappers, goin, NULL); + Delete(goin); + } + + Setattr(p, "emit:goinput", ivar); + + if (cgo_flag) { + bool c_struct_type; + String *ct = cgoTypeForGoValue(p, pt, &c_struct_type); + if (c_struct_type) { + Printv(call, "*(*C.", ct, ")(unsafe.Pointer(&", ivar, "))", NULL); + } else { + Printv(call, "C.", ct, "(", ivar, ")", NULL); + } + } else { + Printv(call, ivar, NULL); + } + + Delete(ln); + + p = nextParm(p); + } + + Printv(call, ")", NULL); + + if (gccgo_flag && !cgo_flag && goout != NULL) { + Printv(call, "\n\t}()", NULL); + } + + if (cgo_flag) { + if (wt) { + // Close the type conversion to the wrapper type. + Printv(call, ")", NULL); + } + if (SwigType_type(result) != T_VOID && !memcpy_ret) { + // Close the type conversion of the return value. + Printv(call, ")", NULL); + } + } + + Printv(call, "\n", NULL); + + Printv(f_go_wrappers, call, NULL); + Delete(call); + + if (memcpy_ret) { + Printv(f_go_wrappers, "\tswig_r = *(*", ret_type, ")(unsafe.Pointer(&swig_r_p))\n", NULL); + } + + goargout(parms); + + if (SwigType_type(result) != T_VOID) { + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goType(n, result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + } + + Printv(f_go_wrappers, "}\n\n", NULL); + + if (ret_type) { + Delete(ret_type); + } + if (wt) { + Delete(wt); + } + } + + // The Go function which invokes the method. This is called by + // the C++ method on the director class. + + if (cgo_flag) { + Printv(f_go_wrappers, "//export ", callback_name, "\n", NULL); + } + + Printv(f_go_wrappers, "func ", callback_name, "(swig_c int", NULL); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + String *tm = goWrapperType(p, Getattr(p, "type"), false); + Printv(f_go_wrappers, ", ", Getattr(p, "lname"), " ", tm, NULL); + Delete(tm); + p = nextParm(p); + } + + Printv(f_go_wrappers, ") ", NULL); + String *result_wrapper = NULL; + if (SwigType_type(result) != T_VOID) { + result_wrapper = goWrapperType(n, result, true); + Printv(f_go_wrappers, "(swig_result ", result_wrapper, ") ", NULL); + } + Printv(f_go_wrappers, "{\n", NULL); + + if (is_ignored) { + Printv(f_go_wrappers, "\treturn\n", NULL); + } else { + bool result_is_interface = false; + String *goout = NULL; + if (SwigType_type(result) != T_VOID) { + result_is_interface = goTypeIsInterface(NULL, result); + Printv(f_go_wrappers, "\tvar swig_r ", NULL); + if (!result_is_interface) { + Printv(f_go_wrappers, goType(n, result), NULL); + } else { + Printv(f_go_wrappers, result_wrapper, NULL); + } + Printv(f_go_wrappers, "\n", NULL); + goout = goTypemapLookup("godirectorout", n, "swig_r"); + } + + String *call = NewString(""); + Printv(call, "\t", NULL); + + if (SwigType_type(result) != T_VOID) { + Printv(call, "swig_r = ", NULL); + if (result_is_interface) { + Printv(call, result_wrapper, "(", NULL); + } + } + Printv(call, "swig_p.", go_with_over_name, "(", NULL); + + String *goincode = NewString(""); + + p = parms; + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (i > 0) { + Printv(call, ", ", NULL); + } + SwigType *pt = Getattr(p, "type"); + + String *ln = NewString(""); + + // If the Go representation is an interface type class, then + // we are receiving a uintptr, and must convert to the + // interface. + bool is_interface = goTypeIsInterface(p, pt); + if (is_interface) { + // Passing is_result as true to goWrapperType gives us the + // name of the Go type we need to convert to an interface. + String *wt = goWrapperType(p, pt, true); + Printv(ln, wt, "(", NULL); + Delete(wt); + } + + Printv(ln, Getattr(p, "lname"), NULL); + + if (is_interface) { + Printv(ln, ")", NULL); + } + + String *goin = goGetattr(p, "tmap:godirectorin"); + if (goin == NULL) { + Printv(call, ln, NULL); + } else { + String *ivar = NewString(""); + Printf(ivar, "_swig_i_%d", i); + String *itm = goType(p, pt); + Printv(f_go_wrappers, "\tvar ", ivar, " ", itm, "\n", NULL); + goin = Copy(goin); + Replaceall(goin, "$input", ln); + Replaceall(goin, "$result", ivar); + Printv(goincode, goin, "\n", NULL); + Delete(goin); + Printv(call, ivar, NULL); + Delete(ivar); + } + + Delete(ln); + + p = nextParm(p); + } + + Printv(call, ")", NULL); + + if (result_is_interface) { + Printv(call, ".Swigcptr())", NULL); + } + Printv(call, "\n", NULL); + + if (gccgo_flag && !cgo_flag) { + if (goout != NULL) { + Printv(f_go_wrappers, "\tfunc() {\n", NULL); + } + Printv(f_go_wrappers, "\tSwigCgocallBack()\n", NULL); + Printv(f_go_wrappers, "\tdefer SwigCgocallBackDone()\n", NULL); + } + + Printv(f_go_wrappers, "\tswig_p := swigDirectorLookup(swig_c).(*", director_struct_name, ")\n", NULL); + Printv(f_go_wrappers, goincode, NULL); + Printv(f_go_wrappers, call, NULL); + Delete(call); + + if (gccgo_flag && !cgo_flag && goout != NULL) { + Printv(f_go_wrappers, "\t}()\n", NULL); + } + + if (SwigType_type(result) != T_VOID) { + if (goout == NULL) { + Printv(f_go_wrappers, "\treturn swig_r\n", NULL); + } else { + String *tm = goImType(n, result); + Printv(f_go_wrappers, "\tvar swig_r_1 ", tm, "\n", NULL); + Replaceall(goout, "$input", "swig_r"); + Replaceall(goout, "$result", "swig_r_1"); + Printv(f_go_wrappers, goout, "\n", NULL); + Printv(f_go_wrappers, "\treturn swig_r_1\n", NULL); + } + } + } + + Printv(f_go_wrappers, "}\n\n", NULL); + + Delete(result_wrapper); + + Delete(upcall_wname); + Delete(upcall_gc_name); + Delete(go_with_over_name); + } + + if (!is_ignored || is_pure_virtual) { + // Declare the method for the director class. + + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); + String *decl = Swig_method_decl(rtype, Getattr(n, "decl"), Getattr(n, "name"), parms, 0); + Printv(f_c_directors_h, " virtual ", decl, NULL); + Delete(decl); + + String *qname = NewString(""); + Printv(qname, "SwigDirector_", class_name, "::", Getattr(n, "name"), NULL); + decl = Swig_method_decl(rtype, Getattr(n, "decl"), qname, parms, 0); + Printv(w->def, decl, NULL); + Delete(decl); + Delete(qname); + + String *throws = buildThrow(n); + if (throws) { + Printv(f_c_directors_h, " ", throws, NULL); + Printv(w->def, " ", throws, NULL); + Delete(throws); + } + + Printv(f_c_directors_h, ";\n", NULL); + + Printv(w->def, " {\n", NULL); + + if (SwigType_type(result) != T_VOID) { + if (!SwigType_isclass(result)) { + if (!(SwigType_ispointer(result) || SwigType_isreference(result))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(result, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(result, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(result, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(result, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (!is_ignored) { + makeDirectorMethodWrapper(n, w, callback_name); + } else { + assert(is_pure_virtual); + Printv(w->code, " _swig_gopanic(\"call to pure virtual function ", Getattr(parent, "sym:name"), name, "\");\n", NULL); + if (SwigType_type(result) != T_VOID) { + String *retstr = SwigType_rcaststr(result, "c_result"); + Printv(w->code, " return ", retstr, ";\n", NULL); + Delete(retstr); + } + } + + Printv(w->code, "}", NULL); + + Replaceall(w->code, "$symname", symname); + Wrapper_print(w, f_c_directors); + } + + Delete(cn); + Delete(go_type_name); + Delete(director_struct_name); + Delete(interface_name); + Delete(callback_name); + Delete(upcall_name); + Delete(go_name); + DelWrapper(w); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * makeDirectorMethodWrapper + * + * Emit the function wrapper for a director method. + * ------------------------------------------------------------ */ + void makeDirectorMethodWrapper(Node *n, Wrapper *w, String *callback_name) { + if (cgo_flag) { + makeCgoDirectorMethodWrapper(n, w, callback_name); + return; + } + + ParmList *parms = Getattr(n, "wrap:parms"); + SwigType *result = Getattr(n, "type"); + + String *callback_wname = Swig_name_wrapper(callback_name); + Append(callback_wname, unique_id); + + if (!gccgo_flag) { + Printv(f_c_directors, "extern \"C\" void ", callback_wname, "(void*, int);\n", NULL); + } else { + Printv(f_c_directors, "extern \"C\" ", NULL); + + String *fnname = NewString(""); + Printv(fnname, callback_wname, "(int", NULL); + + Parm *p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + String *cg = gccgoCTypeForGoValue(p, Getattr(p, "type"), + Getattr(p, "lname")); + Printv(fnname, ", ", cg, NULL); + Delete(cg); + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(fnname, ")", NULL); + + if (SwigType_type(result) == T_VOID) { + Printv(f_c_directors, "void ", fnname, NULL); + } else { + String *tm = gccgoCTypeForGoValue(n, result, fnname); + Printv(f_c_directors, tm, NULL); + Delete(tm); + } + + Delete(fnname); + + Printv(f_c_directors, " __asm__(\"", go_prefix, ".", callback_name, "\");\n", NULL); + } + + if (!gccgo_flag) { + Printv(w->code, " struct {\n", NULL); + Printv(w->code, " intgo go_val;\n", NULL); + + Parm *p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + String *ln = Getattr(p, "lname"); + String *cg = gcCTypeForGoValue(p, Getattr(p, "type"), ln); + Printv(w->code, " ", cg, ";\n", NULL); + Delete(cg); + p = Getattr(p, "tmap:directorin:next"); + } + if (SwigType_type(result) != T_VOID) { + Printv(w->code, " long : 0;\n", NULL); + String *rname = NewString(Swig_cresult_name()); + String *cg = gcCTypeForGoValue(n, result, rname); + Printv(w->code, " ", cg, ";\n", NULL); + Delete(cg); + Delete(rname); + } + + Printv(w->code, " } SWIGSTRUCTPACKED swig_a;\n", NULL); + Printv(w->code, " swig_a.go_val = go_val;\n", NULL); + + p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + String *tm = Getattr(p, "tmap:directorin"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, + line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + String *ln = Getattr(p, "lname"); + String *input = NewString(""); + Printv(input, "swig_a.", ln, NULL); + Setattr(p, "emit:directorinput", input); + Replaceall(tm, "$input", input); + Replaceall(tm, "$owner", "0"); + Delete(input); + Printv(w->code, "\t", tm, "\n", NULL); + Delete(tm); + } + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(w->code, " crosscall2(", callback_wname, ", &swig_a, (int) sizeof swig_a);\n", NULL); + + /* Marshal outputs */ + for (p = parms; p;) { + String *tm; + if ((tm = Getattr(p, "tmap:directorargout"))) { + tm = Copy(tm); + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + if (SwigType_type(result) != T_VOID) { + String *result_str = NewString("c_result"); + String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use type %s as director method result\n", SwigType_str(result, 0)); + } else { + static const String *swig_a_result = NewStringf("swig_a.%s", Swig_cresult_name()); + Replaceall(tm, "$input", swig_a_result); + Replaceall(tm, "$result", "c_result"); + Printv(w->code, " ", tm, "\n", NULL); + String *retstr = SwigType_rcaststr(result, "c_result"); + Printv(w->code, " return ", retstr, ";\n", NULL); + Delete(retstr); + Delete(tm); + } + Delete(result_str); + } + + // The C wrapper code which calls the Go function. + Printv(f_gc_wrappers, "#pragma dynexport ", callback_wname, " ", callback_wname, "\n", NULL); + Printv(f_gc_wrappers, "#pragma cgo_export_static ", callback_wname, " ", callback_wname, "\n", NULL); + Printv(f_gc_wrappers, "#pragma textflag 7\n", NULL); + Printv(f_gc_wrappers, "extern void \xc2\xb7", callback_name, "();\n", NULL); + Printv(f_gc_wrappers, "void\n", NULL); + Printv(f_gc_wrappers, callback_wname, "(void *a, int32 n)\n", NULL); + Printv(f_gc_wrappers, "{\n", NULL); + Printv(f_gc_wrappers, "\truntime\xc2\xb7" "cgocallback(\xc2\xb7", callback_name, ", a, n);\n", NULL); + Printv(f_gc_wrappers, "}\n\n", NULL); + } else { + if (SwigType_type(result) != T_VOID) { + String *r = NewString(Swig_cresult_name()); + String *tm = gccgoCTypeForGoValue(n, result, r); + Wrapper_add_local(w, r, tm); + Delete(tm); + Delete(r); + } + + String *args = NewString(""); + + Parm *p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + String *pn = NewString("g"); + Append(pn, Getattr(p, "lname")); + Setattr(p, "emit:directorinput", pn); + + String *tm = gccgoCTypeForGoValue(n, Getattr(p, "type"), pn); + Wrapper_add_local(w, pn, tm); + Delete(tm); + + tm = Getattr(p, "tmap:directorin"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, + line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", pn); + Replaceall(tm, "$owner", 0); + Printv(w->code, " ", tm, "\n", NULL); + Delete(tm); + + Printv(args, ", ", pn, NULL); + } + + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(w->code, " ", NULL); + if (SwigType_type(result) != T_VOID) { + Printv(w->code, Swig_cresult_name(), " = ", NULL); + } + Printv(w->code, callback_wname, "(go_val", args, ");\n", NULL); + + /* Marshal outputs */ + for (p = parms; p;) { + String *tm; + if ((tm = Getattr(p, "tmap:directorargout"))) { + tm = Copy(tm); + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + if (SwigType_type(result) != T_VOID) { + String *result_str = NewString("c_result"); + String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use type %s as director method result\n", SwigType_str(result, 0)); + } else { + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$result", "c_result"); + Printv(w->code, " ", tm, "\n", NULL); + String *retstr = SwigType_rcaststr(result, "c_result"); + Printv(w->code, " return ", retstr, ";\n", NULL); + Delete(retstr); + Delete(tm); + } + Delete(result_str); + } + } + + Delete(callback_wname); + } + + /* ------------------------------------------------------------ + * makeDirectorMethodWrapper + * + * Emit the function wrapper for a director method for cgo. + * ------------------------------------------------------------ */ + + void makeCgoDirectorMethodWrapper(Node *n, Wrapper *w, String *callback_name) { + ParmList *parms = Getattr(n, "wrap:parms"); + SwigType *result = Getattr(n, "type"); + + Printv(f_c_directors, "extern \"C\" ", NULL); + + String *fnname = Copy(callback_name); + Append(fnname, "(int"); + + Parm *p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + String *cg = gcCTypeForGoValue(p, Getattr(p, "type"), Getattr(p, "lname")); + Printv(fnname, ", ", cg, NULL); + Delete(cg); + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(fnname, ")", NULL); + + if (SwigType_type(result) == T_VOID) { + Printv(f_c_directors, "void ", fnname, NULL); + } else { + String *tm = gcCTypeForGoValue(n, result, fnname); + Printv(f_c_directors, tm, NULL); + Delete(tm); + } + + Delete(fnname); + + Printv(f_c_directors, ";\n", NULL); + + if (SwigType_type(result) != T_VOID) { + String *r = NewString(Swig_cresult_name()); + String *tm = gcCTypeForGoValue(n, result, r); + Wrapper_add_local(w, r, tm); + Delete(tm); + Delete(r); + } + + String *args = NewString(""); + + p = parms; + while (p) { + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + String *pn = NewString("swig_"); + Append(pn, Getattr(p, "lname")); + Setattr(p, "emit:directorinput", pn); + + String *tm = gcCTypeForGoValue(p, Getattr(p, "type"), pn); + Wrapper_add_local(w, pn, tm); + Delete(tm); + + tm = Getattr(p, "tmap:directorin"); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, + line_number, "Unable to use type %s as director method argument\n", SwigType_str(Getattr(p, "type"), 0)); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", pn); + Replaceall(tm, "$owner", 0); + Printv(w->code, " ", tm, "\n", NULL); + Delete(tm); + + Printv(args, ", ", pn, NULL); + } + + p = Getattr(p, "tmap:directorin:next"); + } + + Printv(w->code, " ", NULL); + if (SwigType_type(result) != T_VOID) { + Printv(w->code, Swig_cresult_name(), " = ", NULL); + } + Printv(w->code, callback_name, "(go_val", args, ");\n", NULL); + + /* Marshal outputs */ + for (p = parms; p; ) { + String *tm; + if ((tm = Getattr(p, "tmap:directorargout"))) { + tm = Copy(tm); + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NULL); + Delete(tm); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + if (SwigType_type(result) != T_VOID) { + String *result_str = NewString("c_result"); + String *tm = Swig_typemap_lookup("directorout", n, result_str, NULL); + if (!tm) { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use type %s as director method result\n", SwigType_str(result, 0)); + } else { + tm = Copy(tm); + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$result", "c_result"); + Printv(w->code, " ", tm, "\n", NULL); + String *retstr = SwigType_rcaststr(result, "c_result"); + Printv(w->code, " return ", retstr, ";\n", NULL); + Delete(retstr); + Delete(tm); + } + Delete(result_str); + } + } + + + /* ------------------------------------------------------------ + * classDirectorEnd + * + * Complete support for a director class. + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + (void) n; + + Printv(f_c_directors_h, " private:\n", NULL); + Printv(f_c_directors_h, " intgo go_val;\n", NULL); + Printv(f_c_directors_h, " Swig_memory *swig_mem;\n", NULL); + Printv(f_c_directors_h, "};\n\n", NULL); + + class_name = NULL; + class_node = NULL; + + Delete(class_receiver); + class_receiver = NULL; + + Delete(class_methods); + class_methods = NULL; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorDisown + * + * I think Go does not require a disown method. + * ------------------------------------------------------------ */ + + int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * buildThrow() + * + * Build and return a throw clause if needed. + *--------------------------------------------------------------------*/ + + String *buildThrow(Node *n) { + if (Getattr(n, "noexcept")) + return NewString("noexcept"); + ParmList *throw_parm_list = Getattr(n, "throws"); + if (!throw_parm_list && !Getattr(n, "throw")) + return NULL; + String *ret = NewString("throw("); + if (throw_parm_list) { + Swig_typemap_attach_parms("throws", throw_parm_list, NULL); + } + bool first = true; + for (Parm *p = throw_parm_list; p; p = nextSibling(p)) { + if (Getattr(p, "tmap:throws")) { + if (first) { + first = false; + } else { + Printv(ret, ", ", NULL); + } + String *s = SwigType_str(Getattr(p, "type"), 0); + Printv(ret, s, NULL); + Delete(s); + } + } + Printv(ret, ")", NULL); + return ret; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + * + * We don't need to check upcall when calling methods. + *--------------------------------------------------------------------*/ + + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * makeDispatchFunction + * + * Make a dispatch function for an overloaded C++ function. The + * receiver parameter is the receiver for a method, unless is_upcall + * is true. If is_upcall is true, then the receiver parameter is + * the type of the first argument to the function. + *--------------------------------------------------------------------*/ + + int makeDispatchFunction(Node *n, String *go_name, String *receiver, bool is_static, SwigType *director_struct, bool is_upcall) { + bool is_director = director_struct ? true : false; + + String *nodetype = Getattr(n, "nodeType"); + bool is_constructor = Cmp(nodetype, "constructor") == 0; + bool is_destructor = Cmp(nodetype, "destructor") == 0; + + bool can_use_receiver = (!is_constructor && !is_destructor && !is_upcall); + + bool use_receiver = (!is_static && can_use_receiver); + + bool add_to_interface = (interfaces && !is_constructor && !is_destructor && !is_static && !is_upcall); + + List *dispatch = Swig_overload_rank(n, false); + int nfunc = Len(dispatch); + + SwigType *all_result; + bool mismatch; + if (is_constructor) { + assert(!is_upcall); + if (!is_director) { + all_result = Copy(Getattr(class_node, "classtypeobj")); + } else { + all_result = Copy(director_struct); + } + mismatch = false; + } else { + all_result = NULL; + mismatch = false; + bool any_void = false; + for (int i = 0; i < nfunc; ++i) { + Node *nn = Getitem(dispatch, i); + Node *ni = Getattr(nn, "directorNode") ? Getattr(nn, "directorNode") : nn; + SwigType *result = Getattr(ni, "go:type"); + assert(result); + + if (SwigType_type(result) == T_VOID) { + if (all_result) { + mismatch = true; + } + any_void = true; + } else { + if (any_void) { + mismatch = true; + } else if (!all_result) { + all_result = Copy(result); + } else if (Cmp(result, all_result) != 0) { + mismatch = true; + } + } + } + if (mismatch) { + Delete(all_result); + all_result = NULL; + } else if (all_result) { + ; + } else { + all_result = NewString("void"); + } + } + + Printv(f_go_wrappers, "func ", NULL); + + if (receiver && use_receiver) { + Printv(f_go_wrappers, "(p ", receiver, ") ", NULL); + } + + Printv(f_go_wrappers, go_name, "(", NULL); + if (is_director && is_constructor) { + Printv(f_go_wrappers, "abi interface{}, ", NULL); + assert(!add_to_interface); + } + if (is_upcall) { + Printv(f_go_wrappers, "p *", receiver, ", ", NULL); + assert(!add_to_interface); + } + Printv(f_go_wrappers, "a ...interface{})", NULL); + + if (add_to_interface) { + Printv(interfaces, "\t", go_name, "(a ...interface{})", NULL); + } + + if (mismatch) { + Printv(f_go_wrappers, " interface{}", NULL); + if (add_to_interface) { + Printv(interfaces, " interface{}", NULL); + } + } else if (all_result && SwigType_type(all_result) != T_VOID) { + if (is_director && is_constructor) { + Printv(f_go_wrappers, " ", receiver, NULL); + if (add_to_interface) { + Printv(interfaces, " ", receiver, NULL); + } + } else { + String *tm = goType(n, all_result); + Printv(f_go_wrappers, " ", tm, NULL); + if (add_to_interface) { + Printv(interfaces, " ", tm, NULL); + } + Delete(tm); + } + } + Printv(f_go_wrappers, " {\n", NULL); + if (add_to_interface) { + Printv(interfaces, "\n", NULL); + } + + Printv(f_go_wrappers, "\targc := len(a)\n", NULL); + + for (int i = 0; i < nfunc; ++i) { + int fn = 0; + Node *nn = Getitem(dispatch, i); + Node *ni = Getattr(nn, "directorNode") ? Getattr(nn, "directorNode") : nn; + Parm *pi = Getattr(ni, "wrap:parms"); + + // If we are using a receiver, we want to ignore a leading self + // parameter. Because of the way this is called, there may or + // may not be a self parameter at this point. + if (use_receiver && pi && Getattr(pi, "self")) { + pi = getParm(pi); + if (pi) { + pi = nextParm(pi); + } + } + + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + bool varargs = emit_isvarargs(pi) ? true : false; + + if (varargs) { + Printf(f_go_wrappers, "\tif argc >= %d {\n", num_required); + } else { + if (num_required == num_arguments) { + Printf(f_go_wrappers, "\tif argc == %d {\n", num_required); + } else { + Printf(f_go_wrappers, "\tif argc >= %d && argc <= %d {\n", num_required, num_arguments); + } + } + + // Build list of collisions with the same number of arguments. + List *coll = NewList(); + for (int k = i + 1; k < nfunc; ++k) { + Node *nnk = Getitem(dispatch, k); + Node *nk = Getattr(nnk, "directorNode") ? Getattr(nnk, "directorNode") : nnk; + Parm *pk = Getattr(nk, "wrap:parms"); + if (use_receiver && pk && Getattr(pk, "self")) { + pk = getParm(pk); + if (pk) { + pk = nextParm(pk); + } + } + int nrk = emit_num_required(pk); + int nak = emit_num_arguments(pk); + if ((nrk >= num_required && nrk <= num_arguments) + || (nak >= num_required && nak <= num_arguments) + || (nrk <= num_required && nak >= num_arguments) + || (varargs && nrk >= num_required)) { + Append(coll, nk); + } + } + + int num_braces = 0; + if (Len(coll) > 0 && num_arguments > 0) { + int j = 0; + Parm *pj = pi; + while (pj) { + pj = getParm(pj); + if (!pj) { + break; + } + + // If all the overloads have the same type in this position, + // we can omit the check. + SwigType *tm = goOverloadType(pj, Getattr(pj, "type")); + bool emitcheck = false; + for (int k = 0; k < Len(coll) && !emitcheck; ++k) { + Node *nk = Getitem(coll, k); + Parm *pk = Getattr(nk, "wrap:parms"); + if (use_receiver && pk && Getattr(pk, "self")) { + pk = getParm(pk); + if (pk) { + pk = nextParm(pk); + } + } + int nak = emit_num_arguments(pk); + if (nak <= j) + continue; + int l = 0; + Parm *pl = pk; + while (pl && l <= j) { + pl = getParm(pl); + if (!pl) { + break; + } + if (l == j) { + SwigType *tml = goOverloadType(pl, Getattr(pl, "type")); + if (Cmp(tm, tml) != 0) { + emitcheck = true; + } + Delete(tml); + } + pl = nextParm(pl); + ++l; + } + } + + if (emitcheck) { + if (j >= num_required) { + Printf(f_go_wrappers, "\t\tif argc > %d {\n", j); + ++num_braces; + } + + fn = i + 1; + Printf(f_go_wrappers, "\t\tif _, ok := a[%d].(%s); !ok {\n", j, tm); + Printf(f_go_wrappers, "\t\t\tgoto check_%d\n", fn); + Printv(f_go_wrappers, "\t\t}\n", NULL); + } + + Delete(tm); + + pj = nextParm(pj); + + ++j; + } + } + + for (; num_braces > 0; --num_braces) { + Printv(f_go_wrappers, "\t\t}\n", NULL); + } + + // We may need to generate multiple calls if there are variable + // argument lists involved. Build the start of the call. + + String *start = NewString(""); + + SwigType *result = Getattr(ni, "go:type"); + + if (is_constructor) { + result = all_result; + } else if (is_destructor) { + result = NULL; + } + + if (result && SwigType_type(result) != T_VOID && (!all_result || SwigType_type(all_result) != T_VOID)) { + Printv(start, "return ", NULL); + } + + bool advance_parm = false; + + if (receiver && use_receiver) { + Printv(start, "p.", go_name, NULL); + } else if (can_use_receiver && !isStatic(ni) && pi && Getattr(pi, "self")) { + // This is an overload of a static function and a non-static + // function. + assert(num_required > 0); + SwigType *tm = goWrapperType(pi, Getattr(pi, "type"), true); + String *nm = buildGoName(Getattr(ni, "sym:name"), false, isFriend(ni)); + Printv(start, "a[0].(", tm, ").", nm, NULL); + Delete(nm); + Delete(tm); + advance_parm = true; + } else { + Printv(start, go_name, NULL); + } + + Printv(start, Getattr(ni, "sym:overname"), "(", NULL); + + bool need_comma = false; + + if (is_director && is_constructor) { + Printv(start, "abi", NULL); + need_comma = true; + } + if (is_upcall) { + Printv(start, "p", NULL); + need_comma = true; + } + Parm *p = pi; + int pn = 0; + if (advance_parm) { + p = getParm(p); + if (p) { + p = nextParm(p); + } + ++pn; + } + while (pn < num_required) { + p = getParm(p); + + if (need_comma) { + Printv(start, ", ", NULL); + } + + SwigType *tm = goType(p, Getattr(p, "type")); + Printf(start, "a[%d].(%s)", pn, tm); + Delete(tm); + + need_comma = true; + ++pn; + p = nextParm(p); + } + + String *end = NULL; + if (!result || SwigType_type(result) == T_VOID || (all_result && SwigType_type(all_result) == T_VOID)) { + end = NewString(""); + Printv(end, "return", NULL); + if (!all_result || SwigType_type(all_result) != T_VOID) { + Printv(end, " 0", NULL); + } + } + + if (num_required == num_arguments) { + Printv(f_go_wrappers, "\t\t", start, ")\n", NULL); + if (end) { + Printv(f_go_wrappers, "\t\t", end, "\n", NULL); + } + } else { + Printv(f_go_wrappers, "\t\tswitch argc {\n", NULL); + for (int j = num_required; j <= num_arguments; ++j) { + Printf(f_go_wrappers, "\t\tcase %d:\n", j); + Printv(f_go_wrappers, "\t\t\t", start, NULL); + bool nc = need_comma; + for (int k = num_required; k < j; ++k) { + if (nc) { + Printv(f_go_wrappers, ", ", NULL); + } + Printf(f_go_wrappers, "a[%d]", k); + nc = true; + } + Printv(f_go_wrappers, ")\n", NULL); + if (end) { + Printv(f_go_wrappers, "\t\t\t", end, "\n", NULL); + } + } + Printv(f_go_wrappers, "\t\t}\n", NULL); + } + + Printv(f_go_wrappers, "\t}\n", NULL); + + if (fn != 0) { + Printf(f_go_wrappers, "check_%d:\n", fn); + } + + Delete(coll); + } + + Printv(f_go_wrappers, "\tpanic(\"No match for overloaded function call\")\n", NULL); + Printv(f_go_wrappers, "}\n\n", NULL); + + Delete(all_result); + Delete(dispatch); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * checkFunctionVisibility() + * + * Return true if we should write out a function based on its + * visibility, false otherwise. + * ---------------------------------------------------------------------- */ + + bool checkFunctionVisibility(Node *n, Node *parent) { + // Write out a public function. + if (is_public(n)) + return true; + // Don't write out a private function. + if (is_private(n)) + return false; + // Write a protected function for a director class in + // dirprot_mode. + if (parent == NULL) { + return false; + } + if (dirprot_mode() && Swig_directorclass(parent)) + return true; + // Otherwise don't write out a protected function. + return false; + } + + + /* ---------------------------------------------------------------------- + * exportedName() + * + * Given a C/C++ name, return a name in Go which will be exported. + * If the first character is an upper case letter, this returns a + * copy of its argument. If the first character is a lower case + * letter, this forces it to upper case. Otherwise, this prepends + * 'X'. + * ---------------------------------------------------------------------- */ + + String *exportedName(String *name) { + String *copy = Copy(name); + char c = *Char(copy); + if (islower(c)) { + char l[2]; + char u[2]; + l[0] = c; + l[1] = '\0'; + u[0] = toupper(c); + u[1] = '\0'; + Replace(copy, l, u, DOH_REPLACE_FIRST); + } else if (!isalpha(c)) { + char l[2]; + char u[3]; + l[0] = c; + l[1] = '\0'; + u[0] = 'X'; + u[1] = c; + u[2] = '\0'; + Replace(copy, l, u, DOH_REPLACE_FIRST); + } + String *ret = Swig_name_mangle(copy); + Delete(copy); + return ret; + } + + /* ---------------------------------------------------------------------- + * removeClassname() + * + * If the name starts with the current class name, followed by an + * underscore, remove it. If there is no current class name, this + * simply returns a copy of the name. This undoes Swig's way of + * recording the class name in a member name. + * ---------------------------------------------------------------------- */ + + String *removeClassname(String *name) { + String *copy = Copy(name); + if (class_name) { + char *p = Char(name); + if (Strncmp(name, class_name, Len(class_name)) == 0 && p[Len(class_name)] == '_') { + Replace(copy, class_name, "", DOH_REPLACE_FIRST); + Replace(copy, "_", "", DOH_REPLACE_FIRST); + } + } + return copy; + } + + /* ---------------------------------------------------------------------- + * buildGoName() + * + * Build the name to use for an ordinary function, variable, or + * whatever in Go. The name argument is something like the sym:name + * attribute of the node. If is_static is false, this could be a + * method, and the returned name will be the name of the + * method--i.e., it will not include the class name. + * ---------------------------------------------------------------------- */ + + String *buildGoName(String *name, bool is_static, bool is_friend) { + String *nw = NewString(""); + if (is_static && !is_friend && class_name) { + String *c1 = exportedName(class_name); + Append(nw, c1); + Delete(c1); + } + String *c2 = removeClassname(name); + String *c3 = exportedName(c2); + Append(nw, c3); + Delete(c2); + Delete(c3); + String *ret = Swig_name_mangle(nw); + Delete(nw); + return ret; + } + + /* ---------------------------------------------------------------------- + * buildGoWrapperName() + * + * Build the name to use for a Go wrapper function. This is a + * function called by the real Go function in order to convert C++ + * classes from interfaces to pointers, and other such conversions + * between the Go type and the C++ type. + * ---------------------------------------------------------------------- */ + + String *buildGoWrapperName(String *name, String *overname) { + String *s1 = NewString("_swig_wrap_"); + Append(s1, name); + String *s2 = Swig_name_mangle(s1); + Delete(s1); + if (overname) { + Append(s2, overname); + } + return s2; + } + + /* ---------------------------------------------------------------------- + * checkNameConflict() + * + * Check for a name conflict on the name we are going to use in Go. + * These conflicts are likely because of the enforced + * capitalization. When we find one, issue a warning and return + * false. If the name is OK, return true. + * ---------------------------------------------------------------------- */ + + bool checkNameConflict(String* name, Node* n, const_String_or_char_ptr scope) { + Node *lk = symbolLookup(name, scope); + if (lk) { + String *n1 = Getattr(n, "sym:name"); + if (!n1) { + n1 = Getattr(n, "name"); + } + String *n2 = Getattr(lk, "sym:name"); + if (!n2) { + n2 = Getattr(lk, "name"); + } + Swig_warning(WARN_GO_NAME_CONFLICT, input_file, line_number, + "Ignoring '%s' due to Go name ('%s') conflict with '%s'\n", + n1, name, n2); + return false; + } + bool r = addSymbol(name, n, scope) ? true : false; + assert(r); + return true; + } + + /* ---------------------------------------------------------------------- + * checkIgnoredParameters() + * + * If any of the parameters of this function, or the return type, + * are ignored due to a name conflict, give a warning and return + * false. + * ---------------------------------------------------------------------- */ + + bool checkIgnoredParameters(Node *n, String *go_name) { + ParmList *parms = Getattr(n, "parms"); + if (parms) { + Wrapper *dummy = NewWrapper(); + emit_attach_parmmaps(parms, dummy); + int parm_count = emit_num_arguments(parms); + Parm *p = parms; + + for (int i = 0; i < parm_count; ++i) { + p = getParm(p); + if (!checkIgnoredType(n, go_name, Getattr(p, "type"))) { + DelWrapper(dummy); + return false; + } + p = nextParm(p); + } + + DelWrapper(dummy); + } + + if (!checkIgnoredType(n, go_name, Getattr(n, "type"))) { + return false; + } + + return true; + } + + /* ---------------------------------------------------------------------- + * checkIgnoredType() + * + * If this type is being ignored due to a name conflict, give a + * warning and return false. + * ---------------------------------------------------------------------- */ + + bool checkIgnoredType(Node *n, String *go_name, SwigType *type) { + if (hasGoTypemap(n, type)) { + return true; + } + + SwigType *t = SwigType_typedef_resolve_all(type); + + bool ret = true; + bool is_conflict = false; + Node *e = Language::enumLookup(t); + if (e) { + if (GetFlag(e, "go:conflict")) { + is_conflict = true; + } + } else if (SwigType_issimple(t)) { + Node *cn = classLookup(t); + if (cn) { + if (GetFlag(cn, "go:conflict")) { + is_conflict = true; + } + } + } else if (SwigType_ispointer(t) || SwigType_isarray(t) || SwigType_isqualifier(t) || SwigType_isreference(t)) { + SwigType *r = Copy(t); + if (SwigType_ispointer(r)) { + SwigType_del_pointer(r); + } else if (SwigType_isarray(r)) { + SwigType_del_array(r); + } else if (SwigType_isqualifier(r)) { + SwigType_del_qualifier(r); + } else { + SwigType_del_reference(r); + } + + if (!checkIgnoredType(n, go_name, r)) { + ret = false; + } + + Delete(r); + } + + if (is_conflict) { + String *s = SwigType_str(t, NULL); + Swig_warning(WARN_GO_NAME_CONFLICT, input_file, line_number, + "Ignoring '%s' (Go name '%s') due to Go name conflict for parameter or result type '%s'\n", + Getattr(n, "name"), go_name, s); + Delete(s); + ret = false; + } + + Delete(t); + + return ret; + } + + /* ---------------------------------------------------------------------- + * goType() + * + * Given a SWIG type, return a string for the type in Go. + * ---------------------------------------------------------------------- */ + + String *goType(Node *n, SwigType *type) { + return goTypeWithInfo(n, type, false, NULL); + } + + /* ---------------------------------------------------------------------- + * goImType() + * + * Given a SWIG type, return a string for the intermediate Go type + * to pass to C/C++. This is like goType except that it looks for + * an imtype typemap entry first. + * ---------------------------------------------------------------------- */ + + String *goImType(Node *n, SwigType *type) { + return goTypeWithInfo(n, type, true, NULL); + } + + /* ---------------------------------------------------------------------- + * goTypeWithInfo() + * + * Like goType, but return some more information. + * + * If use_imtype is true, this look for a imtype typemap entry. + * + * If the p_is_interface parameter is not NULL, this sets + * *p_is_interface to indicate whether this type is going to be + * represented by a Go interface type. These are cases where the Go + * code needs to make some adjustments when passing values back and + * forth with C/C++. + * ---------------------------------------------------------------------- */ + + String *goTypeWithInfo(Node *n, SwigType *type, bool use_imtype, bool *p_is_interface) { + if (p_is_interface) { + *p_is_interface = false; + } + + String *ret = NULL; + if (use_imtype) { + if (n && Cmp(type, Getattr(n, "type")) == 0) { + if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) { + ret = Getattr(n, "tmap:imtype"); + } + if (!ret) { + ret = Swig_typemap_lookup("imtype", n, "", NULL); + } + } else { + Parm *p = NewParm(type, "goImType", n); + ret = Swig_typemap_lookup("imtype", p, "", NULL); + Delete(p); + } + } + if (!ret) { + if (n && Cmp(type, Getattr(n, "type")) == 0) { + if (Strcmp(Getattr(n, "nodeType"), "parm") == 0) { + ret = Getattr(n, "tmap:gotype"); + } + if (!ret) { + ret = Swig_typemap_lookup("gotype", n, "", NULL); + } + } else { + Parm *p = NewParm(type, "goType", n); + ret = Swig_typemap_lookup("gotype", p, "", NULL); + Delete(p); + } + } + + if (ret && Strstr(ret, "$gotypename") != 0) { + ret = NULL; + } + + if (ret) { + return Copy(ret); + } + + SwigType *t = SwigType_typedef_resolve_all(type); + + if (SwigType_isenum(t)) { + Node *e = Language::enumLookup(t); + if (e) { + ret = goEnumName(e); + } else if (Strcmp(t, "enum ") == 0) { + ret = NewString("int"); + } else { + // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum + String *tt = Copy(t); + Replace(tt, "enum ", "", DOH_REPLACE_ANY); + ret = exportedName(tt); + Setattr(undefined_enum_types, t, ret); + Delete(tt); + } + } else if (SwigType_isfunctionpointer(t) || SwigType_isfunction(t)) { + ret = NewString("_swig_fnptr"); + } else if (SwigType_ismemberpointer(t)) { + ret = NewString("_swig_memberptr"); + } else if (SwigType_issimple(t)) { + Node *cn = classLookup(t); + if (cn) { + ret = Getattr(cn, "sym:name"); + if (!ret) { + ret = Getattr(cn, "name"); + } + ret = exportedName(ret); + + Node *cnmod = Getattr(cn, "module"); + if (!cnmod || Strcmp(Getattr(cnmod, "name"), module) == 0) { + Setattr(undefined_types, t, t); + } else { + String *nw = NewString(""); + Printv(nw, getModuleName(Getattr(cnmod, "name")), ".", ret, NULL); + Delete(ret); + ret = nw; + } + } else { + // SWIG does not know about this type. + ret = exportedName(t); + Setattr(undefined_types, t, t); + } + if (p_is_interface) { + *p_is_interface = true; + } + } else if (SwigType_ispointer(t) || SwigType_isarray(t)) { + SwigType *r = Copy(t); + if (SwigType_ispointer(r)) { + SwigType_del_pointer(r); + } else { + SwigType_del_array(r); + } + + if (SwigType_type(r) == T_VOID) { + ret = NewString("uintptr"); + } else { + bool is_interface; + String *base = goTypeWithInfo(n, r, false, &is_interface); + + // At the Go level, an unknown or class type is handled as an + // interface wrapping a pointer. This means that if a + // function returns the C type X, we will be wrapping the C + // type X*. In Go we will call that type X. That means that + // if a C function expects X*, we can pass the Go type X. And + // that means that when we see the C type X*, we should use + // the Go type X. + + // The is_interface variable tells us this. However, it will + // be true both for the case of X and for the case of X*. If + // r is a pointer here, then we are looking at X**. There is + // really no good way for us to handle that. + bool is_pointer_to_pointer = false; + if (is_interface) { + SwigType *c = Copy(r); + if (SwigType_isqualifier(c)) { + SwigType_del_qualifier(c); + if (SwigType_ispointer(c) || SwigType_isarray(c)) { + is_pointer_to_pointer = true; + } + } + Delete(c); + } + + if (is_interface) { + if (!is_pointer_to_pointer) { + ret = base; + if (p_is_interface) { + *p_is_interface = true; + } + } else { + ret = NewString("uintptr"); + } + } else { + ret = NewString("*"); + Append(ret, base); + Delete(base); + } + } + + Delete(r); + } else if (SwigType_isreference(t)) { + SwigType *r = Copy(t); + SwigType_del_reference(r); + + // If this is a const reference, and we are looking at a pointer + // to it, then we just use the pointer we already have. + bool add_pointer = true; + if (SwigType_isqualifier(r)) { + String *q = SwigType_parm(r); + if (Strcmp(q, "const") == 0) { + SwigType *c = Copy(r); + SwigType_del_qualifier(c); + if (SwigType_ispointer(c)) { + add_pointer = false; + } + Delete(c); + } + } + if (add_pointer) { + SwigType_add_pointer(r); + } + ret = goTypeWithInfo(n, r, false, p_is_interface); + Delete(r); + } else if (SwigType_isqualifier(t)) { + SwigType *r = Copy(t); + SwigType_del_qualifier(r); + ret = goTypeWithInfo(n, r, false, p_is_interface); + Delete(r); + } else if (SwigType_isvarargs(t)) { + ret = NewString("[]interface{}"); + } + + Delete(t); + + if (!ret) { + Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, "No Go typemap defined for %s\n", SwigType_str(type, 0)); + ret = NewString("uintptr"); + } + + return ret; + } + + /* ---------------------------------------------------------------------- + * cgoTypeForGoValue() + * + * Given a SWIG type, return a string for the C type to use for the + * cgo wrapper code. This always returns a simple identifier, since + * it is used in Go code as C.name. + * + * This sets *c_struct_type if the C type uses a struct where the Go + * type uses a simple type. This is true for strings and slices. + * When this is true the Go code has to jump through unsafe hoops to + * pass the type checker. + * ---------------------------------------------------------------------- */ + + String *cgoTypeForGoValue(Node *n, SwigType *type, bool *c_struct_type) { + *c_struct_type = false; + + bool is_interface; + String *go_type = goTypeWithInfo(n, type, true, &is_interface); + if (is_interface) { + Delete(go_type); + return NewString("uintptr_t"); + } + if (Strcmp(go_type, "uintptr") == 0) { + Delete(go_type); + return NewString("uintptr_t"); + } + if (((char*)Char(go_type))[0] == '*') { + // Treat all pointers as void*. There is no meaningful type + // checking going on here anyhow, and that lets us avoid + // worrying about defining the base type of the pointer. + Delete(go_type); + return NewString("swig_voidp"); + } + + // Check for some Go types that are really pointers under the covers. + bool is_hidden_pointer = Strncmp(go_type, "func(", 5) == 0 || Strncmp(go_type, "map[", 4) == 0 || Strncmp(go_type, "chan ", 5) == 0; + + Delete(go_type); + + String *ct = Getattr(n, "emit:cgotype"); + if (ct) { + *c_struct_type = Getattr(n, "emit:cgotypestruct") ? true : false; + return Copy(ct); + } + + String *t = Copy(type); + if (SwigType_isarray(t)) { + SwigType_del_array(t); + SwigType_add_pointer(t); + } + + bool add_typedef = true; + + static int count; + ++count; + ct = NewStringf("swig_type_%d", count); + + String *gct = gcCTypeForGoValue(n, t, ct); + Delete(t); + + if (Strncmp(gct, "_gostring_", 10) == 0 || Strncmp(gct, "_goslice_", 9) == 0) { + *c_struct_type = true; + Setattr(n, "emit:cgotypestruct", type); + } else { + char *p = Strstr(gct, ct); + if (p != NULL && p > (char*)Char(gct) && p[-1] == '*' && p[Len(ct)] == '\0') { + // Treat all pointers as void*. See above. + Delete(ct); + --count; + ct = NewString("swig_voidp"); + add_typedef = false; + if (is_hidden_pointer) { + // A Go type that is really a pointer, like func, map, chan, + // is being represented in C by a pointer. This is fine, + // but we have to memcpy the type rather than simply + // converting it. + *c_struct_type = true; + Setattr(n, "emit:cgotypestruct", type); + } + } + + if (Strncmp(gct, "bool ", 5) == 0) { + // Change the C++ type bool to the C type _Bool. + Replace(gct, "bool", "_Bool", DOH_REPLACE_FIRST); + } + if (Strncmp(gct, "intgo ", 6) == 0) { + // We #define intgo to swig_intgo for the cgo comment. + Replace(gct, "intgo", "swig_intgo", DOH_REPLACE_FIRST); + } + p = Strstr(gct, ct); + if (p != NULL && p > (char*)Char(gct) && p[-1] == ' ' && p[Len(ct)] == '\0') { + String *q = NewStringWithSize(gct, Len(gct) - Len(ct) - 1); + if (validIdentifier(q)) { + // This is a simple type name, and we can use it directly. + Delete(ct); + --count; + ct = q; + add_typedef = false; + } + } + } + if (add_typedef) { + Printv(f_cgo_comment_typedefs, "typedef ", gct, ";\n", NULL); + } + + Setattr(n, "emit:cgotype", ct); + + Delete(gct); + + return Copy(ct); + } + + /* ---------------------------------------------------------------------- + * goWrapperType() + * + * Given a type, return a string for the type to use for the wrapped + * Go function. This function exists because for a C++ class we + * need to convert interface and reference types. + * ---------------------------------------------------------------------- */ + + String *goWrapperType(Node *n, SwigType *type, bool is_result) { + bool is_interface; + String *ret = goTypeWithInfo(n, type, true, &is_interface); + + // If this is an interface, we want to pass the real type. + if (is_interface) { + Delete(ret); + if (!is_result) { + ret = NewString("uintptr"); + } else { + SwigType *ty = SwigType_typedef_resolve_all(type); + while (true) { + if (SwigType_ispointer(ty)) { + SwigType_del_pointer(ty); + } else if (SwigType_isarray(ty)) { + SwigType_del_array(ty); + } else if (SwigType_isreference(ty)) { + SwigType_del_reference(ty); + } else if (SwigType_isqualifier(ty)) { + SwigType_del_qualifier(ty); + } else { + break; + } + } + assert(SwigType_issimple(ty)); + String *p = goCPointerType(ty, true); + Delete(ty); + ret = p; + } + } + + return ret; + } + + /* ---------------------------------------------------------------------- + * goOverloadType() + * + * Given a type, return the Go type to use when dispatching of + * overloaded functions. This is normally just the usual Go type. + * However, for a C++ class, the usual Go type is an interface type. + * And if that interface type represents a C++ type that SWIG does + * not know about, then the interface type generated for any C++ + * class will match that interface. So for that case, we match on + * the underlying integer type. + * + * It has to work this way so that we can handle a derived type of a + * %ignore'd type. It's unlikely that anybody will have a value of + * an undefined type, but we support it because it worked in the + * past. + * ---------------------------------------------------------------------- */ + + String *goOverloadType(Node *n, SwigType *type) { + SwigType *ty = SwigType_typedef_resolve_all(type); + while (true) { + if (SwigType_ispointer(ty)) { + SwigType_del_pointer(ty); + } else if (SwigType_isarray(ty)) { + SwigType_del_array(ty); + } else if (SwigType_isreference(ty)) { + SwigType_del_reference(ty); + } else if (SwigType_isqualifier(ty)) { + SwigType_del_qualifier(ty); + } else { + break; + } + } + + if (Getattr(undefined_types, ty) && !Getattr(defined_types, ty)) { + return goWrapperType(n, type, true); + } + + return goType(n, type); + } + + /* ---------------------------------------------------------------------- + * goCPointerType() + * + * Return the name of the Go type to use for the C pointer value. + * The regular C type is the name of an interface type which wraps a + * pointer whose name is returned by this function. + * ---------------------------------------------------------------------- */ + + String *goCPointerType(SwigType *type, bool add_to_hash) { + SwigType *ty = SwigType_typedef_resolve_all(type); + Node *cn = classLookup(ty); + String *ex; + String *ret; + if (!cn) { + if (add_to_hash) { + Setattr(undefined_types, ty, ty); + } + ret = NewString("Swigcptr"); + ex = exportedName(ty); + Append(ret, ex); + } else { + String *cname = Getattr(cn, "sym:name"); + if (!cname) { + cname = Getattr(cn, "name"); + } + ex = exportedName(cname); + Node *cnmod = Getattr(cn, "module"); + if (!cnmod || Strcmp(Getattr(cnmod, "name"), module) == 0) { + if (add_to_hash) { + Setattr(undefined_types, ty, ty); + } + ret = NewString("Swigcptr"); + Append(ret, ex); + } else { + ret = NewString(""); + Printv(ret, getModuleName(Getattr(cnmod, "name")), ".Swigcptr", ex, NULL); + } + } + Delete(ty); + Delete(ex); + return ret; + } + + /* ---------------------------------------------------------------------- + * gcCTypeForGoValue() + * + * Given a type, return the C/C++ type which will be used to catch + * the value in Go. This is the 6g/8g version. + * ---------------------------------------------------------------------- */ + + String *gcCTypeForGoValue(Node *n, SwigType *type, String *name) { + bool is_interface; + String *gt = goTypeWithInfo(n, type, true, &is_interface); + + String *tail = NewString(""); + SwigType *t = SwigType_typedef_resolve_all(type); + if (!SwigType_isreference(t)) { + while (Strncmp(gt, "*", 1) == 0) { + Replace(gt, "*", "", DOH_REPLACE_FIRST); + Printv(tail, "*", NULL); + } + } + Delete(t); + + bool is_string = Strcmp(gt, "string") == 0; + bool is_slice = Strncmp(gt, "[]", 2) == 0; + bool is_function = Strcmp(gt, "_swig_fnptr") == 0; + bool is_member = Strcmp(gt, "_swig_memberptr") == 0; + bool is_complex64 = Strcmp(gt, "complex64") == 0; + bool is_complex128 = Strcmp(gt, "complex128") == 0; + bool is_bool = false; + bool is_int8 = false; + bool is_int16 = false; + bool is_int = Strcmp(gt, "int") == 0 || Strcmp(gt, "uint") == 0; + bool is_int32 = false; + bool is_int64 = false; + bool is_float32 = false; + bool is_float64 = false; + + bool has_typemap = (n != NULL && Getattr(n, "tmap:gotype") != NULL) || hasGoTypemap(n, type); + if (has_typemap) { + is_bool = Strcmp(gt, "bool") == 0; + is_int8 = Strcmp(gt, "int8") == 0 || Strcmp(gt, "uint8") == 0 || Strcmp(gt, "byte") == 0; + is_int16 = Strcmp(gt, "int16") == 0 || Strcmp(gt, "uint16") == 0; + is_int32 = Strcmp(gt, "int32") == 0 || Strcmp(gt, "uint32") == 0; + is_int64 = Strcmp(gt, "int64") == 0 || Strcmp(gt, "uint64") == 0; + is_float32 = Strcmp(gt, "float32") == 0; + is_float64 = Strcmp(gt, "float64") == 0; + } + Delete(gt); + + String *ret; + if (is_string) { + // Note that we don't turn a reference to a string into a + // pointer to a string. Strings are immutable anyhow. + ret = NewString(""); + Printv(ret, "_gostring_", tail, " ", name, NULL); + Delete(tail); + return ret; + } else if (is_slice) { + // Slices are always passed as a _goslice_, whether or not references + // are involved. + ret = NewString(""); + Printv(ret, "_goslice_", tail, " ", name, NULL); + Delete(tail); + return ret; + } else if (is_function || is_member) { + ret = NewString(""); + Printv(ret, "void*", tail, " ", name, NULL); + Delete(tail); + return ret; + } else if (is_complex64) { + ret = NewString("_Complex float "); + } else if (is_complex128) { + ret = NewString("_Complex double "); + } else if (is_interface) { + SwigType *t = SwigType_typedef_resolve_all(type); + if (SwigType_ispointer(t)) { + SwigType_del_pointer(t); + } + if (SwigType_isreference(t)) { + SwigType_del_reference(t); + } + SwigType_add_pointer(t); + ret = SwigType_lstr(t, name); + Delete(t); + Delete(tail); + return ret; + } else { + SwigType *t = SwigType_typedef_resolve_all(type); + if (!has_typemap && SwigType_isreference(t)) { + // A const reference to a known type, or to a pointer, is not + // mapped to a pointer. + SwigType_del_reference(t); + if (SwigType_isqualifier(t)) { + String *q = SwigType_parm(t); + if (Strcmp(q, "const") == 0) { + SwigType_del_qualifier(t); + if (hasGoTypemap(n, t) || SwigType_ispointer(t)) { + if (is_int) { + ret = NewString("intgo "); + Append(ret, name); + } else if (is_int64) { + ret = NewString("long long "); + Append(ret, name); + } else { + ret = SwigType_lstr(t, name); + } + Delete(q); + Delete(t); + Delete(tail); + return ret; + } + } + Delete(q); + } + } + + if (Language::enumLookup(t) != NULL) { + is_int = true; + } else { + SwigType *tstripped = SwigType_strip_qualifiers(t); + if (SwigType_isenum(tstripped)) + is_int = true; + Delete(tstripped); + } + + Delete(t); + if (is_bool) { + ret = NewString("bool "); + } else if (is_int8) { + ret = NewString("char "); + } else if (is_int16) { + ret = NewString("short "); + } else if (is_int) { + ret = NewString("intgo "); + } else if (is_int32) { + ret = NewString("int "); + } else if (is_int64) { + ret = NewString("long long "); + } else if (is_float32) { + ret = NewString("float "); + } else if (is_float64) { + ret = NewString("double "); + } else { + Delete(tail); + return SwigType_lstr(type, name); + } + } + + Append(ret, tail); + if (!has_typemap && SwigType_isreference(type)) { + Append(ret, "* "); + } + Append(ret, name); + Delete(tail); + return ret; + } + + /* ---------------------------------------------------------------------- + * gccgoCTypeForGoValue() + * + * Given a type, return the C/C++ type which will be used to catch + * the value in Go. This is the gccgo version. + * ---------------------------------------------------------------------- */ + + String *gccgoCTypeForGoValue(Node *n, SwigType *type, String *name) { + return gcCTypeForGoValue(n, type, name); + } + + /* ---------------------------------------------------------------------- + * goTypeIsInterface + * + * Return whether this C++ type is represented as an interface type + * in Go. These types require adjustments in the Go code when + * passing them back and forth between Go and C++. + * ---------------------------------------------------------------------- */ + + bool goTypeIsInterface(Node *n, SwigType *type) { + bool is_interface; + Delete(goTypeWithInfo(n, type, false, &is_interface)); + return is_interface; + } + + /* ---------------------------------------------------------------------- + * hasGoTypemap + * + * Return whether a type has a "gotype" typemap entry. + * ---------------------------------------------------------------------- */ + + bool hasGoTypemap(Node *n, SwigType *type) { + Parm *p = NewParm(type, "test", n); + SwigType *tm = Swig_typemap_lookup("gotype", p, "", NULL); + Delete(p); + if (tm && Strstr(tm, "$gotypename") == 0) { + Delete(tm); + return true; + } + Delete(tm); + return false; + } + + /* ---------------------------------------------------------------------- + * goEnumName() + * + * Given an enum node, return a string to use for the enum type in Go. + * ---------------------------------------------------------------------- */ + + String *goEnumName(Node *n) { + String *ret = Getattr(n, "go:enumname"); + if (ret) { + return Copy(ret); + } + + if (Equal(Getattr(n, "type"), "enum ")) { + return NewString("int"); + } + + String *type = Getattr(n, "enumtype"); + assert(type); + char *p = Char(type); + int len = Len(type); + String *s = NewString(""); + bool capitalize = true; + for (int i = 0; i < len; ++i, ++p) { + if (*p == ':') { + ++i; + ++p; + assert(*p == ':'); + capitalize = true; + } else if (capitalize) { + Putc(toupper(*p), s); + capitalize = false; + } else { + Putc(*p, s); + } + } + + ret = Swig_name_mangle(s); + Delete(s); + return ret; + } + + + /* ---------------------------------------------------------------------- + * getParm() + * + * Get the real parameter to use. + * ---------------------------------------------------------------------- */ + + Parm *getParm(Parm *p) { + while (p && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + return p; + } + + /* ---------------------------------------------------------------------- + * nextParm() + * + * Return the next parameter. + * ---------------------------------------------------------------------- */ + + Parm *nextParm(Parm *p) { + if (!p) { + return NULL; + } else if (Getattr(p, "tmap:in")) { + return Getattr(p, "tmap:in:next"); + } else { + return nextSibling(p); + } + } + + /* ---------------------------------------------------------------------- + * isStatic + * + * Return whether a node should be considered as static rather than + * as a member. + * ---------------------------------------------------------------------- */ + + bool isStatic(Node *n) { + String *storage = Getattr(n, "storage"); + return (storage && (Swig_storage_isstatic(n) || Strcmp(storage, "friend") == 0) && (!SmartPointer || !Getattr(n, "allocate:smartpointeraccess"))); + } + + /* ---------------------------------------------------------------------- + * isFriend + * + * Return whether a node is a friend. + * ---------------------------------------------------------------------- */ + + bool isFriend(Node *n) { + String *storage = Getattr(n, "storage"); + return storage && Strcmp(storage, "friend") == 0; + } + + /* ---------------------------------------------------------------------- + * goGetattr + * + * Fetch an attribute from a node but return NULL if it is the empty string. + * ---------------------------------------------------------------------- */ + Node *goGetattr(Node *n, const char *name) { + Node *ret = Getattr(n, name); + if (ret != NULL && Len(ret) == 0) { + ret = NULL; + } + return ret; + } + + /* ---------------------------------------------------------------------- + * goTypemapLookup + * + * Look up a typemap but return NULL if it is the empty string. + * ---------------------------------------------------------------------- */ + String *goTypemapLookup(const char *name, Node *node, const char *lname) { + String *ret = Swig_typemap_lookup(name, node, lname, NULL); + if (ret != NULL && Len(ret) == 0) { + ret = NULL; + } + return ret; + } + + /* ---------------------------------------------------------------------- + * getModuleName + * + * Return the name of a module. This is different from module path: + * "some/path/to/module" -> "module". + * ---------------------------------------------------------------------- */ + + String *getModuleName(String *module_path) { + char *suffix = strrchr(Char(module_path), '/'); + if (suffix == NULL) { + return module_path; + } + return Str(suffix + 1); + } + +}; /* class GO */ + +/* ----------------------------------------------------------------------------- + * swig_go() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_go() { + return new GO(); +} +extern "C" Language *swig_go(void) { + return new_swig_go(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +// Usage message. +const char * const GO::usage = "\ +Go Options (available with -go)\n\ + -cgo - Generate cgo input files\n\ + -no-cgo - Do not generate cgo input files\n\ + -gccgo - Generate code for gccgo rather than gc\n\ + -go-pkgpath <p> - Like gccgo -fgo-pkgpath option\n\ + -go-prefix <p> - Like gccgo -fgo-prefix option\n\ + -import-prefix <p> - Prefix to add to %import directives\n\ + -intgosize <s> - Set size of Go int type--32 or 64 bits\n\ + -package <name> - Set name of the Go package to <name>\n\ + -use-shlib - Force use of a shared library\n\ + -soname <name> - Set shared library holding C/C++ code to <name>\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/guile.cxx b/contrib/tools/swig/Source/Modules/guile.cxx new file mode 100644 index 00000000000..461c69e5034 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/guile.cxx @@ -0,0 +1,1683 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * guile.cxx + * + * Guile language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +#include <ctype.h> + +// Note string broken in half for compilers that can't handle long strings +static const char *usage = "\ +Guile Options (available with -guile)\n\ + -emitsetters - Emit procedures-with-setters for variables\n\ + and structure slots.\n\ + -emitslotaccessors - Emit accessor methods for all GOOPS slots\n" "\ + -exportprimitive - Add the (export ...) code from scmstub into the\n\ + GOOPS file.\n\ + -goopsprefix <prefix> - Prepend <prefix> to all goops identifiers\n\ + -Linkage <lstyle> - Use linkage protocol <lstyle> (default `simple')\n\ + Use `module' for native Guile module linking\n\ + (requires Guile >= 1.5.0). Use `passive' for\n\ + passive linking (no C-level module-handling code),\n\ + `ltdlmod' for Guile's old dynamic module\n\ + convention (Guile <= 1.4), or `hobbit' for hobbit\n\ + modules.\n\ + -onlysetters - Don't emit traditional getter and setter\n\ + procedures for structure slots,\n\ + only emit procedures-with-setters.\n\ + -package <name> - Set the path of the module to <name>\n\ + (default NULL)\n\ + -prefix <name> - Use <name> as prefix [default \"gswig_\"]\n\ + -procdoc <file> - Output procedure documentation to <file>\n\ + -procdocformat <format> - Output procedure documentation in <format>;\n\ + one of `guile-1.4', `plain', `texinfo'\n\ + -proxy - Export GOOPS class definitions\n\ + -primsuffix <suffix> - Name appended to primitive module when exporting\n\ + GOOPS classes. (default = \"primitive\")\n\ + -scmstub - Output Scheme file with module declaration and\n\ + exports; only with `passive' and `simple' linkage\n\ + -useclassprefix - Prepend the class name to all goops identifiers\n\ +\n"; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; + + +static String *prefix = NewString("gswig_"); +static char *module = 0; +static String *package = 0; +static enum { + GUILE_LSTYLE_SIMPLE, // call `SWIG_init()' + GUILE_LSTYLE_PASSIVE, // passive linking (no module code) + GUILE_LSTYLE_MODULE, // native guile module linking (Guile >= 1.4.1) + GUILE_LSTYLE_LTDLMOD_1_4, // old (Guile <= 1.4) dynamic module convention + GUILE_LSTYLE_HOBBIT // use (hobbit4d link) +} linkage = GUILE_LSTYLE_SIMPLE; + +static File *procdoc = 0; +static bool scmstub = false; +static String *scmtext; +static bool goops = false; +static String *goopstext; +static String *goopscode; +static String *goopsexport; + +static enum { + GUILE_1_4, + PLAIN, + TEXINFO +} docformat = GUILE_1_4; + +static int emit_setters = 0; +static int only_setters = 0; +static int emit_slot_accessors = 0; +static int struct_member = 0; + +static String *beforereturn = 0; +static String *return_nothing_doc = 0; +static String *return_one_doc = 0; +static String *return_multi_doc = 0; + +static String *exported_symbols = 0; + +static int exporting_destructor = 0; +static String *swigtype_ptr = 0; + +/* GOOPS stuff */ +static String *primsuffix = 0; +static String *class_name = 0; +static String *short_class_name = 0; +static String *goops_class_methods; +static int in_class = 0; +static int have_constructor = 0; +static int useclassprefix = 0; // -useclassprefix argument +static String *goopsprefix = 0; // -goopsprefix argument +static int primRenamer = 0; // if (use-modules ((...) :renamer ...) is exported to GOOPS file +static int exportprimitive = 0; // -exportprimitive argument +static String *memberfunction_name = 0; + +extern "C" { + static int has_classname(Node *class_node) { + return Getattr(class_node, "guile:goopsclassname") ? 1 : 0; + } +} + +class GUILE:public Language { +public: + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i; + + SWIG_library_directory("guile"); + SWIG_typemap_lang("guile"); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(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(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-Linkage") == 0 || strcmp(argv[i], "-linkage") == 0) { + if (argv[i + 1]) { + if (0 == strcmp(argv[i + 1], "ltdlmod")) + linkage = GUILE_LSTYLE_LTDLMOD_1_4; + else if (0 == strcmp(argv[i + 1], "hobbit")) + linkage = GUILE_LSTYLE_HOBBIT; + else if (0 == strcmp(argv[i + 1], "simple")) + linkage = GUILE_LSTYLE_SIMPLE; + else if (0 == strcmp(argv[i + 1], "passive")) + linkage = GUILE_LSTYLE_PASSIVE; + else if (0 == strcmp(argv[i + 1], "module")) + linkage = GUILE_LSTYLE_MODULE; + else + Swig_arg_error(); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-procdoc") == 0) { + if (argv[i + 1]) { + procdoc = NewFile(argv[i + 1], "w", SWIG_output_files()); + if (!procdoc) { + FileErrorDisplay(argv[i + 1]); + SWIG_exit(EXIT_FAILURE); + } + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-procdocformat") == 0) { + if (strcmp(argv[i + 1], "guile-1.4") == 0) + docformat = GUILE_1_4; + else if (strcmp(argv[i + 1], "plain") == 0) + docformat = PLAIN; + else if (strcmp(argv[i + 1], "texinfo") == 0) + docformat = TEXINFO; + else + Swig_arg_error(); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else if (strcmp(argv[i], "-emit-setters") == 0 || strcmp(argv[i], "-emitsetters") == 0) { + emit_setters = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-only-setters") == 0 || strcmp(argv[i], "-onlysetters") == 0) { + emit_setters = 1; + only_setters = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-emit-slot-accessors") == 0 || strcmp(argv[i], "-emitslotaccessors") == 0) { + emit_slot_accessors = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-scmstub") == 0) { + scmstub = true; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + goops = true; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-gh") == 0) { + Printf(stderr, "Deprecated command line option: -gh. Wrappers are always generated for the SCM interface. See documentation for more information regarding the deprecated GH interface.\n"); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-scm") == 0) { + Printf(stderr, "Deprecated command line option: -scm. Wrappers are always generated for the SCM interface. See documentation for more information regarding the deprecated GH interface.\n"); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-primsuffix") == 0) { + if (argv[i + 1]) { + primsuffix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-goopsprefix") == 0) { + if (argv[i + 1]) { + goopsprefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-useclassprefix") == 0) { + useclassprefix = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-exportprimitive") == 0) { + exportprimitive = 1; + // should use Swig_warning() here? + Swig_mark_arg(i); + } + } + } + + // set default value for primsuffix + if (!primsuffix) + primsuffix = NewString("primitive"); + + //goops support can only be enabled if passive or module linkage is used + if (goops) { + if (linkage != GUILE_LSTYLE_PASSIVE && linkage != GUILE_LSTYLE_MODULE) { + Printf(stderr, "guile: GOOPS support requires passive or module linkage\n"); + SWIG_exit(EXIT_FAILURE); + } + } + + if (goops) { + // -proxy implies -emit-setters + emit_setters = 1; + } + + if ((linkage == GUILE_LSTYLE_PASSIVE && scmstub) || linkage == GUILE_LSTYLE_MODULE) + primRenamer = 1; + + if (exportprimitive && primRenamer) { + // should use Swig_warning() ? + Printf(stderr, "guile: Warning: -exportprimitive only makes sense with passive linkage without a scmstub.\n"); + } + + // Make sure `prefix' ends in an underscore + if (prefix) { + const char *px = Char(prefix); + if (px[Len(prefix) - 1] != '_') + Printf(prefix, "_"); + } + + /* Add a symbol for this module */ + Preprocessor_define("SWIGGUILE 1", 0); + /* Read in default typemaps */ + SWIG_config_file("guile_scm.swg"); + allow_overloading(); + + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = 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); + + scmtext = NewString(""); + Swig_register_filebyname("scheme", scmtext); + exported_symbols = NewString(""); + goopstext = NewString(""); + Swig_register_filebyname("goops", goopstext); + goopscode = NewString(""); + goopsexport = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGGUILE\n#define SWIGGUILE\n#endif\n\n"); + + /* Write out directives and declarations */ + + module = Swig_copy_string(Char(Getattr(n, "name"))); + + switch (linkage) { + case GUILE_LSTYLE_SIMPLE: + /* Simple linkage; we have to export the SWIG_init function. The user can + rename the function by a #define. */ + Printf(f_runtime, "#define SWIG_GUILE_INIT_STATIC extern\n"); + break; + default: + /* Other linkage; we make the SWIG_init function static */ + Printf(f_runtime, "#define SWIG_GUILE_INIT_STATIC static\n"); + break; + } + + if (CPlusPlus) { + Printf(f_runtime, "extern \"C\" {\n\n"); + } + Printf(f_runtime, "SWIG_GUILE_INIT_STATIC void\nSWIG_init (void);\n"); + if (CPlusPlus) { + Printf(f_runtime, "\n}\n"); + } + + Printf(f_runtime, "\n"); + + Language::top(n); + + /* Close module */ + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printf(f_init, "}\n\n"); + Printf(f_init, "#ifdef __cplusplus\n}\n#endif\n"); + + String *module_name = NewString(""); + + if (!module) + Printv(module_name, "swig", NIL); + else { + if (package) + Printf(module_name, "%s/%s", package, module); + else + Printv(module_name, module, NIL); + } + emit_linkage(module_name); + + Delete(module_name); + + if (procdoc) { + Delete(procdoc); + procdoc = NULL; + } + Delete(goopscode); + Delete(goopsexport); + Delete(goopstext); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + 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; + } + + void emit_linkage(String *module_name) { + String *module_func = NewString(""); + + if (CPlusPlus) { + Printf(f_init, "extern \"C\" {\n\n"); + } + + Printv(module_func, module_name, NIL); + Replaceall(module_func, "-", "_"); + + switch (linkage) { + case GUILE_LSTYLE_SIMPLE: + Printf(f_init, "\n/* Linkage: simple */\n"); + break; + case GUILE_LSTYLE_PASSIVE: + Printf(f_init, "\n/* Linkage: passive */\n"); + Replaceall(module_func, "/", "_"); + Insert(module_func, 0, "scm_init_"); + Append(module_func, "_module"); + + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + Printf(f_init, " SWIG_init();\n"); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Printf(f_init, "}\n"); + break; + case GUILE_LSTYLE_LTDLMOD_1_4: + Printf(f_init, "\n/* Linkage: ltdlmod */\n"); + Replaceall(module_func, "/", "_"); + Insert(module_func, 0, "scm_init_"); + Append(module_func, "_module"); + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + { + String *mod = NewString(module_name); + Replaceall(mod, "/", " "); + Printf(f_init, " scm_register_module_xxx (\"%s\", (void *) SWIG_init);\n", mod); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Delete(mod); + } + Printf(f_init, "}\n"); + break; + case GUILE_LSTYLE_MODULE: + Printf(f_init, "\n/* Linkage: module */\n"); + Replaceall(module_func, "/", "_"); + Insert(module_func, 0, "scm_init_"); + Append(module_func, "_module"); + + Printf(f_init, "static void SWIG_init_helper(void *data)\n"); + Printf(f_init, "{\n SWIG_init();\n"); + if (Len(exported_symbols) > 0) + Printf(f_init, " scm_c_export(%sNULL);", exported_symbols); + Printf(f_init, "\n}\n\n"); + + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + { + String *mod = NewString(module_name); + if (goops) + Printv(mod, "-", primsuffix, NIL); + Replaceall(mod, "/", " "); + Printf(f_init, " scm_c_define_module(\"%s\",\n", mod); + Printf(f_init, " SWIG_init_helper, NULL);\n"); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Delete(mod); + } + Printf(f_init, "}\n"); + break; + case GUILE_LSTYLE_HOBBIT: + Printf(f_init, "\n/* Linkage: hobbit */\n"); + Replaceall(module_func, "/", "_slash_"); + Insert(module_func, 0, "scm_init_"); + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + { + String *mod = NewString(module_name); + Replaceall(mod, "/", " "); + Printf(f_init, " scm_register_module_xxx (\"%s\", (void *) SWIG_init);\n", mod); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Delete(mod); + } + Printf(f_init, "}\n"); + break; + default: + abort(); // for now + } + + if (scmstub) { + /* Emit Scheme stub if requested */ + String *primitive_name = NewString(module_name); + if (goops) + Printv(primitive_name, "-", primsuffix, NIL); + + String *mod = NewString(primitive_name); + Replaceall(mod, "/", " "); + + String *fname = NewStringf("%s%s.scm", + SWIG_output_directory(), + primitive_name); + Delete(primitive_name); + File *scmstubfile = NewFile(fname, "w", SWIG_output_files()); + if (!scmstubfile) { + FileErrorDisplay(fname); + SWIG_exit(EXIT_FAILURE); + } + Delete(fname); + + Swig_banner_target_lang(scmstubfile, ";;;"); + Printf(scmstubfile, "\n"); + if (linkage == GUILE_LSTYLE_SIMPLE || linkage == GUILE_LSTYLE_PASSIVE) + Printf(scmstubfile, "(define-module (%s))\n\n", mod); + Delete(mod); + Printf(scmstubfile, "%s", scmtext); + if ((linkage == GUILE_LSTYLE_SIMPLE || linkage == GUILE_LSTYLE_PASSIVE) + && Len(exported_symbols) > 0) { + String *ex = NewString(exported_symbols); + Replaceall(ex, ", ", "\n "); + Replaceall(ex, "\"", ""); + Chop(ex); + Printf(scmstubfile, "\n(export %s)\n", ex); + Delete(ex); + } + Delete(scmstubfile); + } + + if (goops) { + String *mod = NewString(module_name); + Replaceall(mod, "/", " "); + + String *fname = NewStringf("%s%s.scm", SWIG_output_directory(), + module_name); + File *goopsfile = NewFile(fname, "w", SWIG_output_files()); + if (!goopsfile) { + FileErrorDisplay(fname); + SWIG_exit(EXIT_FAILURE); + } + Delete(fname); + Swig_banner_target_lang(goopsfile, ";;;"); + Printf(goopsfile, "\n"); + Printf(goopsfile, "(define-module (%s))\n", mod); + Printf(goopsfile, "%s\n", goopstext); + Printf(goopsfile, "(use-modules (oop goops) (Swig common))\n"); + if (primRenamer) { + Printf(goopsfile, "(use-modules ((%s-%s) :renamer (symbol-prefix-proc 'primitive:)))\n", mod, primsuffix); + } + Printf(goopsfile, "%s\n(export %s)", goopscode, goopsexport); + if (exportprimitive) { + String *ex = NewString(exported_symbols); + Replaceall(ex, ", ", "\n "); + Replaceall(ex, "\"", ""); + Chop(ex); + Printf(goopsfile, "\n(export %s)", ex); + Delete(ex); + } + Delete(mod); + Delete(goopsfile); + } + + Delete(module_func); + if (CPlusPlus) { + Printf(f_init, "\n}\n"); + } + } + + /* Return true iff T is a pointer type */ + + int is_a_pointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); + } + + /* Report an error handling the given type. */ + + void throw_unhandled_guile_type_error(SwigType *d) { + Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s.\n", SwigType_str(d, 0)); + } + + /* Write out procedure documentation */ + + void write_doc(const String *proc_name, const String *signature, const String *doc, const String *signature2 = NULL) { + switch (docformat) { + case GUILE_1_4: + Printv(procdoc, "\f\n", NIL); + Printv(procdoc, "(", signature, ")\n", NIL); + if (signature2) + Printv(procdoc, "(", signature2, ")\n", NIL); + Printv(procdoc, doc, "\n", NIL); + break; + case PLAIN: + Printv(procdoc, "\f", proc_name, "\n\n", NIL); + Printv(procdoc, "(", signature, ")\n", NIL); + if (signature2) + Printv(procdoc, "(", signature2, ")\n", NIL); + Printv(procdoc, doc, "\n\n", NIL); + break; + case TEXINFO: + Printv(procdoc, "\f", proc_name, "\n", NIL); + Printv(procdoc, "@deffn primitive ", signature, "\n", NIL); + if (signature2) + Printv(procdoc, "@deffnx primitive ", signature2, "\n", NIL); + Printv(procdoc, doc, "\n", NIL); + Printv(procdoc, "@end deffn\n\n", NIL); + break; + } + } + + /* returns false if the typemap is an empty string */ + bool handle_documentation_typemap(String *output, + const String *maybe_delimiter, Parm *p, const String *typemap, const String *default_doc, const String *name = NULL) { + String *tmp = NewString(""); + String *tm; + if (!(tm = Getattr(p, typemap))) { + Printf(tmp, "%s", default_doc); + tm = tmp; + } + bool result = (Len(tm) > 0); + if (maybe_delimiter && Len(output) > 0 && Len(tm) > 0) { + Printv(output, maybe_delimiter, NIL); + } + const String *pn = !name ? (const String *) Getattr(p, "name") : name; + String *pt = Getattr(p, "type"); + Replaceall(tm, "$name", pn); // legacy for $parmname + Replaceall(tm, "$type", SwigType_str(pt, 0)); + /* $NAME is like $name, but marked-up as a variable. */ + String *ARGNAME = NewString(""); + if (docformat == TEXINFO) + Printf(ARGNAME, "@var{%s}", pn); + else + Printf(ARGNAME, "%(upper)s", pn); + Replaceall(tm, "$NAME", ARGNAME); + Replaceall(tm, "$PARMNAME", ARGNAME); + Printv(output, tm, NIL); + Delete(tmp); + return result; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * Create a function declaration and register it with the interpreter. + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *proc_name = 0; + char source[256]; + Wrapper *f = NewWrapper(); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *signature = NewString(""); + String *doc_body = NewString(""); + String *returns = NewString(""); + String *method_signature = NewString(""); + String *primitive_args = NewString(""); + Hash *scheme_arg_names = NewHash(); + int num_results = 1; + String *tmp = NewString(""); + String *tm; + int i; + int numargs = 0; + int numreq = 0; + String *overname = 0; + int args_passed_as_array = 0; + int scheme_argnum = 0; + bool any_specialized_arg = false; + + // Make a wrapper name for this + String *wname = Swig_name_wrapper(iname); + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + args_passed_as_array = 1; + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Build the name for scheme. + proc_name = NewString(iname); + Replaceall(proc_name, "_", "-"); + + /* Emit locals etc. into f->code; figure out which args to ignore */ + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + numargs = emit_num_arguments(l); + numreq = emit_num_required(l); + + /* Declare return variable */ + + Wrapper_add_local(f, "gswig_result", "SCM gswig_result"); + Wrapper_add_local(f, "gswig_list_p", "SWIGUNUSED int gswig_list_p = 0"); + + /* Open prototype and signature */ + + Printv(f->def, "static SCM\n", wname, " (", NIL); + if (args_passed_as_array) { + Printv(f->def, "int argc, SCM *argv", NIL); + } + Printv(signature, proc_name, NIL); + + /* Now write code to extract the parameters */ + + for (i = 0, p = l; i < numargs; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + int opt_p = (i >= numreq); + + // Produce names of source and target + if (args_passed_as_array) + sprintf(source, "argv[%d]", i); + else + sprintf(source, "s_%d", i); + String *target = Getattr(p, "lname"); + + if (!args_passed_as_array) { + if (i != 0) + Printf(f->def, ", "); + Printf(f->def, "SCM s_%d", i); + } + if (opt_p) { + Printf(f->code, " if (%s != SCM_UNDEFINED) {\n", source); + } + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", target); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printv(f->code, tm, "\n", NIL); + + SwigType *pb = SwigType_typedef_resolve_all(SwigType_base(pt)); + SwigType *pn = Getattr(p, "name"); + String *argname; + scheme_argnum++; + if (pn && !Getattr(scheme_arg_names, pn)) + argname = pn; + else { + /* Anonymous arg or re-used argument name -- choose a name that cannot clash */ + argname = NewStringf("%%arg%d", scheme_argnum); + } + + if (procdoc) { + if (i == numreq) { + /* First optional argument */ + Printf(signature, " #:optional"); + } + /* Add to signature (arglist) */ + handle_documentation_typemap(signature, " ", p, "tmap:in:arglist", "$name", argname); + /* Document the type of the arg in the documentation body */ + handle_documentation_typemap(doc_body, ", ", p, "tmap:in:doc", "$NAME is of type <$type>", argname); + } + + if (goops) { + if (i < numreq) { + if (strcmp("void", Char(pt)) != 0) { + Node *class_node = Swig_symbol_clookup_check(pb, Getattr(n, "sym:symtab"), + has_classname); + String *goopsclassname = !class_node ? NULL : Getattr(class_node, "guile:goopsclassname"); + /* do input conversion */ + if (goopsclassname) { + Printv(method_signature, " (", argname, " ", goopsclassname, ")", NIL); + any_specialized_arg = true; + } else { + Printv(method_signature, " ", argname, NIL); + } + Printv(primitive_args, " ", argname, NIL); + Setattr(scheme_arg_names, argname, p); + } + } + } + + if (!pn) { + Delete(argname); + } + p = Getattr(p, "tmap:in:next"); + } else { + throw_unhandled_guile_type_error(pt); + p = nextSibling(p); + } + if (opt_p) + Printf(f->code, " }\n"); + } + if (Len(doc_body) > 0) + Printf(doc_body, ".\n"); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + /* Pass output arguments back to the caller. */ + + /* Insert argument output code */ + String *returns_argout = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", Getattr(p, "lname")); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + if (procdoc) { + if (handle_documentation_typemap(returns_argout, ", ", p, "tmap:argout:doc", "$NAME (of type $type)")) { + /* A documentation typemap that is not the empty string + indicates that a value is returned to Scheme. */ + num_results++; + } + } + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + if (exporting_destructor) { + /* Mark the destructor's argument as destroyed. */ + String *tm = NewString("SWIG_Guile_MarkPointerDestroyed($input);"); + Replaceall(tm, "$input", Getattr(l, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + Delete(tm); + } + + /* Close prototype */ + + Printf(f->def, ")\n{\n"); + + /* Define the scheme name in C. This define is used by several Guile + macros. */ + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + // Now write code to make the function call + String *actioncode = emit_action(n); + + // Now have return value, figure out what to do with it. + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + Replaceall(tm, "$result", "gswig_result"); + Replaceall(tm, "$target", "gswig_result"); + Replaceall(tm, "$source", Swig_cresult_name()); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_guile_type_error(d); + } + emit_return_variable(n, d, f); + + // Documentation + if ((tm = Getattr(n, "tmap:out:doc"))) { + Printv(returns, tm, NIL); + if (Len(tm) > 0) + num_results = 1; + else + num_results = 0; + } else { + String *s = SwigType_str(d, 0); + Chop(s); + Printf(returns, "<%s>", s); + Delete(s); + num_results = 1; + } + Append(returns, returns_argout); + + + // Dump the argument output code + Printv(f->code, outarg, NIL); + + // Dump the argument cleanup code + Printv(f->code, cleanup, NIL); + + // Look for any remaining cleanup + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NIL); + } + // Wrap things up (in a manner of speaking) + + if (beforereturn) + Printv(f->code, beforereturn, "\n", NIL); + Printv(f->code, "return gswig_result;\n", NIL); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + // Undefine the scheme name + + Printf(f->code, "#undef FUNC_NAME\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + if (!Getattr(n, "sym:overloaded")) { + if (numargs > 10) { + int i; + /* gh_new_procedure would complain: too many args */ + /* Build a wrapper wrapper */ + Printv(f_wrappers, "static SCM\n", wname, "_rest (SCM rest)\n", NIL); + Printv(f_wrappers, "{\n", NIL); + Printf(f_wrappers, "SCM arg[%d];\n", numargs); + Printf(f_wrappers, "SWIG_Guile_GetArgs (arg, rest, %d, %d, \"%s\");\n", numreq, numargs - numreq, proc_name); + Printv(f_wrappers, "return ", wname, "(", NIL); + Printv(f_wrappers, "arg[0]", NIL); + for (i = 1; i < numargs; i++) + Printf(f_wrappers, ", arg[%d]", i); + Printv(f_wrappers, ");\n", NIL); + Printv(f_wrappers, "}\n", NIL); + /* Register it */ + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s_rest);\n", proc_name, wname); + } else if (emit_setters && struct_member && strlen(Char(proc_name)) > 3) { + int len = Len(proc_name); + const char *pc = Char(proc_name); + /* MEMBER-set and MEMBER-get functions. */ + int is_setter = (pc[len - 3] == 's'); + if (is_setter) { + Printf(f_init, "SCM setter = "); + struct_member = 2; /* have a setter */ + } else + Printf(f_init, "SCM getter = "); + /* GOOPS support uses the MEMBER-set and MEMBER-get functions, + so ignore only_setters in this case. */ + if (only_setters && !goops) + Printf(f_init, "scm_c_make_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + else + Printf(f_init, "scm_c_define_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + + if (!is_setter) { + /* Strip off "-get" */ + char *pws_name = (char *) malloc(sizeof(char) * (len - 3)); + strncpy(pws_name, pc, len - 3); + pws_name[len - 4] = 0; + if (struct_member == 2) { + /* There was a setter, so create a procedure with setter */ + Printf(f_init, "scm_c_define"); + Printf(f_init, "(\"%s\", " "scm_make_procedure_with_setter(getter, setter));\n", pws_name); + } else { + /* There was no setter, so make an alias to the getter */ + Printf(f_init, "scm_c_define"); + Printf(f_init, "(\"%s\", getter);\n", pws_name); + } + Printf(exported_symbols, "\"%s\", ", pws_name); + free(pws_name); + } + } else { + /* Register the function */ + if (exporting_destructor) { + Printf(f_init, "((swig_guile_clientdata *)(SWIGTYPE%s->clientdata))->destroy = (guile_destructor) %s;\n", swigtype_ptr, wname); + //Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) %s);\n", swigtype_ptr, wname); + } + Printf(f_init, "scm_c_define_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + } + } else { /* overloaded function; don't export the single methods */ + if (!Getattr(n, "sym:nextSibling")) { + /* Emit overloading dispatch function */ + + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(argc,argv);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "static SCM\n", dname, "(SCM rest)\n{\n", NIL); + Printf(df->code, "#define FUNC_NAME \"%s\"\n", proc_name); + Printf(df->code, "SCM argv[%d];\n", maxargs); + Printf(df->code, "int argc = SWIG_Guile_GetArgs (argv, rest, %d, %d, \"%s\");\n", 0, maxargs, proc_name); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "scm_misc_error(\"%s\", \"No matching method for generic function `%s'\", SCM_EOL);\n", proc_name, iname); + Printf(df->code, "#undef FUNC_NAME\n"); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s);\n", proc_name, dname); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + } + Printf(exported_symbols, "\"%s\", ", proc_name); + + if (!in_class || memberfunction_name) { + // export wrapper into goops file + String *method_def = NewString(""); + String *goops_name; + if (in_class) + goops_name = NewString(memberfunction_name); + else + goops_name = goopsNameMapping(proc_name, ""); + String *primitive_name = NewString(""); + if (primRenamer) + Printv(primitive_name, "primitive:", proc_name, NIL); + else + Printv(primitive_name, proc_name, NIL); + Replaceall(method_signature, "_", "-"); + Replaceall(primitive_args, "_", "-"); + if (!any_specialized_arg) { + /* If there would not be any specialized argument in + the method declaration, we simply re-export the + function. This is a performance optimization. */ + Printv(method_def, "(define ", goops_name, " ", primitive_name, ")\n", NIL); + } else if (numreq == numargs) { + Printv(method_def, "(define-method (", goops_name, method_signature, ")\n", NIL); + Printv(method_def, " (", primitive_name, primitive_args, "))\n", NIL); + } else { + /* Handle optional args. For the rest argument, use a name + that cannot clash. */ + Printv(method_def, "(define-method (", goops_name, method_signature, " . %args)\n", NIL); + Printv(method_def, " (apply ", primitive_name, primitive_args, " %args))\n", NIL); + } + if (in_class) { + /* Defer method definition till end of class definition. */ + Printv(goops_class_methods, method_def, NIL); + } else { + Printv(goopscode, method_def, NIL); + } + Printf(goopsexport, "%s ", goops_name); + Delete(primitive_name); + Delete(goops_name); + Delete(method_def); + } + + if (procdoc) { + String *returns_text = NewString(""); + if (num_results == 0) + Printv(returns_text, return_nothing_doc, NIL); + else if (num_results == 1) + Printv(returns_text, return_one_doc, NIL); + else + Printv(returns_text, return_multi_doc, NIL); + /* Substitute documentation variables */ + static const char *numbers[] = { "zero", "one", "two", "three", + "four", "five", "six", "seven", + "eight", "nine", "ten", "eleven", + "twelve" + }; + if (num_results <= 12) + Replaceall(returns_text, "$num_values", numbers[num_results]); + else { + String *num_results_str = NewStringf("%d", num_results); + Replaceall(returns_text, "$num_values", num_results_str); + Delete(num_results_str); + } + Replaceall(returns_text, "$values", returns); + Printf(doc_body, "\n%s", returns_text); + write_doc(proc_name, signature, doc_body); + Delete(returns_text); + } + + Delete(proc_name); + Delete(outarg); + Delete(cleanup); + Delete(signature); + Delete(method_signature); + Delete(primitive_args); + Delete(doc_body); + Delete(returns_argout); + Delete(returns); + Delete(tmp); + Delete(scheme_arg_names); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * + * Create a link to a C variable. + * This creates a single function PREFIX_var_VARNAME(). + * This function takes a single optional argument. If supplied, it means + * we are setting this variable to some value. If omitted, it means we are + * simply evaluating this variable. Either way, we return the variables + * value. + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + String *proc_name; + Wrapper *f; + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + f = NewWrapper(); + // evaluation function names + + String *var_name = Swig_name_wrapper(iname); + + // Build the name for scheme. + proc_name = NewString(iname); + Replaceall(proc_name, "_", "-"); + Setattr(n, "wrap:name", proc_name); + + if (1 || (SwigType_type(t) != T_USER) || (is_a_pointer(t))) { + + Printf(f->def, "static SCM\n%s(SCM s_0)\n{\n", var_name); + + /* Define the scheme name in C. This define is used by several Guile + macros. */ + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + Wrapper_add_local(f, "gswig_result", "SCM gswig_result"); + + if (!GetFlag(n, "feature:immutable")) { + /* Check for a setting of the variable value */ + Printf(f->code, "if (s_0 != SCM_UNDEFINED) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "s_0"); + Replaceall(tm, "$input", "s_0"); + Replaceall(tm, "$target", name); + /* Printv(f->code,tm,"\n",NIL); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_guile_type_error(t); + } + Printf(f->code, "}\n"); + } + // Now return the value of the variable (regardless + // of evaluating or setting) + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "gswig_result"); + Replaceall(tm, "$result", "gswig_result"); + /* Printv(f->code,tm,"\n",NIL); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_guile_type_error(t); + } + Printf(f->code, "\nreturn gswig_result;\n"); + Printf(f->code, "#undef FUNC_NAME\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + // Now add symbol to the Guile interpreter + + if (!emit_setters || GetFlag(n, "feature:immutable")) { + /* Read-only variables become a simple procedure returning the + value; read-write variables become a simple procedure with + an optional argument. */ + + if (!goops && GetFlag(n, "feature:constasvar")) { + /* need to export this function as a variable instead of a procedure */ + if (scmstub) { + /* export the function in the wrapper, and (set!) it in scmstub */ + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, %d, 0, (swig_guile_proc) %s);\n", proc_name, !GetFlag(n, "feature:immutable"), var_name); + Printf(scmtext, "(set! %s (%s))\n", proc_name, proc_name); + } else { + /* export the variable directly */ + Printf(f_init, "scm_c_define(\"%s\", %s(SCM_UNDEFINED));\n", proc_name, var_name); + } + + } else { + /* Export the function as normal */ + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, %d, 0, (swig_guile_proc) %s);\n", proc_name, !GetFlag(n, "feature:immutable"), var_name); + } + + } else { + /* Read/write variables become a procedure with setter. */ + Printf(f_init, "{ SCM p = scm_c_define_gsubr(\"%s\", 0, 1, 0, (swig_guile_proc) %s);\n", proc_name, var_name); + Printf(f_init, "scm_c_define"); + Printf(f_init, "(\"%s\", " "scm_make_procedure_with_setter(p, p)); }\n", proc_name); + } + Printf(exported_symbols, "\"%s\", ", proc_name); + + // export wrapper into goops file + if (!in_class) { // only if the variable is not part of a class + String *class_name = SwigType_typedef_resolve_all(SwigType_base(t)); + String *goops_name = goopsNameMapping(proc_name, ""); + String *primitive_name = NewString(""); + if (primRenamer) + Printv(primitive_name, "primitive:", NIL); + Printv(primitive_name, proc_name, NIL); + /* Simply re-export the procedure */ + if ((!emit_setters || GetFlag(n, "feature:immutable")) + && GetFlag(n, "feature:constasvar")) { + Printv(goopscode, "(define ", goops_name, " (", primitive_name, "))\n", NIL); + } else { + Printv(goopscode, "(define ", goops_name, " ", primitive_name, ")\n", NIL); + } + Printf(goopsexport, "%s ", goops_name); + Delete(primitive_name); + Delete(class_name); + Delete(goops_name); + } + + if (procdoc) { + /* Compute documentation */ + String *signature = NewString(""); + String *signature2 = NULL; + String *doc = NewString(""); + + if (GetFlag(n, "feature:immutable")) { + Printv(signature, proc_name, NIL); + if (GetFlag(n, "feature:constasvar")) { + Printv(doc, "Is constant ", NIL); + } else { + Printv(doc, "Returns constant ", NIL); + } + if ((tm = Getattr(n, "tmap:varout:doc"))) { + Printv(doc, tm, NIL); + } else { + String *s = SwigType_str(t, 0); + Chop(s); + Printf(doc, "<%s>", s); + Delete(s); + } + } else if (emit_setters) { + Printv(signature, proc_name, NIL); + signature2 = NewString(""); + Printv(signature2, "set! (", proc_name, ") ", NIL); + handle_documentation_typemap(signature2, NIL, n, "tmap:varin:arglist", "new-value"); + Printv(doc, "Get or set the value of the C variable, \n", NIL); + Printv(doc, "which is of type ", NIL); + handle_documentation_typemap(doc, NIL, n, "tmap:varout:doc", "$1_type"); + Printv(doc, "."); + } else { + Printv(signature, proc_name, " #:optional ", NIL); + if ((tm = Getattr(n, "tmap:varin:doc"))) { + Printv(signature, tm, NIL); + } else { + String *s = SwigType_str(t, 0); + Chop(s); + Printf(signature, "new-value <%s>", s); + Delete(s); + } + + Printv(doc, "If NEW-VALUE is provided, " "set C variable to this value.\n", NIL); + Printv(doc, "Returns variable value ", NIL); + if ((tm = Getattr(n, "tmap:varout:doc"))) { + Printv(doc, tm, NIL); + } else { + String *s = SwigType_str(t, 0); + Chop(s); + Printf(doc, "<%s>", s); + Delete(s); + } + } + write_doc(proc_name, signature, doc, signature2); + Delete(signature); + if (signature2) + Delete(signature2); + Delete(doc); + } + + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + Delete(var_name); + Delete(proc_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * + * We create a read-only variable. + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + int constasvar = GetFlag(n, "feature:constasvar"); + + + String *proc_name; + String *var_name; + Wrapper *f; + SwigType *nctype; + String *tm; + + f = NewWrapper(); + + // Make a static variable; + var_name = NewStringf("%sconst_%s", prefix, iname); + + // Strip const qualifier from type if present + + nctype = NewString(type); + if (SwigType_isconst(nctype)) { + Delete(SwigType_pop(nctype)); + } + // Build the name for scheme. + proc_name = NewString(iname); + Replaceall(proc_name, "_", "-"); + + if ((SwigType_type(nctype) == T_USER) && (!is_a_pointer(nctype))) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + Delete(var_name); + DelWrapper(f); + return SWIG_NOWRAP; + } + // See if there's a typemap + + if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$value", value); + Replaceall(tm, "$target", name); + Printv(f_header, tm, "\n", NIL); + } else { + // Create variable and assign it a value + Printf(f_header, "static %s = (%s)(%s);\n", SwigType_str(type, var_name), SwigType_str(type, 0), value); + } + { + /* Hack alert: will cleanup later -- Dave */ + Node *nn = NewHash(); + Setfile(nn, Getfile(n)); + Setline(nn, Getline(n)); + Setattr(nn, "name", var_name); + Setattr(nn, "sym:name", iname); + Setattr(nn, "type", nctype); + SetFlag(nn, "feature:immutable"); + if (constasvar) { + SetFlag(nn, "feature:constasvar"); + } + variableWrapper(nn); + Delete(nn); + } + Delete(var_name); + Delete(nctype); + Delete(proc_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + virtual int classDeclaration(Node *n) { + String *class_name = NewStringf("<%s>", Getattr(n, "sym:name")); + Setattr(n, "guile:goopsclassname", class_name); + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + virtual int classHandler(Node *n) { + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + + class_name = NewString(""); + short_class_name = NewString(""); + Printv(class_name, "<", Getattr(n, "sym:name"), ">", NIL); + Printv(short_class_name, Getattr(n, "sym:name"), NIL); + Replaceall(class_name, "_", "-"); + Replaceall(short_class_name, "_", "-"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + /* Handle inheritance */ + String *base_class = NewString("<"); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator i = First(baselist); + while (i.item) { + Printv(base_class, Getattr(i.item, "sym:name"), NIL); + i = Next(i); + if (i.item) { + Printf(base_class, "> <"); + } + } + } + Printf(base_class, ">"); + Replaceall(base_class, "_", "-"); + + Printv(goopscode, "(define-class ", class_name, " ", NIL); + Printf(goopsexport, "%s ", class_name); + + if (Len(base_class) > 2) { + Printv(goopscode, "(", base_class, ")\n", NIL); + } else { + Printv(goopscode, "(<swig>)\n", NIL); + } + SwigType *ct = NewStringf("p.%s", Getattr(n, "name")); + swigtype_ptr = SwigType_manglestr(ct); + + String *mangled_classname = Swig_name_mangle(Getattr(n, "sym:name")); + /* Export clientdata structure */ + Printf(f_runtime, "static swig_guile_clientdata _swig_guile_clientdata%s = { NULL, SCM_EOL };\n", mangled_classname); + + Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", swigtype_ptr, ", (void *) &_swig_guile_clientdata", mangled_classname, ");\n", NIL); + SwigType_remember(ct); + Delete(ct); + + /* Emit all of the members */ + goops_class_methods = NewString(""); + + in_class = 1; + Language::classHandler(n); + in_class = 0; + + Printv(goopscode, " #:metaclass <swig-metaclass>\n", NIL); + + if (have_constructor) + Printv(goopscode, " #:new-function ", primRenamer ? "primitive:" : "", "new-", short_class_name, "\n", NIL); + + Printf(goopscode, ")\n%s\n", goops_class_methods); + Delete(goops_class_methods); + goops_class_methods = 0; + + + /* export class initialization function */ + if (goops) { + /* export the wrapper function */ + String *funcName = NewString(mangled_classname); + Printf(funcName, "_swig_guile_setgoopsclass"); + String *guileFuncName = NewString(funcName); + Replaceall(guileFuncName, "_", "-"); + + Printv(f_wrappers, "static SCM ", funcName, "(SCM cl) \n", NIL); + Printf(f_wrappers, "#define FUNC_NAME %s\n{\n", guileFuncName); + Printv(f_wrappers, " ((swig_guile_clientdata *)(SWIGTYPE", swigtype_ptr, "->clientdata))->goops_class = cl;\n", NIL); + Printf(f_wrappers, " return SCM_UNSPECIFIED;\n"); + Printf(f_wrappers, "}\n#undef FUNC_NAME\n\n"); + + Printf(f_init, "scm_c_define_gsubr(\"%s\", 1, 0, 0, (swig_guile_proc) %s);\n", guileFuncName, funcName); + Printf(exported_symbols, "\"%s\", ", guileFuncName); + + /* export the call to the wrapper function */ + Printf(goopscode, "(%s%s %s)\n\n", primRenamer ? "primitive:" : "", guileFuncName, class_name); + + Delete(guileFuncName); + Delete(funcName); + } + + Delete(mangled_classname); + + Delete(swigtype_ptr); + swigtype_ptr = 0; + + Delete(class_name); + Delete(short_class_name); + class_name = 0; + short_class_name = 0; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + int memberfunctionHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + memberfunction_name = goopsNameMapping(proc, short_class_name); + Language::memberfunctionHandler(n); + Delete(memberfunction_name); + memberfunction_name = NULL; + Delete(proc); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + int membervariableHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + + if (emit_setters) { + struct_member = 1; + Printf(f_init, "{\n"); + } + + Language::membervariableHandler(n); + + if (emit_setters) { + Printf(f_init, "}\n"); + struct_member = 0; + } + + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + String *goops_name = goopsNameMapping(proc, short_class_name); + + /* The slot name is never qualified with the class, + even if useclassprefix is true. */ + Printv(goopscode, " (", proc, " #:allocation #:virtual", NIL); + /* GOOPS (at least in Guile 1.6.3) only accepts closures, not + primitive procedures for slot-ref and slot-set. */ + Printv(goopscode, "\n #:slot-ref (lambda (obj) (", primRenamer ? "primitive:" : "", short_class_name, "-", proc, "-get", " obj))", NIL); + if (!GetFlag(n, "feature:immutable")) { + Printv(goopscode, "\n #:slot-set! (lambda (obj value) (", primRenamer ? "primitive:" : "", short_class_name, "-", proc, "-set", " obj value))", NIL); + } else { + Printf(goopscode, "\n #:slot-set! (lambda (obj value) (error \"Immutable slot\"))"); + } + if (emit_slot_accessors) { + if (GetFlag(n, "feature:immutable")) { + Printv(goopscode, "\n #:getter ", goops_name, NIL); + } else { + Printv(goopscode, "\n #:accessor ", goops_name, NIL); + } + Printf(goopsexport, "%s ", goops_name); + } + Printv(goopscode, ")\n", NIL); + Delete(proc); + Delete(goops_name); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + int constructorHandler(Node *n) { + Language::constructorHandler(n); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + virtual int destructorHandler(Node *n) { + exporting_destructor = true; + Language::destructorHandler(n); + exporting_destructor = false; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * pragmaDirective() + * ------------------------------------------------------------ */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *cmd = Getattr(n, "name"); + String *value = Getattr(n, "value"); + +# define store_pragma(PRAGMANAME) \ + if (Strcmp(cmd, #PRAGMANAME) == 0) { \ + if (PRAGMANAME) Delete(PRAGMANAME); \ + PRAGMANAME = value ? NewString(value) : NULL; \ + } + + if (Strcmp(lang, "guile") == 0) { + store_pragma(beforereturn) + store_pragma(return_nothing_doc) + store_pragma(return_one_doc) + store_pragma(return_multi_doc); +# undef store_pragma + } + } + return Language::pragmaDirective(n); + } + + + /* ------------------------------------------------------------ + * goopsNameMapping() + * Maps the identifier from C++ to the GOOPS based * on command + * line parameters and such. + * If class_name = "" that means the mapping is for a function or + * variable not attached to any class. + * ------------------------------------------------------------ */ + String *goopsNameMapping(String *name, const_String_or_char_ptr class_name) { + String *n = NewString(""); + + if (Strcmp(class_name, "") == 0) { + // not part of a class, so no class name to prefix + if (goopsprefix) { + Printf(n, "%s%s", goopsprefix, name); + } else { + Printf(n, "%s", name); + } + } else { + if (useclassprefix) { + Printf(n, "%s-%s", class_name, name); + } else { + if (goopsprefix) { + Printf(n, "%s%s", goopsprefix, name); + } else { + Printf(n, "%s", name); + } + } + } + return n; + } + + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + /* Check whether we have an R5RS identifier. Guile supports a + superset of R5RS identifiers, but it's probably a bad idea to use + those. */ + /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ + /* <initial> --> <letter> | <special initial> */ + if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~'))) { + /* <peculiar identifier> --> + | - | ... */ + if ((strcmp(c, "+") == 0) + || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) + return 1; + else + return 0; + } + /* <subsequent> --> <initial> | <digit> | <special subsequent> */ + while (*c) { + if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') + || (*c == '-') || (*c == '.') || (*c == '@'))) + return 0; + c++; + } + return 1; + } + + String *runtimeCode() { + String *s; + s = Swig_include_sys("guile_scm_run.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'guile_scm_run.swg"); + s = NewString(""); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigguilerun.h"); + } +}; + +/* ----------------------------------------------------------------------------- + * swig_guile() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_guile() { + return new GUILE(); +} +extern "C" Language *swig_guile(void) { + return new_swig_guile(); +} diff --git a/contrib/tools/swig/Source/Modules/interface.cxx b/contrib/tools/swig/Source/Modules/interface.cxx new file mode 100644 index 00000000000..fee6cd7dab2 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/interface.cxx @@ -0,0 +1,185 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * interface.cxx + * + * This module contains support for the interface feature. + * This feature is used in language modules where the target language does not + * naturally support C++ style multiple inheritance, but does support inheritance + * from multiple interfaces. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +static bool interface_feature_enabled = false; + +/* ----------------------------------------------------------------------------- + * collect_interface_methods() + * + * Create a list of all the methods from the base classes of class n that are + * marked as an interface. The resulting list is thus the list of methods that + * need to be implemented in order for n to be non-abstract. + * ----------------------------------------------------------------------------- */ + +static List *collect_interface_methods(Node *n) { + List *methods = NewList(); + if (Hash *bases = Getattr(n, "interface:bases")) { + List *keys = Keys(bases); + for (Iterator base = First(keys); base.item; base = Next(base)) { + Node *cls = Getattr(bases, base.item); + if (cls == n) + continue; + for (Node *child = firstChild(cls); child; child = nextSibling(child)) { + if (Cmp(nodeType(child), "cdecl") == 0) { + if (GetFlag(child, "feature:ignore") || Getattr(child, "interface:owner")) + continue; // skip methods propagated to bases + Node *m = Copy(child); + set_nextSibling(m, NIL); + set_previousSibling(m, NIL); + Setattr(m, "interface:owner", cls); + Append(methods, m); + } + } + } + Delete(keys); + } + return methods; +} + +/* ----------------------------------------------------------------------------- + * collect_interface_bases + * ----------------------------------------------------------------------------- */ + +static void collect_interface_bases(Hash *bases, Node *n) { + if (Getattr(n, "feature:interface")) { + String *name = Getattr(n, "interface:name"); + if (!Getattr(bases, name)) + Setattr(bases, name, n); + } + + if (List *baselist = Getattr(n, "bases")) { + for (Iterator base = First(baselist); base.item; base = Next(base)) { + if (!GetFlag(base.item, "feature:ignore")) { + if (Getattr(base.item, "feature:interface")) + collect_interface_bases(bases, base.item); + } + } + } +} + +/* ----------------------------------------------------------------------------- + * collect_interface_base_classes() + * + * Create a hash containing all the classes up the inheritance hierarchy + * marked with feature:interface (including this class n). + * Stops going up the inheritance chain as soon as a class is found without + * feature:interface. + * The idea is to find all the base interfaces that a class must implement. + * ----------------------------------------------------------------------------- */ + +static void collect_interface_base_classes(Node *n) { + if (Getattr(n, "feature:interface")) { + // check all bases are also interfaces + if (List *baselist = Getattr(n, "bases")) { + for (Iterator base = First(baselist); base.item; base = Next(base)) { + if (!GetFlag(base.item, "feature:ignore")) { + if (!Getattr(base.item, "feature:interface")) { + Swig_error(Getfile(n), Getline(n), "Base class '%s' of '%s' is not similarly marked as an interface.\n", SwigType_namestr(Getattr(base.item, "name")), SwigType_namestr(Getattr(n, "name"))); + SWIG_exit(EXIT_FAILURE); + } + } + } + } + } + + Hash *interface_bases = NewHash(); + collect_interface_bases(interface_bases, n); + if (Len(interface_bases) == 0) + Delete(interface_bases); + else + Setattr(n, "interface:bases", interface_bases); +} + +/* ----------------------------------------------------------------------------- + * process_interface_name() + * ----------------------------------------------------------------------------- */ + +static void process_interface_name(Node *n) { + if (Getattr(n, "feature:interface")) { + String *interface_name = Getattr(n, "feature:interface:name"); + if (!Len(interface_name)) { + Swig_error(Getfile(n), Getline(n), "The interface feature for '%s' is missing the name attribute.\n", SwigType_namestr(Getattr(n, "name"))); + SWIG_exit(EXIT_FAILURE); + } + if (Strchr(interface_name, '%')) { + String *name = NewStringf(interface_name, Getattr(n, "sym:name")); + Setattr(n, "interface:name", name); + } else { + Setattr(n, "interface:name", interface_name); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_interface_propagate_methods() + * + * Find all the base classes marked as an interface (with feature:interface) for + * class node n. For each of these, add all of its methods as methods of n so that + * n is not abstract. If class n is also marked as an interface, it will remain + * abstract and not have any methods added. + * ----------------------------------------------------------------------------- */ + +void Swig_interface_propagate_methods(Node *n) { + if (interface_feature_enabled) { + process_interface_name(n); + collect_interface_base_classes(n); + List *methods = collect_interface_methods(n); + bool is_interface = Getattr(n, "feature:interface") != 0; + for (Iterator mi = First(methods); mi.item; mi = Next(mi)) { + if (!is_interface && GetFlag(mi.item, "abstract")) + continue; + String *this_decl = Getattr(mi.item, "decl"); + String *this_decl_resolved = SwigType_typedef_resolve_all(this_decl); + bool identically_overloaded_method = false; // true when a base class' method is implemented in n + if (SwigType_isfunction(this_decl_resolved)) { + String *name = Getattr(mi.item, "name"); + for (Node *child = firstChild(n); child; child = nextSibling(child)) { + if (Getattr(child, "interface:owner")) + break; // at the end of the list are newly appended methods + if (Cmp(nodeType(child), "cdecl") == 0) { + if (checkAttribute(child, "name", name)) { + String *decl = SwigType_typedef_resolve_all(Getattr(child, "decl")); + identically_overloaded_method = Strcmp(decl, this_decl_resolved) == 0; + Delete(decl); + if (identically_overloaded_method) + break; + } + } + } + } + Delete(this_decl_resolved); + if (!identically_overloaded_method) { + // TODO: Fix if the method is overloaded with different arguments / has default args + appendChild(n, mi.item); + } else { + Delete(mi.item); + } + } + Delete(methods); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_interface_feature_enable() + * + * Turn on interface feature support + * ----------------------------------------------------------------------------- */ + +void Swig_interface_feature_enable() { + interface_feature_enabled = true; +} diff --git a/contrib/tools/swig/Source/Modules/java.cxx b/contrib/tools/swig/Source/Modules/java.cxx new file mode 100644 index 00000000000..7734c64714d --- /dev/null +++ b/contrib/tools/swig/Source/Modules/java.cxx @@ -0,0 +1,5002 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * java.cxx + * + * Java language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <limits.h> // for INT_MAX +#include "cparse.h" +#include <ctype.h> +#include "javadoc.h" + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class JAVA:public Language { + static const char *usage; + const String *empty_string; + const String *public_string; + const String *protected_string; + + Hash *swig_types_hash; + 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; + + bool proxy_flag; // Flag for generating proxy classes + bool nopgcpp_flag; // Flag for suppressing the premature garbage collection prevention parameter + bool native_function_flag; // Flag for when wrapping a native function + bool enum_constant_flag; // Flag for when wrapping an enum or constant + bool static_flag; // Flag for when wrapping a static functions or member variables + bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable + bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const + bool global_variable_flag; // Flag for when wrapping a global variable + bool old_variable_names; // Flag for old style variable names in the intermediary class + bool member_func_flag; // flag set when wrapping a member function + bool doxygen; //flag for converting found doxygen to javadoc + bool comment_creation_chatter; //flag for getting information about where comments were created in java.cxx + + String *imclass_name; // intermediary class name + String *module_class_name; // module class name + String *constants_interface_name; // constants interface name + String *imclass_class_code; // intermediary class code + String *proxy_class_def; + String *proxy_class_code; + String *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration + String *module_class_code; + String *proxy_class_name; // proxy class name + String *full_proxy_class_name;// fully qualified proxy class name when using nspace feature, otherwise same as proxy_class_name + String *full_imclass_name; // fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name + String *variable_name; //Name of a variable being wrapped + String *proxy_class_constants_code; + String *module_class_constants_code; + String *enum_code; + String *package; // Optional package name + String *jnipackage; // Package name used in the JNI code + String *package_path; // Package name used internally by JNI (slashes) + String *imclass_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *imclass_baseclass; //inheritance for intermediary class class from %pragma + String *imclass_package; //package in which to generate the intermediary class + String *module_baseclass; //inheritance for module class from %pragma + String *imclass_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *imclass_class_modifiers; //class modifiers for intermediary class overridden by %pragma + String *module_class_modifiers; //class modifiers for module class overridden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *imclass_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *imclass_directors; // Intermediate class director code + String *destructor_call; //C++ destructor call if any + String *destructor_throws_clause; //C++ destructor throws clause if any + + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + int first_class_dmethod; + int curr_class_dmethod; + int nesting_depth; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + +public: + + /* ----------------------------------------------------------------------------- + * JAVA() + * ----------------------------------------------------------------------------- */ + + JAVA():empty_string(NewString("")), + public_string(NewString("public")), + protected_string(NewString("protected")), + swig_types_hash(NULL), + 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), + proxy_flag(true), + nopgcpp_flag(false), + native_function_flag(false), + enum_constant_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + old_variable_names(false), + member_func_flag(false), + doxygen(false), + comment_creation_chatter(false), + imclass_name(NULL), + module_class_name(NULL), + constants_interface_name(NULL), + imclass_class_code(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + interface_class_code(NULL), + module_class_code(NULL), + proxy_class_name(NULL), + full_proxy_class_name(NULL), + full_imclass_name(NULL), + variable_name(NULL), + proxy_class_constants_code(NULL), + module_class_constants_code(NULL), + enum_code(NULL), + package(NULL), + jnipackage(NULL), + package_path(NULL), + imclass_imports(NULL), + module_imports(NULL), + imclass_baseclass(NULL), + imclass_package(NULL), + module_baseclass(NULL), + imclass_interfaces(NULL), + module_interfaces(NULL), + imclass_class_modifiers(NULL), + module_class_modifiers(NULL), + upcasts_code(NULL), + imclass_cppcasts_code(NULL), + imclass_directors(NULL), + destructor_call(NULL), + destructor_throws_clause(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(0), + first_class_dmethod(0), + curr_class_dmethod(0), + nesting_depth(0){ + /* for now, multiple inheritance in directors is disabled, this + should be easy to implement though */ + director_multiple_inheritance = 0; + director_language = 1; + } + + ~JAVA() { + delete doxygenTranslator; + } + + /* ----------------------------------------------------------------------------- + * constructIntermediateClassName() + * + * Construct the fully qualified name of the intermediate class and set + * the full_imclass_name attribute accordingly. + * ----------------------------------------------------------------------------- */ + void constructIntermediateClassName(Node *n) { + String *nspace = Getattr(n, "sym:nspace"); + + if (imclass_package && package) + full_imclass_name = NewStringf("%s.%s.%s", package, imclass_package, imclass_name); + else if (package && nspace) + full_imclass_name = NewStringf("%s.%s", package, imclass_name); + else if (imclass_package) + full_imclass_name = NewStringf("%s.%s", imclass_package, imclass_name); + else + full_imclass_name = NewStringf("%s", imclass_name); + + if (nspace && !package) { + String *name = Getattr(n, "name") ? Getattr(n, "name") : NewString("<unnamed>"); + Swig_warning(WARN_JAVA_NSPACE_WITHOUT_PACKAGE, Getfile(n), Getline(n), + "The nspace feature is used on '%s' without -package. " + "The generated code may not compile as Java does not support types declared in a named package accessing types declared in an unnamed package.\n", name); + } + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class. + * Return NULL if not otherwise the proxy class name, fully qualified with + * package name if the nspace feature is used, unless jnidescriptor is true as + * the package name is handled differently (unfortunately for legacy reasons). + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t, bool jnidescriptor = false) { + String *proxyname = NULL; + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + proxyname = Getattr(n, "proxyname"); + if (!proxyname || jnidescriptor) { + String *nspace = Getattr(n, "sym:nspace"); + String *symname = Copy(Getattr(n, "sym:name")); + if (symname && !GetFlag(n, "feature:flatnested")) { + for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + if (String* name = Getattr(outer_class, "sym:name")) { + Push(symname, jnidescriptor ? "$" : "."); + Push(symname, name); + } + else + return NULL; + } + } + if (nspace) { + if (package && !jnidescriptor) + proxyname = NewStringf("%s.%s.%s", package, nspace, symname); + else + proxyname = NewStringf("%s.%s", nspace, symname); + } else { + proxyname = Copy(symname); + } + if (!jnidescriptor) { + Setattr(n, "proxyname", proxyname); // Cache it + Delete(proxyname); + } + Delete(symname); + } + } + } + return proxyname; + } + + /* ----------------------------------------------------------------------------- + * makeValidJniName() + * ----------------------------------------------------------------------------- */ + + String *makeValidJniName(const String *name) { + String *valid_jni_name = NewString(name); + Replaceall(valid_jni_name, "_", "_1"); + return valid_jni_name; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("java"); + + int doxygen_translator_flags = 0; + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-package") == 0) { + if (argv[i + 1]) { + package = NewString(""); + Printf(package, argv[i + 1]); + if (Len(package) == 0) { + Delete(package); + package = 0; + } + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + Printf(stderr, "Deprecated command line option: %s. Proxy classes are now generated by default.\n", argv[i]); + Swig_mark_arg(i); + proxy_flag = true; + } else if ((strcmp(argv[i], "-doxygen") == 0)) { + Swig_mark_arg(i); + doxygen = true; + scan_doxygen_comments = true; + } else if ((strcmp(argv[i], "-debug-doxygen-translator") == 0)) { + Swig_mark_arg(i); + doxygen_translator_flags |= DoxygenTranslator::debug_translator; + } else if ((strcmp(argv[i], "-debug-doxygen-parser") == 0)) { + Swig_mark_arg(i); + doxygen_translator_flags |= DoxygenTranslator::debug_parser; + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + Swig_mark_arg(i); + proxy_flag = false; + } else if (strcmp(argv[i], "-nopgcpp") == 0) { + Swig_mark_arg(i); + nopgcpp_flag = true; + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } else if (strcmp(argv[i], "-jnic") == 0) { + Swig_mark_arg(i); + Printf(stderr, "Deprecated command line option: -jnic. C JNI calling convention now used when -c++ not specified.\n"); + } else if (strcmp(argv[i], "-nofinalize") == 0) { + Swig_mark_arg(i); + Printf(stderr, "Deprecated command line option: -nofinalize. Use the new javafinalize typemap instead.\n"); + } else if (strcmp(argv[i], "-jnicpp") == 0) { + Swig_mark_arg(i); + Printf(stderr, "Deprecated command line option: -jnicpp. C++ JNI calling convention now used when -c++ specified.\n"); + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + if (doxygen) + doxygenTranslator = new JavaDocConverter(doxygen_translator_flags); + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGJAVA 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("java"); + SWIG_config_file("java.swg"); + + allow_overloading(); + Swig_interface_feature_enable(); + } + + /* --------------------------------------------------------------------- + * 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, "jniclassname")) + imclass_name = Copy(Getattr(optionsnode, "jniclassname")); + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + if (Getattr(optionsnode, "directors")) { + 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("begin", f_begin); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + 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); + + swig_types_hash = NewHash(); + filenames_list = NewList(); + + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + if (!imclass_name) { + imclass_name = NewStringf("%sJNI", Getattr(n, "name")); + module_class_name = Copy(Getattr(n, "name")); + } else { + // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution + if (Cmp(imclass_name, Getattr(n, "name")) == 0) + module_class_name = NewStringf("%sModule", Getattr(n, "name")); + else + module_class_name = Copy(Getattr(n, "name")); + } + constants_interface_name = NewStringf("%sConstants", module_class_name); + + // module class and intermediary classes are always created + if (!addSymbol(imclass_name, n)) + return SWIG_ERROR; + if (!addSymbol(module_class_name, n)) + return SWIG_ERROR; + + imclass_class_code = NewString(""); + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + module_class_constants_code = NewString(""); + imclass_baseclass = NewString(""); + imclass_package = NULL; + imclass_interfaces = NewString(""); + imclass_class_modifiers = NewString(""); + module_class_code = NewString(""); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + module_class_modifiers = NewString(""); + imclass_imports = NewString(""); + imclass_cppcasts_code = NewString(""); + imclass_directors = NewString(""); + upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + jnipackage = NewString(""); + package_path = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGJAVA\n#define SWIGJAVA\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", module_class_name); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_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"); + + String *wrapper_name = NewString(""); + + if (package) { + String *jniname = makeValidJniName(package); + Printv(jnipackage, jniname, NIL); + Delete(jniname); + Replaceall(jnipackage, ".", "_"); + Append(jnipackage, "_"); + Printv(package_path, package, NIL); + Replaceall(package_path, ".", "/"); + } + String *jniname = makeValidJniName(imclass_name); + Printf(wrapper_name, "Java_%s%s_%%f", jnipackage, jniname); + Delete(jniname); + + Swig_name_register("wrapper", Char(wrapper_name)); + if (old_variable_names) { + Swig_name_register("set", "set_%n%v"); + Swig_name_register("get", "get_%n%v"); + } + + Delete(wrapper_name); + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + /* Emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + // Generate the intermediary class + { + String *filen = NewStringf("%s%s.java", outputDirectory(imclass_package), imclass_name); + File *f_im = NewFile(filen, "w", SWIG_output_files()); + if (!f_im) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the intermediary class file + emitBanner(f_im); + + if (imclass_package && package) + Printf(f_im, "package %s.%s;", package, imclass_package); + else if (imclass_package) + Printf(f_im, "package %s;", imclass_package); + else if (package) + Printf(f_im, "package %s;\n", package); + + if (imclass_imports) + Printf(f_im, "%s\n", imclass_imports); + + if (Len(imclass_class_modifiers) > 0) + Printf(f_im, "%s ", imclass_class_modifiers); + Printf(f_im, "%s ", imclass_name); + + if (imclass_baseclass && *Char(imclass_baseclass)) + Printf(f_im, "extends %s ", imclass_baseclass); + if (Len(imclass_interfaces) > 0) + Printv(f_im, "implements ", imclass_interfaces, " ", NIL); + Printf(f_im, "{\n"); + + // Add the intermediary class methods + Replaceall(imclass_class_code, "$module", module_class_name); + Replaceall(imclass_class_code, "$imclassname", imclass_name); + Printv(f_im, imclass_class_code, NIL); + Printv(f_im, imclass_cppcasts_code, NIL); + if (Len(imclass_directors) > 0) + Printv(f_im, "\n", imclass_directors, NIL); + + if (n_dmethods > 0) { + Putc('\n', f_im); + Printf(f_im, " private final static native void swig_module_init();\n"); + Printf(f_im, " static {\n"); + Printf(f_im, " swig_module_init();\n"); + Printf(f_im, " }\n"); + } + // Finish off the class + Printf(f_im, "}\n"); + Delete(f_im); + } + + // Generate the Java module class + { + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), module_class_name); + File *f_module = NewFile(filen, "w", SWIG_output_files()); + if (!f_module) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the module class file + emitBanner(f_module); + + if (package) + Printf(f_module, "package %s;\n", package); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, 0); + if (comment_creation_chatter) + Printf(f_module, "/* This was generated from top() */\n"); + Printv(f_module, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + if (Len(module_class_modifiers) > 0) + Printf(f_module, "%s ", module_class_modifiers); + Printf(f_module, "%s ", module_class_name); + + if (module_baseclass && *Char(module_baseclass)) + Printf(f_module, "extends %s ", module_baseclass); + if (Len(module_interfaces) > 0) { + if (Len(module_class_constants_code) != 0) + Printv(f_module, "implements ", constants_interface_name, ", ", module_interfaces, " ", NIL); + else + Printv(f_module, "implements ", module_interfaces, " ", NIL); + } else { + if (Len(module_class_constants_code) != 0) + Printv(f_module, "implements ", constants_interface_name, " ", NIL); + } + Printf(f_module, "{\n"); + + Replaceall(module_class_code, "$module", module_class_name); + Replaceall(module_class_constants_code, "$module", module_class_name); + + Replaceall(module_class_code, "$imclassname", imclass_name); + Replaceall(module_class_constants_code, "$imclassname", imclass_name); + + // Add the wrapper methods + Printv(f_module, module_class_code, NIL); + + // Finish off the class + Printf(f_module, "}\n"); + Delete(f_module); + } + + // Generate the Java constants interface + if (Len(module_class_constants_code) != 0) { + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), constants_interface_name); + File *f_module = NewFile(filen, "w", SWIG_output_files()); + if (!f_module) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the Java constants interface file + emitBanner(f_module); + + if (package) + Printf(f_module, "package %s;\n", package); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + Printf(f_module, "public interface %s {\n", constants_interface_name); + + // Write out all the global constants + Printv(f_module, module_class_constants_code, NIL); + + // Finish off the Java interface + Printf(f_module, "}\n"); + Delete(f_module); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + emitDirectorUpcalls(); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a Java type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + // 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(swig_types_hash); + swig_types_hash = NULL; + Delete(filenames_list); + filenames_list = NULL; + Delete(imclass_name); + imclass_name = NULL; + Delete(imclass_class_code); + imclass_class_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(module_class_constants_code); + module_class_constants_code = NULL; + Delete(imclass_baseclass); + imclass_baseclass = NULL; + Delete(imclass_package); + imclass_package = NULL; + Delete(imclass_interfaces); + imclass_interfaces = NULL; + Delete(imclass_class_modifiers); + imclass_class_modifiers = NULL; + Delete(module_class_name); + module_class_name = NULL; + Delete(constants_interface_name); + constants_interface_name = NULL; + Delete(module_class_code); + module_class_code = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(module_class_modifiers); + module_class_modifiers = NULL; + Delete(imclass_imports); + imclass_imports = NULL; + Delete(imclass_cppcasts_code); + imclass_cppcasts_code = NULL; + Delete(imclass_directors); + imclass_directors = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(package); + package = NULL; + Delete(jnipackage); + jnipackage = NULL; + Delete(package_path); + package_path = NULL; + Delete(dmethods_seq); + dmethods_seq = NULL; + Delete(dmethods_table); + dmethods_table = NULL; + n_dmethods = 0; + + /* Close all of the files */ + Dump(f_header, f_runtime); + + if (directorsEnabled()) { + Dump(f_directors, f_runtime); + 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_runtime); + Wrapper_pretty_print(f_init, f_runtime); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Dump(f_runtime, f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * emitBanner() + * ----------------------------------------------------------------------------- */ + + void emitBanner(File *f) { + Printf(f, "/* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); + } + + /*----------------------------------------------------------------------- + * Add new director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *imclass_desc, String *class_desc, String *decl) { + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + String *imclass_methodidx = NewStringf("%d", n_dmethods); + 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, "fdesc", Copy(class_desc)); + Setattr(new_udata, "imclass_method", Copy(imclass_method)); + Setattr(new_udata, "imclass_fdesc", Copy(imclass_desc)); + Setattr(new_udata, "imclass_methodidx", imclass_methodidx); + Setattr(new_udata, "class_methodidx", class_methodidx); + Setattr(new_udata, "decl", Copy(decl)); + + Delete(key); + return new_udata; + } + + /*----------------------------------------------------------------------- + * Get director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *getUpcallMethodData(String *director_class, String *decl) { + String *key = NewStringf("%s|%s", director_class, decl); + UpcallData *udata = Getattr(dmethods_table, key); + + Delete(key); + return udata; + } + + /* ---------------------------------------------------------------------- + * nativeWrapper() + * ---------------------------------------------------------------------- */ + + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n, imclass_name)) + 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; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *c_return_type = NewString(""); + String *im_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + int num_arguments = 0; + int gencomma = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + String *nondir_args = NewString(""); + bool is_destructor = (Cmp(Getattr(n, "nodeType"), "destructor") == 0); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(symname, n, imclass_name)) + return SWIG_ERROR; + } + + /* + The rest of this function deals with generating the intermediary class wrapper function (that wraps + a c/c++ function) and generating the JNI c code. Each Java wrapper function has a + matching JNI c function call. + */ + + // A new wrapper function object + Wrapper *f = NewWrapper(); + + // Make a wrapper name for this function + String *jniname = makeValidJniName(overloaded_name); + String *wname = Swig_name_wrapper(jniname); + + Delete(jniname); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("jni", l, f); + Swig_typemap_attach_parms("jtype", l, f); + Swig_typemap_attach_parms("jstype", l, f); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("jni", n, "", 0))) { + Printf(c_return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s\n", SwigType_str(t, 0)); + } + + if ((tm = Swig_typemap_lookup("jtype", n, "", 0))) { + Printf(im_return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype 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 = 0", NIL); + + Printv(f->def, "SWIGEXPORT ", c_return_type, " JNICALL ", wname, "(JNIEnv *jenv, jclass jcls", NIL); + + // Usually these function parameters are unused - The code below ensures + // that compilers do not issue such a warning if configured to do so. + + Printv(f->code, " (void)jenv;\n", NIL); + Printv(f->code, " (void)jcls;\n", 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 Java + if (Getattr(n, "sym:overloaded")) { + // Emit warnings for the few cases that can't be overloaded in Java and give up on generating wrapper + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) { + DelWrapper(f); + return SWIG_OK; + } + } + + Printf(imclass_class_code, " public final static native %s %s(", im_return_type, overloaded_name); + + num_arguments = emit_num_arguments(l); + + // 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 JNI C types of the parameter */ + if ((tm = Getattr(p, "tmap:jni"))) { + Printv(c_param_type, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Get the intermediary class parameter types of the parameter */ + if ((tm = Getattr(p, "tmap:jtype"))) { + Printv(im_param_type, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to intermediary class method */ + if (gencomma) + Printf(imclass_class_code, ", "); + Printf(imclass_class_code, "%s %s", im_param_type, arg); + + // Add parameter to C function + Printv(f->def, ", ", c_param_type, " ", arg, NIL); + + ++gencomma; + + // Premature garbage collection prevention parameter + if (!is_destructor) { + String *pgc_parameter = prematureGarbageCollectionPreventionParameter(pt, p); + if (pgc_parameter) { + Printf(imclass_class_code, ", %s %s_", pgc_parameter, arg); + Printf(f->def, ", jobject %s_", arg); + Printf(f->code, " (void)%s_;\n", arg); + } + } + // Get typemap for this argument + if ((tm = Getattr(p, "tmap:in"))) { + addThrows(n, "tmap:in", p); + Replaceall(tm, "$source", arg); /* deprecated */ + Replaceall(tm, "$target", ln); /* deprecated */ + Replaceall(tm, "$arg", arg); /* deprecated? */ + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + + Printf(nondir_args, "%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); + } + + Printv(f->code, nondir_args, NIL); + Delete(nondir_args); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + addThrows(n, "tmap:check", p); + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + 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"))) { + addThrows(n, "tmap:freearg", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + 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"))) { + addThrows(n, "tmap:argout", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + 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); + } + } + + // Get any Java exception classes in the throws typemap + 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")) { + addThrows(n, "tmap:throws", p); + } + } + } + + // Now write code to make the function call + if (!native_function_flag) { + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + // Handle exception classes specified in the "except" feature's "throws" attribute + addThrows(n, "feature:except", n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + addThrows(n, "tmap:out", n); + Replaceall(tm, "$source", Swig_cresult_name()); /* deprecated */ + Replaceall(tm, "$target", "jresult"); /* deprecated */ + Replaceall(tm, "$result", "jresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s", tm); + 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))) { + addThrows(n, "tmap:newfree", n); + Replaceall(tm, "$source", Swig_cresult_name()); /* deprecated */ + 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))) { + addThrows(n, "tmap:ret", n); + Replaceall(tm, "$source", Swig_cresult_name()); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C function and intermediary class function definitions */ + Printf(imclass_class_code, ")"); + generateThrowsClause(n, imclass_class_code); + Printf(imclass_class_code, ";\n"); + + 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 */ + Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, "); + + if (!is_void_return) + Replaceall(f->code, "$null", "0"); + else + Replaceall(f->code, "$null", ""); + + /* Dump the function out */ + if (!native_function_flag) + Wrapper_print(f, f_wrappers); + + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + moduleClassFunctionHandler(n); + } + + /* + * Generate the proxy class getters/setters for public member variables. + * Not for enums and constants. + */ + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name + bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) != 0; + + String *getter_setter_name = NewString(""); + if (!getter_flag) + Printf(getter_setter_name, "set"); + else + Printf(getter_setter_name, "get"); + Putc(toupper((int) *Char(variable_name)), getter_setter_name); + Printf(getter_setter_name, "%s", Char(variable_name) + 1); + + Setattr(n, "proxyfuncname", getter_setter_name); + Setattr(n, "imfuncname", symname); + + proxyClassFunctionHandler(n); + Delete(getter_setter_name); + } + + Delete(c_return_type); + Delete(im_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(overloaded_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + variable_wrapper_flag = true; + Language::variableWrapper(n); /* Default to functions */ + variable_wrapper_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * 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; + } + + String *getCurrentScopeName(String *nspace) { + String *scope = 0; + if (nspace || getCurrentClass()) { + scope = NewString(""); + if (nspace) + Printf(scope, "%s", nspace); + if (Node* cls = getCurrentClass()) { + if (Node *outer = Getattr(cls, "nested:outer")) { + String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); + for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { + Push(outerClassesPrefix, "."); + Push(outerClassesPrefix, Getattr(outer, "sym:name")); + } + Printv(scope, nspace ? "." : "", outerClassesPrefix, ".", proxy_class_name, NIL); + Delete(outerClassesPrefix); + } else + Printv(scope, nspace ? "." : "", proxy_class_name, NIL); + } + } + return scope; + } + + /* ---------------------------------------------------------------------- + * enumDeclaration() + * + * C/C++ enums can be mapped in one of 4 ways, depending on the java:enum feature specified: + * 1) Simple enums - simple constant within the proxy class or module class + * 2) Typeunsafe enums - simple constant in a Java class (class named after the c++ enum name) + * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) + * 4) Proper enums - proper Java enum + * Anonymous enums always default to 1) + * ---------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call + if (proxy_flag && !is_wrapping_class()) { + // Global enums / enums in a namespace + assert(!full_imclass_name); + constructIntermediateClassName(n); + } + + enum_code = NewString(""); + String *symname = Getattr(n, "sym:name"); + String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; + EnumFeature enum_feature = decodeEnumFeature(n); + String *typemap_lookup_type = Getattr(n, "name"); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum + + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, 0); + if (comment_creation_chatter) + Printf(enum_code, "/* This was generated from enumDeclaration() */\n"); + Printv(enum_code, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + + String *scope = getCurrentScopeName(nspace); + if (!addSymbol(symname, n, scope)) + return SWIG_ERROR; + + // Pure Java baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "javabase", typemap_lookup_type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + + // Emit the enum + Printv(enum_code, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers (enum modifiers really) + " ", symname, *Char(pure_baseclass) ? // Bases + " extends " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " implements " : "", pure_interfaces, " {\n", NIL); + if (proxy_flag && is_wrapping_class()) + Replaceall(enum_code, "$static ", "static "); + else + Replaceall(enum_code, "$static ", ""); + Delete(scope); + } else { + if (symname && !Getattr(n, "unnamedinstance")) + Printf(constants_code, " // %s \n", symname); + // Translate and write javadoc comment for the enum itself if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, " "); + if (comment_creation_chatter) + Printf(constants_code, "/* This was generated from enumDeclaration() */\n"); + Printf(constants_code, Char(doxygen_comments)); + Printf(constants_code, "\n"); + Delete(doxygen_comments); + } + } + + // Emit each enum item + Language::enumDeclaration(n); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum + // Finish the enum declaration + // Typemaps are used to generate the enum definition in a similar manner to proxy classes. + Printv(enum_code, (enum_feature == ProperEnum) ? ";\n" : "", typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class + typemapLookup(n, "javacode", typemap_lookup_type, WARN_NONE), // extra Java code + "}", NIL); + + Replaceall(enum_code, "$javaclassname", symname); + + // Substitute $enumvalues - intended usage is for typesafe enums + if (Getattr(n, "enumvalues")) + Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); + else + Replaceall(enum_code, "$enumvalues", ""); + + if (proxy_flag && is_wrapping_class()) { + // Enums defined within the C++ class are defined within the proxy class + + // Add extra indentation + Replaceall(enum_code, "\n", "\n "); + Replaceall(enum_code, " \n", "\n"); + if (GetFlag(getCurrentClass(), "feature:interface")) + Printv(interface_class_code, " ", enum_code, "\n\n", NIL); + else + Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL); + } else { + // Global enums are defined in their own file + String *output_directory = outputDirectory(nspace); + String *filen = NewStringf("%s%s.java", output_directory, symname); + File *f_enum = NewFile(filen, "w", SWIG_output_files()); + if (!f_enum) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the enum file + emitBanner(f_enum); + + if (package || nspace) { + Printf(f_enum, "package "); + if (package) + Printv(f_enum, package, nspace ? "." : "", NIL); + if (nspace) + Printv(f_enum, nspace, NIL); + Printf(f_enum, ";\n"); + } + + Printv(f_enum, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + Printf(f_enum, "\n"); + Delete(f_enum); + Delete(output_directory); + } + } else { + // Wrap C++ enum with simple constant + Printf(enum_code, "\n"); + if (proxy_flag && is_wrapping_class()) + Printv(proxy_class_constants_code, enum_code, NIL); + else + Printv(module_class_constants_code, enum_code, NIL); + } + + Delete(enum_code); + enum_code = NULL; + + if (proxy_flag && !is_wrapping_class()) { + Delete(full_imclass_name); + full_imclass_name = 0; + } + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + Node *parent = parentNode(n); + int unnamedinstance = GetFlag(parent, "unnamedinstance"); + String *parent_name = Getattr(parent, "name"); + String *nspace = getNSpace(); + String *newsymname = 0; + String *tmpValue; + + // Strange hack from parent method + 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); + } + + { + EnumFeature enum_feature = decodeEnumFeature(parent); + + if ((enum_feature == SimpleEnum) && GetFlag(parent, "scopedenum")) { + newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + symname = newsymname; + } + + // Add to language symbol table + String *scope = 0; + if (unnamedinstance || !parent_name || enum_feature == SimpleEnum) { + String *enumClassPrefix = getEnumClassPrefix(); + if (enumClassPrefix) { + scope = NewString(""); + if (nspace) + Printf(scope, "%s.", nspace); + Printf(scope, "%s", enumClassPrefix); + } else { + scope = Copy(constants_interface_name); + } + } else { + scope = getCurrentScopeName(nspace); + if (!scope) + scope = Copy(Getattr(parent, "sym:name")); + else + Printf(scope, ".%s", Getattr(parent, "sym:name")); + } + if (!addSymbol(symname, n, scope)) + return SWIG_ERROR; + + if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) { + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + } + + // Translate and write javadoc comment if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, " "); + if (comment_creation_chatter) + Printf(enum_code, "/* This was generated from enumvalueDeclaration() */\n"); + Printv(enum_code, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + + if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) { + // Wrap (non-anonymous) C/C++ enum with a proper Java enum + // Emit the enum item. + Printf(enum_code, " %s", symname); + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, "(%s)", value); + Delete(value); + } + } else { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); + Setattr(n, "type", typemap_lookup_type); + const String *tm = typemapLookup(n, "jstype", typemap_lookup_type, WARN_JAVA_TYPEMAP_JSTYPE_UNDEF); + + String *return_type = Copy(tm); + substituteClassname(typemap_lookup_type, return_type); + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if ((enum_feature == TypesafeEnum) && parent_name && !unnamedinstance) { + // Wrap (non-anonymous) enum using the typesafe enum pattern + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, " %s final static %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); + Delete(value); + } else { + Printf(enum_code, " %s final static %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); + } + } else { + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + String *value = enumValue(n); + Printf(enum_code, " %s final static %s %s = %s;\n", methodmods, return_type, symname, value); + Delete(value); + } + Delete(return_type); + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parent, "enumvalues"); + if (!enumvalues) + Setattr(parent, "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + Delete(scope); + } + + Delete(newsymname); + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * Used for wrapping constants - #define or %constant. + * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). + * Java static final variables are generated for these. + * If the %javaconst(1) feature is used then the C constant value is used to initialise the Java final variable. + * If not, a JNI method is generated to get the C constant value for initialisation of the Java final variable. + * However, if the %javaconstvalue feature is used, it overrides all other ways to generate the initialisation. + * Also note that this method might be called for wrapping enum items (when the enum is using %javaconst(0)). + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + SwigType *valuetype = Getattr(n, "valuetype"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + Swig_save("constantWrapper", n, "value", NIL); + + // Translate and write javadoc comment if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, " "); + if (comment_creation_chatter) + Printf(constants_code, "/* This was generated from constantWrapper() */\n"); + Printv(constants_code, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + if (!is_enum_item) { + String *scope = 0; + if (proxy_class_name) { + String *nspace = getNSpace(); + scope = NewString(""); + if (nspace) + Printf(scope, "%s.", nspace); + Printf(scope, "%s", proxy_class_name); + } else { + scope = Copy(constants_interface_name); + } + if (!addSymbol(itemname, n, scope)) + return SWIG_ERROR; + Delete(scope); + } + + // The %javaconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:java:const"); + + /* Adjust the enum type for the Swig_typemap_lookup. + * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ + if (is_enum_item) { + t = Getattr(parentNode(n), "enumtype"); + Setattr(n, "type", t); + } + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("jstype", l, NULL); + + /* Get Java return types */ + bool classname_substituted_flag = false; + + if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { + classname_substituted_flag = substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + // Add the stripped quotes back in + String *new_value = NewString(""); + if (SwigType_type(t) == T_STRING) { + Printf(new_value, "\"%s\"", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } else if (SwigType_type(t) == T_CHAR) { + Printf(new_value, "\'%s\'", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } + + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + Printf(constants_code, " %s final static %s %s = ", methodmods, return_type, itemname); + + // Check for the %javaconstvalue feature + String *value = Getattr(n, "feature:java:constvalue"); + + if (value) { + Printf(constants_code, "%s;\n", value); + } else if (!const_feature_flag) { + // Default enum and constant handling will work with any type of C constant and initialises the Java variable from C through a JNI call. + + if (classname_substituted_flag) { + if (SwigType_isenum(t)) { + // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) + Printf(constants_code, "%s.swigToEnum(%s.%s());\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } + } else { + Printf(constants_code, "%s.%s();\n", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } + + // Each constant and enum value is wrapped with a separate JNI function call + SetFlag(n, "feature:immutable"); + enum_constant_flag = true; + variableWrapper(n); + enum_constant_flag = false; + } else { + // Alternative constant handling will use the C syntax to make a true Java constant and hope that it compiles as Java code + 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 { + Printf(constants_code, "%s;\n", Getattr(n, "value")); + } + } + + // Emit the generated code to appropriate place + // Enums only emit the intermediate and JNI methods, so no proxy or module class wrapper methods needed + if (!is_enum_item) { + if (proxy_flag && wrapping_member_flag) + Printv(proxy_class_constants_code, constants_code, NIL); + else + Printv(module_class_constants_code, constants_code, NIL); + } + // Cleanup + Swig_restore(n); + Delete(new_value); + Delete(return_type); + Delete(constants_code); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * insertDirective() + * ----------------------------------------------------------------------------- */ + + virtual int insertDirective(Node *n) { + int ret = SWIG_OK; + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + + if (!ImportMode && (Cmp(section, "proxycode") == 0)) { + if (proxy_class_code) { + Swig_typemap_replace_embedded_typemap(code, n); + int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0; + Printv(proxy_class_code, Char(code) + offset, "\n", NIL); + } + } else { + ret = Language::insertDirective(n); + } + return ret; + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * jniclassbase - base (extends) for the intermediary class + * jniclasspackage - package in which to generate the intermediary class + * jniclassclassmodifiers - class modifiers for the intermediary class + * jniclasscode - text (java code) is copied verbatim to the intermediary class + * jniclassimports - import statements for the intermediary class + * jniclassinterfaces - interface (implements) for the intermediary class + * + * modulebase - base (extends) for the module class + * moduleclassmodifiers - class modifiers for the module class + * modulecode - text (java code) is copied verbatim to the module class + * moduleimports - import statements for the module class + * moduleinterfaces - interface (implements) for the module class + * + * ----------------------------------------------------------------------------- */ + + 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, "java") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); + + if (Strcmp(code, "jniclassbase") == 0) { + Delete(imclass_baseclass); + imclass_baseclass = Copy(strvalue); + } else if (Strcmp(code, "jniclasspackage") == 0) { + Delete(imclass_package); + imclass_package = Copy(strvalue); + String *imclass_class_package_jniname = makeValidJniName(imclass_package); + Printv(jnipackage, imclass_class_package_jniname, NIL); + Delete(imclass_class_package_jniname); + Replaceall(jnipackage, NSPACE_SEPARATOR, "_"); + Append(jnipackage, "_"); + + String *wrapper_name = NewString(""); + String *imclass_class_jniname = makeValidJniName(imclass_name); + Printf(wrapper_name, "Java_%s%s_%%f", jnipackage, imclass_class_jniname); + Delete(imclass_class_jniname); + + Swig_name_unregister("wrapper"); + Swig_name_register("wrapper", Char(wrapper_name)); + + Delete(wrapper_name); + } else if (Strcmp(code, "jniclassclassmodifiers") == 0) { + Delete(imclass_class_modifiers); + imclass_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "jniclasscode") == 0) { + Printf(imclass_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "jniclassimports") == 0) { + Delete(imclass_imports); + imclass_imports = Copy(strvalue); + } else if (Strcmp(code, "jniclassinterfaces") == 0) { + Delete(imclass_interfaces); + imclass_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(module_class_modifiers); + module_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(module_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "moduleimports") == 0) { + Delete(module_imports); + module_imports = Copy(strvalue); + } else if (Strcmp(code, "moduleinterfaces") == 0) { + Delete(module_interfaces); + module_interfaces = Copy(strvalue); + } else if (Strcmp(code, "moduleimport") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use the moduleimports pragma.\n"); + } else if (Strcmp(code, "moduleinterface") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use the moduleinterfaces pragma.\n"); + } else if (Strcmp(code, "modulemethodmodifiers") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%javamethodmodifiers.\n"); + } else if (Strcmp(code, "allshadowimport") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaimports).\n"); + } else if (Strcmp(code, "allshadowcode") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javacode).\n"); + } else if (Strcmp(code, "allshadowbase") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javabase).\n"); + } else if (Strcmp(code, "allshadowinterface") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javainterfaces).\n"); + } else if (Strcmp(code, "allshadowclassmodifiers") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n"); + } else if (proxy_flag) { + if (Strcmp(code, "shadowcode") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javacode).\n"); + } else if (Strcmp(code, "shadowimport") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaimports).\n"); + } else if (Strcmp(code, "shadowbase") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javabase).\n"); + } else if (Strcmp(code, "shadowinterface") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javainterfaces).\n"); + } else if (Strcmp(code, "shadowclassmodifiers") == 0) { + Swig_error(input_file, line_number, "Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n"); + } else { + Swig_error(input_file, line_number, "Unrecognized pragma.\n"); + } + } else { + Swig_error(input_file, line_number, "Unrecognized pragma.\n"); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * getQualifiedInterfaceName() + * ----------------------------------------------------------------------------- */ + + String *getQualifiedInterfaceName(Node *n) { + String *ret = Getattr(n, "interface:qname"); + if (!ret) { + String *nspace = Getattr(n, "sym:nspace"); + String *symname = Getattr(n, "interface:name"); + if (nspace) { + if (package) + ret = NewStringf("%s.%s.%s", package, nspace, symname); + else + ret = NewStringf("%s.%s", nspace, symname); + } else { + ret = Copy(symname); + } + Setattr(n, "interface:qname", ret); + } + return ret; + } + + /* ----------------------------------------------------------------------------- + * getInterfaceName() + * ----------------------------------------------------------------------------- */ + + String *getInterfaceName(SwigType *t, bool qualified) { + String *interface_name = NULL; + if (proxy_flag) { + Node *n = classLookup(t); + if (n && Getattr(n, "interface:name")) + interface_name = qualified ? getQualifiedInterfaceName(n) : Getattr(n, "interface:name"); + } + return interface_name; + } + + /* ----------------------------------------------------------------------------- + * addInterfaceNameAndUpcasts() + * ----------------------------------------------------------------------------- */ + + void addInterfaceNameAndUpcasts(SwigType *smart, String *interface_list, String *interface_upcasts, Hash *base_list, SwigType *c_classname) { + List *keys = Keys(base_list); + for (Iterator it = First(keys); it.item; it = Next(it)) { + Node *base = Getattr(base_list, it.item); + SwigType *c_baseclassname = Getattr(base, "name"); + String *interface_name = Getattr(base, "interface:name"); + if (Len(interface_list)) + Append(interface_list, ", "); + Append(interface_list, interface_name); + + Node *attributes = NewHash(); + String *interface_code = Copy(typemapLookup(base, "javainterfacecode", Getattr(base, "classtypeobj"), WARN_JAVA_TYPEMAP_INTERFACECODE_UNDEF, attributes)); + String *cptr_method_name = 0; + if (interface_code) { + Replaceall(interface_code, "$interfacename", interface_name); + Printv(interface_upcasts, interface_code, NIL); + cptr_method_name = Copy(Getattr(attributes, "tmap:javainterfacecode:cptrmethod")); + } + if (!cptr_method_name) + cptr_method_name = NewStringf("%s_GetInterfaceCPtr", interface_name); + Replaceall(cptr_method_name, ".", "_"); + Replaceall(cptr_method_name, "$interfacename", interface_name); + + String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), cptr_method_name); + upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); + + Delete(upcast_method_name); + Delete(cptr_method_name); + Delete(interface_code); + } + Delete(keys); + } + + /* ----------------------------------------------------------------------------- + * upcastsCode() + * + * Add code for C++ casting to base class + * ----------------------------------------------------------------------------- */ + + void upcastsCode(SwigType *smart, String *upcast_method_name, SwigType *c_classname, SwigType *c_baseclassname) { + String *jniname = makeValidJniName(upcast_method_name); + String *wname = Swig_name_wrapper(jniname); + + Printf(imclass_cppcasts_code, " public final static native long %s(long jarg1);\n", upcast_method_name); + + String *classname = SwigType_namestr(c_classname); + String *baseclassname = SwigType_namestr(c_baseclassname); + if (smart) { + String *smartnamestr = SwigType_namestr(smart); + String *bsmartnamestr = SwigType_namestr(smart); + + // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates + SwigType *rclassname = SwigType_typedef_resolve_all(classname); + SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname); + Replaceall(bsmartnamestr, rclassname, rbaseclassname); + + Printv(upcasts_code, + "SWIGEXPORT jlong JNICALL ", wname, "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n", + " jlong baseptr = 0;\n" + " ", smartnamestr, " *argp1;\n" + " (void)jenv;\n" + " (void)jcls;\n" + " argp1 = *(", smartnamestr, " **)&jarg1;\n" + " *(", bsmartnamestr, " **)&baseptr = argp1 ? new ", bsmartnamestr, "(*argp1) : 0;\n" + " return baseptr;\n" + "}\n", "\n", NIL); + + Delete(rbaseclassname); + Delete(rclassname); + Delete(bsmartnamestr); + Delete(smartnamestr); + } else { + Printv(upcasts_code, + "SWIGEXPORT jlong JNICALL ", wname, "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n", + " jlong baseptr = 0;\n" + " (void)jenv;\n" + " (void)jcls;\n" + " *(", baseclassname, " **)&baseptr = *(", classname, " **)&jarg1;\n" + " return baseptr;\n" + "}\n", "\n", NIL); + } + + Delete(baseclassname); + Delete(classname); + Delete(wname); + Delete(jniname); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + SwigType *c_classname = Getattr(n, "name"); + SwigType *c_baseclassname = NULL; + String *baseclass = NULL; + String *interface_list = NewStringEmpty(); + String *interface_upcasts = NewStringEmpty(); + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); + SwigType *smart = Swig_cparse_smartptr(n); + + // Inheritance from pure Java classes + Node *attributes = NewHash(); + const String *pure_baseclass = typemapLookup(n, "javabase", typemap_lookup_type, WARN_NONE, attributes); + bool purebase_replace = GetFlag(attributes, "tmap:javabase:replace") ? true : false; + bool purebase_notderived = GetFlag(attributes, "tmap:javabase: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") || Getattr(base.item, "feature:interface"))) { + SwigType *baseclassname = Getattr(base.item, "name"); + if (!c_baseclassname) { + String *name = getProxyName(baseclassname); + if (name) { + c_baseclassname = baseclassname; + baseclass = name; + } + } else { + /* Warn about multiple inheritance for additional base class(es) */ + String *proxyclassname = Getattr(n, "classtypeobj"); + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s, base %s ignored. Multiple inheritance is not supported in Java.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname)); + } + } + base = Next(base); + } + } + } + + Hash *interface_bases = Getattr(n, "interface:bases"); + if (interface_bases) + addInterfaceNameAndUpcasts(smart, interface_list, interface_upcasts, interface_bases, c_classname); + + bool derived = baseclass != 0; + 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; + baseclass = NULL; + if (purebase_notderived) + Swig_error(Getfile(n), Getline(n), "The javabase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s, base %s ignored. Multiple inheritance is not supported in Java. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the javabase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure Java interfaces + const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + + if (*Char(interface_list) && *Char(pure_interfaces)) + Append(interface_list, ", "); + Append(interface_list, pure_interfaces); + // Start writing the proxy class + if (!has_outerclass) // Import statements + Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE),"\n", NIL); + + // Translate and write javadoc comment if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, 0); + if (comment_creation_chatter) + Printf(proxy_class_def, "/* This was generated from emitProxyClassDefAndCPPCasts() */\n"); + Printv(proxy_class_def, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + + if (has_outerclass) + Printv(proxy_class_def, "static ", NIL); // C++ nested classes correspond to static java classes + Printv(proxy_class_def, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $javaclassname", // Class name and bases + (*Char(wanted_base)) ? " extends " : "", wanted_base, *Char(interface_list) ? // Pure Java interfaces + " implements " : "", interface_list, " {", derived ? typemapLookup(n, "javabody_derived", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF) : // main body of class + typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class + NIL); + + // C++ destructor is wrapped by the delete method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + attributes = NewHash(); + const String *destruct_methodname = NULL; + const String *destruct_methodmodifiers = NULL; + const String *destruct_parameters = NULL; + if (derived) { + tm = typemapLookup(n, "javadestruct_derived", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:javadestruct_derived:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:javadestruct_derived:methodmodifiers"); + destruct_parameters = Getattr(attributes, "tmap:javadestruct_derived:parameters"); + } else { + tm = typemapLookup(n, "javadestruct", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:javadestruct:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:javadestruct:methodmodifiers"); + destruct_parameters = Getattr(attributes, "tmap:javadestruct:parameters"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in javadestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(Getfile(n), Getline(n), "No methodmodifiers attribute defined in javadestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_parameters) + destruct_parameters = empty_string; + } + // Emit the finalize and delete methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "javafinalize", typemap_lookup_type, WARN_NONE), NIL); + } + // delete method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$jnicall", destructor_call); + else + Replaceall(destruct, "$jnicall", "throw new UnsupportedOperationException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) { + Printv(proxy_class_def, "\n ", NIL); + const String *methodmods = Getattr(n, "destructmethodmodifiers"); + if (methodmods) + Printv(proxy_class_def, methodmods, NIL); + else + Printv(proxy_class_def, destruct_methodmodifiers, NIL); + Printv(proxy_class_def, " void ", destruct_methodname, "(", destruct_parameters, ")", destructor_throws_clause, " ", destruct, "\n", NIL); + } + } + if (*Char(interface_upcasts)) + Printv(proxy_class_def, interface_upcasts, NIL); + + /* Insert directordisconnect typemap, if this class has directors enabled */ + /* Also insert the swigTakeOwnership and swigReleaseOwnership methods */ + if (feature_director) { + String *destruct_jnicall, *release_jnicall, *take_jnicall; + String *changeown_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "change_ownership"); + + destruct_jnicall = NewStringf("%s()", destruct_methodname); + release_jnicall = NewStringf("%s.%s(this, swigCPtr, false)", full_imclass_name, changeown_method_name); + take_jnicall = NewStringf("%s.%s(this, swigCPtr, true)", full_imclass_name, changeown_method_name); + + emitCodeTypemap(n, false, typemap_lookup_type, "directordisconnect", "methodname", destruct_jnicall); + emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_release", "methodname", release_jnicall); + emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_take", "methodname", take_jnicall); + + Delete(destruct_jnicall); + Delete(changeown_method_name); + Delete(release_jnicall); + Delete(take_jnicall); + } + + Delete(interface_upcasts); + Delete(interface_list); + Delete(attributes); + Delete(destruct); + + // Emit extra user code + Printv(proxy_class_def, typemapLookup(n, "javacode", typemap_lookup_type, WARN_NONE), // extra Java code + "\n", NIL); + + if (derived) { + String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), smart != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); + upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname); + Delete(upcast_method_name); + } + + Delete(smart); + } + + /* ---------------------------------------------------------------------- + * emitInterfaceDeclaration() + * ---------------------------------------------------------------------- */ + + void emitInterfaceDeclaration(Node *n, String *interface_name, File *f_interface, String *nspace) { + if (package || nspace) { + Printf(f_interface, "package "); + if (package) + Printv(f_interface, package, nspace ? "." : "", NIL); + if (nspace) + Printv(f_interface, nspace, NIL); + Printf(f_interface, ";\n"); + } + + Printv(f_interface, typemapLookup(n, "javaimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL); + Printf(f_interface, "public interface %s", interface_name); + if (List *baselist = Getattr(n, "bases")) { + String *bases = 0; + for (Iterator base = First(baselist); base.item; base = Next(base)) { + if (GetFlag(base.item, "feature:ignore") || !Getattr(base.item, "feature:interface")) + continue; // TODO: warn about skipped non-interface bases + String *base_iname = Getattr(base.item, "interface:name"); + if (!bases) + bases = Copy(base_iname); + else { + Append(bases, ", "); + Append(bases, base_iname); + } + } + if (bases) { + Printv(f_interface, " extends ", bases, NIL); + Delete(bases); + } + } + Printf(f_interface, " {\n"); + + Node *attributes = NewHash(); + String *interface_code = Copy(typemapLookup(n, "javainterfacecode", Getattr(n, "classtypeobj"), WARN_JAVA_TYPEMAP_INTERFACECODE_UNDEF, attributes)); + if (interface_code) { + String *interface_declaration = Copy(Getattr(attributes, "tmap:javainterfacecode:declaration")); + if (interface_declaration) { + Replaceall(interface_declaration, "$interfacename", interface_name); + Printv(f_interface, interface_declaration, NIL); + Delete(interface_declaration); + } + Delete(interface_code); + } + } + + /* ---------------------------------------------------------------------- + * classDeclaration() + * ---------------------------------------------------------------------- */ + + int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + File *f_proxy = NULL; + File *f_interface = NULL; + String *old_proxy_class_name = proxy_class_name; + String *old_full_proxy_class_name = full_proxy_class_name; + String *old_full_imclass_name = full_imclass_name; + String *old_destructor_call = destructor_call; + String *old_destructor_throws_clause = destructor_throws_clause; + String *old_proxy_class_constants_code = proxy_class_constants_code; + String *old_proxy_class_def = proxy_class_def; + String *old_proxy_class_code = proxy_class_code; + bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested"); + String *old_interface_class_code = interface_class_code; + interface_class_code = 0; + + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + String *nspace = getNSpace(); + constructIntermediateClassName(n); + + String *outerClassesPrefix = 0; + if (Node *outer = Getattr(n, "nested:outer")) { + outerClassesPrefix = Copy(Getattr(outer, "sym:name")); + for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { + Push(outerClassesPrefix, "."); + Push(outerClassesPrefix, Getattr(outer, "sym:name")); + } + } + if (!nspace) { + full_proxy_class_name = outerClassesPrefix ? NewStringf("%s.%s", outerClassesPrefix, proxy_class_name) : NewStringf("%s", proxy_class_name); + + if (Cmp(proxy_class_name, imclass_name) == 0) { + Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + if (Cmp(proxy_class_name, module_class_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + } else { + if (outerClassesPrefix) { + if (package) + full_proxy_class_name = NewStringf("%s.%s.%s.%s", package, nspace, outerClassesPrefix, proxy_class_name); + else + full_proxy_class_name = NewStringf("%s.%s.%s", nspace, outerClassesPrefix, proxy_class_name); + } else { + if (package) + full_proxy_class_name = NewStringf("%s.%s.%s", package, nspace, proxy_class_name); + else + full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); + } + } + + String *interface_name = Getattr(n, "feature:interface") ? Getattr(n, "interface:name") : 0; + if (outerClassesPrefix) { + String *fnspace = nspace ? NewStringf("%s.%s", nspace, outerClassesPrefix) : outerClassesPrefix; + if (!addSymbol(proxy_class_name, n, fnspace)) + return SWIG_ERROR; + if (interface_name && !addInterfaceSymbol(interface_name, n, fnspace)) + return SWIG_ERROR; + if (nspace) + Delete(fnspace); + Delete(outerClassesPrefix); + } else { + if (!addSymbol(proxy_class_name, n, nspace)) + return SWIG_ERROR; + if (interface_name && !addInterfaceSymbol(interface_name, n, nspace)) + return SWIG_ERROR; + } + + // Each outer proxy class goes into a separate file + if (!has_outerclass) { + String *output_directory = outputDirectory(nspace); + String *filen = NewStringf("%s%s.java", output_directory, proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + Delete(output_directory); + + // Start writing out the proxy class file + emitBanner(f_proxy); + + if (package || nspace) { + Printf(f_proxy, "package "); + if (package) + Printv(f_proxy, package, nspace ? "." : "", NIL); + if (nspace) + Printv(f_proxy, nspace, NIL); + Printf(f_proxy, ";\n"); + } + } + else + ++nesting_depth; + + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + destructor_call = NewString(""); + destructor_throws_clause = NewString(""); + proxy_class_constants_code = NewString(""); + + if (Getattr(n, "feature:interface")) { + interface_class_code = NewString(""); + String *output_directory = outputDirectory(nspace); + String *filen = NewStringf("%s%s.java", output_directory, interface_name); + f_interface = NewFile(filen, "w", SWIG_output_files()); + if (!f_interface) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, filen); // file name ownership goes to the list + emitBanner(f_interface); + emitInterfaceDeclaration(n, interface_name, interface_class_code, nspace); + Delete(filen); + Delete(output_directory); + } + } + + Language::classHandler(n); + + if (proxy_flag) { + emitProxyClassDefAndCPPCasts(n); + + String *javaclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name + + Replaceall(proxy_class_def, "$javaclassname", proxy_class_name); + Replaceall(proxy_class_code, "$javaclassname", proxy_class_name); + Replaceall(proxy_class_constants_code, "$javaclassname", proxy_class_name); + Replaceall(interface_class_code, "$javaclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$javaclazzname", javaclazzname); + Replaceall(proxy_class_code, "$javaclazzname", javaclazzname); + Replaceall(proxy_class_constants_code, "$javaclazzname", javaclazzname); + Replaceall(interface_class_code, "$javaclazzname", javaclazzname); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + Replaceall(proxy_class_constants_code, "$module", module_class_name); + Replaceall(interface_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", full_imclass_name); + Replaceall(proxy_class_code, "$imclassname", full_imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name); + Replaceall(interface_class_code, "$imclassname", full_imclass_name); + + if (!has_outerclass) + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + else { + Swig_offset_string(proxy_class_def, nesting_depth); + Append(old_proxy_class_code, proxy_class_def); + Swig_offset_string(proxy_class_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_code); + } + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) { + if (!has_outerclass) + Printv(f_proxy, proxy_class_constants_code, NIL); + else { + Swig_offset_string(proxy_class_constants_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_constants_code); + } + } + + if (!has_outerclass) { + Printf(f_proxy, "}\n"); + Delete(f_proxy); + f_proxy = NULL; + } else { + for (int i = 0; i < nesting_depth; ++i) + Append(old_proxy_class_code, " "); + Append(old_proxy_class_code, "}\n\n"); + --nesting_depth; + } + + if (f_interface) { + Printv(f_interface, interface_class_code, "}\n", NIL); + Delete(f_interface); + f_interface = 0; + } + + emitDirectorExtraMethods(n); + + Delete(interface_class_code); + interface_class_code = old_interface_class_code; + Delete(javaclazzname); + Delete(proxy_class_name); + proxy_class_name = old_proxy_class_name; + Delete(full_proxy_class_name); + full_proxy_class_name = old_full_proxy_class_name; + Delete(full_imclass_name); + full_imclass_name = old_full_imclass_name; + Delete(destructor_call); + destructor_call = old_destructor_call; + Delete(destructor_throws_clause); + destructor_throws_clause = old_destructor_throws_clause; + Delete(proxy_class_constants_code); + proxy_class_constants_code = old_proxy_class_constants_code; + Delete(proxy_class_def); + proxy_class_def = old_proxy_class_def; + Delete(proxy_class_code); + proxy_class_code = old_proxy_class_code; + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + member_func_flag = true; + Language::memberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + member_func_flag = false; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + member_func_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + member_func_flag = false; + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a Java wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to Java static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the Java class proxy function, which in turn will call "imfuncname" - + * the intermediary (JNI) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + bool is_interface = Getattr(parentNode(n), "feature:interface") != 0 + && !static_flag && Getattr(n, "interface:owner") == 0; + + if (!proxy_flag) + return; + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in directors + if (GetFlag(n, "explicitcall")) + return; + + 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("jtype", l, NULL); + Swig_typemap_attach_parms("jstype", l, NULL); + Swig_typemap_attach_parms("javain", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { + // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type + SwigType *covariant = Getattr(n, "covariant"); + substituteClassname(covariant ? covariant : t, tm); + Printf(return_type, "%s", tm); + if (covariant) + Swig_warning(WARN_JAVA_COVARIANT_RET, input_file, line_number, + "Covariant return types not supported in Java. Proxy method will return %s.\n", SwigType_str(covariant, 0)); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // For wrapping member variables (Javabean setter) + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0); + } + + // Translate and write javadoc comment if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, " "); + if (comment_creation_chatter) + Printf(function_code, "/* This was generated from proxyclassfunctionhandler() */\n"); + Printv(function_code, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + + /* Start generating the proxy function */ + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s ", methodmods); + if (static_flag) + Printf(function_code, "static "); + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + if (is_interface) + Printf(interface_class_code, " %s %s(", return_type, proxy_function_name); + + Printv(imcall, full_imclass_name, ".$imfuncname(", NIL); + if (!static_flag) { + Printf(imcall, "swigCPtr"); + + String *this_type = Copy(getClassType()); + String *name = NewString("jself"); + String *qualifier = Getattr(n, "qualifier"); + if (qualifier) + SwigType_push(this_type, qualifier); + SwigType_add_pointer(this_type); + Parm *this_parm = NewParm(this_type, name, n); + Swig_typemap_attach_parms("jtype", this_parm, NULL); + Swig_typemap_attach_parms("jstype", this_parm, NULL); + + if (prematureGarbageCollectionPreventionParameter(this_type, this_parm)) + Printf(imcall, ", this"); + + Delete(this_parm); + Delete(name); + Delete(this_type); + } + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0) || static_flag) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Java parameter type */ + if ((tm = Getattr(p, "tmap:jstype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, setter_flag); + + // Use typemaps to transform type used in Java proxy wrapper (in proxy class) to type used in JNI function (in intermediary class) + if ((tm = Getattr(p, "tmap:javain"))) { + addThrows(n, "tmap:javain", p); + substituteClassname(pt, tm); + Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) { + Printf(function_code, ", "); + if (is_interface) + Printf(interface_class_code, ", "); + } + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + if (is_interface) + Printf(interface_class_code, "%s %s", param_type, arg); + + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in proxy class) + if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) { + addThrows(n, "tmap:javaout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + 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"); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + + // For director methods: generate code to selectively make a normal polymorphic call or + // an explicit method call - needed to prevent infinite recursion calls in director methods. + Node *explicit_n = Getattr(n, "explicitcallnode"); + if (explicit_n) { + String *ex_overloaded_name = getOverloadedName(explicit_n); + String *ex_intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), ex_overloaded_name); + + String *ex_imcall = Copy(imcall); + Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); + Replaceall(imcall, "$imfuncname", intermediary_function_name); + + String *excode = NewString(""); + if (!Cmp(return_type, "void")) + Printf(excode, "if (getClass() == %s.class) %s; else %s", proxy_class_name, imcall, ex_imcall); + else + Printf(excode, "(getClass() == %s.class) ? %s : %s", proxy_class_name, imcall, ex_imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + Delete(ex_overloaded_name); + Delete(excode); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + + Replaceall(tm, "$jnicall", imcall); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number, "No javaout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (is_interface) { + Printf(interface_class_code, ")"); + generateThrowsClause(n, interface_class_code); + Printf(interface_class_code, ";\n"); + } + generateThrowsClause(n, function_code); + Printf(function_code, " %s\n\n", tm ? tm : empty_string); + Printv(proxy_class_code, function_code, NIL); + + Delete(pre_code); + Delete(post_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *function_code = NewString(""); + String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the javain typemap has code in the pre or post attributes + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *im_return_type = NewString(""); + bool feature_director = (parentNode(n) && Swig_directorclass(n)); + + Language::constructorHandler(n); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(getNSpace(), overloaded_name); + String *imcall = NewString(""); + + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + tm = Getattr(n, "tmap:jtype"); // typemaps were attached earlier to the node + Printf(im_return_type, "%s", tm); + + // Translate and write javadoc comment if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, " "); + if (comment_creation_chatter) + Printf(function_code, "/* This was generated from constructionhandler() */\n"); + Printv(function_code, Char(doxygen_comments), NIL); + Delete(doxygen_comments); + } + + Printf(function_code, " %s %s(", methodmods, proxy_class_name); + Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + + Printv(imcall, full_imclass_name, ".", mangled_overname, "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("jtype", l, NULL); + Swig_typemap_attach_parms("jstype", l, NULL); + Swig_typemap_attach_parms("javain", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Java parameter type */ + if ((tm = Getattr(p, "tmap:jstype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, false); + + // Use typemaps to transform type used in Java wrapper function (in proxy class) to type used in JNI function (in intermediary class) + if ((tm = Getattr(p, "tmap:javain"))) { + addThrows(n, "tmap:javain", p); + substituteClassname(pt, tm); + Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma) { + Printf(function_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } + Printf(function_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", arg); + ++gencomma; + + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } + + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + + Printf(function_code, ")"); + Printf(helper_code, ")"); + generateThrowsClause(n, function_code); + + /* Insert the javaconstruct typemap, doing the replacement for $directorconnect, as needed */ + Hash *attributes = NewHash(); + String *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj"); + String *construct_tm = Copy(typemapLookup(n, "javaconstruct", typemap_lookup_type, + WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF, attributes)); + if (construct_tm) { + if (!feature_director) { + Replaceall(construct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(attributes, "tmap:javaconstruct:directorconnect"); + + if (connect_attr) { + Replaceall(construct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_JAVA_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"javaconstruct\" typemap.\n", + Getattr(n, "name")); + Replaceall(construct_tm, "$directorconnect", ""); + } + } + + Printv(function_code, " ", construct_tm, "\n", NIL); + } + + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + generateThrowsClause(n, helper_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); + } + Printf(helper_code, "\n }\n"); + String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); + Printv(proxy_class_code, helper_code, "\n", NIL); + Replaceall(function_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(function_code, "$imcall", imcall); + } + + Printv(proxy_class_code, function_code, "\n", NIL); + + Delete(helper_args); + Delete(im_return_type); + Delete(pre_code); + Delete(post_code); + Delete(construct_tm); + Delete(attributes); + Delete(overloaded_name); + Delete(imcall); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL); + generateThrowsClause(n, destructor_throws_clause); + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + if (methodmods) + Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * 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; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + 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; + } + + /* ---------------------------------------------------------------------- + * 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; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + + /* Although JNI functions are designed to handle overloaded Java functions, + * a Java long is used for all classes in the SWIG intermediary class. + * The intermediary class methods are thus mangled when overloaded to give + * a unique name. */ + String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * moduleClassFunctionHandler() + * ----------------------------------------------------------------------------- */ + + void moduleClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + + // Translate and write javadoc comment if flagged + if (doxygen && doxygenTranslator->hasDocumentation(n)) { + String *doxygen_comments = doxygenTranslator->getDocumentation(n, " "); + if (comment_creation_chatter) + Printf(function_code, "/* This was generated from moduleClassFunctionHandler() */\n"); + Printv(function_code, doxygen_comments, NIL); + Delete(doxygen_comments); + } + + 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("jstype", l, NULL); + Swig_typemap_attach_parms("javain", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (proxy_flag && global_variable_flag) { + // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name + func_name = NewString(""); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), variable_name)) == 0); + if (setter_flag) + Printf(func_name, "set"); + else + Printf(func_name, "get"); + Putc(toupper((int) *Char(variable_name)), func_name); + Printf(func_name, "%s", Char(variable_name) + 1); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name); + Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + + bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); + 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 Java parameter type */ + if ((tm = Getattr(p, "tmap:jstype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, global_or_member_variable); + + // Use typemaps to transform type used in Java wrapper function (in proxy class) to type used in JNI function (in intermediary class) + if ((tm = Getattr(p, "tmap:javain"))) { + addThrows(n, "tmap:javain", p); + substituteClassname(pt, tm); + Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain 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); + + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } + + p = Getattr(p, "tmap:in:next"); + Delete(arg); + Delete(param_type); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in module class) + if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) { + addThrows(n, "tmap:javaout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + 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"); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$jnicall", imcall); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number, "No javaout typemap defined for %s\n", SwigType_str(t, 0)); + } + + generateThrowsClause(n, function_code); + Printf(function_code, " %s\n\n", tm ? tm : empty_string); + Printv(module_class_code, function_code, NIL); + + Delete(pre_code); + Delete(post_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(func_name); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /*---------------------------------------------------------------------- + * decodeEnumFeature() + * Decode the possible enum features, which are one of: + * %javaenum(simple) + * %javaenum(typeunsafe) - default + * %javaenum(typesafe) + * %javaenum(proper) + *--------------------------------------------------------------------*/ + + EnumFeature decodeEnumFeature(Node *n) { + EnumFeature enum_feature = TypeunsafeEnum; + String *feature = Getattr(n, "feature:java:enum"); + if (feature) { + if (Cmp(feature, "simple") == 0) + enum_feature = SimpleEnum; + else if (Cmp(feature, "typesafe") == 0) + enum_feature = TypesafeEnum; + else if (Cmp(feature, "proper") == 0) + enum_feature = ProperEnum; + } + return enum_feature; + } + + /* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in Java generated + * code. If the %javaconst feature is not used, the string will contain the intermediary + * class call to obtain the enum value. The intermediary class and JNI methods to obtain + * the enum value will be generated. Otherwise the C/C++ enum value will be used if there + * is one and hopefully it will compile as Java code - e.g. 20 as in: enum E{e=20}; + * The %javaconstvalue feature overrides all other ways to generate the constant value. + * The caller must delete memory allocated for the returned string. + * ------------------------------------------------------------------------ */ + + String *enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + + // Check for the %javaconstvalue feature + String *value = Getattr(n, "feature:java:constvalue"); + + if (!value) { + // The %javaconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:java:const"); + + if (const_feature_flag) { + // Use the C syntax to make a true Java constant and hope that it compiles as Java code + value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); + } else { + String *newsymname = 0; + if (!getCurrentClass() || !proxy_flag) { + String *enumClassPrefix = getEnumClassPrefix(); + if (enumClassPrefix) { + // A global scoped enum + newsymname = Swig_name_member(0, enumClassPrefix, symname); + symname = newsymname; + } + } + + // Get the enumvalue from a JNI call + if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), Swig_name_member(0, getEnumClassPrefix(), symname))); + } + Delete(newsymname); + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * + * If jnidescriptor is set, inner class names are separated with '$' otherwise a '.' + * and the package is also not added to the name. + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t, bool jnidescriptor) { + Node *enumname = NULL; + Node *n = enumLookup(t); + if (n) { + enumname = Getattr(n, "enumname"); + if (!enumname || jnidescriptor) { + String *symname = Getattr(n, "sym:name"); + if (symname) { + // Add in class scope when referencing enum if not a global enum + String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); + String *proxyname = 0; + if (scopename_prefix) { + proxyname = getProxyName(scopename_prefix, jnidescriptor); + } + if (proxyname) { + const char *class_separator = jnidescriptor ? "$" : "."; + enumname = NewStringf("%s%s%s", proxyname, class_separator, symname); + } else { + // global enum or enum in a namespace + String *nspace = Getattr(n, "sym:nspace"); + if (nspace) { + if (package && !jnidescriptor) + enumname = NewStringf("%s.%s.%s", package, nspace, symname); + else + enumname = NewStringf("%s.%s", nspace, symname); + } else { + enumname = Copy(symname); + } + } + if (!jnidescriptor) { + Setattr(n, "enumname", enumname); // Cache it + Delete(enumname); + } + Delete(scopename_prefix); + } + } + } + + return enumname; + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $javaclassname with the proxy class name for classes/structs/unions + * that SWIG knows about. Also substitutes enums with enum name. + * Otherwise use the $descriptor name for the Java class name. Note that the $&javaclassname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Note that the path separator is a '.' unless jnidescriptor is set. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * jnidescriptor - if set, inner class names are separated with '$' otherwise a '/' is used for the path separator + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm, bool jnidescriptor = false) { + bool substitution_performed = false; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + SwigType *strippedtype = SwigType_strip_qualifiers(type); + + if (Strstr(tm, "$javaclassname")) { + SwigType *classnametype = Copy(strippedtype); + substituteClassnameSpecialVariable(classnametype, tm, "$javaclassname", jnidescriptor); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$*javaclassname")) { + SwigType *classnametype = Copy(strippedtype); + Delete(SwigType_pop(classnametype)); + if (Len(classnametype) > 0) { + substituteClassnameSpecialVariable(classnametype, tm, "$*javaclassname", jnidescriptor); + substitution_performed = true; + } + Delete(classnametype); + } + if (Strstr(tm, "$&javaclassname")) { + SwigType *classnametype = Copy(strippedtype); + SwigType_add_pointer(classnametype); + substituteClassnameSpecialVariable(classnametype, tm, "$&javaclassname", jnidescriptor); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$javainterfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$javainterfacename", jnidescriptor, true); + substitution_performed = true; + Delete(interfacenametype); + } + if (Strstr(tm, "$*javainterfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + Delete(SwigType_pop(interfacenametype)); + if (Len(interfacenametype) > 0) { + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*javainterfacename", jnidescriptor, true); + substitution_performed = true; + } + Delete(interfacenametype); + } + if (Strstr(tm, "$&javainterfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + SwigType_add_pointer(interfacenametype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&javainterfacename", jnidescriptor, true); + substitution_performed = true; + Delete(interfacenametype); + } + if (Strstr(tm, "$interfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$interfacename", jnidescriptor, false); + substitution_performed = true; + Delete(interfacenametype); + } + if (Strstr(tm, "$*interfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + Delete(SwigType_pop(interfacenametype)); + if (Len(interfacenametype) > 0) { + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*interfacename", jnidescriptor, false); + substitution_performed = true; + } + Delete(interfacenametype); + } + if (Strstr(tm, "$&interfacename")) { + SwigType *interfacenametype = Copy(strippedtype); + SwigType_add_pointer(interfacenametype); + substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&interfacename", jnidescriptor, false); + substitution_performed = true; + Delete(interfacenametype); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable, bool jnidescriptor) { + String *replacementname; + + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype, jnidescriptor); + if (enumname) { + replacementname = Copy(enumname); + } else { + bool anonymous_enum = (Cmp(classnametype, "enum ") == 0); + if (anonymous_enum) { + replacementname = NewString("int"); + } else { + // An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum + replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replace(replacementname, "enum ", "", DOH_REPLACE_ANY); + Setattr(swig_types_hash, replacementname, classnametype); + } + } + } else { + String *classname = getProxyName(classnametype, jnidescriptor); // getProxyName() works for pointers to classes too + if (classname) { + replacementname = Copy(classname); + } else { + // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, replacementname, classnametype); + } + } + if (jnidescriptor) + Replaceall(replacementname,".","/"); + Replaceall(tm, classnamespecialvariable, replacementname); + + Delete(replacementname); + } + + /* ----------------------------------------------------------------------------- + * substituteInterfacenameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteInterfacenameSpecialVariable(SwigType *interfacenametype, String *tm, const char *interfacenamespecialvariable, bool jnidescriptor, bool qualified) { + + String *interfacename = getInterfaceName(interfacenametype/*, jnidescriptor*/, qualified); + if (interfacename) { + String *replacementname = Copy(interfacename); + + if (jnidescriptor) + Replaceall(replacementname,".","/"); + Replaceall(tm, interfacenamespecialvariable, replacementname); + + Delete(replacementname); + } + } + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *swigtype = NewString(""); + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the type wrapper class file + emitBanner(f_swigtype); + + if (package) + Printf(f_swigtype, "package %s;\n", package); + + // Pure Java baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "javabase", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "javainterfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "javaimports", type, WARN_NONE), // Import statements + "\n", typemapLookup(n, "javaclassmodifiers", type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $javaclassname", // Class name and bases + *Char(pure_baseclass) ? " extends " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " implements " : "", pure_interfaces, " {", typemapLookup(n, "javabody", type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class + typemapLookup(n, "javacode", type, WARN_NONE), // extra Java code + "}\n", "\n", NIL); + + Replaceall(swigtype, "$javaclassname", classname); + Replaceall(swigtype, "$module", module_class_name); + Replaceall(swigtype, "$imclassname", imclass_name); + + // For unknown enums + Replaceall(swigtype, "$static ", ""); + Replaceall(swigtype, "$enumvalues", ""); + + Printv(f_swigtype, swigtype, NIL); + + Delete(f_swigtype); + Delete(swigtype); + Delete(n); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * 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 *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + 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; + } + + /* ----------------------------------------------------------------------------- + * addThrows() + * + * Adds exception classes to a throws list. The throws list is the list of classes + * that will form the Java throws clause. Mainly for checked exceptions. + * ----------------------------------------------------------------------------- */ + + void addThrows(Node *n, const String *attribute, Node *parameter) { + // Get the comma separated exception classes for the throws clause - held in typemap/feature's "throws" attribute + String *throws_attribute = NewStringf("%s:throws", attribute); + String *throws = Getattr(parameter, throws_attribute); + + if (throws && Len(throws) > 0) { + String *throws_list = Getattr(n, "java:throwslist"); + if (!throws_list) { + throws_list = NewList(); + Setattr(n, "java:throwslist", throws_list); + } + // Put the exception classes in the throws clause into a temporary List + List *temp_classes_list = Split(throws, ',', INT_MAX); + + // Add the exception classes to the node throws list, but don't duplicate if already in list + if (temp_classes_list && Len(temp_classes_list) > 0) { + for (Iterator cls = First(temp_classes_list); cls.item; cls = Next(cls)) { + String *exception_class = NewString(cls.item); + Replaceall(exception_class, " ", ""); // remove spaces + Replaceall(exception_class, "\t", ""); // remove tabs + if (Len(exception_class) > 0) { + // $javaclassname substitution + SwigType *pt = Getattr(parameter, "type"); + substituteClassname(pt, exception_class); + + // Don't duplicate the Java exception class in the throws clause + bool found_flag = false; + for (Iterator item = First(throws_list); item.item; item = Next(item)) { + if (Strcmp(item.item, exception_class) == 0) + found_flag = true; + } + if (!found_flag) + Append(throws_list, exception_class); + } + Delete(exception_class); + } + } + Delete(temp_classes_list); + } + Delete(throws_attribute); + } + + /* ----------------------------------------------------------------------------- + * generateThrowsClause() + * + * Generates throws clause for checked exception + * ----------------------------------------------------------------------------- */ + + void generateThrowsClause(Node *n, String *code) { + // Add the throws clause into code + List *throws_list = Getattr(n, "java:throwslist"); + if (throws_list) { + Iterator cls = First(throws_list); + Printf(code, " throws %s", cls.item); + while ((cls = Next(cls)).item) + Printf(code, ", %s", cls.item); + } + } + + /* ----------------------------------------------------------------------------- + * prematureGarbageCollectionPreventionParameter() + * + * Get the proxy class name for use in an additional generated parameter. The + * additional parameter is added to a native method call purely to prevent + * premature garbage collection of proxy classes which pass their C++ class pointer + * in a Java long to the JNI layer. + * ----------------------------------------------------------------------------- */ + + String *prematureGarbageCollectionPreventionParameter(SwigType *t, Parm *p) { + String *pgcpp_java_type = 0; + String *jtype = NewString(Getattr(p, "tmap:jtype")); + + // Strip C comments + String *stripped_jtype = Swig_strip_c_comments(jtype); + if (stripped_jtype) { + Delete(jtype); + jtype = stripped_jtype; + } + + // Remove whitespace + Replaceall(jtype, " ", ""); + Replaceall(jtype, "\t", ""); + + if (Cmp(jtype, "long") == 0) { + if (proxy_flag) { + if (!GetFlag(p, "tmap:jtype:nopgcpp") && !nopgcpp_flag) { + String *interface_name = getInterfaceName(t, true); + pgcpp_java_type = interface_name ? interface_name : getProxyName(t); + if (!pgcpp_java_type) { + // Look for proxy class parameters passed to C++ layer using non-default typemaps, ie not one of above types + String *jstype = NewString(Getattr(p, "tmap:jstype")); + if (jstype) { + Hash *classes = getClassHash(); + if (classes) { + // Strip C comments + String *stripped_jstype = Swig_strip_c_comments(jstype); + if (stripped_jstype) { + Delete(jstype); + jstype = stripped_jstype; + } + // Remove whitespace + Replaceall(jstype, " ", ""); + Replaceall(jstype, "\t", ""); + + Iterator ki; + for (ki = First(classes); ki.key; ki = Next(ki)) { + Node *cls = ki.item; + if (cls && !Getattr(cls, "feature:ignore")) { + String *symname = Getattr(cls, "sym:name"); + if (symname && Strcmp(symname, jstype) == 0) { + pgcpp_java_type = symname; + } + } + } + } + } + Delete(jstype); + } + } + } + } + Delete(jtype); + return pgcpp_java_type; + } + + /* ----------------------------------------------------------------------------- + * outputDirectory() + * + * Return the directory to use for generating Java classes/enums and create the + * subdirectory (does not create if language specific outdir does not exist). + * ----------------------------------------------------------------------------- */ + + String *outputDirectory(String *nspace) { + String *output_directory = Copy(SWIG_output_directory()); + if (nspace) { + String *nspace_subdirectory = Copy(nspace); + Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER); + String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory); + if (newdir_error) { + Printf(stderr, "%s\n", newdir_error); + Delete(newdir_error); + SWIG_exit(EXIT_FAILURE); + } + Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0); + Delete(nspace_subdirectory); + } + return output_directory; + } + + /*---------------------------------------------------------------------- + * Start of director methods + *--------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------- + * getUpcallJNIMethod() + *--------------------------------------------------------------------*/ + + String *getUpcallJNIMethod(String *descrip) { + static struct { + char code; + const char *method; + } upcall_methods[] = { + { + 'B', "CallStaticByteMethod"}, { + 'C', "CallStaticCharMethod"}, { + 'D', "CallStaticDoubleMethod"}, { + 'F', "CallStaticFloatMethod"}, { + 'I', "CallStaticIntMethod"}, { + 'J', "CallStaticLongMethod"}, { + 'L', "CallStaticObjectMethod"}, { + 'S', "CallStaticShortMethod"}, { + 'V', "CallStaticVoidMethod"}, { + 'Z', "CallStaticBooleanMethod"}, { + '[', "CallStaticObjectMethod"} + }; + + char code; + int i; + + code = *Char(descrip); + for (i = 0; i < (int) (sizeof(upcall_methods) / sizeof(upcall_methods[0])); ++i) + if (code == upcall_methods[i].code) + return NewString(upcall_methods[i].method); + return NULL; + } + + /*---------------------------------------------------------------------- + * emitDirectorUpcalls() + *--------------------------------------------------------------------*/ + + void emitDirectorUpcalls() { + if (n_dmethods) { + Wrapper *w = NewWrapper(); + String *jni_imclass_name = makeValidJniName(imclass_name); + String *swig_module_init = NewString("swig_module_init"); + String *swig_module_init_jni = makeValidJniName(swig_module_init); + String *dmethod_data = NewString(""); + int n_methods = 0; + Iterator udata_iter; + + udata_iter = First(dmethods_seq); + while (udata_iter.item) { + UpcallData *udata = udata_iter.item; + Printf(dmethod_data, " { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); + ++n_methods; + + udata_iter = Next(udata_iter); + + if (udata_iter.item) + Putc(',', dmethod_data); + Putc('\n', dmethod_data); + } + + Printf(f_runtime, "namespace Swig {\n"); + Printf(f_runtime, " namespace {\n"); + Printf(f_runtime, " jclass jclass_%s = NULL;\n", imclass_name); + Printf(f_runtime, " jmethodID director_method_ids[%d];\n", n_methods); + Printf(f_runtime, " }\n"); + Printf(f_runtime, "}\n"); + + Printf(w->def, "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls) {", jnipackage, jni_imclass_name, swig_module_init_jni); + Printf(w->code, "static struct {\n"); + Printf(w->code, " const char *method;\n"); + Printf(w->code, " const char *signature;\n"); + Printf(w->code, "} methods[%d] = {\n", n_methods); + Printv(w->code, dmethod_data, NIL); + Printf(w->code, "};\n"); + + Wrapper_add_local(w, "i", "int i"); + + Printf(w->code, "Swig::jclass_%s = (jclass) jenv->NewGlobalRef(jcls);\n", imclass_name); + Printf(w->code, "if (!Swig::jclass_%s) return;\n", imclass_name); + Printf(w->code, "for (i = 0; i < (int) (sizeof(methods)/sizeof(methods[0])); ++i) {\n"); + Printf(w->code, " Swig::director_method_ids[i] = jenv->GetStaticMethodID(jcls, methods[i].method, methods[i].signature);\n"); + Printf(w->code, " if (!Swig::director_method_ids[i]) return;\n"); + Printf(w->code, "}\n"); + + Printf(w->code, "}\n"); + + Wrapper_print(w, f_wrappers); + Delete(dmethod_data); + Delete(swig_module_init_jni); + Delete(swig_module_init); + Delete(jni_imclass_name); + DelWrapper(w); + } + } + + /*---------------------------------------------------------------------- + * emitDirectorExtraMethods() + * + * This is where the director connect method is generated. + *--------------------------------------------------------------------*/ + void emitDirectorExtraMethods(Node *n) { + if (!Swig_directorclass(n)) + return; + + // Output the director connect method: + String *jni_imclass_name = makeValidJniName(imclass_name); + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); + String *swig_director_connect_jni = makeValidJniName(swig_director_connect); + String *smartptr = Getattr(n, "feature:smartptr"); + String *dirClassName = directorClassName(n); + Wrapper *code_wrap; + + Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean mem_own, boolean weak_global);\n", + swig_director_connect, full_proxy_class_name); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, + "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jswig_mem_own, " + "jboolean jweak_global) {\n", jnipackage, jni_imclass_name, swig_director_connect_jni); + + if (smartptr) { + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", smartptr, smartptr); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " // Keep a local instance of the smart pointer around while we are using the raw pointer\n"); + Printf(code_wrap->code, " // Avoids using smart pointer specific API.\n"); + Printf(code_wrap->code, " %s *director = static_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName); + } + else { + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " %s *director = static_cast<%s *>(obj);\n", dirClassName, dirClassName); + } + + Printf(code_wrap->code, " director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself), " + "(jswig_mem_own == JNI_TRUE), (jweak_global == JNI_TRUE));\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect_jni); + Delete(swig_director_connect); + + // Output the swigReleaseOwnership, swigTakeOwnership methods: + String *changeown_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "change_ownership"); + String *changeown_jnimethod_name = makeValidJniName(changeown_method_name); + + Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", changeown_method_name, full_proxy_class_name); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, + "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jtake_or_release) {\n", + jnipackage, jni_imclass_name, changeown_jnimethod_name); + + if (Len(smartptr)) { + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", smartptr, smartptr); + Printf(code_wrap->code, " // Keep a local instance of the smart pointer around while we are using the raw pointer\n"); + Printf(code_wrap->code, " // Avoids using smart pointer specific API.\n"); + Printf(code_wrap->code, " %s *director = dynamic_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName); + } else { + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " %s *director = dynamic_cast<%s *>(obj);\n", dirClassName, dirClassName); + } + + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_java_change_ownership(jenv, jself, jtake_or_release ? true : false);\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(changeown_method_name); + Delete(changeown_jnimethod_name); + Delete(norm_name); + Delete(dirClassName); + Delete(jni_imclass_name); + } + + /*---------------------------------------------------------------------- + * emitCodeTypemap() + * + * Output a code typemap that uses $methodname and $jnicall, as used + * in the directordisconnect, director_release and director_take + * typemaps. + *--------------------------------------------------------------------*/ + + void emitCodeTypemap(Node *n, bool derived, SwigType *lookup_type, const String *typemap, const String *methodname, const String *jnicall) { + const String *tm = NULL; + Node *tmattrs = NewHash(); + String *lookup_tmname = NewString(typemap); + String *method_attr_name; + String *method_attr; + + if (derived) { + Append(lookup_tmname, "_derived"); + } + + tm = typemapLookup(n, lookup_tmname, lookup_type, WARN_NONE, tmattrs); + method_attr_name = NewStringf("tmap:%s:%s", lookup_tmname, methodname); + method_attr = Getattr(tmattrs, method_attr_name); + + if (*Char(tm)) { + if (method_attr) { + String *codebody = Copy(tm); + Replaceall(codebody, "$methodname", method_attr); + Replaceall(codebody, "$jnicall", jnicall); + Append(proxy_class_def, codebody); + Delete(codebody); + } else { + Swig_error(input_file, line_number, "No %s method name attribute for %s\n", lookup_tmname, proxy_class_name); + } + } else { + Swig_error(input_file, line_number, "No %s typemap for %s\n", lookup_tmname, proxy_class_name); + } + + Delete(tmattrs); + Delete(lookup_tmname); + // Delete(method_attr); + } + + /* ----------------------------------------------------------------------------- + * substitutePackagePath() + * + * Replace $packagepath using the javapackage typemap associated with passed + * parm or global package if p is 0. "$packagepath/" is replaced with "" if + * no package is set. Note that the path separator is a '/'. + * ----------------------------------------------------------------------------- */ + + void substitutePackagePath(String *text, Parm *p) { + String *pkg_path= 0; + + if (p) + pkg_path = Swig_typemap_lookup("javapackage", p, "", 0); + if (!pkg_path || Len(pkg_path) == 0) + pkg_path = Copy(package_path); + + if (Len(pkg_path) > 0) { + Replaceall(pkg_path, ".", "/"); + Replaceall(text, "$packagepath", pkg_path); + } else { + Replaceall(text, "$packagepath/", empty_string); + Replaceall(text, "$packagepath", empty_string); + } + Delete(pkg_path); + } + + /* --------------------------------------------------------------- + * Canonicalize the JNI field descriptor + * + * Replace the $packagepath and $javaclassname family of special + * variables with the desired package and Java proxy name as + * required in the JNI field descriptors. + * + * !!SFM!! If $packagepath occurs in the field descriptor, but + * package_path isn't set (length == 0), then strip it and the + * optional trailing '/' from the resulting name. + * + * --------------------------------------------------------------- */ + + String *canonicalizeJNIDescriptor(String *descriptor_in, Parm *p) { + SwigType *type = Getattr(p, "type"); + String *descriptor_out = Copy(descriptor_in); + + substituteClassname(type, descriptor_out, true); + substitutePackagePath(descriptor_out, p); + + return descriptor_out; + } + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Java object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + 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); + String *jnidesc = NewString(""); + String *classdesc = NewString(""); + String *jniret_desc = NewString(""); + String *classret_desc = NewString(""); + SwigType *c_ret_type = NULL; + String *jupcall_args = NewString("swigjobj"); + String *imclass_dmethod; + String *callback_def = NewString(""); + String *callback_code = NewString(""); + String *imcall_args = NewString(""); + int classmeth_off = curr_class_dmethod - first_class_dmethod; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + String *qualified_classname = getProxyName(getClassName()); + + // 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("%s", Swig_name_member(getNSpace(), dirclassname, 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 Java 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 = Swig_typemap_lookup("jtype", n, "", 0); + if (tm) { + Printf(callback_def, " public static %s %s(%s jself", tm, imclass_dmethod, qualified_classname); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(returntype, 0)); + } + + String *cdesc = NULL; + SwigType *covariant = Getattr(n, "covariant"); + SwigType *adjustedreturntype = covariant ? covariant : returntype; + Parm *adjustedreturntypeparm = NewParmNode(adjustedreturntype, n); + + if (Swig_typemap_lookup("directorin", adjustedreturntypeparm, "", 0) + && (cdesc = Getattr(adjustedreturntypeparm, "tmap:directorin:descriptor"))) { + + // Note that in the case of polymorphic (covariant) return types, the + // method's return type is changed to be the base of the C++ return + // type + String *jnidesc_canon = canonicalizeJNIDescriptor(cdesc, adjustedreturntypeparm); + Append(classret_desc, jnidesc_canon); + Delete(jnidesc_canon); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, "No or improper directorin 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; + } + + /* Get the JNI field descriptor for this return type, add the JNI field descriptor + to jniret_desc */ + if ((c_ret_type = Swig_typemap_lookup("jni", n, "", 0))) { + Parm *tp = NewParmNode(c_ret_type, n); + + 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); + } + + String *jdesc = NULL; + if (Swig_typemap_lookup("directorin", tp, "", 0) + && (jdesc = Getattr(tp, "tmap:directorin:descriptor"))) { + + // Objects marshalled passing a Java class across JNI boundary use jobject - the nouse flag indicates this + // We need the specific Java class name instead of the generic 'Ljava/lang/Object;' + if (GetFlag(tp, "tmap:directorin:nouse")) + jdesc = cdesc; + String *jnidesc_canon = canonicalizeJNIDescriptor(jdesc, tp); + Append(jniret_desc, jnidesc_canon); + Delete(jnidesc_canon); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_ret_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(adjustedreturntypeparm); + + Swig_director_parms_fixup(l); + + /* Attach the standard typemaps */ + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("jni", l, 0); + Swig_typemap_attach_parms("jtype", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("javadirectorin", l, 0); + Swig_typemap_attach_parms("directorargout", l, w); + + if (!ignored_method) { + /* Add Java environment pointer to wrapper */ + String *jenvstr = NewString("jenv"); + String *jobjstr = NewString("swigjobj"); + + Wrapper_add_localv(w, "swigjnienv", "JNIEnvWrapper", "swigjnienv(this)", NIL, NIL); + Wrapper_add_localv(w, jenvstr, "JNIEnv *", jenvstr, "= swigjnienv.getJNIEnv()", NIL); + Wrapper_add_localv(w, jobjstr, "jobject", jobjstr, "= (jobject) NULL", NIL); + Delete(jenvstr); + Delete(jobjstr); + + /* Preamble code */ + Printf(w->code, "if (!swig_override[%d]) {\n", classmeth_off); + } + + 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_JavaThrowException(JNIEnvWrapper(this).getJNIEnv(), SWIG_JavaDirectorPureVirtual, "); + Printf(w->code, "\"Attempted to invoke pure virtual method %s::%s.\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + + /* Make sure that we return something in the case of a pure + * virtual method call for syntactical reasons. */ + 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, "}\n"); + Printf(w->code, "swigjobj = swig_get_self(jenv);\n"); + Printf(w->code, "if (swigjobj && jenv->IsSameObject(swigjobj, NULL) == JNI_FALSE) {\n"); + } + + /* Start the Java field descriptor for the intermediate class's upcall (insert jself object) */ + Parm *tp = NewParmNode(c_classname, n); + String *jdesc; + + if ((tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (jdesc = Getattr(tp, "tmap:directorin:descriptor"))) { + String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); + Append(jnidesc, jni_canon); + Delete(jni_canon); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap for type %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + + /* Go through argument list, convert from native to Java */ + 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 various typemap's 'throws' clauses */ + addThrows(n, "tmap:directorin", p); + addThrows(n, "tmap:out", p); + + /* And add to the upcall args */ + Printf(jupcall_args, ", %s", arg); + + /* Get parameter's intermediary C type */ + if ((c_param_type = Getattr(p, "tmap:jni"))) { + Parm *tp = NewParm(c_param_type, Getattr(p, "name"), n); + String *desc_tm = NULL, *jdesc = NULL, *cdesc = NULL; + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + if (!ignored_method) + Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + + /* Add input marshalling code and update JNI field descriptor */ + if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (jdesc = Getattr(tp, "tmap:directorin:descriptor")) + && (tm = Getattr(p, "tmap:directorin")) + && (cdesc = Getattr(p, "tmap:directorin:descriptor"))) { + + // Objects marshalled by passing a Java class across the JNI boundary use jobject as the JNI type - + // the nouse flag indicates this. We need the specific Java class name instead of the generic 'Ljava/lang/Object;' + if (GetFlag(tp, "tmap:directorin:nouse")) + jdesc = cdesc; + String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); + Append(jnidesc, jni_canon); + Delete(jni_canon); + + 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 to the intermediate class code if generating the + * intermediate's upcall code */ + if ((tm = Getattr(p, "tmap:jtype"))) { + String *din = Copy(Getattr(p, "tmap:javadirectorin")); + addThrows(n, "tmap:javadirectorin", p); + + if (din) { + Replaceall(din, "$module", module_class_name); + Replaceall(din, "$imclassname", imclass_name); + substituteClassname(pt, din); + Replaceall(din, "$jniinput", ln); + + if (i > 0) + Printf(imcall_args, ", "); + Printf(callback_def, ", %s %s", tm, ln); + + if (Cmp(din, ln)) { + Printv(imcall_args, din, NIL); + } else + Printv(imcall_args, ln, NIL); + + jni_canon = canonicalizeJNIDescriptor(cdesc, p); + Append(classdesc, jni_canon); + Delete(jni_canon); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, "No javadirectorin 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_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype 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"); + + Delete(desc_tm); + } else { + if (!desc_tm) { + Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } else if (!jdesc) { + Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC, input_file, line_number, + "Missing JNI descriptor in directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = Getattr(p, "tmap:directorin:next"); + } else if (!tm) { + Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_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); + } else if (!cdesc) { + Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC, input_file, line_number, + "Missing JNI descriptor in directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = Getattr(p, "tmap:directorin:next"); + } + + output_director = false; + } + + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni 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(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 + // Get any Java exception classes in the throws typemap + ParmList *throw_parm_list = NULL; + + // May need to add Java throws clause to director methods if %catches defined + // Get any Java exception classes in the throws typemap + ParmList *catches_list = Getattr(n, "catchlist"); + if (catches_list) { + Swig_typemap_attach_parms("throws", catches_list, 0); + Swig_typemap_attach_parms("directorthrows", catches_list, 0); + for (p = catches_list; p; p = nextSibling(p)) { + addThrows(n, "tmap:throws", p); + } + } + + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + 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); + Swig_typemap_attach_parms("directorthrows", throw_parm_list, 0); + } + for (p = throw_parm_list; p; p = nextSibling(p)) { + if (Getattr(p, "tmap:throws")) { + // %catches replaces the specified exception specification + if (!catches_list) { + addThrows(n, "tmap:throws", p); + } + + 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"); + + /* Emit the intermediate class's upcall to the actual class */ + + String *upcall = NewStringf("jself.%s(%s)", symname, imcall_args); + + // Handle exception classes specified in the "except" feature's "throws" attribute + addThrows(n, "feature:except", n); + + if (!is_void) { + if ((tm = Swig_typemap_lookup("javadirectorout", n, "", 0))) { + addThrows(n, "tmap:javadirectorout", n); + substituteClassname(returntype, tm); + Replaceall(tm, "$javacall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + if ((tm = Swig_typemap_lookup("out", n, "", 0))) + addThrows(n, "tmap:out", n); + + Delete(tm); + } else + Printf(callback_code, " %s;\n", upcall); + + Printf(callback_code, " }\n"); + Delete(upcall); + + /* Finish off the inherited upcall's definition */ + Putc(')', callback_def); + generateThrowsClause(n, callback_def); + Printf(callback_def, " {\n"); + + if (!ignored_method) { + /* Emit the actual upcall through */ + String *imclass_desc = NewStringf("(%s)%s", jnidesc, jniret_desc); + String *class_desc = NewStringf("(%s)%s", classdesc, classret_desc); + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, imclass_desc, class_desc, decl); + String *methid = Getattr(udata, "imclass_methodidx"); + String *methop = getUpcallJNIMethod(jniret_desc); + + if (!is_void) + Printf(w->code, "jresult = (%s) ", c_ret_type); + + Printf(w->code, "jenv->%s(Swig::jclass_%s, Swig::director_method_ids[%s], %s);\n", methop, imclass_name, methid, jupcall_args); + + // Generate code to handle any Java exception thrown by director delegation + directorExceptHandler(n, catches_list ? catches_list : throw_parm_list, w); + + 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))) { + addThrows(n, "tmap:directorout", n); + 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"))) { + addThrows(n, "tmap:directorargout", p); + Replaceall(tm, "$result", makeParameterName(n, p, i, false)); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(imclass_desc); + Delete(class_desc); + + /* Terminate wrapper code */ + Printf(w->code, "} else {\n"); + Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, \"null upcall object in %s::%s \");\n", + SwigType_namestr(c_classname), SwigType_namestr(name)); + Printf(w->code, "}\n"); + + Printf(w->code, "if (swigjobj) jenv->DeleteLocalRef(swigjobj);\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 (!GetFlag(n, "feature:ignore")) + Printv(imclass_directors, 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); + } + } + + Delete(inline_extra_method); + Delete(qualified_return); + Delete(jnidesc); + Delete(c_ret_type); + Delete(jniret_desc); + Delete(declaration); + Delete(callback_def); + Delete(callback_code); + DelWrapper(w); + + return status; + } + + /* ------------------------------------------------------------ + * directorExceptHandler() + * + * Emit code to map Java exceptions back to C++ exceptions when + * feature("director:except") is applied to a method node. + * This is generated after the Java method upcall. + * ------------------------------------------------------------ */ + + void directorExceptHandler(Node *n, ParmList *throw_parm_list, Wrapper *w) { + + String *directorexcept = Getattr(n, "feature:director:except"); + if (!directorexcept) { + directorexcept = NewString(""); + Printf(directorexcept, "jthrowable $error = jenv->ExceptionOccurred();\n"); + Printf(directorexcept, "if ($error) {"); + Printf(directorexcept, "$directorthrowshandlers\n"); + Printf(directorexcept, " Swig::DirectorException::raise(jenv, $error);\n"); + Printf(directorexcept, "}\n"); + } else { + directorexcept = Copy(directorexcept); + } + + // Can explicitly disable director:except by setting to "" or "0" + if (Len(directorexcept) > 0 && Cmp(directorexcept, "0") != 0) { + + // Replace $packagepath + substitutePackagePath(directorexcept, 0); + + // Replace $directorthrowshandlers with any defined typemap handlers (or nothing) + if (Strstr(directorexcept, "$directorthrowshandlers")) { + String *directorthrowshandlers_code = NewString(""); + + for (Parm *p = throw_parm_list; p; p = nextSibling(p)) { + String *tm = Getattr(p, "tmap:directorthrows"); + + if (tm) { + // replace $packagepath/$javaclassname + String *directorthrows = canonicalizeJNIDescriptor(tm, p); + Printv(directorthrowshandlers_code, directorthrows, NIL); + Delete(directorthrows); + } else { + String *t = Getattr(p,"type"); + Swig_warning(WARN_TYPEMAP_DIRECTORTHROWS_UNDEF, Getfile(n), Getline(n), "No directorthrows typemap defined for %s\n", SwigType_str(t, 0)); + } + } + Replaceall(directorexcept, "$directorthrowshandlers", directorthrowshandlers_code); + Delete(directorthrowshandlers_code); + } + + Replaceall(directorexcept, "$error", "swigerror"); + Printf(w->code, " %s\n", directorexcept); + } + Delete(directorexcept); + } + + /* ------------------------------------------------------------ + * directorPrefixArgs() + * ------------------------------------------------------------ */ + + void directorPrefixArgs(Node *n) { + Parm *p; + + /* Need to prepend 'jenv' to the director constructor's argument list */ + + String *jenv_type = NewString("JNIEnv"); + + SwigType_add_pointer(jenv_type); + + p = NewParm(jenv_type, NewString("jenv"), n); + Setattr(p, "arg:byname", "1"); + set_nextSibling(p, NULL); + + Setattr(n, "director:prefix_args", p); + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + 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); + } + } + + /* insert jenv prefix argument */ + parms = CopyParmList(superparms); + + String *jenv_type = NewString("JNIEnv"); + SwigType_add_pointer(jenv_type); + p = NewParm(jenv_type, NewString("jenv"), n); + set_nextSibling(p, parms); + parms = p; + + directorPrefixArgs(n); + + 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, "}\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(jenv_type); + Delete(parms); + Delete(dirclassname); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + String *dirClassName = directorClassName(n); + Wrapper *w = NewWrapper(); + + Printf(w->def, "%s::%s(JNIEnv *jenv) : %s {", dirClassName, dirClassName, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " %s(JNIEnv *jenv);\n", dirClassName); + DelWrapper(w); + Delete(classtype); + Delete(classname); + Delete(dirClassName); + directorPrefixArgs(n); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + directorDeclaration(n); + + Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); + Printf(f_directors_h, "\npublic:\n"); + Printf(f_directors_h, " void swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global);\n"); + + /* Keep track of the director methods for this class */ + first_class_dmethod = curr_class_dmethod = n_dmethods; + + return Language::classDirectorInit(n); + } + + /* ---------------------------------------------------------------------- + * classDirectorDestructor() + * ---------------------------------------------------------------------- */ + + int classDirectorDestructor(Node *n) { + Node *current_class = getCurrentClass(); + String *full_classname = Getattr(current_class, "name"); + String *classname = Swig_class_name(current_class); + 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); + } + + /* Ensure that correct directordisconnect typemap's method name is called + * here: */ + + Node *disconn_attr = NewHash(); + String *disconn_methodname = NULL; + + typemapLookup(n, "directordisconnect", full_classname, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); + + Printv(w->code, " swig_disconnect_director_self(\"", disconn_methodname, "\");\n", "}\n", NIL); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(disconn_attr); + Delete(classname); + Delete(dirClassName); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + String *full_classname = Getattr(n, "name"); + String *classname = getProxyName(full_classname, true); + String *director_classname = directorClassName(n); + String *internal_classname; + + Wrapper *w = NewWrapper(); + + if (Len(package_path) > 0) + internal_classname = NewStringf("%s/%s", package_path, classname); + else + internal_classname = NewStringf("%s", classname); + + // If the namespace is multiple levels, the result of getNSpace() will have inserted + // .'s to delimit namespaces, so we need to replace those with /'s + Replace(internal_classname, NSPACE_SEPARATOR, "/", DOH_REPLACE_ANY); + + Wrapper_add_localv(w, "baseclass", "static jclass baseclass", "= 0", NIL); + Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global) {", director_classname); + + if (first_class_dmethod != curr_class_dmethod) { + Printf(w->def, "static struct {\n"); + Printf(w->def, "const char *mname;\n"); + Printf(w->def, "const char *mdesc;\n"); + Printf(w->def, "jmethodID base_methid;\n"); + Printf(w->def, "} methods[] = {\n"); + + for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + + Printf(w->def, "{ \"%s\", \"%s\", NULL }", Getattr(udata, "method"), Getattr(udata, "fdesc")); + if (i != curr_class_dmethod - 1) + Putc(',', w->def); + Putc('\n', w->def); + } + + Printf(w->def, "};\n"); + } + + Printf(w->code, "if (swig_set_self(jenv, jself, swig_mem_own, weak_global)) {\n"); + Printf(w->code, "if (!baseclass) {\n"); + Printf(w->code, "baseclass = jenv->FindClass(\"%s\");\n", internal_classname); + Printf(w->code, "if (!baseclass) return;\n"); + Printf(w->code, "baseclass = (jclass) jenv->NewGlobalRef(baseclass);\n"); + Printf(w->code, "}\n"); + + int n_methods = curr_class_dmethod - first_class_dmethod; + + if (n_methods) { + /* Emit the swig_overrides() method and the swig_override array */ + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_overrides(int n) {\n"); + Printf(f_directors_h, " return (n < %d ? swig_override[n] : false);\n", n_methods); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, "protected:\n"); + Printf(f_directors_h, " Swig::BoolArray<%d> swig_override;\n", n_methods); + + /* Emit the code to look up the class's methods, initialize the override array */ + + Printf(w->code, "bool derived = (jenv->IsSameObject(baseclass, jcls) ? false : true);\n"); + Printf(w->code, "for (int i = 0; i < %d; ++i) {\n", n_methods); + Printf(w->code, " if (!methods[i].base_methid) {\n"); + Printf(w->code, " methods[i].base_methid = jenv->GetMethodID(baseclass, methods[i].mname, methods[i].mdesc);\n"); + Printf(w->code, " if (!methods[i].base_methid) return;\n"); + Printf(w->code, " }\n"); + // Generally, derived classes have a mix of overridden and + // non-overridden methods and it is worth making a GetMethodID + // check during initialization to determine if each method is + // overridden, thus avoiding unnecessary calls into Java. + // + // On the other hand, when derived classes are + // expected to override all director methods then the + // GetMethodID calls are inefficient, and it is better to let + // the director unconditionally call up into Java. The resulting code + // will still behave correctly (though less efficiently) when Java + // code doesn't override a given method. + // + // The assumeoverride feature on a director controls whether or not + // overrides are assumed. + if (GetFlag(n, "feature:director:assumeoverride")) { + Printf(w->code, " swig_override[i] = derived;\n"); + } else { + Printf(w->code, " swig_override[i] = false;\n"); + Printf(w->code, " if (derived) {\n"); + Printf(w->code, " jmethodID methid = jenv->GetMethodID(jcls, methods[i].mname, methods[i].mdesc);\n"); + Printf(w->code, " swig_override[i] = (methid != methods[i].base_methid);\n"); + Printf(w->code, " jenv->ExceptionClear();\n"); + Printf(w->code, " }\n"); + } + Printf(w->code, "}\n"); + } else { + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_overrides(int n) {\n"); + Printf(f_directors_h, " return false;\n"); + Printf(f_directors_h, " }\n"); + } + + Printf(f_directors_h, "};\n\n"); + Printf(w->code, "}\n"); + Printf(w->code, "}\n"); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(internal_classname); + + return Language::classDirectorEnd(n); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + *--------------------------------------------------------------------*/ + + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * directorDeclaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void directorDeclaration(Node *n) { + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director(jenv)"); + + String *directorname = directorClassName(n); + String *declaration = Swig_class_declaration(n, directorname); + + Printf(declaration, " : public %s, public Swig::Director", base); + + // Stash stuff for later. + Setattr(n, "director:decl", declaration); + Setattr(n, "director:ctor", class_ctor); + } + + /*---------------------------------------------------------------------- + * nestedClassesSupport() + *--------------------------------------------------------------------*/ + + NestedClassSupport nestedClassesSupport() const { + return NCS_Full; + } +}; /* class JAVA */ + +/* ----------------------------------------------------------------------------- + * swig_java() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_java() { + return new JAVA(); +} +extern "C" Language *swig_java(void) { + return new_swig_java(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *JAVA::usage = "\ +Java Options (available with -java)\n\ + -doxygen - Convert C++ doxygen comments to JavaDoc comments in proxy classes\n\ + -debug-doxygen-parser - Display doxygen parser module debugging information\n\ + -debug-doxygen-translator - Display doxygen translator module debugging information\n\ + -nopgcpp - Suppress premature garbage collection prevention parameter\n\ + -noproxy - Generate the low-level functional interface instead\n\ + of proxy classes\n\ + -oldvarnames - Old intermediary method names for variable wrappers\n\ + -package <name> - Set name of the Java package to <name>\n\ +\n"; diff --git a/contrib/tools/swig/Source/Modules/javascript.cxx b/contrib/tools/swig/Source/Modules/javascript.cxx new file mode 100644 index 00000000000..d2b33b1b429 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/javascript.cxx @@ -0,0 +1,2489 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * javascript.cxx + * + * Javascript language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +/** + * Enables extra debugging information in typemaps. + */ +static bool js_template_enable_debug = false; + +#define ERR_MSG_ONLY_ONE_ENGINE_PLEASE "Only one engine can be specified at a time." + +// keywords used for state variables +#define NAME "name" +#define NAME_MANGLED "name_mangled" +#define TYPE "type" +#define TYPE_MANGLED "type_mangled" +#define WRAPPER_NAME "wrapper" +#define IS_IMMUTABLE "is_immutable" +#define IS_STATIC "is_static" +#define IS_ABSTRACT "is_abstract" +#define GETTER "getter" +#define SETTER "setter" +#define PARENT "parent" +#define PARENT_MANGLED "parent_mangled" +#define CTOR "ctor" +#define CTOR_WRAPPERS "ctor_wrappers" +#define CTOR_DISPATCHERS "ctor_dispatchers" +#define DTOR "dtor" +#define ARGCOUNT "wrap:argc" +#define HAS_TEMPLATES "has_templates" +#define FORCE_CPP "force_cpp" +#define RESET true + +// keys for global state variables +#define CREATE_NAMESPACES "create_namespaces" +#define REGISTER_NAMESPACES "register_namespaces" +#define INITIALIZER "initializer" + +// keys for class scoped state variables +#define MEMBER_VARIABLES "member_variables" +#define MEMBER_FUNCTIONS "member_functions" +#define STATIC_FUNCTIONS "static_functions" +#define STATIC_VARIABLES "static_variables" + + +/** + * A convenience class to manage state variables for emitters. + * The implementation delegates to SWIG Hash DOHs and provides + * named sub-hashes for class, variable, and function states. + */ +class JSEmitterState { + +public: + JSEmitterState(); + ~JSEmitterState(); + DOH *globals(); + DOH *globals(const char *key, DOH *initial = 0); + DOH *clazz(bool reset = false); + DOH *clazz(const char *key, DOH *initial = 0); + DOH *function(bool reset = false); + DOH *function(const char *key, DOH *initial = 0); + DOH *variable(bool reset = false); + DOH *variable(const char *key, DOH *initial = 0); + static int IsSet(DOH *val); + +private: + DOH *getState(const char *key, bool reset = false); + Hash *globalHash; +}; + +/** + * A convenience class that wraps a code snippet used as template + * for code generation. + */ +class Template { + +public: + Template(const String *code); + Template(const String *code, const String *templateName); + Template(const Template & other); + ~Template(); + String *str(); + Template & replace(const String *pattern, const String *repl); + Template & print(DOH *doh); + Template & pretty_print(DOH *doh); + void operator=(const Template & t); + Template & trim(); + +private: + String *code; + String *templateName; +}; + +/** + * JSEmitter represents an abstraction of javascript code generators + * for different javascript engines. + **/ +class JSEmitter { + +protected: + + typedef JSEmitterState State; + + enum MarshallingMode { + Setter, + Getter, + Ctor, + Function + }; + +public: + + enum JSEngine { + JavascriptCore, + V8, + NodeJS + }; + + JSEmitter(JSEngine engine); + + virtual ~ JSEmitter(); + + /** + * Opens output files and temporary output DOHs. + */ + virtual int initialize(Node *n); + + /** + * Writes all collected code into the output file(s). + */ + virtual int dump(Node *n) = 0; + + /** + * Cleans up all open output DOHs. + */ + virtual int close() = 0; + + /** + * Switches the context for code generation. + * + * Classes, global variables and global functions may need to + * be registered in certain static tables. + * This method should be used to switch output DOHs correspondingly. + */ + virtual int switchNamespace(Node *); + + /** + * Invoked at the beginning of the classHandler. + */ + virtual int enterClass(Node *); + + /** + * Invoked at the end of the classHandler. + */ + virtual int exitClass(Node *) { + return SWIG_OK; + }; + + /** + * Invoked at the beginning of the variableHandler. + */ + virtual int enterVariable(Node *); + + /** + * Invoked at the end of the variableHandler. + */ + virtual int exitVariable(Node *) { + return SWIG_OK; + }; + + /** + * Invoked at the beginning of the functionHandler. + */ + virtual int enterFunction(Node *); + + /** + * Invoked at the end of the functionHandler. + */ + virtual int exitFunction(Node *) { + return SWIG_OK; + }; + + /** + * Invoked by functionWrapper callback after call to Language::functionWrapper. + */ + virtual int emitWrapperFunction(Node *n); + + /** + * Invoked by nativeWrapper callback + */ + virtual int emitNativeFunction(Node *n); + + /** + * Invoked from constantWrapper after call to Language::constantWrapper. + **/ + virtual int emitConstant(Node *n); + + /** + * Registers a given code snippet for a given key name. + * + * This method is called by the fragmentDirective handler + * of the JAVASCRIPT language module. + **/ + int registerTemplate(const String *name, const String *code); + + /** + * Retrieve the code template registered for a given name. + */ + Template getTemplate(const String *name); + + State & getState(); + +protected: + + /** + * Generates code for a constructor function. + */ + virtual int emitCtor(Node *n); + + /** + * Generates code for a destructor function. + */ + virtual int emitDtor(Node *n); + + /** + * Generates code for a function. + */ + virtual int emitFunction(Node *n, bool is_member, bool is_static); + + virtual int emitFunctionDispatcher(Node *n, bool /*is_member */ ); + + /** + * Generates code for a getter function. + */ + virtual int emitGetter(Node *n, bool is_member, bool is_static); + + /** + * Generates code for a setter function. + */ + virtual int emitSetter(Node *n, bool is_member, bool is_static); + + virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) = 0; + + virtual String *emitInputTypemap(Node *n, Parm *params, Wrapper *wrapper, String *arg); + + virtual void marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult = 0, bool emitReturnVariable = true); + + virtual void emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params); + + /** + * Helper function to retrieve the first parent class node. + */ + Node *getBaseClass(Node *n); + + Parm *skipIgnoredArgs(Parm *p); + + virtual int createNamespace(String *scope); + + virtual Hash *createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled); + + virtual int emitNamespaces() = 0; + + +protected: + + JSEngine engine; + Hash *templates; + State state; + + // contains context specific data (DOHs) + // to allow generation of namespace related code + // which are switched on namespace change + Hash *namespaces; + Hash *current_namespace; + String *defaultResultName; + File *f_wrappers; +}; + +/* factory methods for concrete JSEmitters: */ + +JSEmitter *swig_javascript_create_JSCEmitter(); +JSEmitter *swig_javascript_create_V8Emitter(); +JSEmitter *swig_javascript_create_NodeJSEmitter(); + +/********************************************************************** + * JAVASCRIPT: SWIG module implementation + **********************************************************************/ + +class JAVASCRIPT:public Language { + +public: + + JAVASCRIPT():emitter(NULL) { + } + ~JAVASCRIPT() { + delete emitter; + } + + virtual int functionHandler(Node *n); + virtual int globalfunctionHandler(Node *n); + virtual int variableHandler(Node *n); + virtual int globalvariableHandler(Node *n); + virtual int staticmemberfunctionHandler(Node *n); + virtual int classHandler(Node *n); + virtual int functionWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int nativeWrapper(Node *n); + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + + /** + * Registers all %fragments assigned to section "templates". + **/ + virtual int fragmentDirective(Node *n); + +public: + + virtual String *getNSpace() const; + +private: + + JSEmitter *emitter; +}; + +/* --------------------------------------------------------------------- + * functionWrapper() + * + * Low level code generator for functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::functionWrapper(Node *n) { + + // note: the default implementation only prints a message + // Language::functionWrapper(n); + emitter->emitWrapperFunction(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * functionHandler() + * + * Function handler for generating wrappers for functions + * --------------------------------------------------------------------- */ +int JAVASCRIPT::functionHandler(Node *n) { + + if (GetFlag(n, "isextension") == 1) { + SetFlag(n, "ismember"); + } + + emitter->enterFunction(n); + Language::functionHandler(n); + emitter->exitFunction(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * globalfunctionHandler() + * + * Function handler for generating wrappers for functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::globalfunctionHandler(Node *n) { + emitter->switchNamespace(n); + Language::globalfunctionHandler(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Function handler for generating wrappers for static member functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::staticmemberfunctionHandler(Node *n) { + /* + * Note: storage=static is removed by Language::staticmemberfunctionHandler. + * So, don't rely on that after here. Instead use the state variable which is + * set by JSEmitter::enterFunction(). + */ + Language::staticmemberfunctionHandler(n); + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * variableHandler() + * + * Function handler for generating wrappers for variables + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::variableHandler(Node *n) { + + emitter->enterVariable(n); + Language::variableHandler(n); + emitter->exitVariable(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * globalvariableHandler() + * + * Function handler for generating wrappers for global variables + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::globalvariableHandler(Node *n) { + emitter->switchNamespace(n); + Language::globalvariableHandler(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * constantHandler() + * + * Function handler for generating wrappers for constants + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::constantWrapper(Node *n) { + emitter->switchNamespace(n); + + // Note: callbacks trigger this wrapper handler + // TODO: handle callback declarations + if (Equal(Getattr(n, "kind"), "function")) { + return SWIG_OK; + } + // TODO: the emitter for constants must be implemented in a cleaner way + // currently we treat it like a read-only variable + // however, there is a remaining bug with function pointer constants + // which could be fixed with a cleaner approach + emitter->emitConstant(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * nativeWrapper() + * + * Function wrapper for generating placeholders for native functions + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::nativeWrapper(Node *n) { + emitter->emitNativeFunction(n); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * classHandler() + * + * Function handler for generating wrappers for class + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::classHandler(Node *n) { + emitter->switchNamespace(n); + + emitter->enterClass(n); + Language::classHandler(n); + emitter->exitClass(n); + + return SWIG_OK; +} + +int JAVASCRIPT::fragmentDirective(Node *n) { + + // catch all fragment directives that have "templates" as location + // and register them at the emitter. + String *section = Getattr(n, "section"); + + if (Equal(section, "templates") && !ImportMode) { + emitter->registerTemplate(Getattr(n, "value"), Getattr(n, "code")); + } else { + return Language::fragmentDirective(n); + } + + return SWIG_OK; +} + +String *JAVASCRIPT::getNSpace() const { + return Language::getNSpace(); +} + +/* --------------------------------------------------------------------- + * top() + * + * Function handler for processing top node of the parse tree + * Wrapper code generation essentially starts from here + * --------------------------------------------------------------------- */ + +int JAVASCRIPT::top(Node *n) { + emitter->initialize(n); + + Language::top(n); + + emitter->dump(n); + emitter->close(); + + return SWIG_OK; +} + +static const char *usage = (char *) "\ +Javascript Options (available with -javascript)\n\ + -jsc - creates a JavascriptCore extension \n\ + -v8 - creates a v8 extension \n\ + -node - creates a node.js extension \n\ + -debug-codetemplates - generates information about the origin of code templates\n"; + + +/* --------------------------------------------------------------------- + * main() + * + * Entry point for the JAVASCRIPT module + * --------------------------------------------------------------------- */ + +void JAVASCRIPT::main(int argc, char *argv[]) { + // Set javascript subdirectory in SWIG library + SWIG_library_directory("javascript"); + + int engine = -1; + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-v8") == 0) { + if (engine != -1) { + Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE); + SWIG_exit(-1); + } + Swig_mark_arg(i); + engine = JSEmitter::V8; + } else if (strcmp(argv[i], "-jsc") == 0) { + if (engine != -1) { + Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE); + SWIG_exit(-1); + } + Swig_mark_arg(i); + engine = JSEmitter::JavascriptCore; + } else if (strcmp(argv[i], "-node") == 0) { + if (engine != -1) { + Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE); + SWIG_exit(-1); + } + Swig_mark_arg(i); + engine = JSEmitter::NodeJS; + } else if (strcmp(argv[i], "-debug-codetemplates") == 0) { + Swig_mark_arg(i); + js_template_enable_debug = true; + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + return; + } + } + } + + switch (engine) { + case JSEmitter::V8: + { + emitter = swig_javascript_create_V8Emitter(); + Preprocessor_define("SWIG_JAVASCRIPT_V8 1", 0); + SWIG_library_directory("javascript/v8"); + // V8 API is C++, so output must be C++ compatible even when wrapping C code + if (!cparse_cplusplus) { + Swig_cparse_cplusplusout(1); + } + break; + } + case JSEmitter::JavascriptCore: + { + emitter = swig_javascript_create_JSCEmitter(); + Preprocessor_define("SWIG_JAVASCRIPT_JSC 1", 0); + SWIG_library_directory("javascript/jsc"); + break; + } + case JSEmitter::NodeJS: + { + emitter = swig_javascript_create_V8Emitter(); + Preprocessor_define("SWIG_JAVASCRIPT_V8 1", 0); + Preprocessor_define("BUILDING_NODE_EXTENSION 1", 0); + SWIG_library_directory("javascript/v8"); + break; + } + default: + { + Printf(stderr, "SWIG Javascript: Unknown engine. Please specify one of '-jsc', '-v8' or '-node'.\n"); + SWIG_exit(-1); + break; + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGJAVASCRIPT 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("javascript"); + + // Set configuration file + SWIG_config_file("javascript.swg"); + + allow_overloading(); +} + +/* ----------------------------------------------------------------------------- + * swig_javascript() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_javascript() { + return new JAVASCRIPT(); +} + +extern "C" Language *swig_javascript(void) { + return new_swig_javascript(); +} + +/********************************************************************** + * Emitter implementations + **********************************************************************/ + +/* ----------------------------------------------------------------------------- + * JSEmitter() + * ----------------------------------------------------------------------------- */ + +JSEmitter::JSEmitter(JSEmitter::JSEngine engine) +: engine(engine), templates(NewHash()), namespaces(NULL), current_namespace(NULL), defaultResultName(NewString("result")), f_wrappers(NULL) { +} + +/* ----------------------------------------------------------------------------- + * ~JSEmitter() + * ----------------------------------------------------------------------------- */ + +JSEmitter::~JSEmitter() { + Delete(templates); +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::RegisterTemplate() : Registers a code template + * + * Note: this is used only by JAVASCRIPT::fragmentDirective(). + * ----------------------------------------------------------------------------- */ + +int JSEmitter::registerTemplate(const String *name, const String *code) { + if (!State::IsSet(state.globals(HAS_TEMPLATES))) { + SetFlag(state.globals(), HAS_TEMPLATES); + } + return Setattr(templates, name, code); +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::getTemplate() : Provides a registered code template + * ----------------------------------------------------------------------------- */ + +Template JSEmitter::getTemplate(const String *name) { + String *templ = Getattr(templates, name); + + if (!templ) { + Printf(stderr, "Could not find template %s\n.", name); + SWIG_exit(EXIT_FAILURE); + } + + Template t(templ, name); + return t; +} + +JSEmitterState & JSEmitter::getState() { + return state; +} + +int JSEmitter::initialize(Node * /*n */ ) { + + if (namespaces != NULL) { + Delete(namespaces); + } + namespaces = NewHash(); + Hash *global_namespace = createNamespaceEntry("exports", 0, 0); + + Setattr(namespaces, "::", global_namespace); + current_namespace = global_namespace; + + f_wrappers = NewString(""); + + return SWIG_OK; +} + +/* --------------------------------------------------------------------- + * skipIgnoredArgs() + * --------------------------------------------------------------------- */ + +Parm *JSEmitter::skipIgnoredArgs(Parm *p) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + return p; +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::getBaseClass() : the node of the base class or NULL + * + * Note: the first base class is provided. Multiple inheritance is not + * supported. + * ----------------------------------------------------------------------------- */ + +Node *JSEmitter::getBaseClass(Node *n) { + // retrieve the first base class that is not %ignored + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + return base.item; + } + return NULL; +} + + /* ----------------------------------------------------------------------------- + * JSEmitter::emitWrapperFunction() : dispatches emitter functions. + * + * This allows to have small sized, dedicated emitting functions. + * All state dependent branching is done here. + * ----------------------------------------------------------------------------- */ + +int JSEmitter::emitWrapperFunction(Node *n) { + int ret = SWIG_OK; + + String *kind = Getattr(n, "kind"); + + if (kind) { + + if (Equal(kind, "function") + // HACK: sneaky.ctest revealed that typedef'd (global) functions must be + // detected via the 'view' attribute. + || (Equal(kind, "variable") && Equal(Getattr(n, "view"), "globalfunctionHandler")) + ) { + bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0; + bool is_static = GetFlag(state.function(), IS_STATIC) != 0; + ret = emitFunction(n, is_member, is_static); + } else if (Cmp(kind, "variable") == 0) { + bool is_static = GetFlag(state.variable(), IS_STATIC) != 0; + // HACK: smartpointeraccessed static variables are not treated as statics + if (GetFlag(n, "allocate:smartpointeraccess")) { + is_static = false; + } + + bool is_member = GetFlag(n, "ismember") != 0; + bool is_setter = GetFlag(n, "memberset") != 0 || GetFlag(n, "varset") != 0; + bool is_getter = GetFlag(n, "memberget") != 0 || GetFlag(n, "varget") != 0; + if (is_setter) { + ret = emitSetter(n, is_member, is_static); + } else if (is_getter) { + ret = emitGetter(n, is_member, is_static); + } else { + Swig_print_node(n); + } + + } else { + Printf(stderr, "Warning: unsupported wrapper function type\n"); + Swig_print_node(n); + ret = SWIG_ERROR; + } + } else { + String *view = Getattr(n, "view"); + + if (Cmp(view, "constructorHandler") == 0) { + ret = emitCtor(n); + } else if (Cmp(view, "destructorHandler") == 0) { + ret = emitDtor(n); + } else { + Printf(stderr, "Warning: unsupported wrapper function type"); + Swig_print_node(n); + ret = SWIG_ERROR; + } + } + + return ret; +} + +int JSEmitter::emitNativeFunction(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + enterFunction(n); + state.function(WRAPPER_NAME, wrapname); + exitFunction(n); + return SWIG_OK; +} + +int JSEmitter::enterClass(Node *n) { + state.clazz(RESET); + state.clazz(NAME, Getattr(n, "sym:name")); + state.clazz("nspace", current_namespace); + + // Creating a mangled name using the current namespace and the symbol name + String *mangled_name = NewString(""); + Printf(mangled_name, "%s_%s", Getattr(current_namespace, NAME_MANGLED), Getattr(n, "sym:name")); + state.clazz(NAME_MANGLED, SwigType_manglestr(mangled_name)); + Delete(mangled_name); + + state.clazz(TYPE, NewString(Getattr(n, "classtype"))); + + String *type = SwigType_manglestr(Getattr(n, "classtypeobj")); + String *classtype_mangled = NewString(""); + Printf(classtype_mangled, "p%s", type); + state.clazz(TYPE_MANGLED, classtype_mangled); + Delete(type); + + String *ctor_wrapper = NewString("_wrap_new_veto_"); + Append(ctor_wrapper, state.clazz(NAME)); + state.clazz(CTOR, ctor_wrapper); + state.clazz(CTOR_DISPATCHERS, NewString("")); + state.clazz(DTOR, NewString("0")); + + // HACK: assume that a class is abstract + // this is resolved by emitCtor (which is only called for non abstract classes) + SetFlag(state.clazz(), IS_ABSTRACT); + + return SWIG_OK; +} + +int JSEmitter::enterFunction(Node *n) { + state.function(RESET); + state.function(NAME, Getattr(n, "sym:name")); + if (Equal(Getattr(n, "storage"), "static")) { + SetFlag(state.function(), IS_STATIC); + } + return SWIG_OK; +} + +int JSEmitter::enterVariable(Node *n) { + // reset the state information for variables. + state.variable(RESET); + + // Retrieve a pure symbol name. Using 'sym:name' as a basis, as it considers %renamings. + if (Equal(Getattr(n, "view"), "memberconstantHandler")) { + // Note: this is kind of hacky/experimental + // For constants/enums 'sym:name' contains e.g., 'Foo_Hello' instead of 'Hello' + state.variable(NAME, Getattr(n, "memberconstantHandler:sym:name")); + } else { + state.variable(NAME, Swig_scopename_last(Getattr(n, "sym:name"))); + } + + if (Equal(Getattr(n, "storage"), "static")) { + SetFlag(state.variable(), IS_STATIC); + } + + if (!Language::instance()->is_assignable(n)) { + SetFlag(state.variable(), IS_IMMUTABLE); + } + // FIXME: test "arrays_global" does not compile with that as it is not allowed to assign to char[] + if (Equal(Getattr(n, "type"), "a().char")) { + SetFlag(state.variable(), IS_IMMUTABLE); + } + + return SWIG_OK; +} + +int JSEmitter::emitCtor(Node *n) { + + Wrapper *wrapper = NewWrapper(); + + bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + + Template t_ctor(getTemplate("js_ctor")); + + String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + if (is_overloaded) { + t_ctor = getTemplate("js_overloaded_ctor"); + Append(wrap_name, Getattr(n, "sym:overname")); + } + Setattr(n, "wrap:name", wrap_name); + // note: we can remove the is_abstract flag now, as this + // is called for non-abstract classes only. + Setattr(state.clazz(), IS_ABSTRACT, 0); + + ParmList *params = Getattr(n, "parms"); + emit_parameter_variables(params, wrapper); + emit_attach_parmmaps(params, wrapper); + // HACK: in test-case `ignore_parameter` emit_attach_parmmaps generated an extra line of applied typemaps. + // Deleting wrapper->code here, to reset, and as it seemed to have no side effect elsewhere + Delete(wrapper->code); + wrapper->code = NewString(""); + + Printf(wrapper->locals, "%sresult;", SwigType_str(Getattr(n, "type"), 0)); + + marshalInputArgs(n, params, wrapper, Ctor, true, false); + String *action = emit_action(n); + Printv(wrapper->code, action, "\n", 0); + + emitCleanupCode(n, wrapper, params); + + t_ctor.replace("$jswrapper", wrap_name) + .replace("$jsmangledtype", state.clazz(TYPE_MANGLED)) + .replace("$jslocals", wrapper->locals) + .replace("$jscode", wrapper->code) + .replace("$jsargcount", Getattr(n, ARGCOUNT)) + .pretty_print(f_wrappers); + + Template t_ctor_case(getTemplate("js_ctor_dispatch_case")); + t_ctor_case.replace("$jswrapper", wrap_name) + .replace("$jsargcount", Getattr(n, ARGCOUNT)); + Append(state.clazz(CTOR_DISPATCHERS), t_ctor_case.str()); + + DelWrapper(wrapper); + + // create a dispatching ctor + if (is_overloaded) { + if (!Getattr(n, "sym:nextSibling")) { + String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + Template t_mainctor(getTemplate("js_ctor_dispatcher")); + t_mainctor.replace("$jswrapper", wrap_name) + .replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsdispatchcases", state.clazz(CTOR_DISPATCHERS)) + .pretty_print(f_wrappers); + state.clazz(CTOR, wrap_name); + } + } else { + state.clazz(CTOR, wrap_name); + } + + return SWIG_OK; +} + +int JSEmitter::emitDtor(Node *n) { + + String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + + SwigType *type = state.clazz(TYPE); + String *p_classtype = SwigType_add_pointer(state.clazz(TYPE)); + String *ctype = SwigType_lstr(p_classtype, ""); + String *free = NewString(""); + + // (Taken from JSCore implementation.) + /* The if (Extend) block was taken from the Ruby implementation. + * The problem is that in the case of an %extend to create a destructor for a struct to coordinate automatic memory cleanup with the Javascript collector, + * the SWIG function was not being generated. More specifically: + struct MyData { + %extend { + ~MyData() { + FreeData($self); + } + } + }; + %newobject CreateData; + struct MyData* CreateData(void); + %delobject FreeData; + void FreeData(struct MyData* the_data); + + where the use case is something like: + var my_data = example.CreateData(); + my_data = null; + + This function was not being generated: + SWIGINTERN void delete_MyData(struct MyData *self){ + FreeData(self); + } + + I don't understand fully why it wasn't being generated. It just seems to happen in the Lua generator. + There is a comment about staticmemberfunctionHandler having an inconsistency and I tracked down dome of the SWIGINTERN void delete_* + code to that function in the Language base class. + The Ruby implementation seems to have an explicit check for if(Extend) and explicitly generates the code, so that's what I'm doing here. + The Ruby implementation does other stuff which I omit. + */ + if (Extend) { + String *wrap = Getattr(n, "wrap:code"); + if (wrap) { + Printv(f_wrappers, wrap, NIL); + } + } + // HACK: this is only for the v8 emitter. maybe set an attribute wrap:action of node + // TODO: generate dtors more similar to other wrappers + // EW: I think this is wrong. delete should only be used when new was used to create. If malloc was used, free needs to be used. + if (SwigType_isarray(type)) { + Printf(free, "delete [] (%s)", ctype); + } else { + Printf(free, "delete (%s)", ctype); + } + + String *destructor_action = Getattr(n, "wrap:action"); + // Adapted from the JSCore implementation. + /* The next challenge is to generate the correct finalize function for JavaScriptCore to call. + Originally, it would use this fragment from javascriptcode.swg + %fragment ("JS_destructordefn", "templates") + %{ + void _wrap_${classname_mangled}_finalize(JSObjectRef thisObject) + { + SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); + if(t && t->swigCMemOwn) free ((${type}*)t->swigCObject); + if(t) free(t); + } + %} + + But for the above example case of %extend to define a destructor on a struct, we need to override the system to not call + free ((${type}*)t->swigCObject); + and substitute it with what the user has provided. + To solve this, I created a variation fragment called JS_destructoroverridedefn: + SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); + if(t && t->swigCMemOwn) { + ${type}* arg1 = (${type}*)t->swigCObject; + ${destructor_action} + } + if(t) free(t); + + Based on what I saw in the Lua and Ruby modules, I use Getattr(n, "wrap:action") + to decide if the user has a preferred destructor action. + Based on that, I decide which fragment to use. + And in the case of the custom action, I substitute that action in. + I noticed that destructor_action has the form + delete_MyData(arg1); + The explicit arg1 is a little funny, so I structured the fragment to create a temporary variable called arg1 to make the generation easier. + This might suggest this solution misunderstands a more complex case. + + Also, there is a problem where destructor_action is always true for me, even when not requesting %extend as above. + So this code doesn't actually quite work as I expect. The end result is that the code still works because + destructor_action calls free like the original template. The one caveat is the string in destructor_action casts to char* which is weird. + I think there is a deeper underlying SWIG issue because I don't think it should be char*. However, it doesn't really matter for free. + + Maybe the fix for the destructor_action always true problem is that this is supposed to be embedded in the if(Extend) block above. + But I don't fully understand the conditions of any of these things, and since it works for the moment, I don't want to break more stuff. + */ + if (destructor_action) { + Template t_dtor = getTemplate("js_dtoroverride"); + state.clazz(DTOR, wrap_name); + t_dtor.replace("${classname_mangled}", state.clazz(NAME_MANGLED)) + .replace("$jswrapper", wrap_name) + .replace("$jsfree", free) + .replace("$jstype", ctype); + + t_dtor.replace("${destructor_action}", destructor_action); + Wrapper_pretty_print(t_dtor.str(), f_wrappers); + } else { + Template t_dtor = getTemplate("js_dtor"); + state.clazz(DTOR, wrap_name); + t_dtor.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jswrapper", wrap_name) + .replace("$jsfree", free) + .replace("$jstype", ctype) + .pretty_print(f_wrappers); + } + + Delete(p_classtype); + Delete(ctype); + Delete(free); + + return SWIG_OK; +} + +int JSEmitter::emitGetter(Node *n, bool is_member, bool is_static) { + Wrapper *wrapper = NewWrapper(); + Template t_getter(getTemplate("js_getter")); + + // prepare wrapper name + String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + Setattr(n, "wrap:name", wrap_name); + state.variable(GETTER, wrap_name); + + // prepare local variables + ParmList *params = Getattr(n, "parms"); + emit_parameter_variables(params, wrapper); + emit_attach_parmmaps(params, wrapper); + + // prepare code part + String *action = emit_action(n); + marshalInputArgs(n, params, wrapper, Getter, is_member, is_static); + marshalOutput(n, params, wrapper, action); + + emitCleanupCode(n, wrapper, params); + + t_getter.replace("$jswrapper", wrap_name) + .replace("$jslocals", wrapper->locals) + .replace("$jscode", wrapper->code) + .pretty_print(f_wrappers); + + DelWrapper(wrapper); + + return SWIG_OK; +} + +int JSEmitter::emitSetter(Node *n, bool is_member, bool is_static) { + + // skip variables that are immutable + if (State::IsSet(state.variable(IS_IMMUTABLE))) { + return SWIG_OK; + } + + Wrapper *wrapper = NewWrapper(); + + Template t_setter(getTemplate("js_setter")); + + // prepare wrapper name + String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + Setattr(n, "wrap:name", wrap_name); + state.variable(SETTER, wrap_name); + + // prepare local variables + ParmList *params = Getattr(n, "parms"); + emit_parameter_variables(params, wrapper); + emit_attach_parmmaps(params, wrapper); + + // prepare code part + String *action = emit_action(n); + marshalInputArgs(n, params, wrapper, Setter, is_member, is_static); + Append(wrapper->code, action); + + emitCleanupCode(n, wrapper, params); + + t_setter.replace("$jswrapper", wrap_name) + .replace("$jslocals", wrapper->locals) + .replace("$jscode", wrapper->code) + .pretty_print(f_wrappers); + + DelWrapper(wrapper); + + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * JSEmitter::emitConstant() : triggers code generation for constants + * ----------------------------------------------------------------------------- */ + +int JSEmitter::emitConstant(Node *n) { + // HACK: somehow it happened under Mac OS X that before everything started + // a lot of SWIG internal constants were emitted + // This didn't happen on other platforms yet... + // we ignore those premature definitions + if (!State::IsSet(state.globals(HAS_TEMPLATES))) { + return SWIG_ERROR; + } + + Wrapper *wrapper = NewWrapper(); + SwigType *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(name); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + + // HACK: forcing usage of cppvalue for v8 (which turned out to fix typdef_struct.i, et. al) + if (State::IsSet(state.globals(FORCE_CPP)) && Getattr(n, "cppvalue") != NULL) { + value = Getattr(n, "cppvalue"); + } + + Template t_getter(getTemplate("js_getter")); + + // call the variable methods as a constants are + // registered in same way + enterVariable(n); + state.variable(GETTER, wname); + // TODO: why do we need this? + Setattr(n, "wrap:name", wname); + + // special treatment of member pointers + if (SwigType_type(type) == T_MPOINTER) { + // TODO: this could go into a code-template + String *mpointer_wname = NewString(""); + Printf(mpointer_wname, "_wrapConstant_%s", iname); + Setattr(n, "memberpointer:constant:wrap:name", mpointer_wname); + String *str = SwigType_str(type, mpointer_wname); + Printf(f_wrappers, "static %s = %s;\n", str, value); + Delete(str); + value = mpointer_wname; + } + + marshalOutput(n, 0, wrapper, NewString(""), value, false); + + t_getter.replace("$jswrapper", wname) + .replace("$jslocals", wrapper->locals) + .replace("$jscode", wrapper->code) + .pretty_print(f_wrappers); + + exitVariable(n); + + DelWrapper(wrapper); + + return SWIG_OK; +} + +int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) { + Wrapper *wrapper = NewWrapper(); + Template t_function(getTemplate("js_function")); + + bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + + // prepare the function wrapper name + String *iname = Getattr(n, "sym:name"); + String *wrap_name = Swig_name_wrapper(iname); + if (is_overloaded) { + t_function = getTemplate("js_overloaded_function"); + Append(wrap_name, Getattr(n, "sym:overname")); + } + Setattr(n, "wrap:name", wrap_name); + state.function(WRAPPER_NAME, wrap_name); + + // prepare local variables + ParmList *params = Getattr(n, "parms"); + emit_parameter_variables(params, wrapper); + emit_attach_parmmaps(params, wrapper); + + // HACK: in test-case `ignore_parameter` emit_attach_parmmaps generates an extra line of applied typemap. + // Deleting wrapper->code here fixes the problem, and seems to have no side effect elsewhere + Delete(wrapper->code); + wrapper->code = NewString(""); + + marshalInputArgs(n, params, wrapper, Function, is_member, is_static); + String *action = emit_action(n); + marshalOutput(n, params, wrapper, action); + emitCleanupCode(n, wrapper, params); + Replaceall(wrapper->code, "$symname", iname); + + t_function.replace("$jswrapper", wrap_name) + .replace("$jslocals", wrapper->locals) + .replace("$jscode", wrapper->code) + .replace("$jsargcount", Getattr(n, ARGCOUNT)) + .pretty_print(f_wrappers); + + + DelWrapper(wrapper); + + return SWIG_OK; +} + +int JSEmitter::emitFunctionDispatcher(Node *n, bool /*is_member */ ) { + Wrapper *wrapper = NewWrapper(); + + // Generate call list, go to first node + Node *sibl = n; + + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + + do { + String *siblname = Getattr(sibl, "wrap:name"); + + if (siblname) { + // handle function overloading + Template t_dispatch_case = getTemplate("js_function_dispatch_case"); + t_dispatch_case.replace("$jswrapper", siblname) + .replace("$jsargcount", Getattr(sibl, ARGCOUNT)); + + Append(wrapper->code, t_dispatch_case.str()); + } + + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + + Template t_function(getTemplate("js_function_dispatcher")); + + // Note: this dispatcher function gets called after the last overloaded function has been created. + // At this time, n.wrap:name contains the name of the last wrapper function. + // To get a valid function name for the dispatcher function we take the last wrapper name and + // substract the extension "sym:overname", + String *wrap_name = NewString(Getattr(n, "wrap:name")); + String *overname = Getattr(n, "sym:overname"); + + Node *methodclass = Swig_methodclass(n); + String *class_name = Getattr(methodclass, "sym:name"); + + int l1 = Len(wrap_name); + int l2 = Len(overname); + Delslice(wrap_name, l1 - l2, l1); + + String *new_string = NewStringf("%s_%s", class_name, wrap_name); + String *final_wrap_name = Swig_name_wrapper(new_string); + + Setattr(n, "wrap:name", final_wrap_name); + state.function(WRAPPER_NAME, final_wrap_name); + + + + t_function.replace("$jslocals", wrapper->locals) + .replace("$jscode", wrapper->code); + + // call this here, to replace all variables + t_function.replace("$jswrapper", final_wrap_name) + .replace("$jsname", state.function(NAME)) + .pretty_print(f_wrappers); + + // Delete the state variable + DelWrapper(wrapper); + + return SWIG_OK; +} + +String *JSEmitter::emitInputTypemap(Node *n, Parm *p, Wrapper *wrapper, String *arg) { + // Get input typemap for current param + String *tm = Getattr(p, "tmap:in"); + SwigType *type = Getattr(p, "type"); + + if (tm != NULL) { + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + // do replacements for built-in variables + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$symname", Getattr(n, "sym:name")); + Printf(wrapper->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(type, 0)); + } + + return tm; +} + +void JSEmitter::marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult, bool emitReturnVariable) { + SwigType *type = Getattr(n, "type"); + String *tm; + Parm *p; + + // adds a declaration for the result variable + if (emitReturnVariable) + emit_return_variable(n, type, wrapper); + // if not given, use default result identifier ('result') for output typemap + if (cresult == 0) + cresult = defaultResultName; + + tm = Swig_typemap_lookup_out("out", n, cresult, wrapper, actioncode); + bool should_own = GetFlag(n, "feature:new") != 0; + + if (tm) { + Replaceall(tm, "$objecttype", Swig_scopename_last(SwigType_str(SwigType_strip_qualifiers(type), 0))); + + if (should_own) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm, "$owner", "0"); + } + Append(wrapper->code, tm); + + if (Len(tm) > 0) { + Printf(wrapper->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(type, 0), Getattr(n, "name")); + } + + if (params) { + for (p = params; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(wrapper->code, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + } + + Replaceall(wrapper->code, "$result", "jsresult"); +} + +void JSEmitter::emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params) { + Parm *p; + String *tm; + + for (p = params; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + //addThrows(n, "tmap:freearg", p); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(wrapper->code, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + if (GetFlag(n, "feature:new")) { + tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0); + if (tm != NIL) { + //addThrows(throws_hash, "newfree", n); + Printv(wrapper->code, tm, "\n", NIL); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Printf(wrapper->code, "%s\n", tm); + Delete(tm); + } +} + +int JSEmitter::switchNamespace(Node *n) { + // HACK: somehow this gets called for member functions. + // We can safely ignore them, as members are not associated to a namespace (only their class) + if (GetFlag(n, "ismember")) { + return SWIG_OK; + } + + // if nspace is deactivated, everything goes into the global scope + if (!GetFlag(n, "feature:nspace")) { + current_namespace = Getattr(namespaces, "::"); + return SWIG_OK; + } + +// EXPERIMENTAL: we want to use Language::getNSpace() here +// However, it is not working yet. +// For namespace functions Language::getNSpace() does not give a valid result +#if 0 + JAVASCRIPT *lang = static_cast<JAVASCRIPT*>(Language::instance()); + String *_nspace = lang->getNSpace(); + if (!Equal(nspace, _nspace)) { + Printf(stdout, "##### Custom vs Language::getNSpace(): %s | %s\n", nspace, _nspace); + Swig_print_node(n); + } +#endif + + String *nspace = Getattr(n, "sym:nspace"); + + if (nspace == NULL) { + // It seems that only classes have 'sym:nspace' set. + // We try to get the namespace from the qualified name (i.e., everything before the last '::') + nspace = Swig_scopename_prefix(Getattr(n, "name")); + } + + // If there is not even a scopename prefix then it must be global scope + if (nspace == NULL) { + current_namespace = Getattr(namespaces, "::"); + return SWIG_OK; + } + + String *scope = NewString(nspace); + // replace "." with "::" that we can use Swig_scopename_last + Replaceall(scope, ".", "::"); + + // if the scope is not yet registered + // create (parent) namespaces recursively + if (!Getattr(namespaces, scope)) { + createNamespace(scope); + } + current_namespace = Getattr(namespaces, scope); + + return SWIG_OK; +} + +int JSEmitter::createNamespace(String *scope) { + + String *parent_scope = Swig_scopename_prefix(scope); + Hash *parent_namespace; + if (parent_scope == 0) { + parent_namespace = Getattr(namespaces, "::"); + } else if (!Getattr(namespaces, parent_scope)) { + createNamespace(parent_scope); + parent_namespace = Getattr(namespaces, parent_scope); + } else { + parent_namespace = Getattr(namespaces, parent_scope); + } + assert(parent_namespace != 0); + + Hash *new_namespace = createNamespaceEntry(Char(scope), Char(Getattr(parent_namespace, "name")), Char(Getattr(parent_namespace, "name_mangled"))); + Setattr(namespaces, scope, new_namespace); + + Delete(parent_scope); + return SWIG_OK; +} + +Hash *JSEmitter::createNamespaceEntry(const char *_name, const char *parent, const char *parent_mangled) { + Hash *entry = NewHash(); + String *name = NewString(_name); + Setattr(entry, NAME, Swig_scopename_last(name)); + Setattr(entry, NAME_MANGLED, Swig_name_mangle(name)); + Setattr(entry, PARENT, NewString(parent)); + Setattr(entry, PARENT_MANGLED, NewString(parent_mangled)); + + Delete(name); + return entry; +} + +/********************************************************************** + * JavascriptCore: JSEmitter implementation for JavascriptCore engine + **********************************************************************/ + +class JSCEmitter:public JSEmitter { + +public: + JSCEmitter(); + virtual ~ JSCEmitter(); + virtual int initialize(Node *n); + virtual int dump(Node *n); + virtual int close(); + +protected: + virtual int enterVariable(Node *n); + virtual int exitVariable(Node *n); + virtual int enterFunction(Node *n); + virtual int exitFunction(Node *n); + virtual int enterClass(Node *n); + virtual int exitClass(Node *n); + virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static); + virtual Hash *createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled); + virtual int emitNamespaces(); + +private: + + String *NULL_STR; + String *VETO_SET; + + // output file and major code parts + File *f_wrap_cpp; + File *f_runtime; + File *f_header; + File *f_init; + +}; + +JSCEmitter::JSCEmitter() +: JSEmitter(JSEmitter::JavascriptCore), NULL_STR(NewString("NULL")), VETO_SET(NewString("JS_veto_set_variable")), f_wrap_cpp(NULL), f_runtime(NULL), f_header(NULL), f_init(NULL) { +} + +JSCEmitter::~JSCEmitter() { + Delete(NULL_STR); + Delete(VETO_SET); +} + + +/* --------------------------------------------------------------------- + * marshalInputArgs() + * + * Process all of the arguments passed into the argv array + * and convert them into C/C++ function arguments using the + * supplied typemaps. + * --------------------------------------------------------------------- */ + +void JSCEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) { + Parm *p; + String *tm; + + // determine an offset index, as members have an extra 'this' argument + // except: static members and ctors. + int startIdx = 0; + if (is_member && !is_static && mode != Ctor) { + startIdx = 1; + } + // store number of arguments for argument checks + int num_args = emit_num_arguments(parms) - startIdx; + String *argcount = NewString(""); + Printf(argcount, "%d", num_args); + Setattr(n, ARGCOUNT, argcount); + + // process arguments + int i = 0; + for (p = parms; p; i++) { + String *arg = NewString(""); + String *type = Getattr(p, "type"); + + // ignore varargs + if (SwigType_isvarargs(type)) + break; + + switch (mode) { + case Getter: + case Function: + if (is_member && !is_static && i == 0) { + Printv(arg, "thisObject", 0); + } else { + Printf(arg, "argv[%d]", i - startIdx); + } + break; + case Setter: + if (is_member && !is_static && i == 0) { + Printv(arg, "thisObject", 0); + } else { + Printv(arg, "value", 0); + } + break; + case Ctor: + Printf(arg, "argv[%d]", i); + break; + default: + throw "Illegal state."; + } + tm = emitInputTypemap(n, p, wrapper, arg); + Delete(arg); + if (tm) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } +} + +int JSCEmitter::initialize(Node *n) { + + JSEmitter::initialize(n); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + /* Initialize I/O */ + f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files()); + if (!f_wrap_cpp) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + /* Initialization of members */ + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + + state.globals(CREATE_NAMESPACES, NewString("")); + state.globals(REGISTER_NAMESPACES, NewString("")); + state.globals(INITIALIZER, NewString("")); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("begin", f_wrap_cpp); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + + Swig_banner(f_wrap_cpp); + + return SWIG_OK; +} + +int JSCEmitter::dump(Node *n) { + /* Get the module name */ + String *module = Getattr(n, "name"); + + Template initializer_define(getTemplate("js_initializer_define")); + initializer_define.replace("$jsname", module).pretty_print(f_header); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printv(f_wrap_cpp, f_runtime, "\n", 0); + Printv(f_wrap_cpp, f_header, "\n", 0); + Printv(f_wrap_cpp, f_wrappers, "\n", 0); + + emitNamespaces(); + + // compose the initializer function using a template + Template initializer(getTemplate("js_initializer")); + initializer.replace("$jsname", module) + .replace("$jsregisterclasses", state.globals(INITIALIZER)) + .replace("$jscreatenamespaces", state.globals(CREATE_NAMESPACES)) + .replace("$jsregisternamespaces", state.globals(REGISTER_NAMESPACES)) + .pretty_print(f_init); + + Printv(f_wrap_cpp, f_init, 0); + + return SWIG_OK; +} + +int JSCEmitter::close() { + Delete(f_runtime); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(namespaces); + Delete(f_wrap_cpp); + return SWIG_OK; +} + +int JSCEmitter::enterFunction(Node *n) { + + JSEmitter::enterFunction(n); + + return SWIG_OK; +} + +int JSCEmitter::exitFunction(Node *n) { + Template t_function = getTemplate("jsc_function_declaration"); + + bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0; + bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + + // handle overloaded functions + if (is_overloaded) { + if (!Getattr(n, "sym:nextSibling")) { + //state.function(WRAPPER_NAME, Swig_name_wrapper(Getattr(n, "name"))); + // create dispatcher + emitFunctionDispatcher(n, is_member); + } else { + //don't register wrappers of overloaded functions in function tables + return SWIG_OK; + } + } + + t_function.replace("$jsname", state.function(NAME)) + .replace("$jswrapper", state.function(WRAPPER_NAME)); + + if (is_member) { + if (GetFlag(state.function(), IS_STATIC)) { + t_function.pretty_print(state.clazz(STATIC_FUNCTIONS)); + } else { + t_function.pretty_print(state.clazz(MEMBER_FUNCTIONS)); + } + } else { + t_function.pretty_print(Getattr(current_namespace, "functions")); + } + + return SWIG_OK; +} + +int JSCEmitter::enterVariable(Node *n) { + JSEmitter::enterVariable(n); + state.variable(GETTER, NULL_STR); + state.variable(SETTER, VETO_SET); + return SWIG_OK; +} + +int JSCEmitter::exitVariable(Node *n) { + Template t_variable(getTemplate("jsc_variable_declaration")); + t_variable.replace("$jsname", state.variable(NAME)) + .replace("$jsgetter", state.variable(GETTER)) + .replace("$jssetter", state.variable(SETTER)); + + if (GetFlag(n, "ismember")) { + if (GetFlag(state.variable(), IS_STATIC) + || Equal(Getattr(n, "nodeType"), "enumitem")) { + t_variable.pretty_print(state.clazz(STATIC_VARIABLES)); + } else { + t_variable.pretty_print(state.clazz(MEMBER_VARIABLES)); + } + } else { + t_variable.pretty_print(Getattr(current_namespace, "values")); + } + + return SWIG_OK; +} + +int JSCEmitter::enterClass(Node *n) { + JSEmitter::enterClass(n); + state.clazz(MEMBER_VARIABLES, NewString("")); + state.clazz(MEMBER_FUNCTIONS, NewString("")); + state.clazz(STATIC_VARIABLES, NewString("")); + state.clazz(STATIC_FUNCTIONS, NewString("")); + + Template t_class_decl = getTemplate("jsc_class_declaration"); + t_class_decl.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .pretty_print(f_wrappers); + + return SWIG_OK; +} + +int JSCEmitter::exitClass(Node *n) { + Template t_class_tables(getTemplate("jsc_class_tables")); + t_class_tables.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsclassvariables", state.clazz(MEMBER_VARIABLES)) + .replace("$jsclassfunctions", state.clazz(MEMBER_FUNCTIONS)) + .replace("$jsstaticclassfunctions", state.clazz(STATIC_FUNCTIONS)) + .replace("$jsstaticclassvariables", state.clazz(STATIC_VARIABLES)) + .pretty_print(f_wrappers); + + /* adds the ctor wrappers at this position */ + // Note: this is necessary to avoid extra forward declarations. + //Append(f_wrappers, state.clazz(CTOR_WRAPPERS)); + + // for abstract classes add a vetoing ctor + if (GetFlag(state.clazz(), IS_ABSTRACT)) { + Template t_veto_ctor(getTemplate("js_veto_ctor")); + t_veto_ctor.replace("$jswrapper", state.clazz(CTOR)) + .replace("$jsname", state.clazz(NAME)) + .pretty_print(f_wrappers); + } + + /* adds a class template statement to initializer function */ + Template t_classtemplate(getTemplate("jsc_class_definition")); + + /* prepare registration of base class */ + String *jsclass_inheritance = NewString(""); + Node *base_class = getBaseClass(n); + if (base_class != NULL) { + Template t_inherit(getTemplate("jsc_class_inherit")); + t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsbaseclassmangled", SwigType_manglestr(Getattr(base_class, "name"))) + .pretty_print(jsclass_inheritance); + } else { + Template t_inherit(getTemplate("jsc_class_noinherit")); + t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .pretty_print(jsclass_inheritance); + } + + t_classtemplate.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsmangledtype", state.clazz(TYPE_MANGLED)) + .replace("$jsclass_inheritance", jsclass_inheritance) + .replace("$jsctor", state.clazz(CTOR)) + .replace("$jsdtor", state.clazz(DTOR)) + .pretty_print(state.globals(INITIALIZER)); + Delete(jsclass_inheritance); + + /* Note: this makes sure that there is a swig_type added for this class */ + SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0")); + + /* adds a class registration statement to initializer function */ + Template t_registerclass(getTemplate("jsc_class_registration")); + t_registerclass.replace("$jsname", state.clazz(NAME)) + .replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsnspace", Getattr(state.clazz("nspace"), NAME_MANGLED)) + .pretty_print(state.globals(INITIALIZER)); + + return SWIG_OK; +} + +Hash *JSCEmitter::createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled) { + Hash *entry = JSEmitter::createNamespaceEntry(name, parent, parent_mangled); + Setattr(entry, "functions", NewString("")); + Setattr(entry, "values", NewString("")); + return entry; +} + +int JSCEmitter::emitNamespaces() { + Iterator it; + for (it = First(namespaces); it.item; it = Next(it)) { + Hash *entry = it.item; + String *name = Getattr(entry, NAME); + String *name_mangled = Getattr(entry, NAME_MANGLED); + String *parent_mangled = Getattr(entry, PARENT_MANGLED); + String *functions = Getattr(entry, "functions"); + String *variables = Getattr(entry, "values"); + + // skip the global namespace which is given by the application + + Template namespace_definition(getTemplate("jsc_nspace_declaration")); + namespace_definition.replace("$jsglobalvariables", variables) + .replace("$jsglobalfunctions", functions) + .replace("$jsnspace", name_mangled) + .replace("$jsmangledname", name_mangled) + .pretty_print(f_wrap_cpp); + + Template t_createNamespace(getTemplate("jsc_nspace_definition")); + t_createNamespace.replace("$jsmangledname", name_mangled); + Append(state.globals(CREATE_NAMESPACES), t_createNamespace.str()); + + // Don't register 'exports' as namespace. It is return to the application. + if (!Equal("exports", name)) { + Template t_registerNamespace(getTemplate("jsc_nspace_registration")); + t_registerNamespace.replace("$jsmangledname", name_mangled) + .replace("$jsname", name) + .replace("$jsparent", parent_mangled); + Append(state.globals(REGISTER_NAMESPACES), t_registerNamespace.str()); + } + } + + return SWIG_OK; +} + +JSEmitter *swig_javascript_create_JSCEmitter() { + return new JSCEmitter(); +} + +/********************************************************************** + * V8: JSEmitter implementation for V8 engine + **********************************************************************/ + +class V8Emitter:public JSEmitter { + +public: + V8Emitter(); + + virtual ~ V8Emitter(); + virtual int initialize(Node *n); + virtual int dump(Node *n); + virtual int close(); + virtual int enterClass(Node *n); + virtual int exitClass(Node *n); + virtual int enterVariable(Node *n); + virtual int exitVariable(Node *n); + virtual int exitFunction(Node *n); + +protected: + virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static); + virtual int emitNamespaces(); + +protected: + /* built-in parts */ + String *f_runtime; + String *f_header; + String *f_init; + String *f_post_init; + + /* part for class templates */ + String *f_class_templates; + + /* parts for initilizer */ + String *f_init_namespaces; + String *f_init_class_templates; + String *f_init_wrappers; + String *f_init_inheritance; + String *f_init_class_instances; + String *f_init_static_wrappers; + String *f_init_register_classes; + String *f_init_register_namespaces; + + // the output cpp file + File *f_wrap_cpp; + + String *NULL_STR; + String *VETO_SET; + String *moduleName; + +}; + +V8Emitter::V8Emitter() +: JSEmitter(JSEmitter::V8), NULL_STR(NewString("0")), VETO_SET(NewString("JS_veto_set_variable")) { +} + +V8Emitter::~V8Emitter() { + Delete(NULL_STR); + Delete(VETO_SET); +} + +int V8Emitter::initialize(Node *n) { + JSEmitter::initialize(n); + + moduleName = Getattr(n, "name"); + + // Get the output file name + String *outfile = Getattr(n, "outfile"); + f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files()); + if (!f_wrap_cpp) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + f_runtime = NewString(""); + f_header = NewString(""); + f_class_templates = NewString(""); + f_init = NewString(""); + f_post_init = NewString(""); + + f_init_namespaces = NewString(""); + f_init_class_templates = NewString(""); + f_init_wrappers = NewString(""); + f_init_inheritance = NewString(""); + f_init_class_instances = NewString(""); + f_init_static_wrappers = NewString(""); + f_init_register_classes = NewString(""); + f_init_register_namespaces = NewString(""); + + // note: this is necessary for built-in generation of SWIG runtime code + Swig_register_filebyname("begin", f_wrap_cpp); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("post-init", f_post_init); + + state.globals(FORCE_CPP, NewString("1")); + + Swig_banner(f_wrap_cpp); + + return SWIG_OK; +} + +int V8Emitter::dump(Node *n) { + /* Get the module name */ + String *module = Getattr(n, "name"); + + Template initializer_define(getTemplate("js_initializer_define")); + initializer_define.replace("$jsname", module).pretty_print(f_header); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printv(f_wrap_cpp, f_runtime, "\n", 0); + Printv(f_wrap_cpp, f_header, "\n", 0); + Printv(f_wrap_cpp, f_class_templates, "\n", 0); + Printv(f_wrap_cpp, f_wrappers, "\n", 0); + + emitNamespaces(); + + // compose the initializer function using a template + // filled with sub-parts + Template initializer(getTemplate("js_initializer")); + initializer.replace("$jsname", moduleName) + .replace("$jsv8nspaces", f_init_namespaces) + .replace("$jsv8classtemplates", f_init_class_templates) + .replace("$jsv8wrappers", f_init_wrappers) + .replace("$jsv8inheritance", f_init_inheritance) + .replace("$jsv8classinstances", f_init_class_instances) + .replace("$jsv8staticwrappers", f_init_static_wrappers) + .replace("$jsv8registerclasses", f_init_register_classes) + .replace("$jsv8registernspaces", f_init_register_namespaces); + Printv(f_init, initializer.str(), 0); + + Printv(f_wrap_cpp, f_init, 0); + + Printv(f_wrap_cpp, f_post_init, 0); + + return SWIG_OK; +} + +int V8Emitter::close() { + Delete(f_runtime); + Delete(f_header); + Delete(f_class_templates); + Delete(f_init_namespaces); + Delete(f_init_class_templates); + Delete(f_init_wrappers); + Delete(f_init_inheritance); + Delete(f_init_class_instances); + Delete(f_init_static_wrappers); + Delete(f_init_register_classes); + Delete(f_init_register_namespaces); + Delete(f_init); + Delete(f_post_init); + Delete(f_wrap_cpp); + return SWIG_OK; +} + +int V8Emitter::enterClass(Node *n) { + JSEmitter::enterClass(n); + + // emit declaration of a v8 class template + Template t_decl_class(getTemplate("jsv8_declare_class_template")); + t_decl_class.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .trim() + .pretty_print(f_class_templates); + + return SWIG_OK; +} + +int V8Emitter::exitClass(Node *n) { + if (GetFlag(state.clazz(), IS_ABSTRACT)) { + Template t_veto_ctor(getTemplate("js_veto_ctor")); + t_veto_ctor.replace("$jswrapper", state.clazz(CTOR)) + .replace("$jsname", state.clazz(NAME)) + .pretty_print(f_wrappers); + } + + /* Note: this makes sure that there is a swig_type added for this class */ + String *clientData = NewString(""); + Printf(clientData, "&%s_clientData", state.clazz(NAME_MANGLED)); + + /* Note: this makes sure that there is a swig_type added for this class */ + SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0")); + + // emit definition of v8 class template + Template t_def_class = getTemplate("jsv8_define_class_template"); + t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsname", state.clazz(NAME)) + .replace("$jsmangledtype", state.clazz(TYPE_MANGLED)) + .replace("$jsdtor", state.clazz(DTOR)) + .trim() + .pretty_print(f_init_class_templates); + + Template t_class_instance = getTemplate("jsv8_create_class_instance"); + t_class_instance.replace("$jsname", state.clazz(NAME)) + .replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsctor", state.clazz(CTOR)) + .trim() + .pretty_print(f_init_class_instances); + + // emit inheritance setup + Node *baseClass = getBaseClass(n); + if (baseClass) { + String *base_name = Getattr(baseClass, "name"); + + Template t_inherit = getTemplate("jsv8_inherit"); + + String *base_name_mangled = SwigType_manglestr(base_name); + t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsbaseclass", base_name_mangled) + .trim() + .pretty_print(f_init_inheritance); + Delete(base_name_mangled); + } + // emit registration of class template + Template t_register = getTemplate("jsv8_register_class"); + t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsname", state.clazz(NAME)) + .replace("$jsparent", Getattr(state.clazz("nspace"), NAME_MANGLED)) + .trim() + .pretty_print(f_init_register_classes); + + return SWIG_OK; +} + +int V8Emitter::enterVariable(Node *n) { + JSEmitter::enterVariable(n); + + state.variable(GETTER, NULL_STR); + state.variable(SETTER, VETO_SET); + + return SWIG_OK; +} + +int V8Emitter::exitVariable(Node *n) { + if (GetFlag(n, "ismember")) { + if (GetFlag(state.variable(), IS_STATIC) || Equal(Getattr(n, "nodeType"), "enumitem")) { + Template t_register = getTemplate("jsv8_register_static_variable"); + t_register.replace("$jsparent", state.clazz(NAME_MANGLED)) + .replace("$jsname", state.variable(NAME)) + .replace("$jsgetter", state.variable(GETTER)) + .replace("$jssetter", state.variable(SETTER)) + .trim() + .pretty_print(f_init_static_wrappers); + } else { + Template t_register = getTemplate("jsv8_register_member_variable"); + t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsname", state.variable(NAME)) + .replace("$jsgetter", state.variable(GETTER)) + .replace("$jssetter", state.variable(SETTER)) + .trim() + .pretty_print(f_init_wrappers); + } + } else { + // Note: a global variable is treated like a static variable + // with the parent being a nspace object (instead of class object) + Template t_register = getTemplate("jsv8_register_static_variable"); + t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED)) + .replace("$jsname", state.variable(NAME)) + .replace("$jsgetter", state.variable(GETTER)) + .replace("$jssetter", state.variable(SETTER)) + .trim() + .pretty_print(f_init_wrappers); + } + + return SWIG_OK; +} + +int V8Emitter::exitFunction(Node *n) { + bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0; + + // create a dispatcher for overloaded functions + bool is_overloaded = GetFlag(n, "sym:overloaded") != 0; + if (is_overloaded) { + if (!Getattr(n, "sym:nextSibling")) { + //state.function(WRAPPER_NAME, Swig_name_wrapper(Getattr(n, "name"))); + emitFunctionDispatcher(n, is_member); + } else { + //don't register wrappers of overloaded functions in function tables + return SWIG_OK; + } + } + // register the function at the specific context + if (is_member) { + if (GetFlag(state.function(), IS_STATIC)) { + Template t_register = getTemplate("jsv8_register_static_function"); + t_register.replace("$jsparent", state.clazz(NAME_MANGLED)) + .replace("$jsname", state.function(NAME)) + .replace("$jswrapper", state.function(WRAPPER_NAME)) + .trim() + .pretty_print(f_init_static_wrappers); + } else { + Template t_register = getTemplate("jsv8_register_member_function"); + t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED)) + .replace("$jsname", state.function(NAME)) + .replace("$jswrapper", state.function(WRAPPER_NAME)) + .trim() + .pretty_print(f_init_wrappers); + } + } else { + // Note: a global function is treated like a static function + // with the parent being a nspace object instead of class object + Template t_register = getTemplate("jsv8_register_static_function"); + t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED)) + .replace("$jsname", state.function(NAME)) + .replace("$jswrapper", state.function(WRAPPER_NAME)) + .trim() + .pretty_print(f_init_static_wrappers); + } + + return SWIG_OK; +} + +void V8Emitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) { + Parm *p; + String *tm; + + int startIdx = 0; + if (is_member && !is_static && mode != Ctor) { + startIdx = 1; + } + // store number of arguments for argument checks + int num_args = emit_num_arguments(parms) - startIdx; + String *argcount = NewString(""); + Printf(argcount, "%d", num_args); + Setattr(n, ARGCOUNT, argcount); + + int i = 0; + for (p = parms; p; i++) { + String *arg = NewString(""); + String *type = Getattr(p, "type"); + + // ignore varargs + if (SwigType_isvarargs(type)) + break; + + switch (mode) { + case Getter: + if (is_member && !is_static && i == 0) { + Printv(arg, "info.Holder()", 0); + } else { + Printf(arg, "args[%d]", i - startIdx); + } + break; + case Function: + if (is_member && !is_static && i == 0) { + Printv(arg, "args.Holder()", 0); + } else { + Printf(arg, "args[%d]", i - startIdx); + } + break; + case Setter: + if (is_member && !is_static && i == 0) { + Printv(arg, "info.Holder()", 0); + } else { + Printv(arg, "value", 0); + } + break; + case Ctor: + Printf(arg, "args[%d]", i); + break; + default: + throw "Illegal state."; + } + + tm = emitInputTypemap(n, p, wrapper, arg); + Delete(arg); + + if (tm) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } +} + +int V8Emitter::emitNamespaces() { + Iterator it; + for (it = First(namespaces); it.item; it = Next(it)) { + Hash *entry = it.item; + String *name = Getattr(entry, NAME); + String *name_mangled = Getattr(entry, NAME_MANGLED); + String *parent = Getattr(entry, PARENT); + String *parent_mangled = Getattr(entry, PARENT_MANGLED); + + bool do_create = true; + bool do_register = true; + + if (Equal(parent, "")) { + do_register = false; + } + // Note: 'exports' is by convention the name of the object where + // globals are stored into + if (Equal(name, "exports")) { + do_create = false; + } + + if (do_create) { + // create namespace object and register it to the parent scope + Template t_create_ns = getTemplate("jsv8_create_namespace"); + t_create_ns.replace("$jsmangledname", name_mangled) + .trim() + .pretty_print(f_init_namespaces); + } + + if (do_register) { + Template t_register_ns = getTemplate("jsv8_register_namespace"); + t_register_ns.replace("$jsmangledname", name_mangled) + .replace("$jsname", name) + .replace("$jsparent", parent_mangled) + .trim(); + + // prepend in order to achieve reversed order of registration statements + String *tmp_register_stmt = NewString(""); + t_register_ns.pretty_print(tmp_register_stmt); + Insert(f_init_register_namespaces, 0, tmp_register_stmt); + Delete(tmp_register_stmt); + } + } + + return SWIG_OK; +} + +JSEmitter *swig_javascript_create_V8Emitter() { + return new V8Emitter(); +} + +/********************************************************************** + * Helper implementations + **********************************************************************/ + +JSEmitterState::JSEmitterState() +: globalHash(NewHash()) { + // initialize sub-hashes + Setattr(globalHash, "class", NewHash()); + Setattr(globalHash, "function", NewHash()); + Setattr(globalHash, "variable", NewHash()); +} + +JSEmitterState::~JSEmitterState() { + Delete(globalHash); +} + +DOH *JSEmitterState::getState(const char *key, bool new_key) { + if (new_key) { + Hash *hash = NewHash(); + Setattr(globalHash, key, hash); + } + return Getattr(globalHash, key); +} + +DOH *JSEmitterState::globals() { + return globalHash; +} + +DOH *JSEmitterState::globals(const char *key, DOH *initial) { + if (initial != 0) { + Setattr(globalHash, key, initial); + } + return Getattr(globalHash, key); +} + +DOH *JSEmitterState::clazz(bool new_key) { + return getState("class", new_key); +} + +DOH *JSEmitterState::clazz(const char *key, DOH *initial) { + DOH *c = clazz(); + if (initial != 0) { + Setattr(c, key, initial); + } + return Getattr(c, key); +} + +DOH *JSEmitterState::function(bool new_key) { + return getState("function", new_key); +} + +DOH *JSEmitterState::function(const char *key, DOH *initial) { + DOH *f = function(); + if (initial != 0) { + Setattr(f, key, initial); + } + return Getattr(f, key); +} + +DOH *JSEmitterState::variable(bool new_key) { + return getState("variable", new_key); +} + +DOH *JSEmitterState::variable(const char *key, DOH *initial) { + DOH *v = variable(); + if (initial != 0) { + Setattr(v, key, initial); + } + return Getattr(v, key); +} + +/*static*/ +int JSEmitterState::IsSet(DOH *val) { + if (!val) { + return 0; + } else { + const char *cval = Char(val); + if (!cval) + return 0; + return (strcmp(cval, "0") != 0) ? 1 : 0; + } +} + +/* ----------------------------------------------------------------------------- + * Template::Template() : creates a Template class for given template code + * ----------------------------------------------------------------------------- */ + +Template::Template(const String *code_) { + + if (!code_) { + Printf(stdout, "Template code was null. Illegal input for template."); + SWIG_exit(EXIT_FAILURE); + } + code = NewString(code_); + templateName = NewString(""); +} + +Template::Template(const String *code_, const String *templateName_) { + + if (!code_) { + Printf(stdout, "Template code was null. Illegal input for template."); + SWIG_exit(EXIT_FAILURE); + } + + code = NewString(code_); + templateName = NewString(templateName_); +} + + +/* ----------------------------------------------------------------------------- + * Template::~Template() : cleans up of Template. + * ----------------------------------------------------------------------------- */ + +Template::~Template() { + Delete(code); + Delete(templateName); +} + +/* ----------------------------------------------------------------------------- + * String* Template::str() : retrieves the current content of the template. + * ----------------------------------------------------------------------------- */ + +String *Template::str() { + if (js_template_enable_debug) { + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *debug_code = NewString(""); + Printf(pre_code, "/* begin fragment(\"%s\") */", templateName); + Printf(post_code, "/* end fragment(\"%s\") */", templateName); + Printf(debug_code, "%s\n%s\n%s\n", pre_code, code, post_code); + + Delete(code); + Delete(pre_code); + Delete(post_code); + + code = debug_code; + } + return code; +} + +Template & Template::trim() { + const char *str = Char(code); + if (str == 0) + return *this; + + int length = Len(code); + if (length == 0) + return *this; + + int idx; + for (idx = 0; idx < length; ++idx) { + if (str[idx] != ' ' && str[idx] != '\t' && str[idx] != '\r' && str[idx] != '\n') + break; + } + int start_pos = idx; + + for (idx = length - 1; idx >= start_pos; --idx) { + if (str[idx] != ' ' && str[idx] != '\t' && str[idx] != '\r' && str[idx] != '\n') + break; + } + int end_pos = idx; + + int new_length = end_pos - start_pos + 1; + char *newstr = new char[new_length + 1]; + memcpy(newstr, str + start_pos, new_length); + newstr[new_length] = 0; + + Delete(code); + code = NewString(newstr); + delete[]newstr; + + return *this; +} + +/* ----------------------------------------------------------------------------- + * Template& Template::replace(const String* pattern, const String* repl) : + * + * replaces all occurrences of a given pattern with a given replacement. + * + * - pattern: the pattern to be replaced + * - repl: the replacement string + * - returns a reference to the Template to allow chaining of methods. + * ----------------------------------------------------------------------------- */ + +Template & Template::replace(const String *pattern, const String *repl) { + Replaceall(code, pattern, repl); + return *this; +} + +Template & Template::print(DOH *doh) { + Printv(doh, str(), 0); + return *this; +} + +Template & Template::pretty_print(DOH *doh) { + Wrapper_pretty_print(str(), doh); + return *this; +} + +Template::Template(const Template & t) { + code = NewString(t.code); + templateName = NewString(t.templateName); +} + +void Template::operator=(const Template & t) { + Delete(code); + Delete(templateName); + code = NewString(t.code); + templateName = NewString(t.templateName); +} diff --git a/contrib/tools/swig/Source/Modules/lang.cxx b/contrib/tools/swig/Source/Modules/lang.cxx new file mode 100644 index 00000000000..f7979b611c2 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/lang.cxx @@ -0,0 +1,3895 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * lang.cxx + * + * Language base class functions. Default C++ handling is also implemented here. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +/* default mode settings */ +static int director_mode = 0; +static int director_protected_mode = 1; +static int all_protected_mode = 0; +static int naturalvar_mode = 0; +Language *Language::this_ = 0; + +/* Set director_protected_mode */ +void Wrapper_director_mode_set(int flag) { + director_mode = flag; +} + +void Wrapper_director_protected_mode_set(int flag) { + director_protected_mode = flag; +} + +void Wrapper_all_protected_mode_set(int flag) { + all_protected_mode = flag; +} + +void Wrapper_naturalvar_mode_set(int flag) { + naturalvar_mode = flag; +} + +extern "C" { + int Swig_director_mode() { + return director_mode; + } + int Swig_director_protected_mode() { + return director_protected_mode; + } + int Swig_all_protected_mode() { + return all_protected_mode; + } + void Language_replace_special_variables(String *method, String *tm, Parm *parm) { + Language::instance()->replaceSpecialVariables(method, tm, parm); + } +} + +/* Some status variables used during parsing */ +static int InClass = 0; /* Parsing C++ or not */ +static String *ClassName = 0; /* This is the real name of the current class */ +static String *EnumClassName = 0; /* Enum class name */ +static String *ClassPrefix = 0; /* Class prefix */ +static String *EnumClassPrefix = 0; /* Prefix for strongly typed enums (including ClassPrefix) */ +static String *NSpace = 0; /* Namespace for the nspace feature */ +static String *ClassType = 0; /* Fully qualified type name to use */ +static String *DirectorClassName = 0; /* Director name of the current class */ +int Abstract = 0; +int ImportMode = 0; +int IsVirtual = 0; +static String *AttributeFunctionGet = 0; +static String *AttributeFunctionSet = 0; +static Node *CurrentClass = 0; +int line_number = 0; +String *input_file = 0; +int SmartPointer = 0; +static Hash *classhash; + +extern int GenerateDefault; +extern int ForceExtern; +extern int AddExtern; + +/* import modes */ + +#define IMPORT_MODE 1 + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_one() + * + * Dispatch a single node + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_one(Node *n) { + int ret = SWIG_OK; + + char *tag = Char(nodeType(n)); + if (!tag) { + /* Printf(stderr,"SWIG: Fatal internal error. Malformed parse tree + node!\n"); */ + return SWIG_OK; + } + + /* Do not proceed if marked with an error */ + + if (Getattr(n, "error")) + return SWIG_OK; + + /* Look for warnings */ + String *wrn = Getattr(n, "feature:warnfilter"); + if (wrn) + Swig_warnfilter(wrn, 1); + + /* ============================================================ + * C/C++ parsing + * ============================================================ */ + + if (strcmp(tag, "extern") == 0) { + ret = externDeclaration(n); + } else if (strcmp(tag, "cdecl") == 0) { + ret = cDeclaration(n); + } else if (strcmp(tag, "enum") == 0) { + ret = enumDeclaration(n); + } else if (strcmp(tag, "enumitem") == 0) { + ret = enumvalueDeclaration(n); + } else if (strcmp(tag, "enumforward") == 0) { + ret = enumforwardDeclaration(n); + } else if (strcmp(tag, "class") == 0) { + ret = classDeclaration(n); + } else if (strcmp(tag, "classforward") == 0) { + ret = classforwardDeclaration(n); + } else if (strcmp(tag, "constructor") == 0) { + ret = constructorDeclaration(n); + } else if (strcmp(tag, "destructor") == 0) { + ret = destructorDeclaration(n); + } else if (strcmp(tag, "access") == 0) { + ret = accessDeclaration(n); + } else if (strcmp(tag, "using") == 0) { + ret = usingDeclaration(n); + } else if (strcmp(tag, "namespace") == 0) { + ret = namespaceDeclaration(n); + } else if (strcmp(tag, "template") == 0) { + ret = templateDeclaration(n); + } else if (strcmp(tag, "lambda") == 0) { + ret = lambdaDeclaration(n); + } + + /* =============================================================== + * SWIG directives + * =============================================================== */ + + else if (strcmp(tag, "top") == 0) { + ret = top(n); + } else if (strcmp(tag, "extend") == 0) { + ret = extendDirective(n); + } else if (strcmp(tag, "apply") == 0) { + ret = applyDirective(n); + } else if (strcmp(tag, "clear") == 0) { + ret = clearDirective(n); + } else if (strcmp(tag, "constant") == 0) { + ret = constantDirective(n); + } else if (strcmp(tag, "fragment") == 0) { + ret = fragmentDirective(n); + } else if (strcmp(tag, "import") == 0) { + ret = importDirective(n); + } else if (strcmp(tag, "include") == 0) { + ret = includeDirective(n); + } else if (strcmp(tag, "insert") == 0) { + ret = insertDirective(n); + } else if (strcmp(tag, "module") == 0) { + ret = moduleDirective(n); + } else if (strcmp(tag, "native") == 0) { + ret = nativeDirective(n); + } else if (strcmp(tag, "pragma") == 0) { + ret = pragmaDirective(n); + } else if (strcmp(tag, "typemap") == 0) { + ret = typemapDirective(n); + } else if (strcmp(tag, "typemapcopy") == 0) { + ret = typemapcopyDirective(n); + } else if (strcmp(tag, "typemapitem") == 0) { + ret = typemapitemDirective(n); + } else if (strcmp(tag, "types") == 0) { + ret = typesDirective(n); + } else { + Swig_error(input_file, line_number, "Unrecognized parse tree node type '%s'\n", tag); + ret = SWIG_ERROR; + } + if (wrn) + Swig_warnfilter(wrn, 0); + return ret; +} + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_children() + * + * Emit all children that match the given type. type = 0 means all types. + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_children(Node *n) { + Node *c; + char *eo = Char(Getattr(n, "feature:emitonlychildren")); + for (c = firstChild(n); c; c = nextSibling(c)) { + if (eo) { + const char *tag = Char(nodeType(c)); + if (strcmp(tag, "cdecl") == 0) { + if (checkAttribute(c, "storage", "typedef")) + tag = "typedef"; + } + if (strstr(eo, tag) == 0) { + continue; + } + } + emit_one(c); + } + return SWIG_OK; +} + + +/* Stubs for dispatcher class. We don't do anything by default---up to derived class + to fill in traversal code */ + +int Dispatcher::defaultHandler(Node *) { + return SWIG_OK; +} +int Dispatcher::extendDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::applyDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::clearDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::constantDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::fragmentDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::importDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::includeDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::insertDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::moduleDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::nativeDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::pragmaDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typemapDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typemapitemDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typemapcopyDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typesDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::cDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::externDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::enumDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::enumvalueDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::enumforwardDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::classDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::templateDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::lambdaDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::classforwardDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::constructorDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::destructorDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::accessDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::usingDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::namespaceDeclaration(Node *n) { + return defaultHandler(n); +} + +/* Allocators */ +Language::Language(): +none_comparison(NewString("$arg != 0")), +director_ctor_code(NewString("")), +director_prot_ctor_code(0), +symtabs(NewHash()), +overloading(0), +multiinput(0), +cplus_runtime(0), +directors(0) { + symbolAddScope(""); // create top level/global symbol table scope + argc_template_string = NewString("argc"); + argv_template_string = NewString("argv[%d]"); + + /* Default director constructor code, passed to Swig_ConstructorToFunction */ + Printv(director_ctor_code, "if ( $comparison ) { /* subclassed */\n", " $director_new \n", "} else {\n", " $nondirector_new \n", "}\n", NIL); + + /* + Default director 'protected' constructor code, disabled by + default. Each language that needs it, has to define it. + */ + director_prot_ctor_code = 0; + director_multiple_inheritance = 1; + director_language = 0; + assert(!this_); + this_ = this; + + doxygenTranslator = NULL; +} + +Language::~Language() { + Delete(symtabs); + Delete(director_ctor_code); + Delete(none_comparison); + this_ = 0; +} + + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *Language::directorClassName(Node *n) { + String *dirclassname; + String *nspace = NewString(Getattr(n, "sym:nspace")); + const char *attrib = "director:classname"; + String *classname = getClassPrefix(); + + Replace(nspace, NSPACE_SEPARATOR, "_", DOH_REPLACE_ANY); + if (Len(nspace) > 0) + dirclassname = NewStringf("SwigDirector_%s_%s", nspace, classname); + else + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + + Delete(nspace); + return dirclassname; + } + +/* ---------------------------------------------------------------------- + emit_one() + ---------------------------------------------------------------------- */ + +int Language::emit_one(Node *n) { + int ret; + int oldext; + if (!n) + return SWIG_OK; + + if (GetFlag(n, "feature:ignore") + && !Getattr(n, "feature:onlychildren")) + return SWIG_OK; + + oldext = Extend; + if (Getattr(n, "feature:extend")) + Extend = 1; + + line_number = Getline(n); + input_file = Getfile(n); + + /* + symtab = Getattr(n,"symtab"); + if (symtab) { + symtab = Swig_symbol_setscope(symtab); + } + */ + ret = Dispatcher::emit_one(n); + /* + if (symtab) { + Swig_symbol_setscope(symtab); + } + */ + Extend = oldext; + return ret; +} + + +static Parm *nonvoid_parms(Parm *p) { + if (p) { + SwigType *t = Getattr(p, "type"); + if (SwigType_type(t) == T_VOID) + return 0; + } + return p; +} + +/* ----------------------------------------------------------------------------- + * cplus_value_type() + * + * Returns the alternative value type needed in C++ for class value + * types. When swig is not sure about using a plain $ltype value, + * since the class doesn't have a default constructor, or it can't be + * assigned, you will get back 'SwigValueWrapper<type >'. + * + * ----------------------------------------------------------------------------- */ + +SwigType *cplus_value_type(SwigType *t) { + return SwigType_alttype(t, 0); +} + +static Node *first_nontemplate(Node *n) { + while (n) { + if (Strcmp(nodeType(n), "template") != 0) + return n; + n = Getattr(n, "sym:nextSibling"); + } + return n; +} + + + +/* -------------------------------------------------------------------------- + * swig_pragma() + * + * Handle swig pragma directives. + * -------------------------------------------------------------------------- */ + +void swig_pragma(char *lang, char *name, char *value) { + if (strcmp(lang, "swig") == 0) { + if ((strcmp(name, "make_default") == 0) || ((strcmp(name, "makedefault") == 0))) { + GenerateDefault = 1; + } else if ((strcmp(name, "no_default") == 0) || ((strcmp(name, "nodefault") == 0))) { + Swig_warning(WARN_DEPRECATED_NODEFAULT, "SWIG", 1, "dangerous, use %%nodefaultctor, %%nodefaultdtor instead.\n"); + GenerateDefault = 0; + } else if (strcmp(name, "attributefunction") == 0) { + String *nvalue = NewString(value); + char *s = strchr(Char(nvalue), ':'); + if (!s) { + Swig_error(input_file, line_number, "Bad value for attributefunction. Expected \"fmtget:fmtset\".\n"); + } else { + *s = 0; + AttributeFunctionGet = NewString(Char(nvalue)); + AttributeFunctionSet = NewString(s + 1); + } + Delete(nvalue); + } else if (strcmp(name, "noattributefunction") == 0) { + AttributeFunctionGet = 0; + AttributeFunctionSet = 0; + } + } +} + +/* -------------------------------------------------------------------------- + * Language::use_naturalvar_mode() + * + * Determine whether to use const ref typemaps instead of pointer typemaps + * for variable access. + * -------------------------------------------------------------------------- */ +int Language::use_naturalvar_mode(Node *n) const { + if (Getattr(n, "unnamed")) + return 0; + + // The naturalvar feature can be attached to either the variable name or the variable's type + // naturalvar on the variable name is more specific and overrides naturalvar on the variable's type + String *naturalvar = Getattr(n, "feature:naturalvar"); + bool explicitly_off = naturalvar && Strcmp(naturalvar, "0") == 0; + int nvar = GetFlag(n, "feature:naturalvar"); + + if (!explicitly_off && !nvar) { + /* look for feature in the class */ + SwigType *ty = Getattr(n, "type"); + SwigType *fullty = SwigType_typedef_resolve_all(ty); + if (SwigType_isclass(fullty)) { + SwigType *tys = SwigType_strip_qualifiers(fullty); + if (!CPlusPlus) { + Replaceall(tys, "struct ", ""); + Replaceall(tys, "union ", ""); + Replaceall(tys, "class ", ""); + } + Node *typenode = Swig_symbol_clookup(tys, 0); + if (typenode) { + naturalvar = Getattr(typenode, "feature:naturalvar"); + explicitly_off = naturalvar && Strcmp(naturalvar, "0") == 0; + nvar = nvar || GetFlag(typenode, "feature:naturalvar"); + } + Delete(tys); + } + Delete(fullty); + } + nvar = nvar || naturalvar_mode; + return explicitly_off ? 0 : nvar ? CWRAP_NATURAL_VAR : 0; +} + +/* ---------------------------------------------------------------------- + * Language::top() - Top of parsing tree + * ---------------------------------------------------------------------- */ + +int Language::top(Node *n) { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + if (Getattr(options, "naturalvar")) { + naturalvar_mode = 1; + } + } + } + classhash = Getattr(n, "classes"); + return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::extendDirective() + * ---------------------------------------------------------------------- */ + +int Language::extendDirective(Node *n) { + save_value<int> oldam(Extend, CWRAP_EXTEND); + save_value<AccessMode> oldmode(cplus_mode, PUBLIC); + emit_children(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::applyDirective() + * ---------------------------------------------------------------------- */ + +int Language::applyDirective(Node *n) { + + Parm *pattern = Getattr(n, "pattern"); + Node *c = firstChild(n); + while (c) { + Parm *apattern = Getattr(c, "pattern"); + if (ParmList_len(pattern) != ParmList_len(apattern)) { + Swig_error(input_file, line_number, "Can't apply (%s) to (%s). Number of arguments don't match.\n", ParmList_str(pattern), ParmList_str(apattern)); + } else { + if (!Swig_typemap_apply(pattern, apattern)) { + Swig_warning(WARN_TYPEMAP_APPLY_UNDEF, input_file, line_number, "Can't apply (%s). No typemaps are defined.\n", ParmList_str(pattern)); + } + } + c = nextSibling(c); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::clearDirective() + * ---------------------------------------------------------------------- */ + +int Language::clearDirective(Node *n) { + Node *p; + for (p = firstChild(n); p; p = nextSibling(p)) { + ParmList *pattern = Getattr(p, "pattern"); + Swig_typemap_clear_apply(pattern); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::constantDirective() + * ---------------------------------------------------------------------- */ + +int Language::constantDirective(Node *n) { + + if (CurrentClass && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + if (!GetFlag(n, "feature:allowexcept")) { + UnsetFlag(n, "feature:except"); + } + if (Getattr(n, "feature:exceptvar")) { + Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); + } + + if (!ImportMode) { + Swig_require("constantDirective", n, "name", "?value", NIL); + String *name = Getattr(n, "name"); + String *value = Getattr(n, "value"); + if (!value) { + value = Copy(name); + } else { + /* if (checkAttribute(n,"type","char")) { + value = NewString(value); + } else { + value = NewStringf("%(escape)s", value); + } + */ + Setattr(n, "rawvalue", value); + value = NewStringf("%(escape)s", value); + if (!Len(value)) + Append(value, "\\0"); + /* Printf(stdout,"'%s' = '%s'\n", name, value); */ + } + Setattr(n, "value", value); + this->constantWrapper(n); + Swig_restore(n); + return SWIG_OK; + } + return SWIG_NOWRAP; +} + +/* ---------------------------------------------------------------------- + * Language::fragmentDirective() + * ---------------------------------------------------------------------- */ + +int Language::fragmentDirective(Node *n) { + if (!(Getattr(n, "emitonly") && ImportMode)) + Swig_fragment_register(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::importDirective() + * ---------------------------------------------------------------------- */ + +int Language::importDirective(Node *n) { + int oldim = ImportMode; + ImportMode = IMPORT_MODE; + emit_children(n); + ImportMode = oldim; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::includeDirective() + * ---------------------------------------------------------------------- */ + +int Language::includeDirective(Node *n) { + emit_children(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::insertDirective() + * ---------------------------------------------------------------------- */ + +int Language::insertDirective(Node *n) { + /* %insert directive */ + if ((!ImportMode) || Getattr(n, "generated")) { + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + File *f = 0; + if (!section) { /* %{ ... %} */ + f = Swig_filebyname("header"); + } else { + f = Swig_filebyname(section); + } + if (f) { + Printf(f, "%s\n", code); + } else { + Swig_error(input_file, line_number, "Unknown target '%s' for %%insert directive.\n", section); + } + return SWIG_OK; + } else { + return SWIG_NOWRAP; + } +} + +/* ---------------------------------------------------------------------- + * Language::moduleDirective() + * ---------------------------------------------------------------------- */ + +int Language::moduleDirective(Node *n) { + (void) n; + /* %module directive */ + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::nativeDirective() + * ---------------------------------------------------------------------- */ + +int Language::nativeDirective(Node *n) { + if (!ImportMode) { + return nativeWrapper(n); + } else { + return SWIG_NOWRAP; + } +} + +/* ---------------------------------------------------------------------- + * Language::pragmaDirective() + * ---------------------------------------------------------------------- */ + +int Language::pragmaDirective(Node *n) { + /* %pragma directive */ + if (!ImportMode) { + String *lan = Getattr(n, "lang"); + String *name = Getattr(n, "name"); + String *value = Getattr(n, "value"); + swig_pragma(Char(lan), Char(name), Char(value)); + /* pragma(Char(lan),Char(name),Char(value)); */ + return SWIG_OK; + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typemapDirective() + * ---------------------------------------------------------------------- */ + +int Language::typemapDirective(Node *n) { + /* %typemap directive */ + String *method = Getattr(n, "method"); + String *code = Getattr(n, "code"); + Parm *kwargs = Getattr(n, "kwargs"); + Node *items = firstChild(n); + static int namewarn = 0; + + + if (code && (Strstr(code, "$source") || (Strstr(code, "$target")))) { + Swig_warning(WARN_TYPEMAP_SOURCETARGET, Getfile(n), Getline(n), "Deprecated typemap feature ($source/$target).\n"); + if (!namewarn) { + Swig_warning(WARN_TYPEMAP_SOURCETARGET, Getfile(n), Getline(n), "The use of $source and $target in a typemap declaration is deprecated.\n\ +For typemaps related to argument input (in,ignore,default,arginit,check), replace\n\ +$source by $input and $target by $1. For typemaps related to return values (out,\n\ +argout,ret,except), replace $source by $1 and $target by $result. See the file\n\ +Doc/Manual/Typemaps.html for complete details.\n"); + namewarn = 1; + } + } + + if (Strcmp(method, "except") == 0) { + Swig_warning(WARN_DEPRECATED_EXCEPT_TM, Getfile(n), Getline(n), "%%typemap(except) is deprecated. Use the %%exception directive.\n"); + } + + if (Strcmp(method, "in") == 0) { + Hash *k; + k = kwargs; + while (k) { + if (checkAttribute(k, "name", "numinputs")) { + if (!multiinput && (GetInt(k, "value") > 1)) { + Swig_error(Getfile(n), Getline(n), "Multiple-input typemaps (numinputs > 1) not supported by this target language module.\n"); + return SWIG_ERROR; + } + break; + } + k = nextSibling(k); + } + if (!k) { + k = NewHash(); + Setattr(k, "name", "numinputs"); + Setattr(k, "value", "1"); + set_nextSibling(k, kwargs); + Setattr(n, "kwargs", k); + kwargs = k; + } + } + + if (Strcmp(method, "ignore") == 0) { + Swig_warning(WARN_DEPRECATED_IGNORE_TM, Getfile(n), Getline(n), "%%typemap(ignore) has been replaced by %%typemap(in,numinputs=0).\n"); + + Clear(method); + Append(method, "in"); + Hash *k = NewHash(); + Setattr(k, "name", "numinputs"); + Setattr(k, "value", "0"); + set_nextSibling(k, kwargs); + Setattr(n, "kwargs", k); + kwargs = k; + } + + /* Replace $descriptor() macros */ + + if (code) { + Setfile(code, Getfile(n)); + Setline(code, Getline(n)); + Swig_cparse_replace_descriptor(code); + } + + while (items) { + Parm *pattern = Getattr(items, "pattern"); + Parm *parms = Getattr(items, "parms"); + + if (code) { + Swig_typemap_register(method, pattern, code, parms, kwargs); + } else { + Swig_typemap_clear(method, pattern); + } + items = nextSibling(items); + } + return SWIG_OK; + +} + +/* ---------------------------------------------------------------------- + * Language::typemapcopyDirective() + * ---------------------------------------------------------------------- */ + +int Language::typemapcopyDirective(Node *n) { + String *method = Getattr(n, "method"); + Parm *pattern = Getattr(n, "pattern"); + Node *items = firstChild(n); + int nsrc = 0; + nsrc = ParmList_len(pattern); + while (items) { + ParmList *npattern = Getattr(items, "pattern"); + if (nsrc != ParmList_len(npattern)) { + Swig_error(input_file, line_number, "Can't copy typemap. Number of types differ.\n"); + } else { + if (Swig_typemap_copy(method, pattern, npattern) < 0) { + Swig_error(input_file, line_number, "Can't copy typemap (%s) %s = %s\n", method, ParmList_str(pattern), ParmList_str(npattern)); + } + } + items = nextSibling(items); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typesDirective() + * ---------------------------------------------------------------------- */ + +int Language::typesDirective(Node *n) { + Parm *parms = Getattr(n, "parms"); + String *convcode = Getattr(n, "convcode"); /* optional user supplied conversion code for custom casting */ + while (parms) { + SwigType *t = Getattr(parms, "type"); + String *v = Getattr(parms, "value"); + if (!v) { + SwigType_remember(t); + } else { + if (SwigType_issimple(t)) { + SwigType_inherit(t, v, 0, convcode); + } + } + parms = nextSibling(parms); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::cDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::cDeclaration(Node *n) { + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *decl = Getattr(n, "decl"); + String *storage = Getattr(n, "storage"); + Node *over; + File *f_header = 0; + SwigType *ty, *fullty; + + if (Getattr(n, "feature:onlychildren")) { + if (GetFlag(n, "feature:ignore")) { + return SWIG_NOWRAP; + } else { + // Found an unignored templated method that has an empty template instantiation (%template()) + // Ignore it unless it has been %rename'd + if (Strncmp(symname, "__dummy_", 8) == 0 && Cmp(storage, "typedef") != 0) { + SetFlag(n, "feature:ignore"); + Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number, + "%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n)); + return SWIG_NOWRAP; + } + } + } + + /* discards nodes following the access control rules */ + if (cplus_mode != PUBLIC || !is_public(n)) { + /* except for friends, they are not affected by access control */ + int isfriend = Cmp(storage, "friend") == 0; + if (!isfriend) { + /* Check what the director needs. If the method is pure virtual, it is always needed. + * Also wrap non-virtual protected members if asked for (allprotected mode). */ + if (!(directorsEnabled() && ((is_member_director(CurrentClass, n) && need_nonpublic_member(n)) || isNonVirtualProtectedAccess(n)))) { + return SWIG_NOWRAP; + } + // Prevent wrapping protected overloaded director methods more than once - + // This bit of code is only needed due to the cDeclaration call in classHandler() + String *wrapname = NewStringf("nonpublic_%s%s", symname, Getattr(n, "sym:overname")); + if (Getattr(CurrentClass, wrapname)) { + Delete(wrapname); + return SWIG_NOWRAP; + } + SetFlag(CurrentClass, wrapname); + Delete(wrapname); + } + } + + if (Cmp(storage, "typedef") == 0) { + Swig_save("cDeclaration", n, "type", NIL); + SwigType *t = Copy(type); + if (t) { + SwigType_push(t, decl); + Setattr(n, "type", t); + typedefHandler(n); + } + Swig_restore(n); + return SWIG_OK; + } + + /* If in import mode, we proceed no further */ + if (ImportMode) + return SWIG_NOWRAP; + + /* If we're in extend mode and there is code, replace the $descriptor macros */ + if (Extend) { + String *code = Getattr(n, "code"); + if (code) { + Setfile(code, Getfile(n)); + Setline(code, Getline(n)); + Swig_cparse_replace_descriptor(code); + } + } + + /* Overloaded symbol check */ + over = Swig_symbol_isoverloaded(n); + if (!overloading) { + if (over) + over = first_nontemplate(over); + if (over && (over != n)) { + Swig_warning(WARN_LANG_OVERLOAD_DECL, input_file, line_number, "Overloaded declaration ignored. %s\n", Swig_name_decl(n)); + Swig_warning(WARN_LANG_OVERLOAD_DECL, Getfile(over), Getline(over), "Previous declaration is %s\n", Swig_name_decl(over)); + return SWIG_NOWRAP; + } + } + + if (!validIdentifier(symname)) { + Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap '%s' unless renamed to a valid identifier.\n", SwigType_namestr(symname)); + return SWIG_NOWRAP; + } + + ty = NewString(type); + SwigType_push(ty, decl); + fullty = SwigType_typedef_resolve_all(ty); + if (SwigType_isfunction(fullty)) { + if (!SwigType_isfunction(ty)) { + Delete(ty); + ty = fullty; + fullty = 0; + ParmList *parms = SwigType_function_parms(ty, n); + Setattr(n, "parms", parms); + } + /* Transform the node into a 'function' node and emit */ + if (!CurrentClass) { + f_header = Swig_filebyname("header"); + + if (AddExtern) { + if (f_header) { + if (Swig_storage_isextern(n) || (ForceExtern && !storage)) { + /* we don't need the 'extern' part in the C/C++ declaration, + and it produces some problems when namespace and SUN + Studio is used. + + Printf(f_header,"extern %s", SwigType_str(ty,name)); + + In fact generating extern declarations is quite error prone and is + no longer the default. Getting it right seems impossible with namespaces + and default arguments and when a method is declared with the various Windows + calling conventions - SWIG doesn't understand Windows (non standard) calling + conventions in the first place, so can't regenerate them. + */ + String *str = SwigType_str(ty, name); + Printf(f_header, "%s", str); + Delete(str); + { + DOH *t = Getattr(n, "throws"); + if (t) { + Printf(f_header, " throw("); + while (t) { + Printf(f_header, "%s", Getattr(t, "type")); + t = nextSibling(t); + if (t) + Printf(f_header, ","); + } + Printf(f_header, ")"); + } + } + Printf(f_header, ";\n"); + } else if (Swig_storage_isexternc(n)) { + /* here 'extern "C"' is needed */ + String *str = SwigType_str(ty, name); + Printf(f_header, "extern \"C\" %s;\n", str); + Delete(str); + } + } + } + } + /* This needs to check qualifiers */ + if (SwigType_isqualifier(ty)) { + SwigType *qual = SwigType_pop(ty); + Setattr(n, "qualifier", qual); + Delete(qual); + } + Delete(SwigType_pop_function(ty)); + DohIncref(type); + Setattr(n, "type", ty); + + functionHandler(n); + + Setattr(n, "type", type); + Delete(ty); + Delete(type); + return SWIG_OK; + } else { + /* Some kind of variable declaration */ + String *declaration = Copy(decl); + Delattr(n, "decl"); + if (!CurrentClass) { + if (Swig_storage_isextern(n) || ForceExtern) { + if (AddExtern) { + f_header = Swig_filebyname("header"); + if (f_header) { + String *str = SwigType_str(ty, name); + Printf(f_header, "%s %s;\n", Getattr(n, "storage"), str); + Delete(str); + } + } + } + } + if (!SwigType_ismutable(ty)) { + SetFlag(n, "feature:immutable"); + } + /* If an array and elements are const, then read-only */ + if (SwigType_isarray(ty)) { + SwigType *tya = SwigType_array_type(ty); + if (SwigType_isconst(tya)) { + SetFlag(n, "feature:immutable"); + } + Delete(tya); + } + DohIncref(type); + Setattr(n, "type", ty); + variableHandler(n); + Setattr(n, "type", type); + Setattr(n, "decl", declaration); + Delete(ty); + Delete(type); + Delete(fullty); + return SWIG_OK; + } +} + +/* ---------------------------------------------------------------------- + * Language::functionHandler() + * ---------------------------------------------------------------------- */ + +int Language::functionHandler(Node *n) { + String *storage = Getattr(n, "storage"); + int isfriend = CurrentClass && Cmp(storage, "friend") == 0; + int isstatic = CurrentClass && Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess")); + Parm *p = Getattr(n, "parms"); + if (GetFlag(n, "feature:del")) { + /* the method acts like a delete operator, ie, we need to disown the parameter */ + if (CurrentClass && !isstatic && !isfriend) { + SetFlag(n, "feature:self:disown"); + } else { + if (p) + SetFlag(p, "wrap:disown"); + } + } + if (!CurrentClass) { + globalfunctionHandler(n); + } else { + if (isstatic) { + staticmemberfunctionHandler(n); + } else if (isfriend) { + int oldInClass = InClass; + InClass = 0; + globalfunctionHandler(n); + InClass = oldInClass; + } else { + // This is a member function, set a flag so the documentation type is correct + SetFlag(n, "memberfunction"); + Node *explicit_n = 0; + if (directorsEnabled() && is_member_director(CurrentClass, n) && !extraDirectorProtectedCPPMethodsRequired()) { + bool virtual_but_not_pure_virtual = (!(Cmp(storage, "virtual")) && (Cmp(Getattr(n, "value"), "0") != 0)); + if (virtual_but_not_pure_virtual) { + // Add additional wrapper which makes an explicit call to the virtual method (ie not a virtual call) + explicit_n = Copy(n); + String *new_symname = Copy(Getattr(n, "sym:name")); + String *suffix = Getattr(parentNode(n), "sym:name"); + Printv(new_symname, "SwigExplicit", suffix, NIL); + Setattr(explicit_n, "sym:name", new_symname); + Delattr(explicit_n, "storage"); + Delattr(explicit_n, "override"); + Delattr(explicit_n, "hides"); + SetFlag(explicit_n, "explicitcall"); + Setattr(n, "explicitcallnode", explicit_n); + } + } + + memberfunctionHandler(n); + + if (explicit_n) { + memberfunctionHandler(explicit_n); + Delattr(explicit_n, "explicitcall"); + Delete(explicit_n); + } + } + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::globalfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::globalfunctionHandler(Node *n) { + + Swig_require("globalfunctionHandler", n, "name", "sym:name", "type", "?parms", NIL); + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + + /* Check for callback mode */ + String *cb = GetFlagAttr(n, "feature:callback"); + if (cb) { + String *cbname = Getattr(n, "feature:callback:name"); + if (!cbname) { + cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", cbname); + } + + callbackfunctionHandler(n); + if (Cmp(cbname, symname) == 0) { + Delete(cbname); + Swig_restore(n); + return SWIG_NOWRAP; + } + Delete(cbname); + } + Setattr(n, "parms", nonvoid_parms(parms)); + + String *extendname = Getattr(n, "extendname"); + String *call = Swig_cfunction_call(extendname ? extendname : name, parms); + String *cres = Swig_cresult(type, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + functionWrapper(n); + + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::callbackfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::callbackfunctionHandler(Node *n) { + Swig_require("callbackfunctionHandler", n, "name", "*sym:name", "*type", "?value", NIL); + String *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *parms = Getattr(n, "parms"); + String *cbname = Getattr(n, "feature:callback:name"); + String *calltype = NewStringf("(%s (*)(%s))(%s)", SwigType_str(type, 0), ParmList_str(parms), SwigType_namestr(name)); + SwigType *cbty = Copy(type); + SwigType_add_function(cbty, parms); + SwigType_add_pointer(cbty); + + Setattr(n, "sym:name", cbname); + Setattr(n, "type", cbty); + Setattr(n, "value", calltype); + + Node *ns = symbolLookup(cbname); + if (!ns) + constantWrapper(n); + + Delete(cbty); + + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::memberfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::memberfunctionHandler(Node *n) { + + Swig_require("memberfunctionHandler", n, "*name", "*sym:name", "*type", "?parms", "?value", NIL); + + String *storage = Getattr(n, "storage"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + ParmList *parms = Getattr(n, "parms"); + String *cb = GetFlagAttr(n, "feature:callback"); + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + IsVirtual = PURE_VIRTUAL; + } else { + IsVirtual = PLAIN_VIRTUAL; + } + } else { + IsVirtual = 0; + } + if (cb) { + Node *cbn = NewHash(); + String *cbname = Getattr(n, "feature:callback:name"); + if (!cbname) { + cbname = NewStringf(cb, symname); + } + + SwigType *cbty = Copy(type); + SwigType_add_function(cbty, parms); + SwigType_add_memberpointer(cbty, ClassName); + String *cbvalue = NewStringf("&%s::%s", ClassName, name); + Setattr(cbn, "sym:name", cbname); + Setattr(cbn, "type", cbty); + Setattr(cbn, "value", cbvalue); + Setattr(cbn, "name", name); + Setfile(cbn, Getfile(n)); + Setline(cbn, Getline(n)); + + memberconstantHandler(cbn); + Setattr(n, "feature:callback:name", Swig_name_member(NSpace, ClassPrefix, cbname)); + + Delete(cb); + Delete(cbn); + Delete(cbvalue); + Delete(cbty); + Delete(cbname); + if (Cmp(cbname, symname) == 0) { + Swig_restore(n); + return SWIG_NOWRAP; + } + } + + String *fname = Swig_name_member(NSpace, ClassPrefix, symname); + if (Extend && SmartPointer) { + if (!Getattr(n, "extendsmartclassname")) { + Setattr(n, "extendsmartclassname", Getattr(CurrentClass, "allocate:smartpointerpointeeclassname")); + } + } + // Set up the type for the cast to this class for use when wrapping const director (virtual) methods. + // Note: protected director methods or when allprotected mode turned on. + String *director_type = 0; + if (!is_public(n) && (is_member_director(CurrentClass, n) || GetFlag(n, "explicitcall") || isNonVirtualProtectedAccess(n))) { + director_type = Copy(DirectorClassName); + String *qualifier = Getattr(n, "qualifier"); + if (qualifier) + SwigType_push(director_type, qualifier); + SwigType_add_pointer(director_type); + } + + int DirectorExtraCall = 0; + if (directorsEnabled() && is_member_director(CurrentClass, n) && !SmartPointer) + if (extraDirectorProtectedCPPMethodsRequired()) + DirectorExtraCall = CWRAP_DIRECTOR_TWO_CALLS; + + if (GetFlag(n, "explicitcall")) + DirectorExtraCall = CWRAP_DIRECTOR_ONE_CALL; + + int extendmember = GetFlag(n, "isextendmember") ? Extend : 0; + int flags = Getattr(n, "template") ? extendmember | SmartPointer : Extend | SmartPointer | DirectorExtraCall; + Swig_MethodToFunction(n, NSpace, ClassType, flags, director_type, is_member_director(CurrentClass, n)); + Setattr(n, "sym:name", fname); + /* Explicitly save low-level and high-level documentation names */ + Setattr(n, "doc:low:name", fname); + Setattr(n, "doc:high:name", symname); + + functionWrapper(n); + + Delete(director_type); + Delete(fname); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::staticmemberfunctionHandler(Node *n) { + + Swig_require("staticmemberfunctionHandler", n, "*name", "*sym:name", "*type", NIL); + Swig_save("staticmemberfunctionHandler", n, "storage", NIL); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + String *cb = GetFlagAttr(n, "feature:callback"); + String *cname, *mrename; + + if (!Extend) { + Node *sb = Getattr(n, "cplus:staticbase"); + String *sname = Getattr(sb, "name"); + if (isNonVirtualProtectedAccess(n)) + cname = NewStringf("%s::%s", DirectorClassName, name); + else + cname = NewStringf("%s::%s", sname, name); + } else { + String *mname = Swig_name_mangle(ClassName); + cname = Swig_name_member(NSpace, mname, name); + Delete(mname); + } + mrename = Swig_name_member(NSpace, ClassPrefix, symname); + + if (Extend) { + String *code = Getattr(n, "code"); + String *defaultargs = Getattr(n, "defaultargs"); + String *mangled = Swig_name_mangle(mrename); + Delete(mrename); + mrename = mangled; + + if (Getattr(n, "sym:overloaded") && code) { + Append(cname, Getattr(defaultargs ? defaultargs : n, "sym:overname")); + } + + if (!defaultargs && code) { + /* Hmmm. An added static member. We have to create a little wrapper for this */ + String *mangled_cname = Swig_name_mangle(cname); + Swig_add_extension_code(n, mangled_cname, parms, type, code, CPlusPlus, 0); + Setattr(n, "extendname", mangled_cname); + Delete(mangled_cname); + } + } + + Setattr(n, "name", cname); + Setattr(n, "sym:name", mrename); + /* Explicitly save low-level and high-level documentation names */ + Setattr(n, "doc:low:name", mrename); + Setattr(n, "doc:high:name", symname); + + if (cb) { + String *cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", Swig_name_member(NSpace, ClassPrefix, cbname)); + Setattr(n, "feature:callback:staticname", name); + } + Delattr(n, "storage"); + + globalfunctionHandler(n); + + Delete(cname); + Delete(mrename); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::variableHandler() + * ---------------------------------------------------------------------- */ + +int Language::variableHandler(Node *n) { + + /* If not a smart-pointer access or added method. We clear + feature:except. There is no way C++ or C would throw + an exception merely for accessing a member data. + + Caveat: Some compilers seem to route attribute access through + methods which can generate exceptions. The feature:allowexcept + allows this. Also, the feature:exceptvar can be used to match + only variables. + */ + if (!(Extend | SmartPointer)) { + if (!GetFlag(n, "feature:allowexcept")) { + UnsetFlag(n, "feature:except"); + } + if (Getattr(n, "feature:exceptvar")) { + Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); + } + } + + if (!CurrentClass) { + globalvariableHandler(n); + } else { + Swig_save("variableHandler", n, "feature:immutable", NIL); + if (SmartPointer) { + /* If a smart-pointer and it's a constant access, we have to set immutable */ + if (!Getattr(CurrentClass, "allocate:smartpointermutable")) { + SetFlag(n, "feature:immutable"); + } + } + if (Swig_storage_isstatic(n) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"))) { + staticmembervariableHandler(n); + } else { + membervariableHandler(n); + } + Swig_restore(n); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::globalvariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::globalvariableHandler(Node *n) { + variableWrapper(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::membervariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::membervariableHandler(Node *n) { + + Swig_require("membervariableHandler", n, "*name", "*sym:name", "*type", NIL); + Swig_save("membervariableHandler", n, "parms", NIL); + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + + if (!AttributeFunctionGet) { + String *mname = Swig_name_member(0, ClassPrefix, symname); + String *mrename_get = Swig_name_get(NSpace, mname); + String *mrename_set = Swig_name_set(NSpace, mname); + Delete(mname); + + /* Create a function to set the value of the variable */ + + int assignable = is_assignable(n); + + if (SmartPointer) { + if (!Getattr(CurrentClass, "allocate:smartpointermutable")) { + assignable = 0; + } + } + + if (assignable) { + int make_set_wrapper = 1; + String *tm = 0; + String *target = 0; + if (!Extend) { + if (SmartPointer) { + if (Swig_storage_isstatic(n)) { + Node *sn = Getattr(n, "cplus:staticbase"); + String *base = Getattr(sn, "name"); + target = NewStringf("%s::%s", base, name); + } else { + String *pname = Swig_cparm_name(0, 0); + target = NewStringf("(*%s)->%s", pname, name); + Delete(pname); + } + } else { + String *pname = isNonVirtualProtectedAccess(n) ? NewString("darg") : Swig_cparm_name(0, 0); + target = NewStringf("%s->%s", pname, name); + Delete(pname); + } + + // This is an input type typemap lookup and so it should not use Node n + // otherwise qualification is done on the parameter name for the setter function + Parm *nin = NewParm(type, name, n); + tm = Swig_typemap_lookup("memberin", nin, target, 0); + Delete(nin); + } + + int flags = Extend | SmartPointer | use_naturalvar_mode(n); + if (isNonVirtualProtectedAccess(n)) + flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + + Swig_MembersetToFunction(n, ClassType, flags); + Setattr(n, "memberset", "1"); + if (!Extend) { + /* Check for a member in typemap here */ + + if (!tm) { + if (SwigType_isarray(type)) { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(type, 0)); + make_set_wrapper = 0; + } + } else { + String *pname0 = Swig_cparm_name(0, 0); + String *pname1 = Swig_cparm_name(0, 1); + Replace(tm, "$source", pname1, DOH_REPLACE_ANY); + Replace(tm, "$target", target, DOH_REPLACE_ANY); + Replace(tm, "$input", pname1, DOH_REPLACE_ANY); + Replace(tm, "$self", pname0, DOH_REPLACE_ANY); + Setattr(n, "wrap:action", tm); + Delete(tm); + Delete(pname0); + Delete(pname1); + } + Delete(target); + } + if (make_set_wrapper) { + Setattr(n, "sym:name", mrename_set); + functionWrapper(n); + } else { + SetFlag(n, "feature:immutable"); + } + /* Restore parameters */ + Setattr(n, "type", type); + Setattr(n, "name", name); + Setattr(n, "sym:name", symname); + Delattr(n, "memberset"); + + /* Delete all attached typemaps and typemap attributes */ + Iterator ki; + for (ki = First(n); ki.key; ki = Next(ki)) { + if (Strncmp(ki.key, "tmap:", 5) == 0) + Delattr(n, ki.key); + } + } + /* Emit get function */ + { + int flags = Extend | SmartPointer | use_naturalvar_mode(n); + if (isNonVirtualProtectedAccess(n)) + flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + Swig_MembergetToFunction(n, ClassType, flags); + Setattr(n, "sym:name", mrename_get); + Setattr(n, "memberget", "1"); + functionWrapper(n); + Delattr(n, "memberget"); + } + Delete(mrename_get); + Delete(mrename_set); + + } else { + + /* This code is used to support the attributefunction directive + where member variables are converted automagically to + accessor functions */ + +#if 0 + Parm *p; + String *gname; + SwigType *vty; + p = NewParm(type, 0, n); + gname = NewStringf(AttributeFunctionGet, symname); + if (!Extend) { + ActionFunc = Copy(Swig_cmemberget_call(name, type)); + cpp_member_func(Char(gname), Char(gname), type, 0); + Delete(ActionFunc); + } else { + String *cname = Swig_name_get(NSpace, name); + cpp_member_func(Char(cname), Char(gname), type, 0); + Delete(cname); + } + Delete(gname); + if (!GetFlag(n, "feature:immutable")) { + gname = NewStringf(AttributeFunctionSet, symname); + vty = NewString("void"); + if (!Extend) { + ActionFunc = Copy(Swig_cmemberset_call(name, type)); + cpp_member_func(Char(gname), Char(gname), vty, p); + Delete(ActionFunc); + } else { + String *cname = Swig_name_set(NSpace, name); + cpp_member_func(Char(cname), Char(gname), vty, p); + Delete(cname); + } + Delete(gname); + } + ActionFunc = 0; +#endif + } + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::staticmembervariableHandler(Node *n) { + Swig_require("staticmembervariableHandler", n, "*name", "*sym:name", "*type", "?value", NIL); + String *value = Getattr(n, "value"); + String *classname = !SmartPointer ? (isNonVirtualProtectedAccess(n) ? DirectorClassName : ClassName) : Getattr(CurrentClass, "allocate:smartpointerpointeeclassname"); + + if (!value || !Getattr(n, "hasconsttype")) { + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *cname, *mrename; + + /* Create the variable name */ + mrename = Swig_name_member(0, ClassPrefix, symname); + cname = NewStringf("%s::%s", classname, name); + + Setattr(n, "sym:name", mrename); + Setattr(n, "name", cname); + + /* Wrap as an ordinary global variable */ + variableWrapper(n); + + Delete(mrename); + Delete(cname); + } else { + + /* This is a C++ static member declaration with an initializer and it's const. + Certain C++ compilers optimize this out so that there is no linkage to a + memory address. Example: + + class Foo { + public: + static const int x = 3; + }; + + Some discussion of this in section 9.4 of the C++ draft standard. + + Also, we have to manage the case: + + class Foo { + public: + %extend { + static const int x = 3; + } + }; + + in which there's no actual Foo::x variable to refer to. In this case, + the best we can do is to wrap the given value verbatim. + */ + + + String *name = Getattr(n, "name"); + String *cname = NewStringf("%s::%s", classname, name); + if (Extend) { + /* the variable is a synthesized one. + There's nothing we can do; we just keep the given value */ + } else { + /* we refer to the value as Foo::x */ + String *value = SwigType_namestr(cname); + Setattr(n, "value", value); + } + + SwigType *t1 = SwigType_typedef_resolve_all(Getattr(n, "type")); + SwigType *t2 = SwigType_strip_qualifiers(t1); + Setattr(n, "type", t2); + Delete(t1); + Delete(t2); + SetFlag(n, "wrappedasconstant"); + memberconstantHandler(n); + Delete(cname); + } + + Swig_restore(n); + return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::externDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::externDeclaration(Node *n) { + return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::enumDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumDeclaration(Node *n) { + if (CurrentClass && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *oldNSpace = NSpace; + NSpace = Getattr(n, "sym:nspace"); + + String *oldEnumClassPrefix = EnumClassPrefix; + if (GetFlag(n, "scopedenum")) { + assert(Getattr(n, "sym:name")); + assert(Getattr(n, "name")); + EnumClassPrefix = ClassPrefix ? NewStringf("%s_", ClassPrefix) : NewString(""); + Printv(EnumClassPrefix, Getattr(n, "sym:name"), NIL); + EnumClassName = Copy(Getattr(n, "name")); + } + if (!ImportMode) { + emit_children(n); + } + + if (GetFlag(n, "scopedenum")) { + Delete(EnumClassName); + EnumClassName = 0; + Delete(EnumClassPrefix); + EnumClassPrefix = oldEnumClassPrefix; + } + NSpace = oldNSpace; + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumvalueDeclaration(Node *n) { + if (CurrentClass && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "*sym:name", "?value", NIL); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + Setattr(n, "value", tmpValue); + + Node *parent = parentNode(n); + if (GetFlag(parent, "scopedenum")) { + String *symname = Swig_name_member(0, Getattr(parent, "sym:name"), Getattr(n, "sym:name")); + Setattr(n, "sym:name", symname); + Delete(symname); + } + + if (!CurrentClass || !cparse_cplusplus) { + Setattr(n, "name", tmpValue); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + } else { + memberconstantHandler(n); + } + + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumforwardDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumforwardDeclaration(Node *n) { + (void) n; + if (GetFlag(n, "enumMissing")) + enumDeclaration(n); // Generate an empty enum in target language + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::memberconstantHandler() + * ----------------------------------------------------------------------------- */ + +int Language::memberconstantHandler(Node *n) { + + Swig_require("memberconstantHandler", n, "*name", "*sym:name", "value", NIL); + + if (!GetFlag(n, "feature:allowexcept")) { + UnsetFlag(n, "feature:except"); + } + if (Getattr(n, "feature:exceptvar")) { + Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); + } + + String *enumvalue_symname = Getattr(n, "enumvalueDeclaration:sym:name"); // Only set if a strongly typed enum + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + + String *mrename = Swig_name_member(0, EnumClassPrefix, enumvalue_symname ? enumvalue_symname : symname); + Setattr(n, "sym:name", mrename); + + String *new_name = 0; + if (Extend) + new_name = Copy(value); + else if (EnumClassName) + new_name = NewStringf("%s::%s", isNonVirtualProtectedAccess(n) ? DirectorClassName : EnumClassName, name); + else + new_name = NewStringf("%s::%s", isNonVirtualProtectedAccess(n) ? DirectorClassName : ClassName, name); + Setattr(n, "name", new_name); + + constantWrapper(n); + Delete(mrename); + Delete(new_name); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typedefHandler() + * ---------------------------------------------------------------------- */ + +int Language::typedefHandler(Node *n) { + /* since this is a recurring issue, we are going to remember the + typedef pointer, if already it is not a pointer or reference, as + in + + typedef void NT; + int func(NT *p); + + see director_basic.i for example. + */ + SwigType *name = Getattr(n, "name"); + SwigType *decl = Getattr(n, "decl"); + if (!SwigType_ispointer(decl) && !SwigType_isreference(decl)) { + SwigType *pname = Copy(name); + SwigType_add_pointer(pname); + SwigType_remember(pname); + Delete(pname); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethod() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethod(Node *n, Node *parent, String *super) { + (void) n; + (void) parent; + (void) super; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructor(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDefaultConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDefaultConstructor(Node *n) { + (void) n; + return SWIG_OK; +} + +static String *vtable_method_id(Node *n) { + String *nodeType = Getattr(n, "nodeType"); + int is_destructor = (Cmp(nodeType, "destructor") == 0); + if (is_destructor) + return 0; + String *name = Getattr(n, "name"); + String *decl = Getattr(n, "decl"); + String *local_decl = SwigType_typedef_resolve_all(decl); + String *tmp = SwigType_pop_function(local_decl); + Delete(local_decl); + local_decl = tmp; + Node *method_id = NewStringf("%s|%s", name, local_decl); + Delete(local_decl); + return method_id; +} + + +/* ---------------------------------------------------------------------- + * Language::unrollVirtualMethods() + * ---------------------------------------------------------------------- */ +int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_director, int &virtual_destructor, int protectedbase) { + Node *ni; + String *nodeType; + String *classname; + String *decl; + bool first_base = false; + // recurse through all base classes to build the vtable + List *bl = Getattr(n, "bases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + if (first_base && !director_multiple_inheritance) + break; + unrollVirtualMethods(bi.item, parent, vm, default_director, virtual_destructor); + first_base = true; + } + } + // recurse through all protected base classes to build the vtable, as needed + bl = Getattr(n, "protectedbases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + if (first_base && !director_multiple_inheritance) + break; + unrollVirtualMethods(bi.item, parent, vm, default_director, virtual_destructor, 1); + first_base = true; + } + } + // find the methods that need directors + classname = Getattr(n, "name"); + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + /* we only need to check the virtual members */ + nodeType = Getattr(ni, "nodeType"); + int is_using = (Cmp(nodeType, "using") == 0); + Node *nn = is_using ? firstChild(ni) : ni; /* assume there is only one child node for "using" nodes */ + if (is_using) { + if (nn) + nodeType = Getattr(nn, "nodeType"); + else + continue; // A private "using" node + } + if (!checkAttribute(nn, "storage", "virtual")) + continue; + if (GetFlag(nn, "final")) + continue; + /* we need to add methods(cdecl) and destructor (to check for throw decl) */ + int is_destructor = (Cmp(nodeType, "destructor") == 0); + if ((Cmp(nodeType, "cdecl") == 0) || is_destructor) { + decl = Getattr(nn, "decl"); + /* extra check for function type and proper access */ + if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(nn)) || need_nonpublic_member(nn))) { + String *name = Getattr(nn, "name"); + Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(nn); + /* Make sure that the new method overwrites the existing: */ + int len = Len(vm); + const int DO_NOT_REPLACE = -1; + int replace = DO_NOT_REPLACE; + for (int i = 0; i < len; i++) { + Node *item = Getitem(vm, i); + String *check_vmid = Getattr(item, "vmid"); + + if (Strcmp(method_id, check_vmid) == 0) { + replace = i; + break; + } + } + /* filling a new method item */ + String *fqdname = NewStringf("%s::%s", classname, name); + Hash *item = NewHash(); + Setattr(item, "fqdname", fqdname); + Node *m = Copy(nn); + + /* Store the complete return type - needed for non-simple return types (pointers, references etc.) */ + SwigType *ty = NewString(Getattr(m, "type")); + SwigType_push(ty, decl); + if (SwigType_isqualifier(ty)) { + Delete(SwigType_pop(ty)); + } + Delete(SwigType_pop_function(ty)); + Setattr(m, "returntype", ty); + + String *mname = NewStringf("%s::%s", Getattr(parent, "name"), name); + /* apply the features of the original method found in the base class */ + Swig_features_get(Swig_cparse_features(), 0, mname, Getattr(m, "decl"), m); + Setattr(item, "methodNode", m); + Setattr(item, "vmid", method_id); + if (replace == DO_NOT_REPLACE) + Append(vm, item); + else + Setitem(vm, replace, item); + Setattr(nn, "directorNode", m); + + Delete(mname); + } + if (is_destructor) { + virtual_destructor = 1; + } + } + } + + /* + We delete all the nodirector methods. This prevents the + generation of 'empty' director classes. + + But this has to be done outside the previous 'for' + and the recursive loop!. + */ + if (n == parent) { + int len = Len(vm); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vm, i); + Node *m = Getattr(item, "methodNode"); + /* retrieve the director features */ + int mdir = GetFlag(m, "feature:director"); + int mndir = GetFlag(m, "feature:nodirector"); + /* 'nodirector' has precedence over 'director' */ + int dir = (mdir || mndir) ? (mdir && !mndir) : 1; + /* check if the method was found only in a base class */ + Node *p = Getattr(m, "parentNode"); + if (p != n) { + Node *c = Copy(m); + Setattr(c, "parentNode", n); + int cdir = GetFlag(c, "feature:director"); + int cndir = GetFlag(c, "feature:nodirector"); + dir = (cdir || cndir) ? (cdir && !cndir) : dir; + Delete(c); + } + if (dir) { + /* be sure the 'nodirector' feature is disabled */ + if (mndir) + Delattr(m, "feature:nodirector"); + } else { + /* or just delete from the vm, since is not a director method */ + Delitem(vm, i); + len--; + i--; + } + } + } + + return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::classDirectorDisown() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDisown(Node *n) { + Node *disown = NewHash(); + String *mrename; + String *symname = Getattr(n, "sym:name"); + mrename = Swig_name_disown(NSpace, symname); + String *type = NewString(ClassType); + String *name = NewString("self"); + SwigType_add_pointer(type); + Parm *p = NewParm(type, name, n); + Delete(name); + Delete(type); + type = NewString("void"); + String *action = NewString(""); + Printv(action, "{\n", "Swig::Director *director = SWIG_DIRECTOR_CAST(arg1);\n", "if (director) director->swig_disown();\n", "}\n", NULL); + Setfile(disown, Getfile(n)); + Setline(disown, Getline(n)); + Setattr(disown, "wrap:action", action); + Setattr(disown, "name", mrename); + Setattr(disown, "sym:name", mrename); + Setattr(disown, "type", type); + Setattr(disown, "parms", p); + Delete(action); + Delete(mrename); + Delete(type); + Delete(p); + + functionWrapper(disown); + Delete(disown); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructors() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructors(Node *n) { + Node *ni; + String *nodeType; + Node *parent = Swig_methodclass(n); + int default_ctor = Getattr(parent, "allocate:default_constructor") ? 1 : 0; + int protected_ctor = 0; + int constructor = 0; + + /* emit constructors */ + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + nodeType = Getattr(ni, "nodeType"); + if (Cmp(nodeType, "constructor") == 0) { + if (GetFlag(ni, "feature:ignore")) + continue; + + Parm *parms = Getattr(ni, "parms"); + if (is_public(ni)) { + /* emit public constructor */ + classDirectorConstructor(ni); + constructor = 1; + if (default_ctor) + default_ctor = !ParmList_numrequired(parms); + } else { + /* emit protected constructor if needed */ + if (need_nonpublic_ctor(ni)) { + classDirectorConstructor(ni); + constructor = 1; + protected_ctor = 1; + if (default_ctor) + default_ctor = !ParmList_numrequired(parms); + } + } + } + } + /* emit default constructor if needed */ + if (!constructor) { + if (!default_ctor) { + /* we get here because the class has no public, protected or + default constructor, therefore, the director class can't be + created, ie, is kind of abstract. */ + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), "Director class '%s' can't be constructed\n", SwigType_namestr(Getattr(n, "name"))); + return SWIG_OK; + } + classDirectorDefaultConstructor(n); + default_ctor = 1; + } + /* this is just to support old java behavior, ie, the default + constructor is always emitted, even when protected, and not + needed, since there is a public constructor already defined. + + (scottm) This code is needed here to make the director_abstract + + test generate compilable code (Example2 in director_abstract.i). + + (mmatus) This is very strange, since swig compiled with gcc3.2.3 + doesn't need it here.... + */ + if (!default_ctor && !protected_ctor) { + if (Getattr(parent, "allocate:default_base_constructor")) { + classDirectorDefaultConstructor(n); + } + } + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethods() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethods(Node *n) { + Node *vtable = Getattr(n, "vtable"); + + int len = Len(vtable); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vtable, i); + String *method = Getattr(item, "methodNode"); + String *fqdname = Getattr(item, "fqdname"); + if (GetFlag(method, "feature:nodirector") || GetFlag(method, "final")) + continue; + + String *wrn = Getattr(method, "feature:warnfilter"); + if (wrn) + Swig_warnfilter(wrn, 1); + + String *type = Getattr(method, "nodeType"); + if (!Cmp(type, "destructor")) { + classDirectorDestructor(method); + } else { + Swig_require("classDirectorMethods", method, "*type", NIL); + assert(Getattr(method, "returntype")); + Setattr(method, "type", Getattr(method, "returntype")); + if (classDirectorMethod(method, n, fqdname) == SWIG_OK) + SetFlag(item, "director"); + Swig_restore(method); + } + if (wrn) + Swig_warnfilter(wrn, 0); + } + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorInit() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorInit(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDestructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDestructor(Node *n) { + /* + Always emit the virtual destructor in the declaration and in the + compilation unit. Been explicit here can't make any damage, and + can solve some nasty C++ compiler problems. + */ + File *f_directors = Swig_filebyname("director"); + File *f_directors_h = Swig_filebyname("director_h"); + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~%s() throw();\n", DirectorClassName); + Printf(f_directors, "%s::~%s() throw() {\n}\n\n", DirectorClassName, DirectorClassName); + } else { + Printf(f_directors_h, " virtual ~%s();\n", DirectorClassName); + Printf(f_directors, "%s::~%s() {\n}\n\n", DirectorClassName, DirectorClassName); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorEnd() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorEnd(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirector() + * ---------------------------------------------------------------------- */ + +int Language::classDirector(Node *n) { + Node *module = Getattr(n, "module"); + String *classtype = Getattr(n, "classtype"); + Hash *directormap = 0; + if (module) { + directormap = Getattr(module, "wrap:directormap"); + if (directormap == 0) { + directormap = NewHash(); + Setattr(module, "wrap:directormap", directormap); + } + } + List *vtable = NewList(); + int virtual_destructor = 0; + unrollVirtualMethods(n, n, vtable, 0, virtual_destructor); + + // Emit all the using base::member statements for non virtual members (allprotected mode) + Node *ni; + String *using_protected_members_code = NewString(""); + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + Node *nodeType = Getattr(ni, "nodeType"); + if (Cmp(nodeType, "destructor") == 0 && GetFlag(ni, "final")) { + String *classtype = Getattr(n, "classtype"); + SWIG_WARN_NODE_BEGIN(ni); + Swig_warning(WARN_LANG_DIRECTOR_FINAL, input_file, line_number, "Destructor %s is final, %s cannot be a director class.\n", Swig_name_decl(ni), classtype); + SWIG_WARN_NODE_END(ni); + SetFlag(n, "feature:nodirector"); + Delete(vtable); + Delete(using_protected_members_code); + return SWIG_OK; + } + bool cdeclaration = (Cmp(nodeType, "cdecl") == 0); + if (cdeclaration && !GetFlag(ni, "feature:ignore")) { + if (isNonVirtualProtectedAccess(ni)) { + Node *overloaded = Getattr(ni, "sym:overloaded"); + // emit the using base::member statement (but only once if the method is overloaded) + if (!overloaded || (overloaded && (overloaded == ni))) + Printf(using_protected_members_code, " using %s::%s;\n", SwigType_namestr(ClassName), Getattr(ni, "name")); + } + } + } + + if (virtual_destructor || Len(vtable) > 0) { + if (!virtual_destructor) { + String *classtype = Getattr(n, "classtype"); + Swig_warning(WARN_LANG_DIRECTOR_VDESTRUCT, input_file, line_number, "Director base class %s has no virtual destructor.\n", classtype); + } + + Setattr(n, "vtable", vtable); + if (directormap != 0) { + Setattr(directormap, classtype, n); + } + classDirectorInit(n); + classDirectorConstructors(n); + classDirectorMethods(n); + + File *f_directors_h = Swig_filebyname("director_h"); + Printv(f_directors_h, using_protected_members_code, NIL); + + classDirectorEnd(n); + } + Delete(vtable); + Delete(using_protected_members_code); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDeclaration() + * ---------------------------------------------------------------------- */ + +static void addCopyConstructor(Node *n) { + Node *cn = NewHash(); + set_nodeType(cn, "constructor"); + Setattr(cn, "access", "public"); + Setfile(cn, Getfile(n)); + Setline(cn, Getline(n)); + + String *cname = Getattr(n, "name"); + SwigType *type = Copy(cname); + String *name = Swig_scopename_last(cname); + String *cc = NewStringf("r.q(const).%s", type); + String *decl = NewStringf("f(%s).", cc); + String *oldname = Getattr(n, "sym:name"); + + if (Getattr(n, "allocate:has_constructor")) { + // to work properly with '%rename Class', we must look + // for any other constructor in the class, which has not been + // renamed, and use its name as oldname. + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + const char *tag = Char(nodeType(c)); + if (strcmp(tag, "constructor") == 0) { + String *cname = Getattr(c, "name"); + String *csname = Getattr(c, "sym:name"); + String *clast = Swig_scopename_last(cname); + if (Equal(csname, clast)) { + oldname = csname; + break; + } + } + } + } + + String *symname = Swig_name_make(cn, cname, name, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + Parm *p = NewParm(cc, "other", n); + + Setattr(cn, "name", name); + Setattr(cn, "sym:name", symname); + SetFlag(cn, "feature:new"); + Setattr(cn, "decl", decl); + Setattr(cn, "parentNode", n); + Setattr(cn, "parms", p); + Setattr(cn, "copy_constructor", "1"); + + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); + Swig_symbol_setscope(oldscope); + + if (on == cn) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_copy_constructor", "1"); + Setattr(n, "copy_constructor_decl", decl); + Setattr(n, "allocate:copy_constructor", "1"); + Delete(access); + } + } + Delete(cn); + Delete(name); + Delete(decl); + Delete(symname); +} + +static void addDefaultConstructor(Node *n) { + Node *cn = NewHash(); + set_nodeType(cn, "constructor"); + Setattr(cn, "access", "public"); + Setfile(cn, Getfile(n)); + Setline(cn, Getline(n)); + + String *cname = Getattr(n, "name"); + String *name = Swig_scopename_last(cname); + String *decl = NewString("f()."); + String *oldname = Getattr(n, "sym:name"); + String *symname = Swig_name_make(cn, cname, name, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + Setattr(cn, "name", name); + Setattr(cn, "sym:name", symname); + SetFlag(cn, "feature:new"); + Setattr(cn, "decl", decl); + Setattr(cn, "parentNode", n); + Setattr(cn, "default_constructor", "1"); + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); + Swig_symbol_setscope(oldscope); + + if (on == cn) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_default_constructor", "1"); + Setattr(n, "allocate:default_constructor", "1"); + Delete(access); + } + } + Delete(cn); + Delete(name); + Delete(decl); + Delete(symname); +} + +static void addDestructor(Node *n) { + Node *cn = NewHash(); + set_nodeType(cn, "destructor"); + Setattr(cn, "access", "public"); + Setfile(cn, Getfile(n)); + Setline(cn, Getline(n)); + + String *cname = Getattr(n, "name"); + String *name = Swig_scopename_last(cname); + Insert(name, 0, "~"); + String *decl = NewString("f()."); + String *symname = Swig_name_make(cn, cname, name, decl, 0); + if (Strcmp(symname, "$ignore") != 0) { + String *possible_nonstandard_symname = NewStringf("~%s", Getattr(n, "sym:name")); + + Setattr(cn, "name", name); + Setattr(cn, "sym:name", symname); + Setattr(cn, "decl", "f()."); + Setattr(cn, "parentNode", n); + + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *nonstandard_destructor = Equal(possible_nonstandard_symname, symname) ? 0 : Swig_symbol_clookup(possible_nonstandard_symname, 0); + Node *on = Swig_symbol_add(symname, cn); + Swig_features_get(Swig_cparse_features(), Swig_symbol_qualifiedscopename(0), name, decl, cn); + Swig_symbol_setscope(oldscope); + + if (on == cn) { + // SWIG accepts a non-standard named destructor in %extend that uses a typedef for the destructor name + // For example: typedef struct X {} XX; %extend X { ~XX() {...} } + // Don't add another destructor if a nonstandard one has been declared + if (!nonstandard_destructor) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_destructor", "1"); + Setattr(n, "allocate:destructor", "1"); + Delete(access); + } + } + Delete(possible_nonstandard_symname); + } + Delete(cn); + Delete(name); + Delete(decl); + Delete(symname); +} + +int Language::classDeclaration(Node *n) { + String *ochildren = Getattr(n, "feature:onlychildren"); + if (ochildren) { + Setattr(n, "feature:emitonlychildren", ochildren); + emit_children(n); + Delattr(n, "feature:emitonlychildren"); + SetFlag(n, "feature:ignore"); + return SWIG_NOWRAP; + } + + // save class local variables for nested classes support + int oldInClass = InClass; + String *oldClassType = ClassType; + String *oldClassPrefix = ClassPrefix; + String *oldEnumClassPrefix = EnumClassPrefix; + String *oldClassName = ClassName; + String *oldDirectorClassName = DirectorClassName; + String *oldNSpace = NSpace; + Node *oldCurrentClass = CurrentClass; + int dir = 0; + + String *kind = Getattr(n, "kind"); + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *unnamed = Getattr(n, "unnamed"); + String *symname = Getattr(n, "sym:name"); + + int strip = CPlusPlus ? 1 : unnamed && tdname; + + if (cplus_mode != PUBLIC) + return SWIG_NOWRAP; + if (!name) { + Swig_warning(WARN_LANG_CLASS_UNNAMED, input_file, line_number, "Can't generate wrappers for unnamed struct/class.\n"); + return SWIG_NOWRAP; + } + + /* Check symbol name for template. If not renamed. Issue a warning */ + if (!validIdentifier(symname)) { + Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap class %s unless renamed to a valid identifier.\n", SwigType_namestr(symname)); + return SWIG_NOWRAP; + } + AccessMode oldAccessMode = cplus_mode; + Node *outerClass = Getattr(n, "nested:outer"); + if (outerClass && oldAccessMode != PUBLIC) + return SWIG_NOWRAP; + ClassName = Copy(name); + ClassPrefix = Copy(symname); + if (Cmp(kind, "class") == 0) { + cplus_mode = PRIVATE; + } else { + cplus_mode = PUBLIC; + } + for (; outerClass; outerClass = Getattr(outerClass, "nested:outer")) { + Push(ClassPrefix, "_"); + Push(ClassPrefix, Getattr(outerClass, "sym:name")); + } + EnumClassPrefix = Copy(ClassPrefix); + if (strip) { + ClassType = Copy(name); + } else { + ClassType = NewStringf("%s %s", kind, name); + } + Setattr(n, "classtypeobj", Copy(ClassType)); + Setattr(n, "classtype", SwigType_namestr(ClassType)); + + InClass = 1; + CurrentClass = n; + NSpace = Getattr(n, "sym:nspace"); + int oldAbstract = Abstract; + + /* Call classHandler() here */ + if (!ImportMode) { + if (directorsEnabled()) { + int ndir = GetFlag(n, "feature:director"); + int nndir = GetFlag(n, "feature:nodirector"); + /* 'nodirector' has precedence over 'director' */ + dir = (ndir || nndir) ? (ndir && !nndir) : 0; + } + int abstract = !dir && abstractClassTest(n); + int odefault = (GenerateDefault && !GetFlag(n, "feature:nodefault")); + + /* default constructor */ + if (!abstract && !GetFlag(n, "feature:nodefaultctor") && odefault) { + if (!Getattr(n, "has_constructor") && !Getattr(n, "allocate:has_constructor") && (Getattr(n, "allocate:default_constructor"))) { + addDefaultConstructor(n); + } + } + /* copy constructor */ + if (CPlusPlus && !abstract && GetFlag(n, "feature:copyctor")) { + if (!Getattr(n, "has_copy_constructor") && !Getattr(n, "allocate:has_copy_constructor") + && (Getattr(n, "allocate:copy_constructor")) + && (!GetFlag(n, "feature:ignore"))) { + addCopyConstructor(n); + } + } + /* default destructor */ + if (!GetFlag(n, "feature:nodefaultdtor") && odefault) { + if (!Getattr(n, "has_destructor") && (!Getattr(n, "allocate:has_destructor")) + && (Getattr(n, "allocate:default_destructor")) + && (!GetFlag(n, "feature:ignore"))) { + addDestructor(n); + } + } + + if (dir) { + DirectorClassName = directorClassName(n); + classDirector(n); + } + /* check for abstract after resolving directors */ + + Abstract = abstractClassTest(n); + classHandler(n); + } else { + Abstract = abstractClassTest(n); + Language::classHandler(n); + } + + Abstract = oldAbstract; + cplus_mode = oldAccessMode; + NSpace = oldNSpace; + InClass = oldInClass; + CurrentClass = oldCurrentClass; + Delete(ClassType); + ClassType = oldClassType; + Delete(EnumClassPrefix); + EnumClassPrefix = oldEnumClassPrefix; + Delete(ClassPrefix); + ClassPrefix = oldClassPrefix; + Delete(ClassName); + ClassName = oldClassName; + if (dir) { + Delete(DirectorClassName); + } + DirectorClassName = oldDirectorClassName; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classHandler() + * ---------------------------------------------------------------------- */ + +int Language::classHandler(Node *n) { + save_value<int> oldExtend(Extend); + if (Getattr(n, "template")) + Extend = 0; + bool hasDirector = Swig_directorclass(n) ? true : false; + + /* Emit all of the class members */ + emit_children(n); + + /* Look for smart pointer handling */ + if (Getattr(n, "allocate:smartpointer")) { + List *methods = Getattr(n, "allocate:smartpointer"); + cplus_mode = PUBLIC; + SmartPointer = CWRAP_SMART_POINTER; + if (Getattr(n, "allocate:smartpointerconst") && Getattr(n, "allocate:smartpointermutable")) { + SmartPointer |= CWRAP_SMART_POINTER_OVERLOAD; + } + Iterator c; + for (c = First(methods); c.item; c = Next(c)) { + emit_one(c.item); + } + SmartPointer = 0; + } + + cplus_mode = PUBLIC; + + /* emit director disown method */ + if (hasDirector) { + classDirectorDisown(n); + + /* Emit additional protected virtual methods - only needed if the language module + * codes logic in the C++ layer instead of the director proxy class method - primarily + * to catch public use of protected methods by the scripting languages. */ + if (dirprot_mode() && extraDirectorProtectedCPPMethodsRequired()) { + Node *vtable = Getattr(n, "vtable"); + String *symname = Getattr(n, "sym:name"); + save_value<AccessMode> old_mode(cplus_mode); + cplus_mode = PROTECTED; + int len = Len(vtable); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vtable, i); + Node *method = Getattr(item, "methodNode"); + SwigType *type = Getattr(method, "nodeType"); + if (Strcmp(type, "cdecl") != 0) + continue; + if (GetFlag(method, "feature:ignore")) + continue; + String *methodname = Getattr(method, "sym:name"); + String *wrapname = NewStringf("%s_%s", symname, methodname); + if (!symbolLookup(wrapname, "") && (!is_public(method))) { + Node *m = Copy(method); + Setattr(m, "director", "1"); + Setattr(m, "parentNode", n); + /* + * There is a bug that needs fixing still... + * This area of code is creating methods which have not been overridden in a derived class (director methods that are protected in the base) + * If the method is overloaded, then Swig_overload_dispatch() incorrectly generates a call to the base wrapper, _wrap_xxx method + * See director_protected_overloaded.i - Possibly sym:overname needs correcting here. + Printf(stdout, "new method: %s::%s(%s)\n", Getattr(parentNode(m), "name"), Getattr(m, "name"), ParmList_str_defaultargs(Getattr(m, "parms"))); + */ + cDeclaration(m); + Delete(m); + } + Delete(wrapname); + } + } + } + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classforwardDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::classforwardDeclaration(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::constructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::constructorDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + + if (!symname) + return SWIG_NOWRAP; + if (!CurrentClass) + return SWIG_NOWRAP; + if (ImportMode) + return SWIG_NOWRAP; + + if (Extend) { + /* extend default constructor can be safely ignored if there is already one */ + int num_required = ParmList_numrequired(Getattr(n, "parms")); + if ((num_required == 0) && Getattr(CurrentClass, "has_default_constructor")) { + return SWIG_NOWRAP; + } + if ((num_required == 1) && Getattr(CurrentClass, "has_copy_constructor")) { + String *ccdecl = Getattr(CurrentClass, "copy_constructor_decl"); + if (ccdecl && (Strcmp(ccdecl, Getattr(n, "decl")) == 0)) { + return SWIG_NOWRAP; + } + } + } + + /* clean protected overloaded constructors, in case they are not needed anymore */ + Node *over = Swig_symbol_isoverloaded(n); + if (over && !Getattr(CurrentClass, "sym:cleanconstructor")) { + int dirclass = Swig_directorclass(CurrentClass); + Node *nn = over; + while (nn) { + if (!is_public(nn)) { + if (!dirclass || !need_nonpublic_ctor(nn)) { + SetFlag(nn, "feature:ignore"); + } + } + nn = Getattr(nn, "sym:nextSibling"); + } + clean_overloaded(over); + Setattr(CurrentClass, "sym:cleanconstructor", "1"); + } + + if ((cplus_mode != PUBLIC)) { + /* check only for director classes */ + if (!Swig_directorclass(CurrentClass) || !need_nonpublic_ctor(n)) + return SWIG_NOWRAP; + } + + /* Name adjustment for %name */ + Swig_save("constructorDeclaration", n, "sym:name", NIL); + + { + String *base = Swig_scopename_last(name); + if ((Strcmp(base, symname) == 0) && (Strcmp(symname, ClassPrefix) != 0)) { + Setattr(n, "sym:name", ClassPrefix); + } + Delete(base); + } + + /* Only create a constructor if the class is not abstract */ + if (!Abstract) { + Node *over; + over = Swig_symbol_isoverloaded(n); + if (over) + over = first_nontemplate(over); + if ((over) && (!overloading)) { + /* If the symbol is overloaded. We check to see if it is a copy constructor. If so, + we invoke copyconstructorHandler() as a special case. */ + if (Getattr(n, "copy_constructor") && (!Getattr(CurrentClass, "has_copy_constructor"))) { + copyconstructorHandler(n); + Setattr(CurrentClass, "has_copy_constructor", "1"); + } else { + if (Getattr(over, "copy_constructor")) + over = Getattr(over, "sym:nextSibling"); + if (over != n) { + Swig_warning(WARN_LANG_OVERLOAD_CONSTRUCT, input_file, line_number, + "Overloaded constructor ignored. %s\n", Swig_name_decl(n)); + Swig_warning(WARN_LANG_OVERLOAD_CONSTRUCT, Getfile(over), Getline(over), + "Previous declaration is %s\n", Swig_name_decl(over)); + } else { + constructorHandler(n); + } + } + } else { + String *expected_name = ClassName; + String *scope = Swig_scopename_check(ClassName) ? Swig_scopename_prefix(ClassName) : 0; + String *actual_name = scope ? NewStringf("%s::%s", scope, name) : NewString(name); + Delete(scope); + if (!Equal(actual_name, expected_name) && !SwigType_istemplate(expected_name) && !SwigType_istemplate(actual_name)) { + // Checking templates is skipped but they ought to be checked... they are just somewhat more tricky to check correctly + bool illegal_name = true; + if (Extend) { + // Check for typedef names used as a constructor name in %extend. This is deprecated except for anonymous + // typedef structs which have had their symbol names adjusted to the typedef name in the parser. + SwigType *name_resolved = SwigType_typedef_resolve_all(actual_name); + SwigType *expected_name_resolved = SwigType_typedef_resolve_all(expected_name); + + if (!CPlusPlus) { + if (Strncmp(name_resolved, "struct ", 7) == 0) + Replace(name_resolved, "struct ", "", DOH_REPLACE_FIRST); + else if (Strncmp(name_resolved, "union ", 6) == 0) + Replace(name_resolved, "union ", "", DOH_REPLACE_FIRST); + } + + illegal_name = !Equal(name_resolved, expected_name_resolved); + if (!illegal_name) + Swig_warning(WARN_LANG_EXTEND_CONSTRUCTOR, input_file, line_number, "Use of an illegal constructor name '%s' in %%extend is deprecated, the constructor name should be '%s'.\n", + SwigType_str(Swig_scopename_last(actual_name), 0), SwigType_str(Swig_scopename_last(expected_name), 0)); + Delete(name_resolved); + Delete(expected_name_resolved); + } + if (illegal_name) { + Swig_warning(WARN_LANG_RETURN_TYPE, input_file, line_number, "Function %s must have a return type. Ignored.\n", Swig_name_decl(n)); + Swig_restore(n); + return SWIG_NOWRAP; + } + } + constructorHandler(n); + } + } + Setattr(CurrentClass, "has_constructor", "1"); + + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * get_director_ctor_code() + * ---------------------------------------------------------------------- */ + +static String *get_director_ctor_code(Node *n, String *director_ctor_code, String *director_prot_ctor_code, List *&abstracts) { + String *director_ctor = director_ctor_code; + int use_director = Swig_directorclass(n); + if (use_director) { + Node *pn = Swig_methodclass(n); + abstracts = Getattr(pn, "abstracts"); + if (director_prot_ctor_code) { + int is_notabstract = GetFlag(pn, "feature:notabstract"); + int is_abstract = abstracts && !is_notabstract; + if (is_protected(n) || is_abstract) { + director_ctor = director_prot_ctor_code; + abstracts = Copy(abstracts); + Delattr(pn, "abstracts"); + } else { + if (is_notabstract) { + abstracts = Copy(abstracts); + Delattr(pn, "abstracts"); + } else { + abstracts = 0; + } + } + } + } + return director_ctor; +} + + +/* ---------------------------------------------------------------------- + * Language::constructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::constructorHandler(Node *n) { + Swig_require("constructorHandler", n, "?name", "*sym:name", "?type", "?parms", NIL); + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_construct(NSpace, symname); + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + List *abstracts = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstracts); + if (!constructor) { + /* if not originally a constructor, still handle it as one */ + Setattr(n, "handled_as_constructor", "1"); + } + + int extendmember = GetFlag(n, "isextendmember") ? Extend : 0; + int flags = Getattr(n, "template") ? extendmember : Extend; + Swig_ConstructorToFunction(n, NSpace, ClassType, none_comparison, director_ctor, CPlusPlus, flags, DirectorClassName); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + if (abstracts) + Setattr(Swig_methodclass(n), "abstracts", abstracts); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::copyconstructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::copyconstructorHandler(Node *n) { + Swig_require("copyconstructorHandler", n, "?name", "*sym:name", "?type", "?parms", NIL); + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_copyconstructor(NSpace, symname); + List *abstracts = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstracts); + Swig_ConstructorToFunction(n, NSpace, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 : Extend, DirectorClassName); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + if (abstracts) + Setattr(Swig_methodclass(n), "abstracts", abstracts); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::destructorDeclaration(Node *n) { + + if (!CurrentClass) + return SWIG_NOWRAP; + if (cplus_mode != PUBLIC && !Getattr(CurrentClass, "feature:unref")) + return SWIG_NOWRAP; + if (ImportMode) + return SWIG_NOWRAP; + + Swig_save("destructorDeclaration", n, "name", "sym:name", NIL); + + char *c = GetChar(n, "sym:name"); + if (c && (*c == '~')) { + Setattr(n, "sym:name", c + 1); + } + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + + if ((Strcmp(name, symname) == 0) || (Strcmp(symname, ClassPrefix) != 0)) { + Setattr(n, "sym:name", ClassPrefix); + } + + String *expected_name = ClassName; + String *scope = Swig_scopename_check(ClassName) ? Swig_scopename_prefix(ClassName) : 0; + String *actual_name = scope ? NewStringf("%s::%s", scope, name) : NewString(name); + Delete(scope); + Replace(actual_name, "~", "", DOH_REPLACE_FIRST); + if (!Equal(actual_name, expected_name) && !(Getattr(n, "template"))) { + bool illegal_name = true; + if (Extend) { + // Check for typedef names used as a destructor name in %extend. This is deprecated except for anonymous + // typedef structs which have had their symbol names adjusted to the typedef name in the parser. + SwigType *name_resolved = SwigType_typedef_resolve_all(actual_name); + SwigType *expected_name_resolved = SwigType_typedef_resolve_all(expected_name); + + if (!CPlusPlus) { + if (Strncmp(name_resolved, "struct ", 7) == 0) + Replace(name_resolved, "struct ", "", DOH_REPLACE_FIRST); + else if (Strncmp(name_resolved, "union ", 6) == 0) + Replace(name_resolved, "union ", "", DOH_REPLACE_FIRST); + } + + illegal_name = !Equal(name_resolved, expected_name_resolved); + if (!illegal_name) + Swig_warning(WARN_LANG_EXTEND_DESTRUCTOR, input_file, line_number, "Use of an illegal destructor name '%s' in %%extend is deprecated, the destructor name should be '%s'.\n", + SwigType_str(Swig_scopename_last(actual_name), 0), SwigType_str(Swig_scopename_last(expected_name), 0)); + Delete(name_resolved); + Delete(expected_name_resolved); + } + + if (illegal_name) { + Swig_warning(WARN_LANG_ILLEGAL_DESTRUCTOR, input_file, line_number, "Illegal destructor name %s. Ignored.\n", Swig_name_decl(n)); + Swig_restore(n); + return SWIG_NOWRAP; + } + } + destructorHandler(n); + + Setattr(CurrentClass, "has_destructor", "1"); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::destructorHandler(Node *n) { + Swig_require("destructorHandler", n, "?name", "*sym:name", NIL); + Swig_save("destructorHandler", n, "type", "parms", NIL); + + String *symname = Getattr(n, "sym:name"); + String *mrename; + char *csymname = Char(symname); + if (*csymname == '~') + csymname += 1; + + mrename = Swig_name_destroy(NSpace, csymname); + + Swig_DestructorToFunction(n, NSpace, ClassType, CPlusPlus, Extend); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::accessDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::accessDeclaration(Node *n) { + String *kind = Getattr(n, "kind"); + if (Cmp(kind, "public") == 0) { + cplus_mode = PUBLIC; + } else if (Cmp(kind, "private") == 0) { + cplus_mode = PRIVATE; + } else if (Cmp(kind, "protected") == 0) { + cplus_mode = PROTECTED; + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::namespaceDeclaration() + * ----------------------------------------------------------------------------- */ + +int Language::namespaceDeclaration(Node *n) { + if (Getattr(n, "alias")) + return SWIG_OK; + if (Getattr(n, "unnamed")) + return SWIG_OK; + emit_children(n); + return SWIG_OK; +} + +int Language::validIdentifier(String *s) { + char *c = Char(s); + while (*c) { + if (!(isalnum(*c) || (*c == '_'))) + return 0; + c++; + } + return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::usingDeclaration() + * ----------------------------------------------------------------------------- */ + +int Language::usingDeclaration(Node *n) { + if ((cplus_mode == PUBLIC) || (!is_public(n) && dirprot_mode())) { + Node *np = Copy(n); + Node *c; + for (c = firstChild(np); c; c = nextSibling(c)) { + /* it seems for some cases this is needed, like A* A::boo() */ + if (CurrentClass) + Setattr(c, "parentNode", CurrentClass); + emit_one(c); + } + Delete(np); + } + return SWIG_OK; +} + +/* Stubs. Language modules need to implement these */ + +/* ---------------------------------------------------------------------- + * Language::constantWrapper() + * ---------------------------------------------------------------------- */ + +int Language::constantWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *str = SwigType_str(type, name); + Printf(stdout, "constantWrapper : %s = %s\n", str, value); + Delete(str); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::variableWrapper() + * ---------------------------------------------------------------------- */ + +int Language::variableWrapper(Node *n) { + Swig_require("variableWrapper", n, "*name", "*sym:name", "*type", "?parms", "?varset", "?varget", NIL); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + + Delattr(n,"varset"); + Delattr(n,"varget"); + + String *newsymname = 0; + if (!CurrentClass && EnumClassPrefix) { + newsymname = Swig_name_member(0, EnumClassPrefix, symname); + symname = newsymname; + } + + /* If no way to set variables. We simply create functions */ + int assignable = is_assignable(n); + int flags = use_naturalvar_mode(n); + if (!GetFlag(n, "wrappedasconstant")) + flags = flags | Extend; + + if (assignable) { + int make_set_wrapper = 1; + String *tm = Swig_typemap_lookup("globalin", n, name, 0); + + Swig_VarsetToFunction(n, flags); + String *sname = Swig_name_set(NSpace, symname); + Setattr(n, "sym:name", sname); + Delete(sname); + + if (!tm) { + if (SwigType_isarray(type)) { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(type, 0)); + make_set_wrapper = 0; + } + } else { + String *pname0 = Swig_cparm_name(0, 0); + Replace(tm, "$source", pname0, DOH_REPLACE_ANY); + Replace(tm, "$target", name, DOH_REPLACE_ANY); + Replace(tm, "$input", pname0, DOH_REPLACE_ANY); + Setattr(n, "wrap:action", tm); + Delete(tm); + Delete(pname0); + } + if (make_set_wrapper) { + Setattr(n, "varset", "1"); + functionWrapper(n); + } else { + SetFlag(n, "feature:immutable"); + } + /* Restore parameters */ + Setattr(n, "sym:name", symname); + Setattr(n, "type", type); + Setattr(n, "name", name); + Delattr(n, "varset"); + + /* Delete all attached typemaps and typemap attributes */ + Iterator ki; + for (ki = First(n); ki.key; ki = Next(ki)) { + if (Strncmp(ki.key, "tmap:", 5) == 0) + Delattr(n, ki.key); + } + } + + Swig_VargetToFunction(n, flags); + String *gname = Swig_name_get(NSpace, symname); + Setattr(n, "sym:name", gname); + Delete(gname); + Setattr(n, "varget", "1"); + functionWrapper(n); + Delattr(n, "varget"); + Swig_restore(n); + Delete(newsymname); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::functionWrapper() + * ---------------------------------------------------------------------- */ + +int Language::functionWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + + Printf(stdout, "functionWrapper : %s\n", SwigType_str(type, NewStringf("%s(%s)", name, ParmList_str_defaultargs(parms)))); + Printf(stdout, " action : %s\n", Getattr(n, "wrap:action")); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::nativeWrapper() + * ----------------------------------------------------------------------------- */ + +int Language::nativeWrapper(Node *n) { + (void) n; + return SWIG_OK; +} + +void Language::main(int argc, char *argv[]) { + (void) argc; + (void) argv; +} + +/* ----------------------------------------------------------------------------- + * Language::addSymbol() + * + * Adds a symbol entry into the target language symbol tables. + * Returns 1 if the symbol is added successfully. + * Prints an error message and returns 0 if a conflict occurs. + * The scope is optional for target languages and if supplied must be a fully + * qualified scope and the symbol s must not contain any scope qualifiers. + * ----------------------------------------------------------------------------- */ + +int Language::addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { + //Printf( stdout, "addSymbol: %s %s\n", s, scope ); + Hash *symbols = Getattr(symtabs, scope ? scope : ""); + if (!symbols) { + symbols = symbolAddScope(scope); + } else { + Node *c = Getattr(symbols, s); + if (c && (c != n)) { + if (scope && Len(scope) > 0) + Swig_error(input_file, line_number, "'%s' is multiply defined in the generated target language module in scope '%s'.\n", s, scope); + else + Swig_error(input_file, line_number, "'%s' is multiply defined in the generated target language module.\n", s); + Swig_error(Getfile(c), Getline(c), "Previous declaration of '%s'\n", s); + return 0; + } + } + Setattr(symbols, s, n); + return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::addInterfaceSymbol() + * + * Adds a symbol entry into the target language symbol tables - for the interface + * feature only. + * Returns 1 if the symbol is added successfully. + * The scope is as per addSymbol. + * ----------------------------------------------------------------------------- */ + +int Language::addInterfaceSymbol(const String *interface_name, Node *n, const_String_or_char_ptr scope) { + if (interface_name) { + Node *existing_symbol = symbolLookup(interface_name, scope); + if (existing_symbol) { + String *proxy_class_name = Getattr(n, "sym:name"); + Swig_error(input_file, line_number, "The interface feature name '%s' for proxy class '%s' is already defined in the generated target language module in scope '%s'.\n", + interface_name, proxy_class_name, scope); + Swig_error(Getfile(existing_symbol), Getline(existing_symbol), "Previous declaration of '%s'\n", interface_name); + return 0; + } + if (!addSymbol(interface_name, n, scope)) + return 0; + } + return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolAddScope() + * + * Creates a scope (symbols Hash) for given name. This method is auxiliary, + * you don't have to call it - addSymbols will lazily create scopes automatically. + * If scope with given name already exists, then do nothing. + * Returns newly created (or already existing) scope. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolAddScope(const_String_or_char_ptr scope) { + Hash *symbols = symbolScopeLookup(scope); + if(!symbols) { + // The order in which the following code is executed is important. In the Language + // constructor addScope("") is called to create a top level scope. + // Thus we must first add a symbols hash to symtab and only then add pseudo + // symbols to the top-level scope. + + // New scope which has not been added by the target language - lazily created. + symbols = NewHash(); + Setattr(symtabs, scope, symbols); + + // Add the new scope as a symbol in the top level scope. + // Alternatively the target language must add it in before attempting to add symbols into the scope. + const_String_or_char_ptr top_scope = ""; + Hash *topscope_symbols = Getattr(symtabs, top_scope); + Hash *pseudo_symbol = NewHash(); + Setattr(pseudo_symbol, "sym:scope", "1"); + Setattr(topscope_symbols, scope, pseudo_symbol); + } + return symbols; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolScopeLookup() + * + * Lookup and returns a symtable (hash) representing given scope. Hash contains + * all symbols in this scope. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolScopeLookup( const_String_or_char_ptr scope ) { + Hash *symbols = Getattr(symtabs, scope ? scope : ""); + return symbols; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolScopePseudoSymbolLookup() + * + * For every scope there is a special pseudo-symbol in the top scope (""). It + * exists solely to detect name clashes. This pseudo symbol may contain a few properties, + * but more could be added. This is also true for the top level scope (""). + * It contains a pseudo symbol with name "" (empty). Pseudo symbol contains the + * following properties: + * sym:scope = "1" - a flag that this is a scope pseudo symbol + * + * Pseudo symbols are a Hash*, not a Node*. + * There is no difference from symbolLookup() method except for signature + * and return type. + * ----------------------------------------------------------------------------- */ +Hash* Language::symbolScopePseudoSymbolLookup( const_String_or_char_ptr scope ) +{ + /* Getting top scope */ + const_String_or_char_ptr top_scope = ""; + Hash *symbols = Getattr(symtabs, top_scope); + return Getattr(symbols, scope); +} + +/* ----------------------------------------------------------------------------- + * Language::dumpSymbols() + * ----------------------------------------------------------------------------- */ + +void Language::dumpSymbols() { + Printf(stdout, "LANGUAGE SYMBOLS start =======================================\n"); + + Node *table = symtabs; + Iterator ki = First(table); + while (ki.key) { + String *k = ki.key; + Printf(stdout, "===================================================\n"); + Printf(stdout, "%s -\n", k); + { + Symtab *symtab = Getattr(table, k); + Iterator it = First(symtab); + while (it.key) { + String *symname = it.key; + Printf(stdout, " %s\n", symname); + it = Next(it); + } + } + ki = Next(ki); + } + + Printf(stdout, "LANGUAGE SYMBOLS finish =======================================\n"); +} + +/* ----------------------------------------------------------------------------- + * Language::symbolLookup() + * ----------------------------------------------------------------------------- */ + +Node *Language::symbolLookup(const String *s, const_String_or_char_ptr scope) { + Hash *symbols = Getattr(symtabs, scope ? scope : ""); + if (!symbols) { + return NULL; + } + return Getattr(symbols, s); +} + +/* ----------------------------------------------------------------------------- + * Language::classLookup() + * + * Tries to locate a class from a type definition + * ----------------------------------------------------------------------------- */ + +Node *Language::classLookup(const SwigType *s) { + static Hash *classtypes = 0; + + Node *n = 0; + + /* Look in hash of cached values */ + n = classtypes ? Getattr(classtypes, s) : 0; + if (!n) { + Symtab *stab = 0; + SwigType *ty1 = SwigType_typedef_resolve_all(s); + SwigType *ty2 = SwigType_strip_qualifiers(ty1); + + String *base = SwigType_base(ty2); + + Replaceall(base, "class ", ""); + Replaceall(base, "struct ", ""); + Replaceall(base, "union ", ""); + + if (strncmp(Char(base), "::", 2) == 0) { + String *oldbase = base; + base = NewString(Char(base) + 2); + Delete(oldbase); + } + + String *prefix = SwigType_prefix(ty2); + + /* Do a symbol table search on the base type */ + while (!n) { + Hash *nstab; + n = Swig_symbol_clookup(base, stab); + if (!n) + break; + if (Strcmp(nodeType(n), "class") == 0) + break; + Node *sibling = n; + while (sibling) { + sibling = Getattr(sibling, "csym:nextSibling"); + if (sibling && Strcmp(nodeType(sibling), "class") == 0) + break; + } + if (sibling) + break; + n = parentNode(n); + if (!n) + break; + nstab = Getattr(n, "sym:symtab"); + n = 0; + if ((!nstab) || (nstab == stab)) { + break; + } + stab = nstab; + } + if (n) { + /* Found a match. Look at the prefix. We only allow + the cases where we want a proxy class for the particular type */ + bool acceptable_prefix = + (Len(prefix) == 0) || // simple type (pass by value) + (Strcmp(prefix, "p.") == 0) || // pointer + (Strcmp(prefix, "r.") == 0) || // reference + (Strcmp(prefix, "z.") == 0) || // rvalue reference + SwigType_prefix_is_simple_1D_array(prefix); // Simple 1D array (not arrays of pointers/references) + // Also accept pointer by const reference, not non-const pointer reference + if (!acceptable_prefix && (Strcmp(prefix, "r.p.") == 0)) { + Delete(prefix); + prefix = SwigType_prefix(ty1); + acceptable_prefix = (Strncmp(prefix, "r.q(const", 9) == 0); + } + if (acceptable_prefix) { + SwigType *cs = Copy(s); + if (!classtypes) + classtypes = NewHash(); + Setattr(classtypes, cs, n); + Delete(cs); + } else { + n = 0; + } + } + Delete(prefix); + Delete(base); + Delete(ty2); + Delete(ty1); + } + if (n && (GetFlag(n, "feature:ignore") || Getattr(n, "feature:onlychildren"))) { + n = 0; + } + + return n; +} + +/* ----------------------------------------------------------------------------- + * Language::enumLookup() + * + * Finds and returns the Node containing the enum declaration for the (enum) + * type passed in. + * ----------------------------------------------------------------------------- */ + +Node *Language::enumLookup(SwigType *s) { + static Hash *enumtypes = 0; + + Node *n = 0; + + /* Look in hash of cached values */ + n = enumtypes ? Getattr(enumtypes, s) : 0; + if (!n) { + Symtab *stab = 0; + SwigType *lt = SwigType_ltype(s); + SwigType *ty1 = SwigType_typedef_resolve_all(lt); + SwigType *ty2 = SwigType_strip_qualifiers(ty1); + + String *base = SwigType_base(ty2); + + Replaceall(base, "enum ", ""); + String *prefix = SwigType_prefix(ty2); + + if (strncmp(Char(base), "::", 2) == 0) { + String *oldbase = base; + base = NewString(Char(base) + 2); + Delete(oldbase); + } + + /* Look for type in symbol table */ + while (!n) { + Hash *nstab; + n = Swig_symbol_clookup(base, stab); + if (!n) + break; + if (Equal(nodeType(n), "enum")) + break; + if (Equal(nodeType(n), "enumforward") && GetFlag(n, "enumMissing")) + break; + n = parentNode(n); + if (!n) + break; + nstab = Getattr(n, "sym:symtab"); + n = 0; + if ((!nstab) || (nstab == stab)) { + break; + } + stab = nstab; + } + if (n) { + /* Found a match. Look at the prefix. We only allow simple types. */ + if (Len(prefix) == 0) { /* Simple type */ + if (!enumtypes) + enumtypes = NewHash(); + Setattr(enumtypes, Copy(s), n); + } else { + n = 0; + } + } + Delete(prefix); + Delete(base); + Delete(ty2); + Delete(ty1); + Delete(lt); + } + if (n && (GetFlag(n, "feature:ignore"))) { + n = 0; + } + + return n; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_overloading() + * ----------------------------------------------------------------------------- */ + +void Language::allow_overloading(int val) { + overloading = val; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_multiple_input() + * ----------------------------------------------------------------------------- */ + +void Language::allow_multiple_input(int val) { + multiinput = val; +} + +/* ----------------------------------------------------------------------------- + * Language::enable_cplus_runtime_mode() + * ----------------------------------------------------------------------------- */ + +void Language::enable_cplus_runtime_mode() { + cplus_runtime = 1; +} + +/* ----------------------------------------------------------------------------- + * Language::cplus_runtime_mode() + * ----------------------------------------------------------------------------- */ + +int Language::cplus_runtime_mode() { + return cplus_runtime; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_directors() + * ----------------------------------------------------------------------------- */ + +void Language::allow_directors(int val) { + directors = val; +} + +/* ----------------------------------------------------------------------------- + * Language::directorsEnabled() + * ----------------------------------------------------------------------------- */ + +int Language::directorsEnabled() const { + return director_language && CPlusPlus && (directors || director_mode); +} + +/* ----------------------------------------------------------------------------- + * Language::allow_dirprot() + * ----------------------------------------------------------------------------- */ + +void Language::allow_dirprot(int val) { + director_protected_mode = val; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_allprotected() + * ----------------------------------------------------------------------------- */ + +void Language::allow_allprotected(int val) { + all_protected_mode = val; +} + +/* ----------------------------------------------------------------------------- + * Language::dirprot_mode() + * ----------------------------------------------------------------------------- */ + +int Language::dirprot_mode() const { + return directorsEnabled() ? director_protected_mode : 0; +} + +/* ----------------------------------------------------------------------------- + * Language::need_nonpublic_ctor() + * ----------------------------------------------------------------------------- */ + +int Language::need_nonpublic_ctor(Node *n) { + /* + detects when a protected constructor is needed, which is always + the case if 'dirprot' mode is used. However, if that is not the + case, we will try to strictly emit what is minimal to don't break + the generated, while preserving compatibility with java, which + always try to emit the default constructor. + + rules: + + - when dirprot mode is used, the protected constructors are + always needed. + + - the protected default constructor is always needed. + + - if dirprot mode is not used, the protected constructors will be + needed only if: + + - there is no any public constructor in the class, and + - there is no protected default constructor + + In that case, all the declared protected constructors are + needed since we don't know which one to pick up. + + Note: given all the complications here, I am always in favor to + always enable 'dirprot', since is the C++ idea of protected + members, and use %ignore for the method you don't want to add in + the director class. + */ + if (directorsEnabled()) { + if (is_protected(n)) { + if (dirprot_mode()) { + /* when using dirprot mode, the protected constructors are + always needed */ + return 1; + } else { + int is_default_ctor = !ParmList_numrequired(Getattr(n, "parms")); + if (is_default_ctor) { + /* the default protected constructor is always needed, for java compatibility */ + return 1; + } else { + /* check if there is a public constructor */ + Node *parent = Swig_methodclass(n); + int public_ctor = Getattr(parent, "allocate:default_constructor") + || Getattr(parent, "allocate:public_constructor"); + if (!public_ctor) { + /* if not, the protected constructor will be needed only + if there is no protected default constructor declared */ + int no_prot_default_ctor = !Getattr(parent, "allocate:default_base_constructor"); + return no_prot_default_ctor; + } + } + } + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Language::need_nonpublic_member() + * ----------------------------------------------------------------------------- */ +int Language::need_nonpublic_member(Node *n) { + if (directorsEnabled() && DirectorClassName) { + if (is_protected(n)) { + if (dirprot_mode()) { + /* when using dirprot mode, the protected members are always needed. */ + return 1; + } else { + /* if the method is pure virtual, we need it. */ + int pure_virtual = (Cmp(Getattr(n, "value"), "0") == 0); + return pure_virtual; + } + } + } + return 0; +} + + +/* ----------------------------------------------------------------------------- + * Language::is_smart_pointer() + * ----------------------------------------------------------------------------- */ + +int Language::is_smart_pointer() const { + return SmartPointer; +} + +/* ----------------------------------------------------------------------------- + * Language::makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ +String *Language::makeParameterName(Node *n, Parm *p, int arg_num, bool setter) const { + + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Check if parameter name is a duplicate. + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + + // If the parameter has no name at all or has a non-unique name, replace it with "argN". + if (!pn || count > 1) { + arg = NewStringf("arg%d", arg_num); + } else { + // Otherwise, try to use the original C name, but modify it if necessary to avoid conflicting with the language keywords. + arg = Swig_name_make(p, 0, pn, 0, 0); + } + + if (setter && Cmp(arg, "self") != 0) { + // Some languages (C#) insist on calling the input variable "value" while + // others (D, Java) could, in principle, use something different but this + // would require more work, and so we just use "value" for them too. + // For setters the parameter name sometimes includes C++ scope resolution which needs removing. + Delete(arg); + arg = NewString("value"); + } + + return arg; +} + +/* ----------------------------------------------------------------------------- + * Language::() + * ----------------------------------------------------------------------------- */ + +bool Language::isNonVirtualProtectedAccess(Node *n) const { + // Ideally is_non_virtual_protected_access() would contain all this logic, see + // comments therein about vtable. + return DirectorClassName && is_non_virtual_protected_access(n); +} + +/* ----------------------------------------------------------------------------- + * Language::extraDirectorProtectedCPPMethodsRequired() + * ----------------------------------------------------------------------------- */ + +bool Language::extraDirectorProtectedCPPMethodsRequired() const { + return true; +} + +/* ----------------------------------------------------------------------------- + * Language::nestedClassesSupport() + * ----------------------------------------------------------------------------- */ + +Language::NestedClassSupport Language::nestedClassesSupport() const { + return NCS_Unknown; +} + +/* ----------------------------------------------------------------------------- + * Language::kwargsSupport() + * ----------------------------------------------------------------------------- */ + +bool Language::kwargsSupport() const { + return false; +} + +/* ----------------------------------------------------------------------------- + * Language::is_wrapping_class() + * ----------------------------------------------------------------------------- */ + +int Language::is_wrapping_class() const { + return InClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getCurrentClass() + * ----------------------------------------------------------------------------- */ + +Node *Language::getCurrentClass() const { + return CurrentClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getNSpace() + * ----------------------------------------------------------------------------- */ + +String *Language::getNSpace() const { + return NSpace; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassName() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassName() const { + return ClassName; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassPrefix() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassPrefix() const { + return ClassPrefix; +} + +/* ----------------------------------------------------------------------------- + * Language::getEnumClassPrefix() + * ----------------------------------------------------------------------------- */ + +String *Language::getEnumClassPrefix() const { + return EnumClassPrefix; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassType() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassType() const { + return ClassType; +} + +/* ----------------------------------------------------------------------------- + * Language::abstractClassTest() + * ----------------------------------------------------------------------------- */ +//#define SWIG_DEBUG +int Language::abstractClassTest(Node *n) { + /* check for non public operator new */ + if (GetFlag(n, "feature:notabstract")) + return 0; + if (Getattr(n, "allocate:nonew")) + return 1; + + // A class cannot be instantiated if one of its bases has a private destructor + // Note that if the above does not hold the class can be instantiated if its own destructor is private + List *bases = Getattr(n, "bases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *b = Getitem(bases, i); + if (GetFlag(b, "allocate:private_destructor")) + return 1; + } + } + + /* now check for the rest */ + List *abstracts = Getattr(n, "abstracts"); + if (!abstracts) + return 0; + int labs = Len(abstracts); +#ifdef SWIG_DEBUG + List *allbases = Getattr(n, "allbases"); + Printf(stderr, "testing %s %d %d\n", Getattr(n, "name"), labs, Len(allbases)); +#endif + if (!labs) + return 0; /*strange, but need to be fixed */ + if (abstracts && !directorsEnabled()) + return 1; + if (!GetFlag(n, "feature:director")) + return 1; + + Node *dirabstract = 0; + Node *vtable = Getattr(n, "vtable"); + if (vtable) { +#ifdef SWIG_DEBUG + Printf(stderr, "vtable %s %d %d\n", Getattr(n, "name"), Len(vtable), labs); +#endif + for (int i = 0; i < labs; i++) { + Node *ni = Getitem(abstracts, i); + Node *method_id = vtable_method_id(ni); + if (!method_id) + continue; + bool exists_item = false; + int len = Len(vtable); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vtable, i); + String *check_item = Getattr(item, "vmid"); + if (Strcmp(method_id, check_item) == 0) { + exists_item = true; + break; + } + } +#ifdef SWIG_DEBUG + Printf(stderr, "method %s %d\n", method_id, exists_item ? 1 : 0); +#endif + Delete(method_id); + if (!exists_item) { + dirabstract = ni; + break; + } + } + if (dirabstract) { + if (is_public(dirabstract)) { + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), + "Director class '%s' is abstract, abstract method '%s' is not accessible, maybe due to multiple inheritance or 'nodirector' feature\n", + SwigType_namestr(Getattr(n, "name")), Getattr(dirabstract, "name")); + } else { + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), + "Director class '%s' is abstract, abstract method '%s' is private\n", SwigType_namestr(Getattr(n, "name")), Getattr(dirabstract, "name")); + } + return 1; + } + } else { + return 1; + } + return 0; +} + +void Language::setSubclassInstanceCheck(String *nc) { + none_comparison = nc; +} + +void Language::setOverloadResolutionTemplates(String *argc, String *argv) { + Delete(argc_template_string); + argc_template_string = Copy(argc); + Delete(argv_template_string); + argv_template_string = Copy(argv); +} + +int Language::is_assignable(Node *n) { + if (GetFlag(n, "feature:immutable")) + return 0; + SwigType *type = Getattr(n, "type"); + Node *cn = 0; + SwigType *ftd = SwigType_typedef_resolve_all(type); + SwigType *td = SwigType_strip_qualifiers(ftd); + if (SwigType_type(td) == T_USER) { + cn = Swig_symbol_clookup(td, 0); + if (cn) { + if ((Strcmp(nodeType(cn), "class") == 0)) { + if (Getattr(cn, "allocate:noassign")) { + SetFlag(n, "feature:immutable"); + Delete(ftd); + Delete(td); + return 0; + } + } + } + } + Delete(ftd); + Delete(td); + return 1; +} + +String *Language::runtimeCode() { + return NewString(""); +} + +String *Language::defaultExternalRuntimeFilename() { + return 0; +} + +/* ----------------------------------------------------------------------------- + * Language::replaceSpecialVariables() + * + * Language modules should implement this if special variables are to be handled + * correctly in the $typemap(...) special variable macro. + * method - typemap method name + * tm - string containing typemap contents + * parm - a parameter describing the typemap type to be handled + * ----------------------------------------------------------------------------- */ +void Language::replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + (void)tm; + (void)parm; +} + +Language *Language::instance() { + return this_; +} + +Hash *Language::getClassHash() const { + return classhash; +} + diff --git a/contrib/tools/swig/Source/Modules/lua.cxx b/contrib/tools/swig/Source/Modules/lua.cxx new file mode 100644 index 00000000000..188b11c2b0a --- /dev/null +++ b/contrib/tools/swig/Source/Modules/lua.cxx @@ -0,0 +1,2282 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * lua.cxx + * + * Lua language module for SWIG. + * ----------------------------------------------------------------------------- */ + +/* NEW LANGUAGE NOTE: + * ver001 + this is simply a copy of tcl8.cxx, which has been renamed + * ver002 + all non essential code commented out, program now does virtually nothing + it prints to stderr the list of functions to wrap, but does not create + the XXX_wrap.c file + * ver003 + added back top(), still prints the list of fns to stderr + but now creates a rather empty XXX_wrap.c with some basic boilerplate code + * ver004 + very basic version of functionWrapper() + also uncommented usage_string() to keep compiler happy + this will start producing proper looking code soon (I hope) + produced the wrapper code, but without any type conversion (in or out) + generates a few warning because of no wrappering + does not generate SWIG_init() + reason for this is that lua.swg is empty + we will need to add code into this to make it work + * ver005/6 + massive rework, basing work on the pike module instead of tcl + (pike module it only 1/3 of the size)(though not as complete) + * ver007 + added simple type checking + * ver008 + INPUT, OUTPUT, INOUT typemaps handled (though not all types yet) + * ver009 + class support: ok for basic types, but methods still TDB + (code is VERY messed up & needs to be cleaned) + * ver010 + Added support for embedded Lua. Try swig -lua -help for more information +*/ + +#include "swigmod.h" +#include "cparse.h" + +/**** Diagnostics: + With the #define REPORT(), you can change the amount of diagnostics given + This helps me search the parse tree & figure out what is going on inside SWIG + (because its not clear or documented) +*/ +#define REPORT(T,D) // no info: +//#define REPORT(T,D) {Printf(stdout,T"\n");} // only title +//#define REPORT(T,D) {Printf(stdout,T" %p\n",n);} // title & pointer +//#define REPORT(T,D) {Printf(stdout,T"\n");display_mapping(D);} // the works +//#define REPORT(T,D) {Printf(stdout,T"\n");if(D)Swig_print_node(D);} // the works + +void display_mapping(DOH *d) { + if (d == 0 || !DohIsMapping(d)) + return; + for (Iterator it = First(d); it.item; it = Next(it)) { + if (DohIsString(it.item)) + Printf(stdout, " %s = %s\n", it.key, it.item); + else if (DohIsMapping(it.item)) + Printf(stdout, " %s = <mapping>\n", it.key); + else if (DohIsSequence(it.item)) + Printf(stdout, " %s = <sequence>\n", it.key); + else + Printf(stdout, " %s = <unknown>\n", it.key); + } +} + +extern "C" +{ + static int compareByLen(const DOH *f, const DOH *s) { + return Len(s) - Len(f); + } +} + + +/* NEW LANGUAGE NOTE:*********************************************** + most of the default options are handled by SWIG + you can add new ones here + (though for now I have not bothered) +NEW LANGUAGE NOTE:END ************************************************/ +static const char *usage = "\ +Lua Options (available with -lua)\n\ + -elua - Generates LTR compatible wrappers for smaller devices running elua\n\ + -eluac - LTR compatible wrappers in \"crass compress\" mode for elua\n\ + -elua-emulate - Emulates behaviour of eLua. Useful only for testing.\n\ + Incompatible with -elua/-eluac options.\n\ + -nomoduleglobal - Do not register the module name as a global variable \n\ + but return the module table from calls to require.\n\ + -no-old-metatable-bindings\n\ + - Disable support for old-style bindings name generation, some\n\ + old-style members scheme etc.\n\ + -squash-bases - Squashes symbols from all inheritance tree of a given class\n\ + into itself. Emulates pre-SWIG3.0 inheritance. Insignificantly\n\ + speeds things up, but increases memory consumption.\n\ +\n"; + +static int nomoduleglobal = 0; +static int elua_ltr = 0; +static int eluac_ltr = 0; +static int elua_emulate = 0; +static int squash_bases = 0; +/* The new metatable bindings were introduced in SWIG 3.0.0. + * old_metatable_bindings in v2: + * 1. static methods will be put into the scope their respective class + * belongs to as well as into the class scope itself. (only for classes without %nspace given) + * 2. The layout in elua mode is somewhat different + */ +static int old_metatable_bindings = 1; +static int old_compatible_names = 1; // This flag can temporarily disable backward compatible names generation if old_metatable_bindings is enabled + +/* NEW LANGUAGE NOTE:*********************************************** + To add a new language, you need to derive your class from + Language and the overload various virtual functions + (more on this as I figure it out) +NEW LANGUAGE NOTE:END ************************************************/ + +class LUA:public Language { +private: + + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + String *s_luacode; // luacode to be called during init + String *module; //name of the module + + // Parameters for current class. NIL if not parsing class + int have_constructor; + int have_destructor; + String *destructor_action; + // This variable holds the name of the current class in Lua. Usually it is + // the same as C++ class name, but rename directives can change it. + String *proxy_class_name; + // This is a so called fully qualified symname - the above proxy class name + // prepended with class namespace. If class Lua name is the same as class C++ name, + // then it is basically C++ fully qualified name with colons replaced with dots. + String *full_proxy_class_name; + // All static methods and/or variables are treated as if they were in the + // special C++ namespace $(classname).SwigStatic. This is internal mechanism only + // and is not visible to user in any manner. This variable holds the name + // of such pseudo-namespace a.k.a the result of above expression evaluation + String *class_static_nspace; + // This variable holds the name of generated C function that acts as a constructor + // for the currently parsed class. + String *constructor_name; + + // Many wrappers forward calls to each other, for example staticmembervariableHandler + // forwards calls to variableHandler, which, in turn, makes to call to functionWrapper. + // In order to access information about whether it is a static member of class or just + // a plain old variable, the current array is kept and used as a 'log' of the call stack. + enum TState { + NO_CPP, + VARIABLE, + GLOBAL_FUNC, + GLOBAL_VAR, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + STATIC_FUNC, + STATIC_VAR, + STATIC_CONST, // enums and things like static const int x = 5; + ENUM_CONST, // This is only needed for backward compatibility in C mode + + STATES_COUNT + }; + bool current[STATES_COUNT]; + +public: + + /* --------------------------------------------------------------------- + * LUA() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + LUA(): + f_begin(0), + f_runtime(0), + f_header(0), + f_wrappers(0), + f_init(0), + f_initbeforefunc(0), + s_luacode(0), + module(0), + have_constructor(0), + have_destructor(0), + destructor_action(0), + proxy_class_name(0), + full_proxy_class_name(0), + class_static_nspace(0), + constructor_name(0) { + for (int i = 0; i < STATES_COUNT; i++) + current[i] = false; + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is called to initialise the system & read any command line args + most of this is boilerplate code, except the command line args + which depends upon what args your code supports + NEW LANGUAGE NOTE:END *********************************************** */ + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + /* Set location of SWIG library */ + SWIG_library_directory("lua"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { // usage flags + fputs(usage, stdout); + } else if (strcmp(argv[i], "-nomoduleglobal") == 0) { + nomoduleglobal = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-elua") == 0) { + elua_ltr = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-eluac") == 0) { + eluac_ltr = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-no-old-metatable-bindings") == 0) { + Swig_mark_arg(i); + old_metatable_bindings = 0; + } else if (strcmp(argv[i], "-squash-bases") == 0) { + Swig_mark_arg(i); + squash_bases = 1; + } else if (strcmp(argv[i], "-elua-emulate") == 0) { + Swig_mark_arg(i); + elua_emulate = 1; + } + } + } + + if (elua_emulate && (eluac_ltr || elua_ltr )) { + Printf(stderr, "Cannot have -elua-emulate with either -eluac or -elua\n"); + Swig_arg_error(); + } + + // Set elua_ltr if elua_emulate is requested + if(elua_emulate) + elua_ltr = 1; + + /* NEW LANGUAGE NOTE:*********************************************** + This is the boilerplate code, setting a few #defines + and which lib directory to use + the SWIG_library_directory() is also boilerplate code + but it always seems to be the first line of code + NEW LANGUAGE NOTE:END *********************************************** */ + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGLUA 1", 0); + + /* Set language-specific configuration file */ + SWIG_config_file("lua.swg"); + + /* Set typemap language */ + SWIG_typemap_lang("lua"); + + /* Enable overloaded methods support */ + allow_overloading(); + } + + + + + /* NEW LANGUAGE NOTE:*********************************************** + After calling main, SWIG parses the code to wrap (I believe) + then calls top() + in this is more boilerplate code to set everything up + and a call to Language::top() + which begins the code generations by calling the member fns + after all that is more boilerplate code to close all down + (overall there is virtually nothing here that needs to be edited + just use as is) + NEW LANGUAGE NOTE:END *********************************************** */ + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + /* Get the module name */ + module = Getattr(n, "name"); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + /* Open the output file */ + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_initbeforefunc = 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("initbeforefunc", f_initbeforefunc); + + + s_luacode = NewString(""); + Swig_register_filebyname("luacode", s_luacode); + + current[NO_CPP] = true; + + /* Standard stuff for the SWIG runtime section */ + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGLUA\n#define SWIGLUA\n#endif\n\n"); + + emitLuaFlavor(f_runtime); + + if (nomoduleglobal) { + Printf(f_runtime, "#define SWIG_LUA_NO_MODULE_GLOBAL\n"); + } else { + Printf(f_runtime, "#define SWIG_LUA_MODULE_GLOBAL\n"); + } + if (squash_bases) + Printf(f_runtime, "#define SWIG_LUA_SQUASH_BASES\n"); + + // if (NoInclude) { + // Printf(f_runtime, "#define SWIG_NOINCLUDE\n"); + // } + + Printf(f_runtime, "\n"); + + //String *init_name = NewStringf("%(title)s_Init", module); + //Printf(f_header, "#define SWIG_init %s\n", init_name); + //Printf(f_header, "#define SWIG_name \"%s\"\n", module); + /* SWIG_import is a special function name for importing within Lua5.1 */ + //Printf(f_header, "#define SWIG_import luaopen_%s\n\n", module); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + Printf(f_header, "#define SWIG_init luaopen_%s\n", module); + Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module); + Printf(f_header, "#define SWIG_LUACODE luaopen_%s_luacode\n", module); + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* %init code inclusion, effectively in the SWIG_init function */ + Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n"); + Language::top(n); + Printf(f_init, "/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); + Printf(f_init, "}\n"); + + // Done. Close up the module & write to the wrappers + closeNamespaces(f_wrappers); + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + /* NEW LANGUAGE NOTE:*********************************************** + this basically combines several of the strings together + and then writes it all to a file + NEW LANGUAGE NOTE:END *********************************************** */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + /* for the Lua code it needs to be properly escaped to be added into the C/C++ code */ + escapeCode(s_luacode); + Printf(f_begin, "const char* SWIG_LUACODE=\n \"%s\";\n\n", s_luacode); + Wrapper_pretty_print(f_init, f_begin); + /* Close all of the files */ + Delete(s_luacode); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_initbeforefunc); + Delete(f_runtime); + Delete(f_begin); + + /* Done */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * cDeclaration() + * It copies sym:name to lua:name to preserve its original value + * ------------------------------------------------------------ */ + + virtual int cDeclaration(Node *n) { + // class 'Language' is messing with symname in a really heavy way. + // Although documentation states that sym:name is a name in + // the target language space, it is not true. sym:name and + // its derivatives are used in various places, including + // behind-the-scene C code generation. The best way is not to + // touch it at all. + // But we need to know what was the name of function/variable + // etc that user desired, that's why we store correct symname + // as lua:name + String *symname = Getattr(n, "sym:name"); + if (symname) + Setattr(n, "lua:name", symname); + return Language::cDeclaration(n); + } + virtual int constructorDeclaration(Node *n) { + Setattr(n, "lua:name", Getattr(n, "sym:name")); + return Language::constructorDeclaration(n); + } + virtual int destructorDeclaration(Node *n) { + Setattr(n, "lua:name", Getattr(n, "sym:name")); + return Language::destructorDeclaration(n); + } + /* NEW LANGUAGE NOTE:*********************************************** + This is it! + you get this one right, and most of your work is done + but its going to take some file to get it working right + quite a bit of this is generally boilerplate code + (or stuff I don't understand) + that which matters will have extra added comments + NEW LANGUAGE NOTE:END *********************************************** */ + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + /* ----------------------------------------------------------------------- + * registerMethod() + * + * Determines wrap name of a method, its scope etc and calls + * registerMethod overload with correct arguments + * Overloaded variant adds method to the "methods" array of specified lua scope/class + * ---------------------------------------------------------------------- */ + + void registerMethod(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { + String *symname = Getattr(n, "sym:name"); + assert(symname); + + if (Getattr(n, "sym:nextSibling")) + return; + + // Lua scope. It is not symbol NSpace, it is the actual key to retrieve getCArraysHash. + String *luaScope = luaCurrentSymbolNSpace(); + if (overwrite) + luaScope = overwriteLuaScope; + + String *wrapname = 0; + String *mrename; + if (current[NO_CPP] || !getCurrentClass()) { + mrename = symname; + } else { + assert(!current[NO_CPP]); + if (current[STATIC_FUNC] || current[MEMBER_FUNC]) { + mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); + } else { + mrename = symname; + } + } + wrapname = Swig_name_wrapper(mrename); + registerMethod(n, wrapname, luaScope); + } + + /* ----------------------------------------------------------------------- + * registerMethod() + * + * Add method to the "methods" C array of given namespace/class + * ---------------------------------------------------------------------- */ + + void registerMethod(Node *n, String* wname, String *luaScope) { + assert(n); + Hash *nspaceHash = getCArraysHash(luaScope); + String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); + String *lua_name = Getattr(n, "lua:name"); + if (elua_ltr || eluac_ltr) + Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); + else + Printv(s_ns_methods_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); + // Add to the metatable if method starts with '__' + const char * tn = Char(lua_name); + if (tn[0]=='_' && tn[1] == '_' && !eluac_ltr) { + String *metatable_tab = Getattr(nspaceHash, "metatable"); + assert(metatable_tab); + if (elua_ltr) + Printv(metatable_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); + else + Printv(metatable_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); + } + } + + virtual int functionWrapper(Node *n) { + REPORT("functionWrapper", n); + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *lua_name = Getattr(n, "lua:name"); + assert(lua_name); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *tm; + int i; + //Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!luaAddSymbol(lua_name, n)) { + return SWIG_ERROR; + } + } + + /* NEW LANGUAGE NOTE:*********************************************** + the wrapper object holds all the wrapper code + we need to add a couple of local variables + NEW LANGUAGE NOTE:END *********************************************** */ + Wrapper *f = NewWrapper(); + Wrapper_add_local(f, "SWIG_arg", "int SWIG_arg = 0"); + + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + if (current[CONSTRUCTOR]) { + if (constructor_name != 0) + Delete(constructor_name); + constructor_name = Copy(wname); + } + + /* NEW LANGUAGE NOTE:*********************************************** + the format of a lua fn is: + static int wrap_XXX(lua_State* L){...} + this line adds this into the wrapper code + NEW LANGUAGE NOTE:END *********************************************** */ + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); + + /* NEW LANGUAGE NOTE:*********************************************** + this prints the list of args, eg for a C fn + int gcd(int x,int y); + it will print + int arg1; + int arg2; + NEW LANGUAGE NOTE:END *********************************************** */ + /* Write code to extract function parameters. */ + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + int varargs = emit_isvarargs(l); + + // Check if we have to ignore arguments that are passed by LUA. + // Needed for unary minus, where lua passes two arguments and + // we have to ignore the second. + + int args_to_ignore = 0; + if (Getattr(n, "lua:ignore_args")) { + args_to_ignore = GetInt(n, "lua:ignore_args"); + } + + + /* NEW LANGUAGE NOTE:*********************************************** + from here on in, it gets rather hairy + this is the code to convert from the scripting language to C/C++ + some of the stuff will refer to the typemaps code written in your swig file + (lua.swg), and some is done in the code here + I suppose you could do all the conversion in C, but it would be a nightmare to do + NEW LANGUAGE NOTE:END *********************************************** */ + /* Generate code for argument marshalling */ + // String *description = NewString(""); + /* NEW LANGUAGE NOTE:*********************************************** + argument_check is a new feature I added to check types of arguments: + eg for int gcd(int,int) + I want to check that arg1 & arg2 really are integers + NEW LANGUAGE NOTE:END *********************************************** */ + String *argument_check = NewString(""); + String *argument_parse = NewString(""); + String *checkfn = NULL; + char source[64]; + Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n", Swig_name_str(n), num_required + args_to_ignore, num_arguments + args_to_ignore); + + 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"); + + /* Look for an input typemap */ + sprintf(source, "%d", i + 1); + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + /* NEW LANGUAGE NOTE:*********************************************** + look for a 'checkfn' typemap + this an additional parameter added to the in typemap + if found the type will be tested for + this will result in code either in the + argument_check or argument_parse string + NEW LANGUAGE NOTE:END *********************************************** */ + if ((checkfn = Getattr(p, "tmap:in:checkfn"))) { + if (i < num_required) { + Printf(argument_check, "if(!%s(L,%s))", checkfn, source); + } else { + Printf(argument_check, "if(lua_gettop(L)>=%s && !%s(L,%s))", source, checkfn, source); + } + Printf(argument_check, " SWIG_fail_arg(\"%s\",%s,\"%s\");\n", Swig_name_str(n), source, SwigType_str(pt, 0)); + } + /* NEW LANGUAGE NOTE:*********************************************** + lua states the number of arguments passed to a function using the fn + lua_gettop() + we can use this to deal with default arguments + NEW LANGUAGE NOTE:END *********************************************** */ + if (i < num_required) { + Printf(argument_parse, "%s\n", tm); + } else { + Printf(argument_parse, "if(lua_gettop(L)>=%s){%s}\n", source, tm); + } + p = Getattr(p, "tmap:in:next"); + continue; + } else { + /* NEW LANGUAGE NOTE:*********************************************** + // why is this code not called when I don't have a typemap? + // instead of giving a warning, no code is generated + NEW LANGUAGE NOTE:END *********************************************** */ + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + + // add all argcheck code + Printv(f->code, argument_check, argument_parse, NIL); + + /* Check for trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + String *outarg = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + // // managing the number of returning variables + // if (numoutputs=Getattr(p,"tmap:argout:numoutputs")){ + // int i=GetInt(p,"tmap:argout:numoutputs"); + // printf("got argout:numoutputs of %d\n",i); + // returnval+=GetInt(p,"tmap:argout:numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", Swig_cresult_name()); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Remember C name of the wrapping function + Setattr(n, "wrap:name", wname); + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* NEW LANGUAGE NOTE:*********************************************** + FIXME: + returns 1 if there is a void return type + this is because there is a typemap for void + NEW LANGUAGE NOTE:END *********************************************** */ + // Return value if necessary + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + // managing the number of returning variables + // if (numoutputs=Getattr(tm,"numoutputs")){ + // int i=GetInt(tm,"numoutputs"); + // printf("return numoutputs %d\n",i); + // returnval+=GetInt(tm,"numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", Swig_cresult_name()); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + // returnval++; + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, 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))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } + + + /* Close the function */ + Printv(f->code, "return SWIG_arg;\n", NIL); + // add the failure cleanup code: + Printv(f->code, "\nif(0) SWIG_fail;\n", NIL); + Printv(f->code, "\nfail:\n", NIL); + Printv(f->code, "$cleanup", "lua_error(L);\n", NIL); + Printv(f->code, "return SWIG_arg;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", Swig_cresult_name()); + + /* Dump the function out */ + /* in Lua we will not emit the destructor as a wrapper function, + Lua will automatically call the destructor when the object is free'd + However: you cannot just skip this function as it will not emit + any custom destructor (using %extend), as you need to call emit_action() + Therefore we go though the whole function, + but do not write the code into the wrapper + */ + if (!current[DESTRUCTOR]) { + Wrapper_print(f, f_wrappers); + } + + /* NEW LANGUAGE NOTE:*********************************************** + register the function in SWIG + different language mappings seem to use different ideas + NEW LANGUAGE NOTE:END *********************************************** */ + /* Now register the function with the interpreter. */ + int result = SWIG_OK; + if (Getattr(n, "sym:overloaded")) { + if (!Getattr(n, "sym:nextSibling")) { + result = dispatchFunction(n); + } + } + + Delete(argument_check); + Delete(argument_parse); + + Delete(cleanup); + Delete(outarg); + // Delete(description); + DelWrapper(f); + + return result; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * + * Emit overloading dispatch function + * ------------------------------------------------------------ */ + + /* NEW LANGUAGE NOTE:*********************************************** + This is an extra function used for overloading of functions + it checks the args & then calls the relevant fn + most of the real work in again typemaps: + look for %typecheck(SWIG_TYPECHECK_*) in the .swg file + NEW LANGUAGE NOTE:END *********************************************** */ + int dispatchFunction(Node *n) { + //REPORT("dispatchFunction", n); + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "return %s(L);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *lua_name = Getattr(n, "lua:name"); + assert(lua_name); + String *wname = Swig_name_wrapper(symname); + + //Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); + + if (!luaAddSymbol(lua_name, n)) { + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + return SWIG_ERROR; + } + + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "int argv[%d]={1", maxargs + 1); + for (int i = 1; i <= maxargs; i++) { + Printf(tmp, ",%d", i + 1); + } + Printf(tmp, "}"); + Wrapper_add_local(f, "argv", tmp); + Printf(f->code, "argc = lua_gettop(L);\n"); + + Replaceall(dispatch, "$args", "self,args"); + Printv(f->code, dispatch, "\n", NIL); + + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + String *fulldecl = Swig_name_decl(sibl); + Printf(protoTypes, "\n\" %s\\n\"", fulldecl); + Delete(fulldecl); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(f->code, "SWIG_Lua_pusherrstring(L,\"Wrong arguments for overloaded function '%s'\\n\"\n" + "\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); + Delete(protoTypes); + + Printf(f->code, "lua_error(L);return 0;\n"); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + + // Remember C name of the wrapping function + Setattr(n, "wrap:name", wname); + + if (current[CONSTRUCTOR]) { + if (constructor_name != 0) + Delete(constructor_name); + constructor_name = Copy(wname); + } + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * Add variable to "attributes" C arrays of given namespace or class. + * Input is node. Based on the state of "current" array it determines + * the name of the getter function, setter function etc and calls + * registerVariable overload with necessary params. + * Lua scope could be overwritten. (Used only for backward compatibility) + * ------------------------------------------------------------ */ + + void registerVariable(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { + int assignable = is_assignable(n); + String *symname = Getattr(n, "sym:name"); + assert(symname); + + // Lua scope. It is not symbol NSpace, it is the actual key to retrieve getCArraysHash. + String *luaScope = luaCurrentSymbolNSpace(); + if (overwrite) + luaScope = overwriteLuaScope; + + // Getter and setter + String *getName = 0; + String *setName = 0; + String *mrename = 0; + if (current[NO_CPP] || !getCurrentClass()) { + // Global variable + getName = Swig_name_get(getNSpace(), symname); + if (assignable) + setName = Swig_name_set(getNSpace(), symname); + } else { + assert(!current[NO_CPP]); + if (current[STATIC_VAR] ) { + mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); + getName = Swig_name_get(0, mrename); + if (assignable) + setName = Swig_name_set(0, mrename); + } else if (current[MEMBER_VAR]) { + mrename = Swig_name_member(0, getClassPrefix(), symname); + getName = Swig_name_get(getNSpace(), mrename); + if (assignable) + setName = Swig_name_set(getNSpace(), mrename); + } else { + assert(false); + } + } + + getName = Swig_name_wrapper(getName); + if (setName) + setName = Swig_name_wrapper(setName); + registerVariable(luaScope, n, getName, setName); + } + + /* ------------------------------------------------------------ + * registerVariable() + * + * Add variable to the "attributes" (or "get"/"set" in + * case of elua_ltr) C arrays of given namespace or class + * ------------------------------------------------------------ */ + + void registerVariable(String *lua_nspace_or_class_name, Node *n, String *getName, String *setName) { + String *unassignable = NewString("SWIG_Lua_set_immutable"); + if (setName == 0 || GetFlag(n, "feature:immutable")) { + setName = unassignable; + } + Hash *nspaceHash = getCArraysHash(lua_nspace_or_class_name); + String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); + String *s_ns_var_tab = Getattr(nspaceHash, "attributes"); + String *lua_name = Getattr(n, "lua:name"); + if (elua_ltr) { + String *s_ns_dot_get = Getattr(nspaceHash, "get"); + String *s_ns_dot_set = Getattr(nspaceHash, "set"); + Printf(s_ns_dot_get, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, getName); + Printf(s_ns_dot_set, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, setName); + } else if (eluac_ltr) { + Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_get", "\")", ", LFUNCVAL(", getName, ")", "},\n", NIL); + Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_set", "\")", ", LFUNCVAL(", setName, ")", "},\n", NIL); + } else { + Printf(s_ns_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, lua_name, getName, setName); + } + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + /* NEW LANGUAGE NOTE:*********************************************** + Language::variableWrapper(n) will generate two wrapper fns + Foo_get & Foo_set by calling functionWrapper() + so we will just add these into the variable lists + ideally we should not have registered these as functions, + only WRT this variable will look into this later. + NEW LANGUAGE NOTE:END *********************************************** */ + // REPORT("variableWrapper", n); + String *lua_name = Getattr(n, "lua:name"); + assert(lua_name); + current[VARIABLE] = true; + // let SWIG generate the wrappers + int result = Language::variableWrapper(n); + + // It is impossible to use registerVariable, because sym:name of the Node is currently + // in an undefined state - the callees of this function may have modified it. + // registerVariable should be used from respective callees.* + current[VARIABLE] = false; + return result; + } + + + /* ------------------------------------------------------------ + * Add constant to appropriate C array. constantRecord is an array record. + * Actually, in current implementation it is resolved consttab typemap + * ------------------------------------------------------------ */ + + void registerConstant(String *nspace, String *constantRecord) { + Hash *nspaceHash = getCArraysHash(nspace); + String *s_const_tab = 0; + if (eluac_ltr || elua_ltr) + // In elua everything goes to "methods" tab + s_const_tab = Getattr(nspaceHash, "methods"); + else + s_const_tab = Getattr(nspaceHash, "constants"); + + assert(s_const_tab); + Printf(s_const_tab, " %s,\n", constantRecord); + + if ((eluac_ltr || elua_ltr) && old_metatable_bindings) { + s_const_tab = Getattr(nspaceHash, "constants"); + assert(s_const_tab); + Printf(s_const_tab, " %s,\n", constantRecord); + } + + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + REPORT("constantWrapper", n); + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *lua_name = Getattr(n, "lua:name"); + if (lua_name == 0) + lua_name = iname; + String *nsname = Copy(iname); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + String *lua_name_v2 = 0; + String *tm_v2 = 0; + String *iname_v2 = 0; + Node *n_v2 = 0; + + if (!luaAddSymbol(lua_name, n)) + return SWIG_ERROR; + + Swig_save("lua_constantMember", n, "sym:name", NIL); + Setattr(n, "sym:name", lua_name); + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", lua_name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + registerConstant(luaCurrentSymbolNSpace(), tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", lua_name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(f_init, "%s\n", tm); + } else { + Delete(nsname); + nsname = 0; + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + Swig_restore(n); + return SWIG_NOWRAP; + } + + bool make_v2_compatible = old_metatable_bindings && getCurrentClass() && old_compatible_names; + + if (make_v2_compatible) { + // Don't do anything for enums in C mode - they are already + // wrapped correctly + if (CPlusPlus || !current[ENUM_CONST]) { + lua_name_v2 = Swig_name_member(0, proxy_class_name, lua_name); + iname_v2 = Swig_name_member(0, proxy_class_name, iname); + n_v2 = Copy(n); + if (!luaAddSymbol(iname_v2, n, getNSpace())) { + Swig_restore(n); + return SWIG_ERROR; + } + + Setattr(n_v2, "sym:name", lua_name_v2); + tm_v2 = Swig_typemap_lookup("consttab", n_v2, name, 0); + if (tm_v2) { + Replaceall(tm_v2, "$source", value); + Replaceall(tm_v2, "$target", lua_name_v2); + Replaceall(tm_v2, "$value", value); + Replaceall(tm_v2, "$nsname", nsname); + registerConstant(getNSpace(), tm_v2); + } else { + tm_v2 = Swig_typemap_lookup("constcode", n_v2, name, 0); + if (!tm_v2) { + // This can't be. + assert(false); + Swig_restore(n); + return SWIG_ERROR; + } + Replaceall(tm_v2, "$source", value); + Replaceall(tm_v2, "$target", lua_name_v2); + Replaceall(tm_v2, "$value", value); + Replaceall(tm_v2, "$nsname", nsname); + Printf(f_init, "%s\n", tm_v2); + } + Delete(n_v2); + } + } + + Swig_restore(n); + Delete(nsname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + // REPORT("nativeWrapper", n); + String *symname = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + if (!luaAddSymbol(wrapname, n)) + return SWIG_ERROR; + + Hash *nspaceHash = getCArraysHash(getNSpace()); + String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); + Printv(s_ns_methods_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); + // return Language::nativeWrapper(n); // this does nothing... + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + current[STATIC_CONST] = true; + current[ENUM_CONST] = true; + // There is some slightly specific behaviour with enums. Basically, + // their NSpace may be tracked separately. The code below tries to work around + // this issue to some degree. + // The idea is the same as in classHandler - to drop old names generation if + // enum is in class in namespace. + const int old_compatible_names_saved = old_compatible_names; + if (getNSpace() || ( Getattr(n, "sym:nspace") != 0 && Len(Getattr(n, "sym:nspace")) > 0 ) ) { + old_compatible_names = 0; + } + int result = Language::enumDeclaration(n); + current[STATIC_CONST] = false; + current[ENUM_CONST] = false; + old_compatible_names = old_compatible_names_saved; + return result; + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", "*sym:name", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + Node *parent = parentNode(n); + + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + Setattr(n, "value", tmpValue); + + Setattr(n, "name", tmpValue); /* for wrapping of enums in a namespace when emit_action is used */ + + if (GetFlag(parent, "scopedenum")) { + symname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + Setattr(n, "sym:name", symname); + Delete(symname); + } + + int result = constantWrapper(n); + + Delete(tmpValue); + Swig_restore(n); + return result; + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + + /* ------------------------------------------------------------ + * Helper function that adds record to appropriate C arrays + * ------------------------------------------------------------ */ + + void registerClass(String *scope, String *wrap_class) { + assert(wrap_class); + Hash *nspaceHash = getCArraysHash(scope); + String *ns_classes = Getattr(nspaceHash, "classes"); + Printv(ns_classes, "&", wrap_class, ",\n", NIL); + if (elua_ltr || eluac_ltr) { + String *ns_methods = Getattr(nspaceHash, "methods"); + Hash *class_hash = getCArraysHash(class_static_nspace); + assert(class_hash); + String *cls_methods = Getattr(class_hash, "methods:name"); + assert(cls_methods); + Printv(ns_methods, tab4, "{LSTRKEY(\"", proxy_class_name, "\")", ", LROVAL(", cls_methods, ")", "},\n", NIL); + } + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + //REPORT("classHandler", n); + + String *mangled_full_proxy_class_name = 0; + String *destructor_name = 0; + String *nspace = getNSpace(); + + constructor_name = 0; + have_constructor = 0; + have_destructor = 0; + destructor_action = 0; + assert(class_static_nspace == 0); + assert(full_proxy_class_name == 0); + assert(proxy_class_name == 0); + + current[NO_CPP] = false; + + proxy_class_name = Getattr(n, "sym:name"); + // We have to enforce nspace here, because technically we are already + // inside class parsing (getCurrentClass != 0), but we should register + // class in its parent namespace + if (!luaAddSymbol(proxy_class_name, n, nspace)) + return SWIG_ERROR; + + if (nspace == 0) + full_proxy_class_name = NewStringf("%s", proxy_class_name); + else + full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); + + assert(full_proxy_class_name); + mangled_full_proxy_class_name = Swig_name_mangle(full_proxy_class_name); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType *fr_t = SwigType_typedef_resolve_all(t); /* Create fully resolved type */ + SwigType *t_tmp = 0; + t_tmp = SwigType_typedef_qualified(fr_t); // Temporal variable + Delete(fr_t); + fr_t = SwigType_strip_qualifiers(t_tmp); + String *mangled_fr_t = 0; + mangled_fr_t = SwigType_manglestr(fr_t); + // not sure exactly how this works, + // but tcl has a static hashtable of all classes emitted and then only emits code for them once. + // this fixes issues in test suites: template_default2 & template_specialization + + // * if i understand correctly, this is a bug. + // * consider effect on template_specialization_defarg + + static Hash *emitted = NewHash(); + if (GetFlag(emitted, mangled_fr_t)) { + full_proxy_class_name = 0; + proxy_class_name = 0; + return SWIG_NOWRAP; + } + SetFlag(emitted, mangled_fr_t); + + // We treat class T as both 'class' and 'namespace'. All static members, attributes + // and constants are considered part of namespace T, all members - part of the 'class' + // Now, here is a trick. Static methods, attributes and non-static methods and attributes + // are described with same structures - swig_lua_attribute/swig_lua_method. Instead of calling + // getCArraysHash(class name) to initialize things for static methods/attributes and then + // manually doing same initialization for non-static methods, we call getCArraysHash 2 times: + // 1) With name "class name" + "." + "SwigStatic" to initialize static things + // 2) With "class name" to initialize non-static things + Hash *instance_cls = getCArraysHash(full_proxy_class_name, false); + assert(instance_cls); + String *s_attr_tab_name = Getattr(instance_cls, "attributes:name"); + String *s_methods_tab_name = Getattr(instance_cls, "methods:name"); + SetFlag(instance_cls, "lua:no_namespaces"); + SetFlag(instance_cls, "lua:no_classes"); + SetFlag(instance_cls, "lua:class_instance"); + + /* There is no use for "constants", "classes" and "namespaces" arrays. + * All constants are considered part of static part of class. + */ + + class_static_nspace = NewStringf("%s%sSwigStatic", full_proxy_class_name, NSPACE_SEPARATOR); + Hash *static_cls = getCArraysHash(class_static_nspace, false); + assert(static_cls); + SetFlag(static_cls, "lua:no_namespaces"); + SetFlag(static_cls, "lua:class_static"); + + // Notifying instance_cls and static_cls hashes about each other + Setattr(instance_cls, "lua:class_instance:static_hash", static_cls); + Setattr(static_cls, "lua:class_static:instance_hash", instance_cls); + + const int old_compatible_names_saved = old_compatible_names; + // If class has %nspace enabled, then generation of backward compatible names + // should be disabled + if (getNSpace()) { + old_compatible_names = 0; + } + + /* There is no use for "classes" and "namespaces" arrays. Subclasses are not supported + * by SWIG and namespaces couldn't be nested inside classes (C++ Standard) + */ + // Generate normal wrappers + Language::classHandler(n); + + old_compatible_names = old_compatible_names_saved; + + SwigType_add_pointer(t); + + // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' + String *wrap_class_name = Swig_name_wrapper(NewStringf("class_%s", mangled_full_proxy_class_name)); + String *wrap_class = NewStringf("&%s", wrap_class_name); + SwigType_remember_clientdata(t, wrap_class); + + String *rt = Copy(getClassType()); + SwigType_add_pointer(rt); + + // Adding class to appropriate namespace + registerClass(nspace, wrap_class_name); + Hash *nspaceHash = getCArraysHash(nspace); + + // Register the class structure with the type checker + // Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_full_proxy_class_name); + + // emit a function to be called to delete the object + if (have_destructor) { + destructor_name = NewStringf("swig_delete_%s", mangled_full_proxy_class_name); + Printv(f_wrappers, "static void ", destructor_name, "(void *obj) {\n", NIL); + if (destructor_action) { + Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); + Printv(f_wrappers, destructor_action, "\n", NIL); + } else { + if (CPlusPlus) { + Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); + } else { + Printv(f_wrappers, " free((char *) obj);\n", NIL); + } + } + Printf(f_wrappers, "}\n"); + } + // Wrap constructor wrapper into one more proxy function. It will be used as class namespace __call method, thus + // allowing both + // Module.ClassName.StaticMethod to access static method/variable/constant + // Module.ClassName() to create new object + if (have_constructor) { + assert(constructor_name); + String *constructor_proxy_name = NewStringf("_proxy_%s", constructor_name); + Printv(f_wrappers, "static int ", constructor_proxy_name, "(lua_State *L) {\n", NIL); + Printv(f_wrappers, + tab4, "assert(lua_istable(L,1));\n", + tab4, "lua_pushcfunction(L,", constructor_name, ");\n", + tab4, "assert(!lua_isnil(L,-1));\n", + tab4, "lua_replace(L,1); /* replace our table with real constructor */\n", + tab4, "lua_call(L,lua_gettop(L)-1,1);\n", + tab4, "return 1;\n}\n", NIL); + Delete(constructor_name); + constructor_name = constructor_proxy_name; + if (elua_ltr) { + String *static_cls_metatable_tab = Getattr(static_cls, "metatable"); + assert(static_cls_metatable_tab); + Printf(static_cls_metatable_tab, " {LSTRKEY(\"__call\"), LFUNCVAL(%s)},\n", constructor_name); + } else if (eluac_ltr) { + String *ns_methods_tab = Getattr(nspaceHash, "methods"); + assert(ns_methods_tab); + Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "new_", proxy_class_name, "\")", ", LFUNCVAL(", constructor_name, ")", "},\n", NIL); + } + } + if (have_destructor) { + if (eluac_ltr) { + String *ns_methods_tab = Getattr(nspaceHash, "methods"); + assert(ns_methods_tab); + Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "free_", mangled_full_proxy_class_name, "\")", ", LFUNCVAL(", destructor_name, ")", "},\n", NIL); + } + } + + closeCArraysHash(full_proxy_class_name, f_wrappers); + closeCArraysHash(class_static_nspace, f_wrappers); + + + // Handle inheritance + // note: with the idea of class hierarchies spread over multiple modules + // cf test-suite: imports.i + // it is not possible to just add the pointers to the base classes to the code + // (as sometimes these classes are not present) + // therefore we instead hold the name of the base class and a null pointer + // at runtime: we can query the swig type manager & see if the class exists + // if so, we can get the pointer to the base class & replace the null pointer + // if the type does not exist, then we cannot... + String *base_class = NewString(""); + String *base_class_names = NewString(""); + + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + // stores a null pointer & the name + Printf(base_class, "0,"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + + b = Next(b); + index++; + } + } + // First, print class static part + printCArraysDefinition(class_static_nspace, proxy_class_name, f_wrappers); + + assert(mangled_full_proxy_class_name); + assert(base_class); + assert(base_class_names); + assert(proxy_class_name); + assert(full_proxy_class_name); + + // Then print class instance part + Printv(f_wrappers, "static swig_lua_class *swig_", mangled_full_proxy_class_name, "_bases[] = {", base_class, "0};\n", NIL); + Delete(base_class); + Printv(f_wrappers, "static const char *swig_", mangled_full_proxy_class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); + Delete(base_class_names); + + Printv(f_wrappers, "static swig_lua_class _wrap_class_", mangled_full_proxy_class_name, " = { \"", proxy_class_name, "\", \"", full_proxy_class_name, "\", &SWIGTYPE", + SwigType_manglestr(t), ",", NIL); + + if (have_constructor) { + Printv(f_wrappers, constructor_name, NIL); + Delete(constructor_name); + constructor_name = 0; + } else { + Printf(f_wrappers, "0"); + } + + if (have_destructor) { + Printv(f_wrappers, ", ", destructor_name, NIL); + } else { + Printf(f_wrappers, ",0"); + } + Printf(f_wrappers, ", %s, %s, &%s", s_methods_tab_name, s_attr_tab_name, Getattr(static_cls, "cname")); + + if (!eluac_ltr) { + Printf(f_wrappers, ", %s", Getattr(instance_cls,"metatable:name")); + } + else + Printf(f_wrappers, ", 0"); + + Printf(f_wrappers, ", swig_%s_bases, swig_%s_base_names };\n\n", mangled_full_proxy_class_name, mangled_full_proxy_class_name); + + current[NO_CPP] = true; + Delete(class_static_nspace); + class_static_nspace = 0; + Delete(mangled_full_proxy_class_name); + mangled_full_proxy_class_name = 0; + Delete(destructor_name); + destructor_name = 0; + Delete(full_proxy_class_name); + full_proxy_class_name = 0; + proxy_class_name = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *symname = GetChar(n, "sym:name"); + //Printf(stdout,"memberfunctionHandler %s %s\n",name,iname); + + // Special case unary minus: LUA passes two parameters for the + // wrapper function while we want only one. Tell our + // functionWrapper to ignore a parameter. + + if (Cmp(symname, "__unm") == 0) { + //Printf(stdout, "unary minus: ignore one argument\n"); + SetInt(n, "lua:ignore_args", 1); + } + + current[MEMBER_FUNC] = true; + Language::memberfunctionHandler(n); + + registerMethod(n); + current[MEMBER_FUNC] = false; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + // REPORT("membervariableHandler",n); + current[MEMBER_VAR] = true; + Language::membervariableHandler(n); + registerVariable(n); + current[MEMBER_VAR] = false; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * + * Method for adding C++ member constructor + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + // REPORT("constructorHandler", n); + current[CONSTRUCTOR] = true; + Language::constructorHandler(n); + current[CONSTRUCTOR] = false; + //constructor_name = NewString(Getattr(n, "sym:name")); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + REPORT("destructorHandler", n); + current[DESTRUCTOR] = true; + Language::destructorHandler(n); + current[DESTRUCTOR] = false; + have_destructor = 1; + destructor_action = Getattr(n, "wrap:action"); + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * globalfunctionHandler() + * + * It can be called: + * 1. Usual C/C++ global function. + * 2. During class parsing for functions declared/defined as friend + * 3. During class parsing from staticmemberfunctionHandler + * ---------------------------------------------------------------------- */ + + virtual int globalfunctionHandler(Node *n) { + bool oldVal = current[NO_CPP]; + if (!current[STATIC_FUNC]) // If static function, don't switch to NO_CPP + current[NO_CPP] = true; + const int result = Language::globalfunctionHandler(n); + + if (!current[STATIC_FUNC]) // Register only if not called from static function handler + registerMethod(n); + current[NO_CPP] = oldVal; + return result; + } + + /* ---------------------------------------------------------------------- + * globalvariableHandler() + * + * Sets "current" array correctly + * ---------------------------------------------------------------------- */ + + virtual int globalvariableHandler(Node *n) { + bool oldVal = current[NO_CPP]; + current[GLOBAL_VAR] = true; + current[NO_CPP] = true; + + const int result = Language::globalvariableHandler(n); + registerVariable(n); + + current[GLOBAL_VAR] = false; + current[NO_CPP] = oldVal; + return result; + } + + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + REPORT("staticmemberfunctionHandler", n); + current[STATIC_FUNC] = true; + + const int result = Language::staticmemberfunctionHandler(n); + registerMethod(n); + + if (old_metatable_bindings && result == SWIG_OK && old_compatible_names) { + Swig_require("lua_staticmemberfunctionHandler", n, "*lua:name", NIL); + String *lua_name = Getattr(n, "lua:name"); + // Although this function uses Swig_name_member, it actually generates the Lua name, + // not the C++ name. This is because an earlier version used such a scheme for static function + // name generation and we have to maintain backward compatibility. + String *compat_name = Swig_name_member(0, proxy_class_name, lua_name); + Setattr(n, "lua:name", compat_name); + registerMethod(n, true, getNSpace()); + Delete(compat_name); + Swig_restore(n); + } + + current[STATIC_FUNC] = false;; + return result; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * + * Create a C++ constant + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + REPORT("memberconstantHandler", n); + int result = Language::memberconstantHandler(n); + + return result; + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + REPORT("staticmembervariableHandler", n); + current[STATIC_VAR] = true; + //String *symname = Getattr(n, "sym:name"); + int result = Language::staticmembervariableHandler(n); + if (!GetFlag(n, "wrappedasconstant")) { + registerVariable(n); + } + + if (result == SWIG_OK) { + // This will add static member variable to the class namespace with name ClassName_VarName + if (old_metatable_bindings && old_compatible_names) { + Swig_save("lua_staticmembervariableHandler", n, "lua:name", NIL); + String *lua_name = Getattr(n, "lua:name"); + // Although this function uses Swig_name_member, it actually generates the Lua name, + // not the C++ name. This is because an earlier version used such a scheme for static function + // name generation and we have to maintain backward compatibility. + String *v2_name = Swig_name_member(NIL, proxy_class_name, lua_name); + if (!GetFlag(n, "wrappedasconstant")) { + Setattr(n, "lua:name", v2_name); + // Registering static var in the class parent nspace + registerVariable(n, true, getNSpace()); + } + // If static member variable was wrapped as a constant, then + // constant wrapper has already performed all actions necessary for old_metatable_bindings + Delete(v2_name); + Swig_restore(n); + } + } + current[STATIC_VAR] = false; + + return result; + } + + + /* --------------------------------------------------------------------- + * external runtime generation + * --------------------------------------------------------------------- */ + + /* This is to support the usage + SWIG -external-runtime <filename> + The code consists of two functions: + String *runtimeCode() // returns a large string with all the runtimes in + String *defaultExternalRuntimeFilename() // returns the default filename + I am writing a generic solution, even though SWIG-Lua only has one file right now... + */ + String *runtimeCode() { + String *s = NewString(""); + const char *filenames[] = { "luarun.swg", 0 }; // must be 0 terminated + + emitLuaFlavor(s); + + String *sfile = 0; + for (int i = 0; filenames[i] != 0; i++) { + sfile = Swig_include_sys(filenames[i]); + if (!sfile) { + Printf(stderr, "*** Unable to open '%s'\n", filenames[i]); + } else { + Append(s, sfile); + Delete(sfile); + } + } + + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigluarun.h"); + } + + /* --------------------------------------------------------------------- + * helpers + * --------------------------------------------------------------------- */ + + void emitLuaFlavor(String *s) { + if (elua_emulate) { + Printf(s, "/*This is only emulation!*/\n"); + Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); + Printf(s, "#define SWIG_LUA_ELUA_EMULATE\n"); + } else if (elua_ltr) + Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); + else if (eluac_ltr) + Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUAC\n"); + else + Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_LUA\n"); + } + + + /* ----------------------------------------------------------------------------- + * escapeCode() + * + * This is to convert the string of Lua code into a proper string, which can then be + * emitted into the C/C++ code. + * Basically it is a lot of search & replacing of odd sequences + * ---------------------------------------------------------------------------- */ + + void escapeCode(String *str) { + //Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str); + Chop(str); // trim + Replace(str, "\\", "\\\\", DOH_REPLACE_ANY); // \ to \\ (this must be done first) + Replace(str, "\"", "\\\"", DOH_REPLACE_ANY); // " to \" + Replace(str, "\n", "\\n\"\n \"", DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line) + //Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str); + } + + /* ----------------------------------------------------------------------------- + * rawGetCArraysHash(String *name) + * + * A small helper to hide implementation of how CArrays hashes are stored + * ---------------------------------------------------------------------------- */ + + Hash *rawGetCArraysHash(const_String_or_char_ptr name) { + Hash *scope = symbolScopeLookup( name ? name : "" ); + if(!scope) + return 0; + + Hash *carrays_hash = Getattr(scope, "lua:cdata"); + return carrays_hash; + } + + /* ----------------------------------------------------------------------------- + * getCArraysHash() + * + * Each namespace can be described with a hash that stores C arrays + * where members of the namespace should be added. All these hashes are stored + * inside the symbols table, in pseudo-symbol for every namespace. + * nspace could be NULL (NSPACE_TODO), that means functions and variables and classes + * that are not in any namespace (this is default for SWIG unless %nspace feature is used). + * You can later set some attributes that will affect behaviour of functions that use this hash: + * "lua:no_namespaces" will disable "namespaces" array. + * "lua:no_classes" will disable "classes" array. + * For every component ("attributes", "methods", etc) there are subcomponents: + * XXX:name - name of the C array that stores data for component + * XXX:decl - statement with forward declaration of this array; + * Namespace could be automatically registered to its parent if 'reg' == true. This can only be + * done during the first call (a.k.a when nspace is created). + * ---------------------------------------------------------------------------- */ + + Hash *getCArraysHash(String *nspace, bool reg = true) { + Hash *scope = symbolScopeLookup(nspace ? nspace : ""); + if(!scope) { + symbolAddScope( nspace ? nspace : "" ); + scope = symbolScopeLookup(nspace ? nspace : ""); + assert(scope); + } + Hash *carrays_hash = Getattr(scope, "lua:cdata"); + if (carrays_hash != 0) + return carrays_hash; + carrays_hash = NewHash(); + String *mangled_name = 0; + if (nspace == 0 || Len(nspace) == 0) + mangled_name = NewString("SwigModule"); + else + mangled_name = Swig_name_mangle(nspace); + String *cname = NewStringf("swig_%s", mangled_name); + + Setattr(carrays_hash, "cname", cname); + + String *attr_tab = NewString(""); + String *attr_tab_name = NewStringf("swig_%s_attributes", mangled_name); + String *attr_tab_decl = NewString(""); + Printv(attr_tab, "static swig_lua_attribute ", NIL); + Printv(attr_tab, attr_tab_name, "[]", NIL); + Printv(attr_tab_decl, attr_tab, ";\n", NIL); + Printv(attr_tab, " = {\n", NIL); + Setattr(carrays_hash, "attributes", attr_tab); + Setattr(carrays_hash, "attributes:name", attr_tab_name); + Setattr(carrays_hash, "attributes:decl", attr_tab_decl); + + String *methods_tab = NewString(""); + String *methods_tab_name = NewStringf("swig_%s_methods", mangled_name); + String *methods_tab_decl = NewString(""); + if (elua_ltr || eluac_ltr) // In this case methods array also acts as namespace rotable + Printf(methods_tab, "const LUA_REG_TYPE "); + else + Printf(methods_tab, "static swig_lua_method "); + Printv(methods_tab, methods_tab_name, "[]", NIL); + Printv(methods_tab_decl, methods_tab, ";\n", NIL); + Printv(methods_tab, "= {\n", NIL); + Setattr(carrays_hash, "methods", methods_tab); + Setattr(carrays_hash, "methods:name", methods_tab_name); + Setattr(carrays_hash, "methods:decl", methods_tab_decl); + + String *const_tab = NewString(""); + String *const_tab_name = NewStringf("swig_%s_constants", mangled_name); + String *const_tab_decl = NewString(""); + if (elua_ltr || eluac_ltr) // In this case const array holds rotable with namespace constants + Printf(const_tab, "const LUA_REG_TYPE "); + else + Printf(const_tab, "static swig_lua_const_info "); + Printv(const_tab, const_tab_name, "[]", NIL); + Printv(const_tab_decl, const_tab, ";", NIL); + Printv(const_tab, "= {\n", NIL); + Setattr(carrays_hash, "constants", const_tab); + Setattr(carrays_hash, "constants:name", const_tab_name); + Setattr(carrays_hash, "constants:decl", const_tab_decl); + + String *classes_tab = NewString(""); + String *classes_tab_name = NewStringf("swig_%s_classes", mangled_name); + String *classes_tab_decl = NewString(""); + Printf(classes_tab, "static swig_lua_class* "); + Printv(classes_tab, classes_tab_name, "[]", NIL); + Printv(classes_tab_decl, classes_tab, ";", NIL); + Printv(classes_tab, "= {\n", NIL); + Setattr(carrays_hash, "classes", classes_tab); + Setattr(carrays_hash, "classes:name", classes_tab_name); + Setattr(carrays_hash, "classes:decl", classes_tab_decl); + + String *namespaces_tab = NewString(""); + String *namespaces_tab_name = NewStringf("swig_%s_namespaces", mangled_name); + String *namespaces_tab_decl = NewString(""); + Printf(namespaces_tab, "static swig_lua_namespace* "); + Printv(namespaces_tab, namespaces_tab_name, "[]", NIL); + Printv(namespaces_tab_decl, namespaces_tab, ";", NIL); + Printv(namespaces_tab, " = {\n", NIL); + Setattr(carrays_hash, "namespaces", namespaces_tab); + Setattr(carrays_hash, "namespaces:name", namespaces_tab_name); + Setattr(carrays_hash, "namespaces:decl", namespaces_tab_decl); + + if (elua_ltr) { + String *get_tab = NewString(""); + String *get_tab_name = NewStringf("swig_%s_get", mangled_name); + String *get_tab_decl = NewString(""); + Printv(get_tab, "const LUA_REG_TYPE ", get_tab_name, "[]", NIL); + Printv(get_tab_decl, get_tab, ";", NIL); + Printv(get_tab, " = {\n", NIL); + Setattr(carrays_hash, "get", get_tab); + Setattr(carrays_hash, "get:name", get_tab_name); + Setattr(carrays_hash, "get:decl", get_tab_decl); + + String *set_tab = NewString(""); + String *set_tab_name = NewStringf("swig_%s_set", mangled_name); + String *set_tab_decl = NewString(""); + Printv(set_tab, "const LUA_REG_TYPE ", set_tab_name, "[]", NIL); + Printv(set_tab_decl, set_tab, ";", NIL); + Printv(set_tab, " = {\n", NIL); + Setattr(carrays_hash, "set", set_tab); + Setattr(carrays_hash, "set:name", set_tab_name); + Setattr(carrays_hash, "set:decl", set_tab_decl); + + } + if (!eluac_ltr) { + String *metatable_tab = NewString(""); + String *metatable_tab_name = NewStringf("swig_%s_meta", mangled_name); + String *metatable_tab_decl = NewString(""); + if (elua_ltr) // In this case const array holds rotable with namespace constants + Printf(metatable_tab, "const LUA_REG_TYPE "); + else + Printf(metatable_tab, "static swig_lua_method "); + Printv(metatable_tab, metatable_tab_name, "[]", NIL); + Printv(metatable_tab_decl, metatable_tab, ";", NIL); + Printv(metatable_tab, " = {\n", NIL); + Setattr(carrays_hash, "metatable", metatable_tab); + Setattr(carrays_hash, "metatable:name", metatable_tab_name); + Setattr(carrays_hash, "metatable:decl", metatable_tab_decl); + } + + Setattr(scope, "lua:cdata", carrays_hash); + assert(rawGetCArraysHash(nspace)); + + if (reg && nspace != 0 && Len(nspace) != 0 && GetFlag(carrays_hash, "lua:no_reg") == 0) { + // Split names into components + List *components = Split(nspace, '.', -1); + String *parent_path = NewString(""); + int len = Len(components); + String *name = Copy(Getitem(components, len - 1)); + for (int i = 0; i < len - 1; i++) { + if (i > 0) + Printv(parent_path, NSPACE_SEPARATOR, NIL); + String *item = Getitem(components, i); + Printv(parent_path, item, NIL); + } + Hash *parent = getCArraysHash(parent_path, true); + String *namespaces_tab = Getattr(parent, "namespaces"); + Printv(namespaces_tab, "&", cname, ",\n", NIL); + if (elua_ltr || eluac_ltr) { + String *methods_tab = Getattr(parent, "methods"); + Printv(methods_tab, tab4, "{LSTRKEY(\"", name, "\")", ", LROVAL(", methods_tab_name, ")", "},\n", NIL); + } + Setattr(carrays_hash, "name", name); + + Delete(components); + Delete(parent_path); + } else if (!reg) // This namespace shouldn't be registered. Lets remember it. + SetFlag(carrays_hash, "lua:no_reg"); + + Delete(mangled_name); + mangled_name = 0; + return carrays_hash; + } + + /* ----------------------------------------------------------------------------- + * closeCArraysHash() + * + * Functions add end markers {0,0,...,0} to all arrays, prints them to + * output and marks hash as closed (lua:closed). Consequent attempts to + * close the same hash will result in an error. + * closeCArraysHash DOES NOT print structure that describes namespace, it only + * prints array. You can use printCArraysDefinition to print structure. + * if "lua:no_namespaces" is set, then array for "namespaces" won't be printed + * if "lua:no_classes" is set, then array for "classes" won't be printed + * ----------------------------------------------------------------------------- */ + + void closeCArraysHash(String *nspace, File *output) { + Hash *carrays_hash = rawGetCArraysHash(nspace); + assert(carrays_hash); + assert(GetFlag(carrays_hash, "lua:closed") == 0); + + SetFlag(carrays_hash, "lua:closed"); + + // Do arrays describe class instance part or class static part + const int is_instance = GetFlag(carrays_hash, "lua:class_instance"); + + + String *attr_tab = Getattr(carrays_hash, "attributes"); + Printf(attr_tab, " {0,0,0}\n};\n"); + Printv(output, attr_tab, NIL); + + String *const_tab = Getattr(carrays_hash, "constants"); + String *const_tab_name = Getattr(carrays_hash, "constants:name"); + if (elua_ltr || eluac_ltr) + Printv(const_tab, tab4, "{LNILKEY, LNILVAL}\n", "};\n", NIL); + else + Printf(const_tab, " {0,0,0,0,0,0}\n};\n"); + + // For the sake of compiling with -Wall -Werror we print constants + // only when necessary + int need_constants = 0; + if ( (elua_ltr || eluac_ltr) && (old_metatable_bindings) ) + need_constants = 1; + else if (!is_instance) // static part need constants tab + need_constants = 1; + + if (need_constants) + Printv(output, const_tab, NIL); + + if (elua_ltr) { + // Put forward declaration of metatable array + Printv(output, "extern ", Getattr(carrays_hash, "metatable:decl"), "\n", NIL); + } + String *methods_tab = Getattr(carrays_hash, "methods"); + String *metatable_tab_name = Getattr(carrays_hash, "metatable:name"); + if (elua_ltr || eluac_ltr) { + if (old_metatable_bindings) + Printv(methods_tab, tab4, "{LSTRKEY(\"const\"), LROVAL(", const_tab_name, ")},\n", NIL); + if (elua_ltr) { + Printv(methods_tab, tab4, "{LSTRKEY(\"__metatable\"), LROVAL(", metatable_tab_name, ")},\n", NIL); + } + + Printv(methods_tab, tab4, "{LSTRKEY(\"__disown\"), LFUNCVAL(SWIG_Lua_class_disown)},\n", NIL); + Printv(methods_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + } else + Printf(methods_tab, " {0,0}\n};\n"); + Printv(output, methods_tab, NIL); + + if (!GetFlag(carrays_hash, "lua:no_classes")) { + String *classes_tab = Getattr(carrays_hash, "classes"); + Printf(classes_tab, " 0\n};\n"); + Printv(output, classes_tab, NIL); + } + + if (!GetFlag(carrays_hash, "lua:no_namespaces")) { + String *namespaces_tab = Getattr(carrays_hash, "namespaces"); + Printf(namespaces_tab, " 0\n};\n"); + Printv(output, namespaces_tab, NIL); + } + if (elua_ltr) { + String *get_tab = Getattr(carrays_hash, "get"); + String *set_tab = Getattr(carrays_hash, "set"); + Printv(get_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + Printv(set_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + Printv(output, get_tab, NIL); + Printv(output, set_tab, NIL); + } + + // Heuristic whether we need to print metatable or not. + // For the sake of compiling with -Wall -Werror we don't print + // metatable for static part. + int need_metatable = 0; + if (eluac_ltr) + need_metatable = 0; + else if(!is_instance) + need_metatable = 0; + else + need_metatable = 1; + + if (need_metatable) { + String *metatable_tab = Getattr(carrays_hash, "metatable"); + assert(metatable_tab); + if (elua_ltr) { + String *get_tab_name = Getattr(carrays_hash, "get:name"); + String *set_tab_name = Getattr(carrays_hash, "set:name"); + + if (GetFlag(carrays_hash, "lua:class_instance")) { + Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_class_get)},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_class_set)},\n", NIL); + } else { + Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_namespace_get)},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_namespace_set)},\n", NIL); + } + + Printv(metatable_tab, tab4, "{LSTRKEY(\"__gc\"), LFUNCVAL(SWIG_Lua_class_destruct)},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\".get\"), LROVAL(", get_tab_name, ")},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\".set\"), LROVAL(", set_tab_name, ")},\n", NIL); + Printv(metatable_tab, tab4, "{LSTRKEY(\".fn\"), LROVAL(", Getattr(carrays_hash, "methods:name"), ")},\n", NIL); + + if (GetFlag(carrays_hash, "lua:class_instance")) { + String *static_cls = Getattr(carrays_hash, "lua:class_instance:static_hash"); + assert(static_cls); + // static_cls is swig_lua_namespace. This structure can't be use with eLua(LTR) + // Instead structure describing its methods isused + String *static_cls_cname = Getattr(static_cls, "methods:name"); + assert(static_cls_cname); + Printv(metatable_tab, tab4, "{LSTRKEY(\".static\"), LROVAL(", static_cls_cname, ")},\n", NIL); + // Put forward declaration of this array + Printv(output, "extern ", Getattr(static_cls, "methods:decl"), "\n", NIL); + } else if (GetFlag(carrays_hash, "lua:class_static")) { + Hash *instance_cls = Getattr(carrays_hash, "lua:class_static:instance_hash"); + assert(instance_cls); + String *instance_cls_metatable_name = Getattr(instance_cls, "metatable:name"); + assert(instance_cls_metatable_name); + Printv(metatable_tab, tab4, "{LSTRKEY(\".instance\"), LROVAL(", instance_cls_metatable_name, ")},\n", NIL); + } + + Printv(metatable_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); + } else { + Printf(metatable_tab, " {0,0}\n};\n"); + } + + Printv(output, metatable_tab, NIL); + } + + Printv(output, "\n", NIL); + } + + /* ----------------------------------------------------------------------------- + * closeNamespaces() + * + * Recursively close all non-closed namespaces. Prints data to dataOutput. + * ----------------------------------------------------------------------------- */ + + void closeNamespaces(File *dataOutput) { + // Special handling for empty module. + if (symbolScopeLookup("") == 0 || rawGetCArraysHash("") == 0) { + // Module is empty. Create hash for global scope in order to have swig_SwigModule + // variable in resulting file + getCArraysHash(0); + } + // Because we can't directly access 'symtabs', instead we access + // top-level scope and look on all scope pseudo-symbols in it. + Hash *top_scope = symbolScopeLookup(""); + assert(top_scope); + Iterator ki = First(top_scope); + List *to_close = NewList(); + while (ki.key) { + assert(ki.item); + if (Getattr(ki.item, "sym:scope")) { + // We have a pseudo symbol. Lets get actual scope for this pseudo symbol + Hash *carrays_hash = rawGetCArraysHash(ki.key); + assert(carrays_hash); + if (GetFlag(carrays_hash, "lua:closed") == 0) + Append(to_close, ki.key); + } + ki = Next(ki); + } + SortList(to_close, &compareByLen); + int len = Len(to_close); + for (int i = 0; i < len; i++) { + String *key = Getitem(to_close, i); + closeCArraysHash(key, dataOutput); + Hash *carrays_hash = rawGetCArraysHash(key); + String *name = 0; // name - name of the namespace as it should be visible in Lua + if (DohLen(key) == 0) // This is global module + name = module; + else + name = Getattr(carrays_hash, "name"); + assert(name); + printCArraysDefinition(key, name, dataOutput); + } + Delete(to_close); + } + + /* ----------------------------------------------------------------------------- + * printCArraysDefinition() + * + * This function prints to output a definition of namespace in form + * swig_lua_namespace $cname = { attr_array, methods_array, ... , namespaces_array }; + * You can call this function as many times as is necessary. + * 'name' is a user-visible name that this namespace will have in Lua. It shouldn't + * be a fully qualified name, just its own name. + * ----------------------------------------------------------------------------- */ + + void printCArraysDefinition(String *nspace, String *name, File *output) { + Hash *carrays_hash = getCArraysHash(nspace, false); + + String *cname = Getattr(carrays_hash, "cname"); // cname - name of the C structure that describes namespace + assert(cname); + Printv(output, "static swig_lua_namespace ", cname, " = ", NIL); + + String *null_string = NewString("0"); + String *attr_tab_name = Getattr(carrays_hash, "attributes:name"); + String *methods_tab_name = Getattr(carrays_hash, "methods:name"); + String *const_tab_name = Getattr(carrays_hash, "constants:name"); + String *classes_tab_name = Getattr(carrays_hash, "classes:name"); + String *namespaces_tab_name = Getattr(carrays_hash, "namespaces:name"); + bool has_classes = GetFlag(carrays_hash, "lua:no_classes") == 0; + bool has_namespaces = GetFlag(carrays_hash, "lua:no_namespaces") == 0; + + Printv(output, "{\n", + tab4, "\"", name, "\",\n", + tab4, methods_tab_name, ",\n", + tab4, attr_tab_name, ",\n", + tab4, const_tab_name, ",\n", + tab4, (has_classes) ? classes_tab_name : null_string, ",\n", + tab4, (has_namespaces) ? namespaces_tab_name : null_string, "\n};\n", NIL); + Delete(null_string); + } + + /* ----------------------------------------------------------------------------- + * luaCurrentSymbolNSpace() + * + * This function determines actual namespace/scope where any symbol at the + * current moment should be placed. It looks at the 'current' array + * and depending on where are we - static class member/function, + * instance class member/function or just global functions decides + * where symbol should be put. + * The namespace/scope doesn't depend from symbol, only from 'current' + * ----------------------------------------------------------------------------- */ + + String *luaCurrentSymbolNSpace() { + String *scope = 0; + // If outside class, than NSpace is used. + // If inside class, but current[NO_CPP], then this is friend function. It belongs to NSpace + if (!getCurrentClass() || current[NO_CPP]) { + scope = getNSpace(); + } else if (current[ENUM_CONST] && !CPlusPlus ) { + // Enums in C mode go to NSpace + scope = getNSpace(); + } else { + // If inside class, then either class static namespace or class fully qualified name is used + assert(!current[NO_CPP]); + if (current[STATIC_FUNC] || current[STATIC_VAR] || current[STATIC_CONST]) { + scope = class_static_nspace; + } else if (current[MEMBER_VAR] || current[CONSTRUCTOR] || current[DESTRUCTOR] + || current[MEMBER_FUNC]) { + scope = full_proxy_class_name; + } else { // Friend functions are handled this way + scope = class_static_nspace; + } + assert(scope); + } + return scope; + } + + /* ----------------------------------------------------------------------------- + * luaAddSymbol() + * + * Our implementation of addSymbol. Determines scope correctly, then + * forwards to Language::addSymbol + * ----------------------------------------------------------------------------- */ + + int luaAddSymbol(const String *s, const Node *n) { + String *scope = luaCurrentSymbolNSpace(); + return luaAddSymbol(s, n, scope); + } + + /* ----------------------------------------------------------------------------- + * luaAddSymbol() + * + * Overload. Enforces given scope. Actually, it simply forwards call to Language::addSymbol + * ----------------------------------------------------------------------------- */ + + int luaAddSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { + int result = Language::addSymbol(s, n, scope); + if (!result) + Printf(stderr, "addSymbol(%s to scope %s) failed\n", s, scope); + return result; + } + +}; + +/* NEW LANGUAGE NOTE:*********************************************** + in order to add you language into swig, you need to make the following changes: + - write this file (obviously) + - add into the makefile (not 100% clear on how to do this) + - edit swigmain.cxx to add your module + +near the top of swigmain.cxx, look for this code & add you own codes +======= begin change ========== +extern "C" { + Language *swig_tcl(void); + Language *swig_python(void); + //etc,etc,etc... + Language *swig_lua(void); // this is my code +} + + //etc,etc,etc... + +swig_module modules[] = { + {"-guile", swig_guile, "Guile"}, + {"-java", swig_java, "Java"}, + //etc,etc,etc... + {"-lua", swig_lua, "Lua"}, // this is my code + {NULL, NULL, NULL} // this must come at the end of the list +}; +======= end change ========== + +This is all that is needed + +NEW LANGUAGE NOTE:END ************************************************/ + +/* ----------------------------------------------------------------------------- + * swig_lua() - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_lua(void) { + return new LUA(); +} diff --git a/contrib/tools/swig/Source/Modules/main.cxx b/contrib/tools/swig/Source/Modules/main.cxx new file mode 100644 index 00000000000..d8f2ab6b4f0 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/main.cxx @@ -0,0 +1,1416 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * main.cxx + * + * Main entry point to the SWIG core. + * ----------------------------------------------------------------------------- */ + +#include "swigconfig.h" + +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "swigmod.h" + +#include "swigwarn.h" +#include "cparse.h" +#include <ctype.h> +#include <errno.h> +#include <limits.h> // for INT_MAX + +// Global variables + +static Language *lang = 0; // Language method +int CPlusPlus = 0; +int Extend = 0; // Extend flag +int ForceExtern = 0; // Force extern mode +int GenerateDefault = 1; // Generate default constructors +int Verbose = 0; +int AddExtern = 0; +int NoExcept = 0; +int SwigRuntime = 0; // 0 = no option, 1 = -runtime, 2 = -noruntime + +/* Suppress warning messages for private inheritance, preprocessor evaluation etc... + WARN_PP_EVALUATION 202 + WARN_PARSE_PRIVATE_INHERIT 309 + WARN_PARSE_BUILTIN_NAME 321 + WARN_PARSE_REDUNDANT 322 + WARN_TYPE_ABSTRACT 403 + WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED 405 + WARN_LANG_OVERLOAD_CONST 512 + */ +#define EXTRA_WARNINGS "202,309,403,405,512,321,322" + +extern "C" { + extern String *ModuleName; + extern int ignore_nested_classes; + extern int kwargs_supported; +} + +/* usage string split into multiple parts otherwise string is too big for some compilers */ +/* naming conventions for commandline options - no underscores, no capital letters, join words together + * except when using a common prefix, then use '-' to separate, eg the debug-xxx options */ +static const char *usage1 = (const char *) "\ +\nGeneral Options\n\ + -addextern - Add extra extern declarations\n\ + -c++ - Enable C++ processing\n\ + -co <file> - Check <file> out of the SWIG library\n\ + -copyctor - Automatically generate copy constructors wherever possible\n\ + -cpperraswarn - Treat the preprocessor #error statement as #warning (default)\n\ + -cppext <ext> - Change file extension of generated C++ files to <ext>\n\ + (default is cxx)\n\ + -copyright - Display copyright notices\n\ + -debug-classes - Display information about the classes found in the interface\n\ + -debug-module <n>- Display module parse tree at stages 1-4, <n> is a csv list of stages\n\ + -debug-symtabs - Display symbol tables information\n\ + -debug-symbols - Display target language symbols in the symbol tables\n\ + -debug-csymbols - Display C symbols in the symbol tables\n\ + -debug-lsymbols - Display target language layer symbols\n\ + -debug-tags - Display information about the tags found in the interface\n\ + -debug-template - Display information for debugging templates\n\ + -debug-top <n> - Display entire parse tree at stages 1-4, <n> is a csv list of stages\n\ + -debug-typedef - Display information about the types and typedefs in the interface\n\ + -debug-typemap - Display typemap debugging information\n\ + -debug-tmsearch - Display typemap search debugging information\n\ + -debug-tmused - Display typemaps used debugging information\n\ + -directors - Turn on director mode for all the classes, mainly for testing\n\ + -dirprot - Turn on wrapping of protected members for director classes (default)\n\ + -D<symbol> - Define a symbol <symbol> (for conditional compilation)\n\ +"; + +static const char *usage2 = (const char *) "\ + -E - Preprocess only, does not generate wrapper code\n\ + -external-runtime [file] - Export the SWIG runtime stack\n\ + -fakeversion <v>- Make SWIG fake the program version number to <v>\n\ + -fcompact - Compile in compact mode\n\ + -features <list>- Set global features, where <list> is a comma separated list of\n\ + features, eg -features directors,autodoc=1\n\ + If no explicit value is given to the feature, a default of 1 is used\n\ + -fastdispatch - Enable fast dispatch mode to produce faster overload dispatcher code\n\ + -Fmicrosoft - Display error/warning messages in Microsoft format\n\ + -Fstandard - Display error/warning messages in commonly used format\n\ + -fvirtual - Compile in virtual elimination mode\n\ + -help - Display help\n\ + -I- - Don't search the current directory\n\ + -I<dir> - Look for SWIG files in directory <dir>\n\ + -ignoremissing - Ignore missing include files\n\ + -importall - Follow all #include statements as imports\n\ + -includeall - Follow all #include statements\n\ + -l<ifile> - Include SWIG library file <ifile>\n\ +"; + +static const char *usage3 = (const char *) "\ + -macroerrors - Report errors inside macros\n\ + -makedefault - Create default constructors/destructors (the default)\n\ + -M - List all dependencies\n\ + -MD - Is equivalent to `-M -MF <file>', except `-E' is not implied\n\ + -MF <file> - Generate dependencies into <file> and continue generating wrappers\n\ + -MM - List dependencies, but omit files in SWIG library\n\ + -MMD - Like `-MD', but omit files in SWIG library\n\ + -module <name> - Set module name to <name>\n\ + -MP - Generate phony targets for all dependencies\n\ + -MT <target> - Set the target of the rule emitted by dependency generation\n\ + -nocontract - Turn off contract checking\n\ + -nocpperraswarn - Do not treat the preprocessor #error statement as #warning\n\ + -nodefault - Do not generate default constructors nor default destructors\n\ + -nodefaultctor - Do not generate implicit default constructors\n\ + -nodefaultdtor - Do not generate implicit default destructors\n\ + -nodirprot - Do not wrap director protected members\n\ + -noexcept - Do not wrap exception specifiers\n\ + -nofastdispatch - Disable fast dispatch mode (default)\n\ + -nopreprocess - Skip the preprocessor step\n\ + -notemplatereduce - Disable reduction of the typedefs in templates\n\ +"; + +static const char *usage4 = (const char *) "\ + -O - Enable the optimization options:\n\ + -fastdispatch -fvirtual\n\ + -o <outfile> - Set name of C/C++ output file to <outfile>\n\ + -oh <headfile> - Set name of C++ output header file for directors to <headfile>\n\ + -outcurrentdir - Set default output dir to current dir instead of input file's path\n\ + -outdir <dir> - Set language specific files output directory to <dir>\n\ + -pcreversion - Display PCRE version information\n\ + -small - Compile in virtual elimination and compact mode\n\ + -swiglib - Report location of SWIG library and exit\n\ + -templatereduce - Reduce all the typedefs in templates\n\ + -v - Run in verbose mode\n\ + -version - Display SWIG version number\n\ + -Wall - Remove all warning suppression, also implies -Wextra\n\ + -Wallkw - Enable keyword warnings for all the supported languages\n\ + -Werror - Treat warnings as errors\n\ + -Wextra - Adds the following additional warnings: " EXTRA_WARNINGS "\n\ + -w<list> - Suppress/add warning messages, eg -w401,+321 - see Warnings.html\n\ + -xmlout <file> - Write XML version of the parse tree to <file> after normal processing\n\ +\n\ +Options can also be defined using the SWIG_FEATURES environment variable, for example:\n\ +\n\ + $ SWIG_FEATURES=\"-Wall\"\n\ + $ export SWIG_FEATURES\n\ + $ swig -python interface.i\n\ +\n\ +is equivalent to:\n\ +\n\ + $ swig -Wall -python interface.i\n\ +\n\ +Arguments may also be passed in a file, separated by whitespace. For example:\n\ +\n\ + $ echo \"-Wall -python interface.i\" > args.txt\n\ + $ swig @args.txt\n\ +\n"; + +// Local variables +static String *LangSubDir = 0; // Target language library subdirectory +static String *SwigLib = 0; // Library directory +static String *SwigLibWinUnix = 0; // Extra library directory on Windows +static int freeze = 0; +static String *lang_config = 0; +static const char *hpp_extension = "h"; +static const char *cpp_extension = "cxx"; +static const char *depends_extension = "d"; +static String *outdir = 0; +static String *xmlout = 0; +static int outcurrentdir = 0; +static int help = 0; +static int checkout = 0; +static int cpp_only = 0; +static int no_cpp = 0; +static String *outfile_name = 0; +static String *outfile_name_h = 0; +static int tm_debug = 0; +static int dump_symtabs = 0; +static int dump_symbols = 0; +static int dump_csymbols = 0; +static int dump_lang_symbols = 0; +static int dump_tags = 0; +static int dump_module = 0; +static int dump_top = 0; +static int dump_xml = 0; +static int browse = 0; +static int dump_typedef = 0; +static int dump_classes = 0; +static int werror = 0; +static int depend = 0; +static int depend_only = 0; +static int depend_phony = 0; +static int memory_debug = 0; +static int allkw = 0; +static DOH *cpps = 0; +static String *dependencies_file = 0; +static String *dependencies_target = 0; +static int external_runtime = 0; +static String *external_runtime_name = 0; +enum { STAGE1=1, STAGE2=2, STAGE3=4, STAGE4=8, STAGEOVERFLOW=16 }; +static List *libfiles = 0; +static List *all_output_files = 0; + +/* ----------------------------------------------------------------------------- + * check_extension() + * + * Checks the extension of a file to see if we should emit extern declarations. + * ----------------------------------------------------------------------------- */ + +static bool check_extension(String *filename) { + bool wanted = false; + const char *name = Char(filename); + if (!name) + return 0; + String *extension = Swig_file_extension(name); + const char *c = Char(extension); + if ((strcmp(c, ".c") == 0) || + (strcmp(c, ".C") == 0) || (strcmp(c, ".cc") == 0) || (strcmp(c, ".cxx") == 0) || (strcmp(c, ".c++") == 0) || (strcmp(c, ".cpp") == 0)) { + wanted = true; + } + Delete(extension); + return wanted; +} + +/* ----------------------------------------------------------------------------- + * install_opts() + * + * Install all command line options as preprocessor symbols + * ----------------------------------------------------------------------------- */ + +static void install_opts(int argc, char *argv[]) { + int i; + int noopt = 0; + char *c; + for (i = 1; i < (argc - 1); i++) { + if (argv[i]) { + if ((*argv[i] == '-') && (!isupper(*(argv[i] + 1)))) { + String *opt = NewStringf("SWIGOPT%(upper)s", argv[i]); + Replaceall(opt, "-", "_"); + c = Char(opt); + noopt = 0; + while (*c) { + if (!(isalnum(*c) || (*c == '_'))) { + noopt = 1; + break; + } + c++; + } + if (((i + 1) < (argc - 1)) && (argv[i + 1]) && (*argv[i + 1] != '-')) { + Printf(opt, " %s", argv[i + 1]); + i++; + } else { + Printf(opt, " 1"); + } + if (!noopt) { + /* Printf(stdout,"%s\n", opt); */ + Preprocessor_define(opt, 0); + } + Delete(opt); + } + } + } +} + +/* ----------------------------------------------------------------------------- + * decode_numbers_list() + * + * Decode comma separated list into a binary number of the inputs or'd together + * eg list="1,4" will return (2^0 || 2^3) = 0x1001 + * ----------------------------------------------------------------------------- */ + +static unsigned int decode_numbers_list(String *numlist) { + unsigned int decoded_number = 0; + if (numlist) { + List *numbers = Split(numlist, ',', INT_MAX); + if (numbers && Len(numbers) > 0) { + for (Iterator it = First(numbers); it.item; it = Next(it)) { + String *numstring = it.item; + // TODO: check that it is a number + int number = atoi(Char(numstring)); + if (number > 0 && number <= 16) { + decoded_number |= (1 << (number-1)); + } + } + } + } + return decoded_number; +} + +/* ----------------------------------------------------------------------------- + * Sets the output directory for language specific (proxy) files from the + * C wrapper file if not set and corrects the directory name and adds a trailing + * file separator if necessary. + * ----------------------------------------------------------------------------- */ + +static void configure_outdir(const String *c_wrapper_outfile) { + + // Use the C wrapper file's directory if the output directory has not been set by user + if (!outdir || Len(outdir) == 0) + outdir = Swig_file_dirname(c_wrapper_outfile); + + Swig_filename_correct(outdir); + + // Add trailing file delimiter if not present in output directory name + if (Len(outdir) > 0) { + const char *outd = Char(outdir); + if (strcmp(outd + strlen(outd) - strlen(SWIG_FILE_DELIMITER), SWIG_FILE_DELIMITER) != 0) + Printv(outdir, SWIG_FILE_DELIMITER, NIL); + } +} + +/* This function sets the name of the configuration file */ +void SWIG_config_file(const_String_or_char_ptr filename) { + lang_config = NewString(filename); +} + +/* Sets the target language subdirectory name */ +void SWIG_library_directory(const char *subdirectory) { + LangSubDir = NewString(subdirectory); +} + +// Returns the directory for generating language specific files (non C/C++ files) +const String *SWIG_output_directory() { + assert(outdir); + return outdir; +} + +void SWIG_config_cppext(const char *ext) { + cpp_extension = ext; +} + +List *SWIG_output_files() { + assert(all_output_files); + return all_output_files; +} + +void SWIG_setfeature(const char *cfeature, const char *cvalue) { + Hash *features_hash = Swig_cparse_features(); + String *name = NewString(""); + String *fname = NewString(cfeature); + String *fvalue = NewString(cvalue); + Swig_feature_set(features_hash, name, 0, fname, fvalue, 0); + Delete(name); + Delete(fname); + Delete(fvalue); +} + + +void SWIG_setfeatures(const char *c) { + char feature[64]; + char *fb = feature; + char *fe = fb + 63; + Hash *features_hash = Swig_cparse_features(); + String *name = NewString(""); + /* Printf(stderr,"all features %s\n", c); */ + while (*c) { + char *f = fb; + String *fname = NewString("feature:"); + String *fvalue = NewString(""); + while ((f != fe) && *c != '=' && *c != ',' && *c) { + *(f++) = *(c++); + } + *f = 0; + Printf(fname, "%s", feature); + if (*c && *(c++) == '=') { + char value[64]; + char *v = value; + char *ve = v + 63; + while ((v != ve) && *c != ',' && *c && !isspace(*c)) { + *(v++) = *(c++); + } + *v = 0; + Printf(fvalue, "%s", value); + } else { + Printf(fvalue, "1"); + } + /* Printf(stderr,"%s %s\n", fname, fvalue); */ + Swig_feature_set(features_hash, name, 0, fname, fvalue, 0); + Delete(fname); + Delete(fvalue); + } + Delete(name); +} + +/* This function handles the -external-runtime command option */ +static void SWIG_dump_runtime() { + String *outfile; + File *runtime; + String *s; + + outfile = external_runtime_name; + if (!outfile) { + outfile = lang->defaultExternalRuntimeFilename(); + if (!outfile) { + Printf(stderr, "*** Please provide a filename for the external runtime\n"); + SWIG_exit(EXIT_FAILURE); + } + } + + runtime = NewFile(outfile, "w", SWIG_output_files()); + if (!runtime) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(runtime); + Printf(runtime, "\n"); + + s = Swig_include_sys("swiglabels.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swiglabels.swg'\n"); + Delete(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + s = Swig_include_sys("swigerrors.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swigerrors.swg'\n"); + Delete(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + s = Swig_include_sys("swigrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swigrun.swg'\n"); + Delete(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + s = lang->runtimeCode(); + Printf(runtime, "%s", s); + Delete(s); + + s = Swig_include_sys("runtime.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'runtime.swg'\n"); + Delete(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + Delete(runtime); + SWIG_exit(EXIT_SUCCESS); +} + +static void getoptions(int argc, char *argv[]) { + int i; + // Get options + for (i = 1; i < argc; i++) { + if (argv[i] && !Swig_check_marked(i)) { + if (strncmp(argv[i], "-I-", 3) == 0) { + // Don't push/pop directories + Swig_set_push_dir(0); + Swig_mark_arg(i); + } else if (strncmp(argv[i], "-I", 2) == 0) { + // Add a new directory search path + char *a = Swig_copy_string(argv[i] + 2); + Swig_add_directory((DOH *) a); + free(a); + Swig_mark_arg(i); + } else if (strncmp(argv[i], "-D", 2) == 0) { + String *d = NewString(argv[i] + 2); + Replace(d, "=", " ", DOH_REPLACE_ANY | DOH_REPLACE_FIRST); + Preprocessor_define((DOH *) d, 0); + Delete(d); + // Create a symbol + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-E") == 0) { + cpp_only = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nopreprocess") == 0) { + no_cpp = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-verbose") == 0) || (strcmp(argv[i], "-v") == 0)) { + Verbose = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-c++") == 0) { + CPlusPlus = 1; + Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); + Swig_cparse_cplusplus(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-c++out") == 0) { + // Undocumented + Swig_cparse_cplusplusout(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fcompact") == 0) { + Wrapper_compact_print_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fvirtual") == 0) { + Wrapper_virtual_elimination_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastdispatch") == 0) { + Wrapper_fast_dispatch_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastdispatch") == 0) { + Wrapper_fast_dispatch_mode_set(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-naturalvar") == 0) { + Wrapper_naturalvar_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-directors") == 0) { + SWIG_setfeature("feature:director", "1"); + Wrapper_director_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dirprot") == 0) { + Wrapper_director_protected_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nodirprot") == 0) { + Wrapper_director_protected_mode_set(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-pcreversion") == 0) { + String *version = Swig_pcre_version(); + Printf(stdout, "%s\n", version); + Delete(version); + Swig_mark_arg(i); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-small") == 0) { + Wrapper_compact_print_mode_set(1); + Wrapper_virtual_elimination_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-runtime") == 0) { // Used to also accept -c. removed in swig-1.3.36 + Swig_mark_arg(i); + Swig_warning(WARN_DEPRECATED_OPTC, "SWIG", 1, "-runtime, -noruntime command line options are deprecated.\n"); + SwigRuntime = 1; + } else if (strcmp(argv[i], "-noruntime") == 0) { + Swig_mark_arg(i); + Swig_warning(WARN_DEPRECATED_OPTC, "SWIG", 1, "-runtime, -noruntime command line options are deprecated.\n"); + SwigRuntime = 2; + } else if (strcmp(argv[i], "-external-runtime") == 0) { + external_runtime = 1; + Swig_mark_arg(i); + if (argv[i + 1]) { + external_runtime_name = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + i++; + } + } else if ((strcmp(argv[i], "-make_default") == 0) || (strcmp(argv[i], "-makedefault") == 0)) { + GenerateDefault = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-no_default") == 0) || (strcmp(argv[i], "-nodefault") == 0)) { + GenerateDefault = 0; + Swig_warning(WARN_DEPRECATED_NODEFAULT, "SWIG", 1, "dangerous, use -nodefaultctor, -nodefaultdtor instead.\n"); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-nodefaultctor") == 0)) { + SWIG_setfeature("feature:nodefaultctor", "1"); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-nodefaultdtor") == 0)) { + SWIG_setfeature("feature:nodefaultdtor", "1"); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-copyctor") == 0)) { + SWIG_setfeature("feature:copyctor", "1"); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noexcept") == 0) { + NoExcept = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noextern") == 0) { + Swig_warning(WARN_DEPRECATED_NOEXTERN, "SWIG", 1, "-noextern command line option is deprecated; extern is no longer generated by default.\n"); + AddExtern = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-addextern") == 0) { + AddExtern = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-template") == 0) || (strcmp(argv[i], "-debug_template") == 0) || (strcmp(argv[i], "-show_templates") == 0)) { + Swig_cparse_debug_templates(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-templatereduce") == 0) { + SWIG_cparse_template_reduce(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-notemplatereduce") == 0) { + SWIG_cparse_template_reduce(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-macroerrors") == 0) { + Swig_cparse_follow_locators(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-swiglib") == 0) { + Printf(stdout, "%s\n", SwigLib); + if (SwigLibWinUnix) + Printf(stdout, "%s\n", SwigLibWinUnix); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-o") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outfile_name = NewString(argv[i + 1]); + Swig_filename_correct(outfile_name); + if (!outfile_name_h || !dependencies_file) { + char *ext = strrchr(Char(outfile_name), '.'); + String *basename = ext ? NewStringWithSize(Char(outfile_name), (int)(Char(ext) - Char(outfile_name))) : NewString(outfile_name); + if (!dependencies_file) { + dependencies_file = NewStringf("%s.%s", basename, depends_extension); + } + if (!outfile_name_h) { + Printf(basename, ".%s", hpp_extension); + outfile_name_h = NewString(basename); + } + Delete(basename); + } + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-oh") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outfile_name_h = NewString(argv[i + 1]); + Swig_filename_correct(outfile_name_h); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-fakeversion") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + Swig_set_fakeversion(argv[i + 1]); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-version") == 0) { + fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); + fprintf(stdout, "\nCompiled with %s [%s]\n", SWIG_CXX, SWIG_PLATFORM); + fprintf(stdout, "\nConfigured options: %cpcre\n", +#ifdef HAVE_PCRE + '+' +#else + '-' +#endif + ); + fprintf(stdout, "\nPlease see %s for reporting bugs and further information\n", PACKAGE_BUGREPORT); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-copyright") == 0) { + fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); + fprintf(stdout, "Copyright (c) 1995-1998\n"); + fprintf(stdout, "University of Utah and the Regents of the University of California\n"); + fprintf(stdout, "Copyright (c) 1998-2005\n"); + fprintf(stdout, "University of Chicago\n"); + fprintf(stdout, "Copyright (c) 2005-2006\n"); + fprintf(stdout, "Arizona Board of Regents (University of Arizona)\n"); + SWIG_exit(EXIT_SUCCESS); + } else if (strncmp(argv[i], "-l", 2) == 0) { + // Add a new directory search path + Append(libfiles, argv[i] + 2); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-co") == 0) { + checkout = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-features") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + SWIG_setfeatures(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-freeze") == 0) { + freeze = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-includeall") == 0) { + Preprocessor_include_all(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-importall") == 0) { + Preprocessor_import_all(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-ignoremissing") == 0) { + Preprocessor_ignore_missing(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cpperraswarn") == 0) { + Preprocessor_error_as_warning(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocpperraswarn") == 0) { + Preprocessor_error_as_warning(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppext") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + SWIG_config_cppext(argv[i + 1]); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-debug-typemap") == 0) || (strcmp(argv[i], "-debug_typemap") == 0) || (strcmp(argv[i], "-tm_debug") == 0)) { + tm_debug = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-tmsearch") == 0) { + Swig_typemap_search_debug_set(); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-tmused") == 0) { + Swig_typemap_used_debug_set(); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-module") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + ModuleName = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-M") == 0) { + depend = 1; + depend_only = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MM") == 0) { + depend = 2; + depend_only = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MF") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + dependencies_file = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-MD") == 0) { + depend = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MMD") == 0) { + depend = 2; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MP") == 0) { + depend_phony = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MT") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + if (!dependencies_target) + dependencies_target = NewString(argv[i + 1]); + else + Printf(dependencies_target, " %s", argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-outdir") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outdir = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-outcurrentdir") == 0) { + Swig_mark_arg(i); + outcurrentdir = 1; + } else if (strcmp(argv[i], "-Wall") == 0) { + Swig_mark_arg(i); + Swig_warnall(); + } else if (strcmp(argv[i], "-Wallkw") == 0) { + allkw = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Werror") == 0) { + werror = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Wextra") == 0) { + Swig_mark_arg(i); + Swig_warnfilter(EXTRA_WARNINGS, 0); + } else if (strncmp(argv[i], "-w", 2) == 0) { + Swig_mark_arg(i); + Swig_warnfilter(argv[i] + 2, 1); + } else if (strcmp(argv[i], "-debug-symtabs") == 0) { + dump_symtabs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-symbols") == 0) { + dump_symbols = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-csymbols") == 0) { + dump_csymbols = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-lsymbols") == 0) { + dump_lang_symbols = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-tags") == 0) || (strcmp(argv[i], "-dump_tags") == 0)) { + dump_tags = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-top") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + String *dump_list = NewString(argv[i + 1]); + dump_top = decode_numbers_list(dump_list); + if (dump_top < STAGE1 || dump_top >= STAGEOVERFLOW) + Swig_arg_error(); + else + Swig_mark_arg(i + 1); + Delete(dump_list); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-debug-module") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + String *dump_list = NewString(argv[i + 1]); + dump_module = decode_numbers_list(dump_list); + if (dump_module < STAGE1 || dump_module >= STAGEOVERFLOW) + Swig_arg_error(); + else + Swig_mark_arg(i + 1); + Delete(dump_list); + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-dump_tree") == 0) || (strcmp(argv[i], "-dump_top") == 0)) { + dump_top |= STAGE4; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_module") == 0) { + dump_module |= STAGE4; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_parse_module") == 0) { + dump_module |= STAGE1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_parse_top") == 0) { + dump_top |= STAGE1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_xml") == 0) { + dump_xml = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-xmlout") == 0) { + dump_xml = 1; + Swig_mark_arg(i); + if (argv[i + 1]) { + xmlout = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-nocontract") == 0) { + Swig_mark_arg(i); + Swig_contract_mode_set(0); + } else if (strcmp(argv[i], "-browse") == 0) { + browse = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-typedef") == 0) || (strcmp(argv[i], "-dump_typedef") == 0)) { + dump_typedef = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-classes") == 0) || (strcmp(argv[i], "-dump_classes") == 0)) { + dump_classes = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-memory") == 0) || (strcmp(argv[i], "-dump_memory") == 0)) { + memory_debug = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Fstandard") == 0) { + Swig_error_msg_format(EMF_STANDARD); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Fmicrosoft") == 0) { + Swig_error_msg_format(EMF_MICROSOFT); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-O") == 0) { + Wrapper_virtual_elimination_mode_set(1); + Wrapper_fast_dispatch_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage1, stdout); + fputs(usage2, stdout); + fputs(usage3, stdout); + fputs(usage4, stdout); + Swig_mark_arg(i); + help = 1; + } + } + } +} + +int SWIG_main(int argc, char *argv[], const TargetLanguageModule *tlm) { + char *c; + + /* Initialize the SWIG core */ + Swig_init(); + + // Default warning suppression + Swig_warnfilter(EXTRA_WARNINGS, 1); + + // Initialize the preprocessor + Preprocessor_init(); + + // Set lang to a dummy value if no target language was specified so we + // can process options enough to handle -version, etc. + lang = tlm ? tlm->fac() : new Language; + + // Set up some default symbols (available in both SWIG interface files + // and C files) + + Preprocessor_define((DOH *) "SWIG 1", 0); + Preprocessor_define((DOH *) "__STDC__", 0); + + // Set the SWIG version value in format 0xAABBCC from package version expected to be in format A.B.C + String *package_version = NewString(PACKAGE_VERSION); /* Note that the fakeversion has not been set at this point */ + char *token = strtok(Char(package_version), "."); + String *vers = NewString("SWIG_VERSION 0x"); + int count = 0; + while (token) { + int len = (int)strlen(token); + assert(len == 1 || len == 2); + Printf(vers, "%s%s", (len == 1) ? "0" : "", token); + token = strtok(NULL, "."); + count++; + } + Delete(package_version); + assert(count == 3); // Check version format is correct + + /* Turn on contracts */ + + Swig_contract_mode_set(1); + Preprocessor_define(vers, 0); + + /* Turn off directors mode */ + Wrapper_director_mode_set(0); + Wrapper_director_protected_mode_set(1); + + // Inform the parser if the nested classes should be ignored unless explicitly told otherwise via feature:flatnested + ignore_nested_classes = lang->nestedClassesSupport() == Language::NCS_Unknown ? 1 : 0; + + kwargs_supported = lang->kwargsSupport() ? 1 : 0; + + // Create Library search directories + + // Check for SWIG_LIB environment variable + if ((c = getenv("SWIG_LIB")) == (char *) 0) { +#if defined(_WIN32) + char buf[MAX_PATH]; + char *p; + if (!(GetModuleFileName(0, buf, MAX_PATH) == 0 || (p = strrchr(buf, '\\')) == 0)) { + *(p + 1) = '\0'; + SwigLib = NewStringf("%sLib", buf); // Native windows installation path + } else { + SwigLib = NewStringf(""); // Unexpected error + } + if (Len(SWIG_LIB_WIN_UNIX) > 0) + SwigLibWinUnix = NewString(SWIG_LIB_WIN_UNIX); // Unix installation path using a drive letter (for msys/mingw) +#else + SwigLib = NewString(SWIG_LIB); +#endif + } else { + SwigLib = NewString(c); + } + + libfiles = NewList(); + all_output_files = NewList(); + + /* Check for SWIG_FEATURES environment variable */ + + getoptions(argc, argv); + + // Define the __cplusplus symbol + if (CPlusPlus) + Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); + + // Parse language dependent options + lang->main(argc, argv); + + if (help) { + Printf(stdout, "\nNote: 'swig -<lang> -help' displays options for a specific target language.\n\n"); + SWIG_exit(EXIT_SUCCESS); // Exit if we're in help mode + } + + // Check all of the options to make sure we're cool. + // Don't check for an input file if -external-runtime is passed + Swig_check_options(external_runtime ? 0 : 1); + + if (CPlusPlus && cparse_cplusplusout) { + Printf(stderr, "The -c++out option is for C input but C++ input has been requested via -c++\n"); + SWIG_exit(EXIT_FAILURE); + } + + install_opts(argc, argv); + + // Add language dependent directory to the search path + { + String *rl = NewString(""); + Printf(rl, ".%sswig_lib%s%s", SWIG_FILE_DELIMITER, SWIG_FILE_DELIMITER, LangSubDir); + Swig_add_directory(rl); + if (SwigLibWinUnix) { + rl = NewString(""); + Printf(rl, "%s%s%s", SwigLibWinUnix, SWIG_FILE_DELIMITER, LangSubDir); + Swig_add_directory(rl); + } + rl = NewString(""); + Printf(rl, "%s%s%s", SwigLib, SWIG_FILE_DELIMITER, LangSubDir); + Swig_add_directory(rl); + } + + Swig_add_directory((String *) "." SWIG_FILE_DELIMITER "swig_lib"); + if (SwigLibWinUnix) + Swig_add_directory((String *) SwigLibWinUnix); + Swig_add_directory(SwigLib); + + if (Verbose) { + Printf(stdout, "Language subdirectory: %s\n", LangSubDir); + Printf(stdout, "Search paths:\n"); + List *sp = Swig_search_path(); + Iterator s; + for (s = First(sp); s.item; s = Next(s)) { + Printf(stdout, " %s\n", s.item); + } + } + // handle the -external-runtime argument + if (external_runtime) + SWIG_dump_runtime(); + + // If we made it this far, looks good. go for it.... + + input_file = NewString(argv[argc - 1]); + Swig_filename_correct(input_file); + + // If the user has requested to check out a file, handle that + if (checkout) { + DOH *s; + String *outfile = input_file; + if (outfile_name) + outfile = outfile_name; + + if (Verbose) + Printf(stdout, "Handling checkout...\n"); + + s = Swig_include(input_file); + if (!s) { + Printf(stderr, "Unable to locate '%s' in the SWIG library.\n", input_file); + } else { + FILE *f = Swig_open(outfile); + if (f) { + fclose(f); + Printf(stderr, "File '%s' already exists. Checkout aborted.\n", outfile); + } else { + File *f_outfile = NewFile(outfile, "w", SWIG_output_files()); + if (!f_outfile) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } else { + if (Verbose) + Printf(stdout, "'%s' checked out from the SWIG library.\n", outfile); + Printv(f_outfile, s, NIL); + Delete(f_outfile); + } + } + } + } else { + // Run the preprocessor + if (Verbose) + Printf(stdout, "Preprocessing...\n"); + + { + int i; + String *fs = NewString(""); + FILE *df = Swig_open(input_file); + if (!df) { + df = Swig_include_open(input_file); + if (!df) { + char *cfile = Char(input_file); + if (cfile && cfile[0] == '-') { + Printf(stderr, "Unable to find option or file '%s', ", input_file); + Printf(stderr, "Use 'swig -help' for more information.\n"); + } else { + Printf(stderr, "Unable to find file '%s'.\n", input_file); + } + SWIG_exit(EXIT_FAILURE); + } else { + Swig_warning(WARN_DEPRECATED_INPUT_FILE, "SWIG", 1, "Use of the include path to find the input file is deprecated and will not work with ccache. Please include the path when specifying the input file.\n"); // so that behaviour is like c/c++ compilers + } + } + + if (!tlm) { + Printf(stderr, "No target language specified.\n"); + Printf(stderr, "Use 'swig -help' for more information.\n"); + SWIG_exit(EXIT_FAILURE); + } + + if (!no_cpp) { + fclose(df); + Printf(fs, "%%include <swig.swg>\n"); + if (allkw) { + Printf(fs, "%%include <allkw.swg>\n"); + } + if (lang_config) { + Printf(fs, "\n%%include <%s>\n", lang_config); + } + Printf(fs, "%%include(maininput=\"%s\") \"%s\"\n", Swig_filename_escape(input_file), Swig_filename_escape(Swig_last_file())); + for (i = 0; i < Len(libfiles); i++) { + Printf(fs, "\n%%include \"%s\"\n", Swig_filename_escape(Getitem(libfiles, i))); + } + Seek(fs, 0, SEEK_SET); + cpps = Preprocessor_parse(fs); + Delete(fs); + } else { + cpps = Swig_read_file(df); + fclose(df); + } + if (Swig_error_count()) { + SWIG_exit(EXIT_FAILURE); + } + if (cpp_only) { + Printf(stdout, "%s", cpps); + SWIG_exit(EXIT_SUCCESS); + } + if (depend) { + if (!no_cpp) { + String *outfile; + File *f_dependencies_file = 0; + + String *inputfile_filename = outcurrentdir ? Swig_file_filename(input_file): Copy(input_file); + String *basename = Swig_file_basename(inputfile_filename); + if (!outfile_name) { + if (CPlusPlus || lang->cplus_runtime_mode()) { + outfile = NewStringf("%s_wrap.%s", basename, cpp_extension); + } else { + outfile = NewStringf("%s_wrap.c", basename); + } + } else { + outfile = NewString(outfile_name); + } + if (dependencies_file && Len(dependencies_file) != 0) { + f_dependencies_file = NewFile(dependencies_file, "w", SWIG_output_files()); + if (!f_dependencies_file) { + FileErrorDisplay(dependencies_file); + SWIG_exit(EXIT_FAILURE); + } + } else if (!depend_only) { + String *filename = NewStringf("%s_wrap.%s", basename, depends_extension); + f_dependencies_file = NewFile(filename, "w", SWIG_output_files()); + if (!f_dependencies_file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + } else + f_dependencies_file = stdout; + if (dependencies_target) { + Printf(f_dependencies_file, "%s: ", Swig_filename_escape_space(dependencies_target)); + } else { + Printf(f_dependencies_file, "%s: ", Swig_filename_escape_space(outfile)); + } + List *files = Preprocessor_depend(); + List *phony_targets = NewList(); + for (int i = 0; i < Len(files); i++) { + int use_file = 1; + if (depend == 2) { + if ((Strncmp(Getitem(files, i), SwigLib, Len(SwigLib)) == 0) || (SwigLibWinUnix && (Strncmp(Getitem(files, i), SwigLibWinUnix, Len(SwigLibWinUnix)) == 0))) + use_file = 0; + } + if (use_file) { + Printf(f_dependencies_file, "\\\n %s ", Swig_filename_escape_space(Getitem(files, i))); + if (depend_phony) + Append(phony_targets, Getitem(files, i)); + } + } + Printf(f_dependencies_file, "\n"); + if (depend_phony) { + for (int i = 0; i < Len(phony_targets); i++) { + Printf(f_dependencies_file, "\n%s:\n", Swig_filename_escape_space(Getitem(phony_targets, i))); + } + } + + if (f_dependencies_file != stdout) + Delete(f_dependencies_file); + if (depend_only) + SWIG_exit(EXIT_SUCCESS); + Delete(inputfile_filename); + Delete(basename); + Delete(phony_targets); + } else { + Printf(stderr, "Cannot generate dependencies with -nopreprocess\n"); + // Actually we could but it would be inefficient when just generating dependencies, as it would be done after Swig_cparse + SWIG_exit(EXIT_FAILURE); + } + } + Seek(cpps, 0, SEEK_SET); + } + + /* Register a null file with the file handler */ + Swig_register_filebyname("null", NewString("")); + + // Pass control over to the specific language interpreter + if (Verbose) { + fprintf(stdout, "Starting language-specific parse...\n"); + fflush(stdout); + } + + Node *top = Swig_cparse(cpps); + + if (dump_top & STAGE1) { + Printf(stdout, "debug-top stage 1\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE1) { + Printf(stdout, "debug-module stage 1\n"); + Swig_print_tree(Getattr(top, "module")); + } + if (!CPlusPlus) { + if (Verbose) + Printf(stdout, "Processing unnamed structs...\n"); + Swig_nested_name_unnamed_c_structs(top); + } + Swig_extend_unused_check(); + + if (Verbose) { + Printf(stdout, "Processing types...\n"); + } + Swig_process_types(top); + + if (dump_top & STAGE2) { + Printf(stdout, "debug-top stage 2\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE2) { + Printf(stdout, "debug-module stage 2\n"); + Swig_print_tree(Getattr(top, "module")); + } + + if (Verbose) { + Printf(stdout, "C++ analysis...\n"); + } + Swig_default_allocators(top); + + if (CPlusPlus) { + if (Verbose) + Printf(stdout, "Processing nested classes...\n"); + Swig_nested_process_classes(top); + } + + if (dump_top & STAGE3) { + Printf(stdout, "debug-top stage 3\n"); + Swig_print_tree(top); + } + if (top && (dump_module & STAGE3)) { + Printf(stdout, "debug-module stage 3\n"); + Swig_print_tree(Getattr(top, "module")); + } + + if (Verbose) { + Printf(stdout, "Generating wrappers...\n"); + } + + if (top && dump_classes) { + Hash *classes = Getattr(top, "classes"); + if (classes) { + Printf(stdout, "Classes\n"); + Printf(stdout, "------------\n"); + Iterator ki; + for (ki = First(classes); ki.key; ki = Next(ki)) { + Printf(stdout, "%s\n", ki.key); + } + } + } + + if (dump_typedef) { + SwigType_print_scope(); + } + + if (dump_symtabs) { + Swig_symbol_print_tables(Swig_symbol_global_scope()); + Swig_symbol_print_tables_summary(); + } + + if (dump_symbols) { + Swig_symbol_print_symbols(); + } + + if (dump_csymbols) { + Swig_symbol_print_csymbols(); + } + + if (dump_tags) { + Swig_print_tags(top, 0); + } + if (top) { + if (!Getattr(top, "name")) { + Printf(stderr, "No module name specified using %%module or -module.\n"); + SWIG_exit(EXIT_FAILURE); + } else { + /* Set some filename information on the object */ + String *infile = scanner_get_main_input_file(); + if (!infile) { + Printf(stderr, "Missing input file in preprocessed output.\n"); + SWIG_exit(EXIT_FAILURE); + } + Setattr(top, "infile", infile); // Note: if nopreprocess then infile is the original input file, otherwise input_file + Setattr(top, "inputfile", input_file); + + String *infile_filename = outcurrentdir ? Swig_file_filename(infile): Copy(infile); + String *basename = Swig_file_basename(infile_filename); + if (!outfile_name) { + if (CPlusPlus || lang->cplus_runtime_mode()) { + Setattr(top, "outfile", NewStringf("%s_wrap.%s", basename, cpp_extension)); + } else { + Setattr(top, "outfile", NewStringf("%s_wrap.c", basename)); + } + } else { + Setattr(top, "outfile", outfile_name); + } + if (!outfile_name_h) { + Setattr(top, "outfile_h", NewStringf("%s_wrap.%s", basename, hpp_extension)); + } else { + Setattr(top, "outfile_h", outfile_name_h); + } + configure_outdir(Getattr(top, "outfile")); + if (Swig_contract_mode_get()) { + Swig_contracts(top); + } + + // Check the extension for a c/c++ file. If so, we're going to declare everything we see as "extern" + ForceExtern = check_extension(input_file); + + if (tlm->status == Experimental) { + Swig_warning(WARN_LANG_EXPERIMENTAL, "SWIG", 1, "Experimental target language. " + "Target language %s specified by %s is an experimental language. " + "Please read about SWIG experimental languages, http://swig.org/Doc4.0/Introduction.html#Introduction_experimental_status.\n", + tlm->help ? tlm->help : "", tlm->name); + } + + lang->top(top); + + if (browse) { + Swig_browser(top, 0); + } + Delete(infile_filename); + Delete(basename); + } + } + if (dump_lang_symbols) { + lang->dumpSymbols(); + } + if (dump_top & STAGE4) { + Printf(stdout, "debug-top stage 4\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE4) { + Printf(stdout, "debug-module stage 4\n"); + Swig_print_tree(Getattr(top, "module")); + } + if (dump_xml && top) { + delete lang; + lang = 0; + Swig_print_xml(top, xmlout); + } + Delete(top); + } + if (tm_debug) + Swig_typemap_debug(); + if (memory_debug) + DohMemoryDebug(); + + char *outfiles = getenv("CCACHE_OUTFILES"); + if (outfiles) { + File *f_outfiles = NewFile(outfiles, "w", 0); + if (!f_outfiles) { + Printf(stderr, "Failed to write list of output files to the filename '%s' specified in CCACHE_OUTFILES environment variable - ", outfiles); + FileErrorDisplay(outfiles); + SWIG_exit(EXIT_FAILURE); + } else { + int i; + for (i = 0; i < Len(all_output_files); i++) + Printf(f_outfiles, "%s\n", Getitem(all_output_files, i)); + Delete(f_outfiles); + } + } + + // Deletes + Delete(libfiles); + Preprocessor_delete(); + + while (freeze) { + } + + delete lang; + + int error_count = werror ? Swig_warn_count() : 0; + error_count += Swig_error_count(); + + if (error_count != 0) + SWIG_exit(error_count); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * SWIG_exit() + * + * Cleanup and either freeze or exit + * ----------------------------------------------------------------------------- */ + +void SWIG_exit(int exit_code) { + while (freeze) { + } + + if (exit_code > 0) { + CloseAllOpenFiles(); + + /* Remove all generated files */ + if (all_output_files) { + for (int i = 0; i < Len(all_output_files); i++) { + String *filename = Getitem(all_output_files, i); + int removed = remove(Char(filename)); + if (removed == -1) + fprintf(stderr, "On exit, could not delete file %s: %s\n", Char(filename), strerror(errno)); + } + } + } + + exit(exit_code); +} diff --git a/contrib/tools/swig/Source/Modules/mzscheme.cxx b/contrib/tools/swig/Source/Modules/mzscheme.cxx new file mode 100644 index 00000000000..788681330a9 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/mzscheme.cxx @@ -0,0 +1,819 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * mzscheme.cxx + * + * Mzscheme language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +#include <ctype.h> + +static const char *usage = "\ +Mzscheme Options (available with -mzscheme)\n\ + -declaremodule - Create extension that declares a module\n\ + -dynamic-load <lib>,[lib,...] - Do not link with these libraries, dynamic load them\n\ + -noinit - Do not emit module initialization code\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ +"; + +static String *fieldnames_tab = 0; +static String *convert_tab = 0; +static String *convert_proto_tab = 0; +static String *struct_name = 0; +static String *mangled_struct_name = 0; + +static String *prefix = 0; +static bool declaremodule = false; +static bool noinit = false; +static String *load_libraries = NULL; +static String *module = 0; +static const char *mzscheme_path = "mzscheme"; +static String *init_func_def = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; + +// Used for garbage collection +static int exporting_destructor = 0; +static String *swigtype_ptr = 0; +static String *cls_swigtype = 0; + +class MZSCHEME:public Language { +public: + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + int i; + + SWIG_library_directory(mzscheme_path); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + SWIG_exit(0); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-declaremodule") == 0) { + declaremodule = true; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noinit") == 0) { + noinit = true; + Swig_mark_arg(i); + } + else if (strcmp(argv[i], "-dynamic-load") == 0) { + if (argv[i + 1]) { + Delete(load_libraries); + load_libraries = NewString(argv[i + 1]); + Swig_mark_arg(i++); + Swig_mark_arg(i); + } else { + Swig_arg_error(); + } + } + } + } + + // If a prefix has been specified make sure it ends in a '_' (not actually used!) + if (prefix) { + const char *px = Char(prefix); + if (px[Len(prefix) - 1] != '_') + Printf(prefix, "_"); + } else + prefix = NewString("swig_"); + + // Add a symbol for this module + + Preprocessor_define("SWIGMZSCHEME 1", 0); + + // Set name of typemaps + + SWIG_typemap_lang("mzscheme"); + + // Read in default typemaps */ + SWIG_config_file("mzscheme.swg"); + allow_overloading(); + + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = 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); + + init_func_def = NewString(""); + Swig_register_filebyname("init", init_func_def); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGMZSCHEME\n#define SWIGMZSCHEME\n#endif\n\n"); + + module = Getattr(n, "name"); + + Language::top(n); + + SwigType_emit_type_table(f_runtime, f_wrappers); + if (!noinit) { + if (declaremodule) { + Printf(f_init, "#define SWIG_MZSCHEME_CREATE_MENV(env) scheme_primitive_module(scheme_intern_symbol(\"%s\"), env)\n", module); + } else { + Printf(f_init, "#define SWIG_MZSCHEME_CREATE_MENV(env) (env)\n"); + } + Printf(f_init, "%s\n", Char(init_func_def)); + if (declaremodule) { + Printf(f_init, "\tscheme_finish_primitive_module(menv);\n"); + } + Printf(f_init, "\treturn scheme_void;\n}\n"); + Printf(f_init, "Scheme_Object *scheme_initialize(Scheme_Env *env) {\n"); + + if (load_libraries) { + Printf(f_init, "mz_set_dlopen_libraries(\"%s\");\n", load_libraries); + } + + Printf(f_init, "\treturn scheme_reload(env);\n"); + Printf(f_init, "}\n"); + + Printf(f_init, "Scheme_Object *scheme_module_name(void) {\n"); + if (declaremodule) { + Printf(f_init, " return scheme_intern_symbol((char*)\"%s\");\n", module); + } else { + Printf(f_init, " return scheme_make_symbol((char*)\"%s\");\n", module); + } + Printf(f_init, "}\n"); + } + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + 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; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * Create a function declaration and register it with the interpreter. + * ------------------------------------------------------------ */ + + void throw_unhandled_mzscheme_type_error(SwigType *d) { + Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s.\n", SwigType_str(d, 0)); + } + + /* Return true iff T is a pointer type */ + + int + is_a_pointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); + } + + virtual int functionWrapper(Node *n) { + char *iname = GetChar(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Parm *p; + + Wrapper *f = NewWrapper(); + String *proc_name = NewString(""); + String *target = NewString(""); + String *arg = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *build = NewString(""); + String *tm; + int i = 0; + int numargs; + int numreq; + String *overname = 0; + + if (load_libraries) { + ParmList *parms = Getattr(n, "parms"); + SwigType *type = Getattr(n, "type"); + String *name = NewString("caller"); + Setattr(n, "wrap:action", Swig_cresult(type, Swig_cresult_name(), Swig_cfunction_call(name, parms))); + } + + // Make a wrapper name for this + String *wname = Swig_name_wrapper(iname); + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Build the name for Scheme. + Printv(proc_name, iname, NIL); + Replaceall(proc_name, "_", "-"); + + // writing the function wrapper function + Printv(f->def, "static Scheme_Object *", wname, " (", NIL); + Printv(f->def, "int argc, Scheme_Object **argv", NIL); + Printv(f->def, ")\n{", NIL); + + /* Define the scheme name in C. This define is used by several + macros. */ + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + numargs = emit_num_arguments(l); + numreq = emit_num_required(l); + + /* Add the holder for the pointer to the function to be opened */ + if (load_libraries) { + Wrapper_add_local(f, "_function_loaded", "static int _function_loaded=(1==0)"); + Wrapper_add_local(f, "_the_function", "static void *_the_function=NULL"); + { + String *parms = ParmList_protostr(l); + String *func = NewStringf("(*caller)(%s)", parms); + Wrapper_add_local(f, "caller", SwigType_lstr(d, func)); /*"(*caller)()")); */ + } + } + + // adds local variables + Wrapper_add_local(f, "lenv", "int lenv = 1"); + Wrapper_add_local(f, "values", "Scheme_Object *values[MAXVALUES]"); + + if (load_libraries) { + Printf(f->code, "if (!_function_loaded) { _the_function=mz_load_function(\"%s\");_function_loaded=(1==1); }\n", iname); + Printf(f->code, "if (!_the_function) { scheme_signal_error(\"Cannot load C function '%s'\"); }\n", iname); + Printf(f->code, "caller=_the_function;\n"); + } + + // Now write code to extract the parameters (this is super ugly) + + for (i = 0, p = l; i < numargs; i++) { + /* Skip ignored arguments */ + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + // Produce names of source and target + Clear(target); + Clear(arg); + String *source = NewStringf("argv[%d]", i); + Printf(target, "%s", ln); + Printv(arg, Getattr(p, "name"), NIL); + + if (i >= numreq) { + Printf(f->code, "if (argc > %d) {\n", i); + } + // Handle parameter types. + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", target); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:in:next"); + } else { + // no typemap found + // check if typedef and resolve + throw_unhandled_mzscheme_type_error(pt); + p = nextSibling(p); + } + if (i >= numreq) { + Printf(f->code, "}\n"); + } + Delete(source); + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + // Pass output arguments back to the caller. + + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* Deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* Deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Free up any memory allocated for the arguments. + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + // Now write code to make the function call + + String *actioncode = emit_action(n); + + // Now have return value, figure out what to do with it. + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$target", "values[0]"); + Replaceall(tm, "$result", "values[0]"); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_mzscheme_type_error(d); + } + emit_return_variable(n, d, f); + + // Dump the argument output code + Printv(f->code, Char(outarg), NIL); + + // Dump the argument cleanup code + Printv(f->code, Char(cleanup), NIL); + + // Look for any remaining cleanup + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NIL); + } + // Wrap things up (in a manner of speaking) + + Printv(f->code, tab4, "return SWIG_MzScheme_PackageValues(lenv, values);\n", NIL); + Printf(f->code, "#undef FUNC_NAME\n"); + Printv(f->code, "}\n", NIL); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, f_wrappers); + + if (!Getattr(n, "sym:overloaded")) { + + // Now register the function + char temp[256]; + sprintf(temp, "%d", numargs); + if (exporting_destructor) { + Printf(init_func_def, "SWIG_TypeClientData(SWIGTYPE%s, (void *) %s);\n", swigtype_ptr, wname); + } + Printf(init_func_def, "scheme_add_global(\"%s\", scheme_make_prim_w_arity(%s,\"%s\",%d,%d),menv);\n", proc_name, wname, proc_name, numreq, numargs); + } else { + if (!Getattr(n, "sym:nextSibling")) { + /* Emit overloading dispatch function */ + + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(argc,argv);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "static Scheme_Object *\n", dname, "(int argc, Scheme_Object **argv) {", NIL); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "scheme_signal_error(\"No matching function for overloaded '%s'\");\n", iname); + Printf(df->code, "return NULL;\n", iname); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printf(init_func_def, "scheme_add_global(\"%s\", scheme_make_prim_w_arity(%s,\"%s\",%d,%d),menv);\n", proc_name, dname, proc_name, 0, maxargs); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + } + + Delete(proc_name); + Delete(target); + Delete(arg); + Delete(outarg); + Delete(cleanup); + Delete(build); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * + * Create a link to a C variable. + * This creates a single function _wrap_swig_var_varname(). + * This function takes a single optional argument. If supplied, it means + * we are setting this variable to some value. If omitted, it means we are + * simply evaluating this variable. Either way, we return the variables + * value. + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + String *proc_name = NewString(""); + String *tm; + String *tm2 = NewString(""); + String *argnum = NewString("0"); + String *arg = NewString("argv[0]"); + Wrapper *f; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + f = NewWrapper(); + + // evaluation function names + String *var_name = Swig_name_wrapper(iname); + + // Build the name for scheme. + Printv(proc_name, iname, NIL); + Replaceall(proc_name, "_", "-"); + Setattr(n, "wrap:name", proc_name); + + if ((SwigType_type(t) != T_USER) || (is_a_pointer(t))) { + + Printf(f->def, "static Scheme_Object *%s(int argc, Scheme_Object** argv) {\n", var_name); + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + Wrapper_add_local(f, "swig_result", "Scheme_Object *swig_result"); + + if (!GetFlag(n, "feature:immutable")) { + /* Check for a setting of the variable value */ + Printf(f->code, "if (argc) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "argv[0]"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "argv[0]"); + Replaceall(tm, "$argnum", "1"); + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_mzscheme_type_error(t); + } + Printf(f->code, "}\n"); + } + // Now return the value of the variable (regardless + // of evaluating or setting) + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "swig_result"); + Replaceall(tm, "$result", "swig_result"); + /* Printf (f->code, "%s\n", tm); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_mzscheme_type_error(t); + } + Printf(f->code, "\nreturn swig_result;\n"); + Printf(f->code, "#undef FUNC_NAME\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + // Now add symbol to the MzScheme interpreter + + Printv(init_func_def, + "scheme_add_global(\"", proc_name, "\", scheme_make_prim_w_arity(", var_name, ", \"", proc_name, "\", ", "0", ", ", "1", "), menv);\n", NIL); + + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + Delete(var_name); + Delete(proc_name); + Delete(argnum); + Delete(arg); + Delete(tm2); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + + String *var_name = NewString(""); + String *proc_name = NewString(""); + String *rvalue = NewString(""); + String *temp = NewString(""); + String *tm; + + // Make a static variable; + + Printf(var_name, "_wrap_const_%s", Swig_name_mangle(Getattr(n, "sym:name"))); + + // Build the name for scheme. + Printv(proc_name, iname, NIL); + Replaceall(proc_name, "_", "-"); + + if ((SwigType_type(type) == T_USER) && (!is_a_pointer(type))) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + // See if there's a typemap + + Printv(rvalue, value, NIL); + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 1)) { + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "\"", temp, "\"", NIL); + } + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 0)) { + Delete(temp); + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "'", temp, "'", NIL); + } + if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { + Replaceall(tm, "$source", rvalue); + Replaceall(tm, "$value", rvalue); + Replaceall(tm, "$target", name); + Printf(f_init, "%s\n", tm); + } else { + // Create variable and assign it a value + + Printf(f_header, "static %s = ", SwigType_lstr(type, var_name)); + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + if ((SwigType_type(type) == T_STRING)) { + Printf(f_header, "\"%s\";\n", value); + } else if (SwigType_type(type) == T_CHAR && !is_enum_item) { + Printf(f_header, "\'%s\';\n", value); + } else { + Printf(f_header, "%s;\n", value); + } + + // Now create a variable declaration + + { + /* Hack alert: will cleanup later -- Dave */ + Node *nn = NewHash(); + Setfile(nn, Getfile(n)); + Setline(nn, Getline(n)); + Setattr(nn, "name", var_name); + Setattr(nn, "sym:name", iname); + Setattr(nn, "type", type); + SetFlag(nn, "feature:immutable"); + variableWrapper(nn); + Delete(nn); + } + } + Delete(proc_name); + Delete(rvalue); + Delete(temp); + return SWIG_OK; + } + + virtual int destructorHandler(Node *n) { + exporting_destructor = true; + Language::destructorHandler(n); + exporting_destructor = false; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + virtual int classHandler(Node *n) { + String *mangled_classname = 0; + String *real_classname = 0; + String *scm_structname = NewString(""); + SwigType *ctype_ptr = NewStringf("p.%s", getClassType()); + + SwigType *t = NewStringf("p.%s", Getattr(n, "name")); + swigtype_ptr = SwigType_manglestr(t); + Delete(t); + + cls_swigtype = SwigType_manglestr(Getattr(n, "name")); + + + fieldnames_tab = NewString(""); + convert_tab = NewString(""); + convert_proto_tab = NewString(""); + + struct_name = Getattr(n, "sym:name"); + mangled_struct_name = Swig_name_mangle(Getattr(n, "sym:name")); + + Printv(scm_structname, struct_name, NIL); + Replaceall(scm_structname, "_", "-"); + + real_classname = Getattr(n, "name"); + mangled_classname = Swig_name_mangle(real_classname); + + Printv(fieldnames_tab, "static const char *_swig_struct_", cls_swigtype, "_field_names[] = { \n", NIL); + + Printv(convert_proto_tab, "static Scheme_Object *_swig_convert_struct_", cls_swigtype, "(", SwigType_str(ctype_ptr, "ptr"), ");\n", NIL); + + Printv(convert_tab, "static Scheme_Object *_swig_convert_struct_", cls_swigtype, "(", SwigType_str(ctype_ptr, "ptr"), ")\n {\n", NIL); + + Printv(convert_tab, + tab4, "Scheme_Object *obj;\n", tab4, "Scheme_Object *fields[_swig_struct_", cls_swigtype, "_field_names_cnt];\n", tab4, "int i = 0;\n\n", NIL); + + /* Generate normal wrappers */ + Language::classHandler(n); + + Printv(convert_tab, tab4, "obj = scheme_make_struct_instance(", "_swig_struct_type_", cls_swigtype, ", i, fields);\n", NIL); + Printv(convert_tab, tab4, "return obj;\n}\n\n", NIL); + + Printv(fieldnames_tab, "};\n", NIL); + + Printv(f_header, "static Scheme_Object *_swig_struct_type_", cls_swigtype, ";\n", NIL); + + Printv(f_header, fieldnames_tab, NIL); + Printv(f_header, "#define _swig_struct_", cls_swigtype, "_field_names_cnt (sizeof(_swig_struct_", cls_swigtype, "_field_names)/sizeof(char*))\n", NIL); + + Printv(f_header, convert_proto_tab, NIL); + Printv(f_wrappers, convert_tab, NIL); + + Printv(init_func_def, "_swig_struct_type_", cls_swigtype, + " = SWIG_MzScheme_new_scheme_struct(menv, \"", scm_structname, "\", ", + "_swig_struct_", cls_swigtype, "_field_names_cnt,", "(char**) _swig_struct_", cls_swigtype, "_field_names);\n", NIL); + + Delete(mangled_classname); + Delete(swigtype_ptr); + swigtype_ptr = 0; + Delete(fieldnames_tab); + Delete(convert_tab); + Delete(ctype_ptr); + Delete(convert_proto_tab); + struct_name = 0; + mangled_struct_name = 0; + Delete(cls_swigtype); + cls_swigtype = 0; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + Language::membervariableHandler(n); + + if (!is_smart_pointer()) { + String *symname = Getattr(n, "sym:name"); + String *name = Getattr(n, "name"); + SwigType *type = Getattr(n, "type"); + String *swigtype = SwigType_manglestr(Getattr(n, "type")); + String *tm = 0; + String *access_mem = NewString(""); + SwigType *ctype_ptr = NewStringf("p.%s", Getattr(n, "type")); + + Printv(fieldnames_tab, tab4, "\"", symname, "\",\n", NIL); + Printv(access_mem, "(ptr)->", name, NIL); + if ((SwigType_type(type) == T_USER) && (!is_a_pointer(type))) { + Printv(convert_tab, tab4, "fields[i++] = ", NIL); + Printv(convert_tab, "_swig_convert_struct_", swigtype, "((", SwigType_str(ctype_ptr, 0), ")&((ptr)->", name, "));\n", NIL); + } else if ((tm = Swig_typemap_lookup("varout", n, access_mem, 0))) { + Replaceall(tm, "$result", "fields[i++]"); + Printv(convert_tab, tm, "\n", NIL); + } else + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported member variable type %s (ignored).\n", SwigType_str(type, 0)); + + Delete(access_mem); + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + /* Check whether we have an R5RS identifier. */ + /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ + /* <initial> --> <letter> | <special initial> */ + if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~'))) { + /* <peculiar identifier> --> + | - | ... */ + if ((strcmp(c, "+") == 0) + || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) + return 1; + else + return 0; + } + /* <subsequent> --> <initial> | <digit> | <special subsequent> */ + while (*c) { + if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') + || (*c == '-') || (*c == '.') || (*c == '@'))) + return 0; + c++; + } + return 1; + } + + String *runtimeCode() { + String *s = Swig_include_sys("mzrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'mzrun.swg'\n"); + s = NewString(""); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigmzrun.h"); + } +}; + +/* ----------------------------------------------------------------------------- + * swig_mzscheme() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_mzscheme() { + return new MZSCHEME(); +} +extern "C" Language *swig_mzscheme(void) { + return new_swig_mzscheme(); +} diff --git a/contrib/tools/swig/Source/Modules/nested.cxx b/contrib/tools/swig/Source/Modules/nested.cxx new file mode 100644 index 00000000000..0fcd5ad1820 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/nested.cxx @@ -0,0 +1,453 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * nested.cxx + * + * Nested structs support + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +// Nested classes processing section +static Hash *classhash = 0; + +static String *make_name(Node *n, String *name, SwigType *decl) { + int destructor = name && (*(Char(name)) == '~'); + if (String *yyrename = Getattr(n, "class_rename")) { + String *s = NewString(yyrename); + Delattr(n, "class_rename"); + if (destructor && (*(Char(s)) != '~')) { + Insert(s, 0, "~"); + } + return s; + } + + if (!name) + return 0; + return Swig_name_make(n, 0, name, decl, 0); +} + +// C version of add_symbols() +static void add_symbols_c(Node *n) { + String *decl; + String *wrn = 0; + String *symname = 0; + int iscdecl = Cmp(nodeType(n), "cdecl") == 0; + Setattr(n, "ismember", "1"); + Setattr(n, "access", "public"); + if (Getattr(n, "sym:name")) + return; + decl = Getattr(n, "decl"); + if (!SwigType_isfunction(decl)) { + String *name = Getattr(n, "name"); + String *makename = Getattr(n, "parser:makename"); + if (iscdecl) { + String *storage = Getattr(n, "storage"); + if (Cmp(storage, "typedef") == 0) { + Setattr(n, "kind", "typedef"); + } else { + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + Setattr(n, "kind", "variable"); + if (value && Len(value)) { + Setattr(n, "hasvalue", "1"); + } + if (type) { + SwigType *ty; + SwigType *tmp = 0; + if (decl) { + ty = tmp = Copy(type); + SwigType_push(ty, decl); + } else { + ty = type; + } + if (!SwigType_ismutable(ty)) { + SetFlag(n, "hasconsttype"); + SetFlag(n, "feature:immutable"); + } + if (tmp) + Delete(tmp); + } + if (!type) { + Printf(stderr, "notype name %s\n", name); + } + } + } + Swig_features_get(Swig_cparse_features(), 0, name, 0, n); + if (makename) { + symname = make_name(n, makename, 0); + Delattr(n, "parser:makename"); /* temporary information, don't leave it hanging around */ + } else { + makename = name; + symname = make_name(n, makename, 0); + } + + if (!symname) { + symname = Copy(Getattr(n, "unnamed")); + } + if (symname) { + wrn = Swig_name_warning(n, 0, symname, 0); + } + } else { + String *name = Getattr(n, "name"); + SwigType *fdecl = Copy(decl); + SwigType *fun = SwigType_pop_function(fdecl); + if (iscdecl) { + Setattr(n, "kind", "function"); + } + + Swig_features_get(Swig_cparse_features(), 0, name, fun, n); + + symname = make_name(n, name, fun); + wrn = Swig_name_warning(n, 0, symname, fun); + + Delete(fdecl); + Delete(fun); + + } + if (!symname) + return; + if (GetFlag(n, "feature:ignore")) { + /* Only add to C symbol table and continue */ + Swig_symbol_add(0, n); + } else if (strncmp(Char(symname), "$ignore", 7) == 0) { + char *c = Char(symname) + 7; + SetFlag(n, "feature:ignore"); + if (strlen(c)) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0, Getfile(n), Getline(n), "%s\n", c + 1); + SWIG_WARN_NODE_END(n); + } + Swig_symbol_add(0, n); + } else { + Node *c; + if ((wrn) && (Len(wrn))) { + String *metaname = symname; + if (!Getmeta(metaname, "already_warned")) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0, Getfile(n), Getline(n), "%s\n", wrn); + SWIG_WARN_NODE_END(n); + Setmeta(metaname, "already_warned", "1"); + } + } + c = Swig_symbol_add(symname, n); + + if (c != n) { + /* symbol conflict attempting to add in the new symbol */ + if (Getattr(n, "sym:weak")) { + Setattr(n, "sym:name", symname); + } else { + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + int redefined = Swig_need_redefined_warn(n, c, true); + if (redefined) { + Printf(en, "Identifier '%s' redefined (ignored)", symname); + Printf(ec, "previous definition of '%s'", symname); + } else { + Printf(en, "Redundant redeclaration of '%s'", symname); + Printf(ec, "previous declaration of '%s'", symname); + } + if (Cmp(symname, Getattr(n, "name"))) { + Printf(en, " (Renamed from '%s')", SwigType_namestr(Getattr(n, "name"))); + } + Printf(en, ","); + if (Cmp(symname, Getattr(c, "name"))) { + Printf(ec, " (Renamed from '%s')", SwigType_namestr(Getattr(c, "name"))); + } + Printf(ec, "."); + SWIG_WARN_NODE_BEGIN(n); + if (redefined) { + Swig_warning(WARN_PARSE_REDEFINED, Getfile(n), Getline(n), "%s\n", en); + Swig_warning(WARN_PARSE_REDEFINED, Getfile(c), Getline(c), "%s\n", ec); + } else { + Swig_warning(WARN_PARSE_REDUNDANT, Getfile(n), Getline(n), "%s\n", en); + Swig_warning(WARN_PARSE_REDUNDANT, Getfile(c), Getline(c), "%s\n", ec); + } + SWIG_WARN_NODE_END(n); + Printf(e, "%s:%d:%s\n%s:%d:%s\n", Getfile(n), Getline(n), en, Getfile(c), Getline(c), ec); + Setattr(n, "error", e); + Delete(e); + Delete(en); + Delete(ec); + } + } + } + Delete(symname); +} + +/* Strips C-style and C++-style comments from string in-place. */ +static void strip_comments(char *string) { + int state = 0; + /* + * 0 - not in comment + * 1 - in c-style comment + * 2 - in c++-style comment + * 3 - in string + * 4 - after reading / not in comments + * 5 - after reading * in c-style comments + * 6 - after reading \ in strings + */ + char *c = string; + while (*c) { + switch (state) { + case 0: + if (*c == '\"') + state = 3; + else if (*c == '/') + state = 4; + break; + case 1: + if (*c == '*') + state = 5; + *c = ' '; + break; + case 2: + if (*c == '\n') + state = 0; + else + *c = ' '; + break; + case 3: + if (*c == '\"') + state = 0; + else if (*c == '\\') + state = 6; + break; + case 4: + if (*c == '/') { + *(c - 1) = ' '; + *c = ' '; + state = 2; + } else if (*c == '*') { + *(c - 1) = ' '; + *c = ' '; + state = 1; + } else + state = 0; + break; + case 5: + if (*c == '/') + state = 0; + else + state = 1; + *c = ' '; + break; + case 6: + state = 3; + break; + } + ++c; + } +} + +// Create a %insert with a typedef to make a new name visible to C +static Node *create_insert(Node *n, bool noTypedef = false) { + // format a typedef + String *ccode = Getattr(n, "code"); + Push(ccode, " "); + if (noTypedef) { + Push(ccode, Getattr(n, "name")); + Push(ccode, " "); + Push(ccode, Getattr(n, "kind")); + } else { + Push(ccode, Getattr(n, "kind")); + Push(ccode, "typedef "); + Append(ccode, " "); + Append(ccode, Getattr(n, "tdname")); + } + Append(ccode, ";"); + + /* Strip comments - further code may break in presence of comments. */ + strip_comments(Char(ccode)); + + /* Make all SWIG created typedef structs/unions/classes unnamed else + redefinition errors occur - nasty hack alert. */ + if (!noTypedef) { + const char *types_array[3] = { "struct", "union", "class" }; + for (int i = 0; i < 3; i++) { + char *code_ptr = Char(ccode); + while (code_ptr) { + /* Replace struct name (as in 'struct name {...}' ) with whitespace + name will be between struct and opening brace */ + + code_ptr = strstr(code_ptr, types_array[i]); + if (code_ptr) { + char *open_bracket_pos; + code_ptr += strlen(types_array[i]); + open_bracket_pos = strchr(code_ptr, '{'); + if (open_bracket_pos) { + /* Make sure we don't have something like struct A a; */ + char *semi_colon_pos = strchr(code_ptr, ';'); + if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) + while (code_ptr < open_bracket_pos) + *code_ptr++ = ' '; + } + } + } + } + } + { + /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ + char *code_ptr = Char(ccode); + while (code_ptr) { + code_ptr = strstr(code_ptr, "%constant"); + if (code_ptr) { + char *directive_end_pos = strchr(code_ptr, ';'); + if (directive_end_pos) { + while (code_ptr <= directive_end_pos) + *code_ptr++ = ' '; + } + } + } + } + Node *newnode = NewHash(); + set_nodeType(newnode, "insert"); + Setfile(newnode, Getfile(n)); + Setline(newnode, Getline(n)); + String *code = NewStringEmpty(); + Wrapper_pretty_print(ccode, code); + Setattr(newnode, "code", code); + Delete(code); + Delattr(n, "code"); + return newnode; +} + +static void insertNodeAfter(Node *n, Node *c) { + Node *g = parentNode(n); + set_parentNode(c, g); + Node *ns = nextSibling(n); + if (Node *outer = Getattr(c, "nested:outer")) { + while (ns && outer == Getattr(ns, "nested:outer")) { + n = ns; + ns = nextSibling(n); + } + } + if (!ns) { + set_lastChild(g, c); + } else { + set_nextSibling(c, ns); + set_previousSibling(ns, c); + } + set_nextSibling(n, c); + set_previousSibling(c, n); +} + +void Swig_nested_name_unnamed_c_structs(Node *n) { + if (!n) + return; + if (!classhash) + classhash = Getattr(n, "classes"); + Node *c = firstChild(n); + while (c) { + Node *next = nextSibling(c); + if (String *declName = Getattr(c, "nested:unnamed")) { + if (Node *outer = Getattr(c, "nested:outer")) { + // generate a name + String *name = NewStringf("%s_%s", Getattr(outer, "name"), declName); + Delattr(c, "nested:unnamed"); + // set the name to the class and symbol table + Setattr(c, "tdname", name); + Setattr(c, "name", name); + Swig_symbol_setscope(Getattr(c, "symtab")); + Swig_symbol_setscopename(name); + // now that we have a name - gather base symbols + if (List *publicBases = Getattr(c, "baselist")) { + List *bases = Swig_make_inherit_list(name, publicBases, 0); + Swig_inherit_base_symbols(bases); + Delete(bases); + } + Setattr(classhash, name, c); + + // Merge the extension into the symbol table + if (Node *am = Getattr(Swig_extend_hash(), name)) { + Swig_extend_merge(c, am); + Swig_extend_append_previous(c, am); + Delattr(Swig_extend_hash(), name); + } + Swig_symbol_popscope(); + + // process declarations following this type (assign correct new type) + SwigType *ty = Copy(name); + Node *decl = nextSibling(c); + List *declList = NewList(); + while (decl && Getattr(decl, "nested:unnamedtype") == c) { + Setattr(decl, "type", ty); + Append(declList, decl); + Delattr(decl, "nested:unnamedtype"); + SetFlag(decl, "feature:immutable"); + add_symbols_c(decl); + decl = nextSibling(decl); + } + Delete(ty); + Swig_symbol_setscope(Swig_symbol_global_scope()); + add_symbols_c(c); + + Node *ins = create_insert(c); + insertNodeAfter(c, ins); + removeNode(c); + insertNodeAfter(n, c); + Delete(ins); + Delattr(c, "nested:outer"); + } else { + // global unnamed struct - ignore it and it's instances + SetFlag(c, "feature:ignore"); + while (next && Getattr(next, "nested:unnamedtype") == c) { + SetFlag(next, "feature:ignore"); + next = nextSibling(next); + } + c = next; + continue; + } + } else if (cparse_cplusplusout) { + if (Getattr(c, "nested:outer")) { + Node *ins = create_insert(c, true); + insertNodeAfter(c, ins); + Delete(ins); + Delattr(c, "nested:outer"); + } + } + // process children + Swig_nested_name_unnamed_c_structs(c); + c = next; + } +} + +static void remove_outer_class_reference(Node *n) { + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + if (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None) { + Delattr(c, "nested:outer"); + remove_outer_class_reference(c); + } + } +} + +void Swig_nested_process_classes(Node *n) { + if (!n) + return; + Node *c = firstChild(n); + while (c) { + Node *next = nextSibling(c); + if (!Getattr(c, "templatetype")) { + if (GetFlag(c, "nested") && (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None)) { + removeNode(c); + if (!checkAttribute(c, "access", "public")) + SetFlag(c, "feature:ignore"); + else if (Strcmp(nodeType(n),"extend") == 0 && Strcmp(nodeType(parentNode(n)),"class") == 0) + insertNodeAfter(parentNode(n), c); + else + insertNodeAfter(n, c); + } + Swig_nested_process_classes(c); + } + c = next; + } + remove_outer_class_reference(n); +} + diff --git a/contrib/tools/swig/Source/Modules/ocaml.cxx b/contrib/tools/swig/Source/Modules/ocaml.cxx new file mode 100644 index 00000000000..9f7504b871c --- /dev/null +++ b/contrib/tools/swig/Source/Modules/ocaml.cxx @@ -0,0 +1,1889 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * ocaml.cxx + * + * Ocaml language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +#include <ctype.h> + +static const char *usage = "\ +Ocaml Options (available with -ocaml)\n\ + -oldvarnames - Old intermediary method names for variable wrappers\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -suffix <name> - Deprecated alias for general option -cppext\n\ + -where - Emit library location\n\ +\n"; + +static int classmode = 0; +static int in_constructor = 0, in_destructor = 0, in_copyconst = 0; +static int const_enum = 0; +static int static_member_function = 0; +static int generate_sizeof = 0; +static String *prefix = 0; +static const char *ocaml_path = "ocaml"; +static bool old_variable_names = false; +static String *classname = 0; +static String *module = 0; +static String *init_func_def = 0; +static String *f_classtemplate = 0; +static SwigType *name_qualifier_type = 0; + +static Hash *seen_enums = 0; +static Hash *seen_enumvalues = 0; +static Hash *seen_constructors = 0; + +static File *f_header = 0; +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_mlout = 0; +static File *f_mliout = 0; +static File *f_mlbody = 0; +static File *f_mlibody = 0; +static File *f_mltail = 0; +static File *f_mlitail = 0; +static File *f_enumtypes_type = 0; +static File *f_enumtypes_value = 0; +static File *f_class_ctors = 0; +static File *f_class_ctors_end = 0; +static File *f_enum_to_int = 0; +static File *f_int_to_enum = 0; + +class OCAML:public Language { +public: + + OCAML() { + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", "} else {\n", " caml_failwith(\"accessing abstract class or protected constructor\"); \n", "}\n", NIL); + director_multiple_inheritance = 1; + director_language = 1; + } + + String *Swig_class_name(Node *n) { + String *name; + name = Copy(Getattr(n, "sym:name")); + return name; + } + + void PrintIncludeArg() { + Printv(stdout, SWIG_LIB, SWIG_FILE_DELIMITER, ocaml_path, "\n", NIL); + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i; + + prefix = 0; + + SWIG_library_directory(ocaml_path); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + SWIG_exit(0); + } else if (strcmp(argv[i], "-where") == 0) { + PrintIncludeArg(); + SWIG_exit(0); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-suffix") == 0) { + if (argv[i + 1]) { + Printf(stderr, "swig: warning: -suffix option deprecated. SWIG 3.0.4 and later provide a -cppext option which should be used instead.\n"); + SWIG_config_cppext(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else + Swig_arg_error(); + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } + } + } + + // If a prefix has been specified make sure it ends in a '_' (not actually used!) + if (prefix) { + const char *px = Char(prefix); + if (px[Len(prefix) - 1] != '_') + Printf(prefix, "_"); + } else + prefix = NewString("swig_"); + + // Add a symbol for this module + + Preprocessor_define("SWIGOCAML 1", 0); + // Set name of typemaps + + SWIG_typemap_lang("ocaml"); + + // Read in default typemaps */ + SWIG_config_file("ocaml.i"); + allow_overloading(); + + } + + /* Swig_director_declaration() + * + * Generate the full director class declaration, complete with base classes. + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + * + */ + + String *Swig_director_declaration(Node *n) { + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *base = Getattr(n, "classtype"); + String *declaration = Swig_class_declaration(n, directorname); + Printf(declaration, " : public %s, public Swig::Director {\n", base); + Delete(classname); + Delete(directorname); + return declaration; + } + + void emitBanner(File *f) { + Printf(f, "(* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ---------------------------------------------------------------------------- *)\n\n"); + } + + /* ------------------------------------------------------------ + * top() + * + * Recognize the %module, and capture the module name. + * Create the default enum cases. + * Set up the named outputs: + * + * init + * ml + * mli + * wrapper + * header + * runtime + * directors + * directors_h + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* Set comparison with none for ConstructorToFunction */ + setSubclassInstanceCheck(NewString("caml_list_nth(args,0) != Val_unit")); + + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + String *mod_docstring = NULL; + { + Node *module = Getattr(n, "module"); + if (module) { + Node *options = Getattr(module, "options"); + if (options) { + if (Getattr(options, "directors")) { + allow_directors(); + } + if (Getattr(options, "dirprot")) { + allow_dirprot(); + } + if (Getattr(options, "sizeof")) { + generate_sizeof = 1; + } + mod_docstring = Getattr(options, "docstring"); + } + } + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors = NewString(""); + f_directors_h = NewString(""); + f_enumtypes_type = NewString(""); + f_enumtypes_value = NewString(""); + init_func_def = NewString(""); + f_mlbody = NewString(""); + f_mlibody = NewString(""); + f_mltail = NewString(""); + f_mlitail = NewString(""); + f_class_ctors = NewString(""); + f_class_ctors_end = NewString(""); + f_enum_to_int = NewString(""); + f_int_to_enum = NewString(""); + f_classtemplate = NewString(""); + + module = Getattr(n, "name"); + + seen_constructors = NewHash(); + seen_enums = NewHash(); + seen_enumvalues = NewHash(); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("init", init_func_def); + 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("mli", f_mlibody); + Swig_register_filebyname("ml", f_mlbody); + Swig_register_filebyname("mlitail", f_mlitail); + Swig_register_filebyname("mltail", f_mltail); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + Swig_register_filebyname("classtemplate", f_classtemplate); + Swig_register_filebyname("class_ctors", f_class_ctors); + + if (old_variable_names) { + Swig_name_register("set", "%n%v__set__"); + Swig_name_register("get", "%n%v__get__"); + } + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGOCAML\n#define SWIGOCAML\n#endif\n\n"); + + Printf(f_runtime, "#define SWIG_MODULE \"%s\"\n", module); + /* Module name */ + Printf(f_mlbody, "let module_name = \"%s\"\n", module); + Printf(f_mlibody, "val module_name : string\n"); + Printf(f_enum_to_int, + "let enum_to_int x (v : c_obj) =\n" + " match v with\n" + " C_enum _y ->\n" + " (let y = _y in match (x : c_enum_type) with\n" + " `unknown -> " " (match y with\n" " `Int x -> (Swig.C_int x)\n" " | _ -> raise (LabelNotFromThisEnum v))\n"); + + Printf(f_int_to_enum, "let int_to_enum x y =\n" " match (x : c_enum_type) with\n" " `unknown -> C_enum (`Int y)\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + Printf(f_runtime, "\n"); + + /* Produce the enum_to_int and int_to_enum functions */ + + Printf(f_enumtypes_type, "open Swig\n" "type c_enum_type = [ \n `unknown\n"); + Printf(f_enumtypes_value, "type c_enum_value = [ \n `Int of int\n"); + String *mlfile = NewString(""); + String *mlifile = NewString(""); + + Printv(mlfile, module, ".ml", NIL); + Printv(mlifile, module, ".mli", NIL); + + String *mlfilen = NewStringf("%s%s", SWIG_output_directory(), mlfile); + if ((f_mlout = NewFile(mlfilen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(mlfilen); + SWIG_exit(EXIT_FAILURE); + } + String *mlifilen = NewStringf("%s%s", SWIG_output_directory(), mlifile); + if ((f_mliout = NewFile(mlifilen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(mlifilen); + SWIG_exit(EXIT_FAILURE); + } + emitBanner(f_mlout); + emitBanner(f_mliout); + + Language::top(n); + + if (mod_docstring) { + if (Len(mod_docstring)) { + Printv(f_mliout, "(** ", mod_docstring, " *)\n", NIL); + } + Delete(mod_docstring); + mod_docstring = NULL; + } + + Printf(f_enum_to_int, ") | _ -> (C_int (get_int v))\n" "let _ = Callback.register \"%s_enum_to_int\" enum_to_int\n", module); + Printf(f_mlibody, "val enum_to_int : c_enum_type -> c_obj -> Swig.c_obj\n"); + + Printf(f_int_to_enum, "let _ = Callback.register \"%s_int_to_enum\" int_to_enum\n", module); + Printf(f_mlibody, "val int_to_enum : c_enum_type -> int -> c_obj\n"); + Printf(f_init, "#define SWIG_init f_%s_init\n" "%s" "}\n", module, init_func_def); + Printf(f_mlbody, "external f_init : unit -> unit = \"f_%s_init\" ;;\n" "let _ = f_init ()\n", module); + Printf(f_enumtypes_type, "]\n"); + Printf(f_enumtypes_value, "]\n\n" "type c_obj = c_enum_value c_obj_t\n"); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + + SwigType_emit_type_table(f_runtime, f_wrappers); + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_directors_h, f_header); + Dump(f_header, f_begin); + Dump(f_directors, f_wrappers); + 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); + + Dump(f_enumtypes_type, f_mlout); + Dump(f_enumtypes_value, f_mlout); + Dump(f_mlbody, f_mlout); + Dump(f_enum_to_int, f_mlout); + Dump(f_int_to_enum, f_mlout); + Delete(f_int_to_enum); + Delete(f_enum_to_int); + Dump(f_class_ctors, f_mlout); + Dump(f_class_ctors_end, f_mlout); + Dump(f_mltail, f_mlout); + Delete(f_mlout); + + Dump(f_enumtypes_type, f_mliout); + Dump(f_enumtypes_value, f_mliout); + Dump(f_mlibody, f_mliout); + Dump(f_mlitail, f_mliout); + Delete(f_mliout); + + return SWIG_OK; + } + + /* Produce an error for the given type */ + void throw_unhandled_ocaml_type_error(SwigType *d, const char *types) { + Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s (%s).\n", SwigType_str(d, 0), types); + } + + /* Return true iff T is a pointer type */ + int + is_a_pointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); + } + + /* + * Delete one reference from a given type. + */ + + void oc_SwigType_del_reference(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + Delete(SwigType_pop(t)); + c = Char(t); + } + if (strncmp(c, "r.", 2)) { + printf("Fatal error. SwigType_del_pointer applied to non-pointer.\n"); + abort(); + } + Replace(t, "r.", "", DOH_REPLACE_ANY | DOH_REPLACE_FIRST); + } + + void oc_SwigType_del_array(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + Delete(SwigType_pop(t)); + c = Char(t); + } + if (strncmp(c, "a(", 2) == 0) { + Delete(SwigType_pop(t)); + } + } + + /* + * Return true iff T is a reference type + */ + + int + is_a_reference(SwigType *t) { + return SwigType_isreference(SwigType_typedef_resolve_all(t)); + } + + int + is_an_array(SwigType *t) { + return SwigType_isarray(SwigType_typedef_resolve_all(t)); + } + + virtual int membervariableHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + Language::membervariableHandler(n); + + String *mname = Swig_name_member(NSPACE_TODO, classname, symname); + String *getname = Swig_name_get(NSPACE_TODO, mname); + String *mangled_getname = mangleNameForCaml(getname); + Delete(getname); + + if (!GetFlag(n, "feature:immutable")) { + String *setname = Swig_name_set(NSPACE_TODO, mname); + String *mangled_setname = mangleNameForCaml(setname); + Delete(setname); + Printf(f_class_ctors, " \"[%s]\", (fun args -> " "if args = (C_list [ raw_ptr ]) then _%s args else _%s args) ;\n", symname, mangled_getname, mangled_setname); + Delete(mangled_setname); + } else { + Printf(f_class_ctors, " \"[%s]\", (fun args -> " "if args = (C_list [ raw_ptr ]) then _%s args else C_void) ;\n", symname, mangled_getname); + } + Delete(mangled_getname); + Delete(mname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * Create a function declaration and register it with the interpreter. + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + char *iname = GetChar(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + String *return_type_normalized = normalizeTemplatedClassName(d); + ParmList *l = Getattr(n, "parms"); + int director_method = 0; + Parm *p; + + Wrapper *f = NewWrapper(); + String *proc_name = NewString(""); + String *target = NewString(""); + String *arg = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *build = NewString(""); + String *tm; + int i = 0; + int numargs; + int numreq; + int newobj = GetFlag(n, "feature:new"); + String *nodeType = Getattr(n, "nodeType"); + int destructor = (!Cmp(nodeType, "destructor")); + String *overname = 0; + bool isOverloaded = Getattr(n, "sym:overloaded") ? true : false; + // For overloaded functions, only the dispatch function needs to be exposed in the ml and mli files. + bool expose_func = !isOverloaded || !Getattr(n, "sym:nextSibling"); + + // Make a wrapper name for this + String *wname = Swig_name_wrapper(iname); + if (isOverloaded) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + if (overname) { + Append(wname, overname); + } + /* Do this to disambiguate functions emitted from different modules */ + Append(wname, module); + + Setattr(n, "wrap:name", wname); + + // Build the name for Scheme. + Printv(proc_name, "_", iname, NIL); + String *mangled_name = mangleNameForCaml(proc_name); + + if (classmode && in_constructor && expose_func) { // Emit constructor for object + String *mangled_name_nounder = NewString((char *) (Char(mangled_name)) + 1); + Printf(f_class_ctors_end, "let %s clst = _%s clst\n", mangled_name_nounder, mangled_name_nounder); + Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name_nounder); + Delete(mangled_name_nounder); + } else if (classmode && in_destructor) { + Printf(f_class_ctors, " \"~\", %s ;\n", mangled_name); + } else if (classmode && !in_constructor && !in_destructor && !static_member_function && + !Getattr(n, "membervariableHandler:sym:name") && expose_func) { + String *opname = Copy(Getattr(n, "memberfunctionHandler:sym:name")); + + Replaceall(opname, "operator ", ""); + Printf(f_class_ctors, " \"%s\", %s ;\n", opname, mangled_name); + Delete(opname); + } + + if (classmode && in_constructor) { + Setattr(seen_constructors, mangled_name, "true"); + } + // writing the function wrapper function + Printv(f->def, "SWIGEXT CAML_VALUE ", wname, " (", NIL); + Printv(f->def, "CAML_VALUE args", NIL); + Printv(f->def, ")\n{", NIL); + + /* Define the scheme name in C. This define is used by several + macros. */ + //Printv(f->def, "#define FUNC_NAME \"", mangled_name, "\"", NIL); + + // adds local variables + Wrapper_add_local(f, "args", "CAMLparam1(args)"); + Wrapper_add_local(f, "ret", "SWIG_CAMLlocal2(swig_result,rv)"); + d = SwigType_typedef_qualified(d); + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + numargs = emit_num_arguments(l); + numreq = emit_num_required(l); + if (!isOverloaded) { + if (numargs > 0) { + if (numreq > 0) { + Printf(f->code, "if (caml_list_length(args) < %d || caml_list_length(args) > %d) {\n", numreq, numargs); + } else { + Printf(f->code, "if (caml_list_length(args) > %d) {\n", numargs); + } + Printf(f->code, "caml_invalid_argument(\"Incorrect number of arguments passed to '%s'\");\n}\n", iname); + } else { + Printf(f->code, "if (caml_list_length(args) > 0) caml_invalid_argument(\"'%s' takes no arguments\");\n", iname); + } + } + Printf(f->code, "swig_result = Val_unit;\n"); + + // Now write code to extract the parameters (this is super ugly) + + for (i = 0, p = l; i < numargs; i++) { + /* Skip ignored arguments */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + pt = SwigType_typedef_qualified(pt); + + // Produce names of source and target + Clear(target); + Clear(arg); + String *source = NewStringf("caml_list_nth(args,%d)", i); + Printf(target, "%s", ln); + Printv(arg, Getattr(p, "name"), NIL); + + if (i >= numreq) { + Printf(f->code, "if (caml_list_length(args) > %d) {\n", i); + } + // Handle parameter types. + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", target); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:in:next"); + } else { + // no typemap found + // check if typedef and resolve + throw_unhandled_ocaml_type_error(pt, "in"); + p = nextSibling(p); + } + if (i >= numreq) { + Printf(f->code, "}\n"); + } + Delete(source); + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + // Pass output arguments back to the caller. + + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* Deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* Deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Replaceall(tm, "$ntype", normalizeTemplatedClassName(Getattr(p, "type"))); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Free up any memory allocated for the arguments. + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* if the object is a director, and the method call originated from its + * underlying ocaml object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in ocaml. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Append(f->code, "upcall = (director);\n"); + } + + // Now write code to make the function call + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + Replaceall(tm, "$source", "swig_result"); + Replaceall(tm, "$target", "rv"); + Replaceall(tm, "$result", "rv"); + Replaceall(tm, "$ntype", return_type_normalized); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_ocaml_type_error(d, "out"); + } + emit_return_variable(n, d, f); + + // Dump the argument output code + Printv(f->code, Char(outarg), NIL); + + // Dump the argument cleanup code + Printv(f->code, Char(cleanup), NIL); + + // Look for any remaining cleanup + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", "swig_result"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + // Free any memory allocated by the function being wrapped.. + + if ((tm = Swig_typemap_lookup("swig_result", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NIL); + } + // Wrap things up (in a manner of speaking) + + Printv(f->code, tab4, "swig_result = caml_list_append(swig_result,rv);\n", NIL); + Printv(f->code, tab4, "CAMLreturn(swig_result);\n", NIL); + Printv(f->code, "}\n", NIL); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, f_wrappers); + + if (isOverloaded) { + if (!Getattr(n, "sym:nextSibling")) { + int maxargs; + Wrapper *df = NewWrapper(); + String *dispatch = Swig_overload_dispatch(n, + "free(argv);\n" "CAMLreturn(%s(args));\n", + &maxargs); + + Wrapper_add_local(df, "argv", "CAML_VALUE *argv"); + + /* Undifferentiate name .. this is the dispatch function */ + wname = Swig_name_wrapper(iname); + /* Do this to disambiguate functions emitted from different + * modules */ + Append(wname, module); + + Printv(df->def, + "SWIGEXT CAML_VALUE ", wname, "(CAML_VALUE args) {\n" " CAMLparam1(args);\n" " int i;\n" " int argc = caml_list_length(args);\n", NIL); + Printv(df->code, + "argv = (CAML_VALUE *)malloc( argc * sizeof( CAML_VALUE ) );\n" + "for( i = 0; i < argc; i++ ) {\n" " argv[i] = caml_list_nth(args,i);\n" "}\n", NIL); + Printv(df->code, dispatch, "\nfree(argv);\n", NIL); + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); + String *protoTypes = NewString(""); + do { + String *fulldecl = Swig_name_decl(sibl); + Printf(protoTypes, "\n\" %s\\n\"", fulldecl); + Delete(fulldecl); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(df->code, "caml_failwith(\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" + "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", iname, protoTypes); + Delete(protoTypes); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + + DelWrapper(df); + Delete(dispatch); + } + } + + if (expose_func) { + Printf(f_mlbody, "external %s_f : c_obj list -> c_obj list = \"%s\" ;;\n", mangled_name, wname); + Printf(f_mlbody, "let %s arg = match %s_f (%s(fnhelper arg)) with\n", mangled_name, mangled_name, + in_constructor && Swig_directorclass(getCurrentClass()) ? "director_core_helper " : ""); + Printf(f_mlbody, " [] -> C_void\n" + "| [x] -> (if %s then Gc.finalise \n" + " (fun x -> ignore ((invoke x) \"~\" C_void)) x) ; x\n" + "| lst -> C_list lst ;;\n", newobj ? "true" : "false"); + } + + if ((!classmode || in_constructor || in_destructor || static_member_function) && expose_func) + Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name); + + Delete(proc_name); + Delete(target); + Delete(arg); + Delete(outarg); + Delete(cleanup); + Delete(build); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * + * Create a link to a C variable. + * This creates a single function _wrap_varname(). + * This function takes a single optional argument. If supplied, it means + * we are setting this variable to some value. If omitted, it means we are + * simply evaluating this variable. We return the value of the variable + * in both cases. + * + * symname is the name of the variable with respect to C. This + * may need to differ from the original name in the case of enums. + * enumvname is the name of the variable with respect to ocaml. This + * will vary if the variable has been renamed. + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + char *name = GetChar(n, "feature:symname"); + String *iname = Getattr(n, "feature:enumvname"); + String *mname = mangleNameForCaml(iname); + SwigType *t = Getattr(n, "type"); + + String *proc_name = NewString(""); + String *tm; + Wrapper *f; + + if (!name) { + name = GetChar(n, "name"); + } + + if (!iname) { + iname = Getattr(n, "sym:name"); + mname = mangleNameForCaml(NewString(iname)); + } + + if (!iname || !addSymbol(iname, n)) + return SWIG_ERROR; + + f = NewWrapper(); + + // evaluation function names + String *var_name = Swig_name_wrapper(iname); + + // Build the name for OCaml. + Printv(proc_name, iname, NIL); + Setattr(n, "wrap:name", proc_name); + + Printf(f->def, "SWIGEXT CAML_VALUE %s(CAML_VALUE args) {\n", var_name); + // Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + Wrapper_add_local(f, "args", "CAMLparam1(args)"); + Wrapper_add_local(f, "swig_result", "SWIG_CAMLlocal1(swig_result)"); + Printf(f->code, "swig_result = Val_unit;\n"); + + if (!GetFlag(n, "feature:immutable")) { + /* Check for a setting of the variable value */ + Printf(f->code, "if (args != Val_int(0)) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "args"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "args"); + emit_action_code(n, f->code, tm); + } else if ((tm = Swig_typemap_lookup("in", n, name, 0))) { + Replaceall(tm, "$source", "args"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "args"); + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_ocaml_type_error(t, "varin/in"); + } + Printf(f->code, "}\n"); + } + // Now return the value of the variable (regardless + // of evaluating or setting) + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "swig_result"); + Replaceall(tm, "$result", "swig_result"); + emit_action_code(n, f->code, tm); + } else if ((tm = Swig_typemap_lookup("out", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "swig_result"); + Replaceall(tm, "$result", "swig_result"); + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_ocaml_type_error(t, "varout/out"); + } + + Printf(f->code, "\nCAMLreturn(swig_result);\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + // Now add symbol to the Ocaml interpreter + + if (GetFlag(n, "feature:immutable")) { + Printf(f_mlbody, "external _%s : c_obj -> Swig.c_obj = \"%s\" \n", mname, var_name); + Printf(f_mlibody, "val _%s : c_obj -> Swig.c_obj\n", iname); + if (const_enum) { + Printf(f_enum_to_int, " | `%s -> _%s C_void\n", mname, mname); + Printf(f_int_to_enum, " if y = (get_int (_%s C_void)) then `%s else\n", mname, mname); + } + } else { + Printf(f_mlbody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name); + Printf(f_mlibody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name); + } + + Delete(var_name); + Delete(proc_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler -- + * Overridden to set static_member_function + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + static_member_function = 1; + Language::staticmemberfunctionHandler(n); + static_member_function = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * + * The one trick here is that we have to make sure we rename the + * constant to something useful that doesn't collide with the + * original if any exists. + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "feature:symname"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + SwigType *qname = Getattr(n, "qualified:name"); + + if (qname) + value = qname; + + if (!name) { + name = mangleNameForCaml(Getattr(n, "name")); + Insert(name, 0, "_swig_wrap_"); + Setattr(n, "feature:symname", name); + } + // See if there's a typemap + + // Create variable and assign it a value + Printf(f_header, "static %s = %s;\n", SwigType_str(type, name), value); + SetFlag(n, "feature:immutable"); + variableWrapper(n); + return SWIG_OK; + } + + int constructorHandler(Node *n) { + int ret; + + in_constructor = 1; + ret = Language::constructorHandler(n); + in_constructor = 0; + + return ret; + } + + /* destructorHandler: + * Turn on destructor flag to inform decisions in functionWrapper + */ + + int destructorHandler(Node *n) { + int ret; + + in_destructor = 1; + ret = Language::destructorHandler(n); + in_destructor = 0; + + return ret; + } + + /* copyconstructorHandler: + * Turn on constructor and copyconstructor flags for functionWrapper + */ + + int copyconstructorHandler(Node *n) { + int ret; + + in_copyconst = 1; + in_constructor = 1; + ret = Language::copyconstructorHandler(n); + in_constructor = 0; + in_copyconst = 0; + + return ret; + } + + /** + * A simple, somewhat general purpose function for writing to multiple + * streams from a source template. This allows the user to define the + * class definition in ways different from the one I have here if they + * want to. It will also make the class definition system easier to + * fiddle with when I want to change methods, etc. + */ + + void Multiwrite(String *s) { + char *find_marker = strstr(Char(s), "(*Stream:"); + while (find_marker) { + char *next = strstr(find_marker, "*)"); + find_marker += strlen("(*Stream:"); + + if (next) { + int num_chars = (int)(next - find_marker); + String *stream_name = NewString(find_marker); + Delslice(stream_name, num_chars, Len(stream_name)); + File *fout = Swig_filebyname(stream_name); + if (fout) { + next += strlen("*)"); + char *following = strstr(next, "(*Stream:"); + find_marker = following; + if (!following) + following = next + strlen(next); + String *chunk = NewString(next); + Delslice(chunk, (int)(following - next), Len(chunk)); + Printv(fout, chunk, NIL); + } + } + } + } + + bool isSimpleType(String *name) { + char *ch = Char(name); + + return !(strchr(ch, '(') || strchr(ch, '<') || strchr(ch, ')') || strchr(ch, '>')); + } + + /* We accept all chars in identifiers because we use strings to index + * them. */ + int validIdentifier(String *name) { + return Len(name) > 0 ? 1 : 0; + } + + /* classHandler + * + * Create a "class" definition for ocaml. I thought quite a bit about + * how I should do this part of it, and arrived here, using a function + * invocation to select a method, and dispatch. This can obviously be + * done better, but I can't see how, given that I want to support + * overloaded methods, out parameters, and operators. + * + * I needed a system that would do this: + * + * a Be able to call these methods: + * int foo( int x ); + * float foo( int x, int &out ); + * + * b Be typeable, even in the presence of mutually dependent classes. + * + * c Support some form of operator invocation. + * + * (c) I chose strings for the method names so that "+=" would be a + * valid method name, and the somewhat natural << (invoke x) "+=" y >> + * would work. + * + * (a) (b) Since the c_obj type exists, it's easy to return C_int in one + * case and C_list [ C_float ; C_int ] in the other. This makes tricky + * problems with out parameters disappear; they're simply appended to the + * return list. + * + * (b) Since every item that comes from C++ is the same type, there is no + * problem with the following: + * + * class Foo; + * class Bar { Foo *toFoo(); } + * class Foo { Bar *toBar(); } + * + * Since the Objective caml types of Foo and Bar are the same. Now that + * I correctly incorporate SWIG's typechecking, this isn't a big deal. + * + * The class is in the form of a function returning a c_obj. The c_obj + * is a C_obj containing a function which invokes a method on the + * underlying object given its type. + * + * The name emitted here is normalized before being sent to + * Callback.register, because we need this string to look up properly + * when the typemap passes the descriptor string. I've been considering + * some, possibly more forgiving method that would do some transformations + * on the $descriptor in order to find a potential match. This is for + * later. + * + * Important things to note: + * + * We rely on exception handling (BadMethodName) in order to call an + * ancestor. This can be improved. + * + * The method used to get :classof could be improved to look at the type + * info that the base pointer contains. It's really an error to have a + * SWIG-generated object that does not contain type info, since the + * existence of the object means that SWIG knows the type. + * + * :parents could use :classof to tell what class it is and make a better + * decision. This could be nice, (i.e. provide a run-time graph of C++ + * classes represented);. + * + * I can't think of a more elegant way of converting a C_obj fun to a + * pointer than "operator &"... + * + * Added a 'sizeof' that will allow you to do the expected thing. + * This should help users to fill buffer structs and the like (as is + * typical in windows-styled code). It's only enabled if you give + * %feature(sizeof) and then, only for simple types. + * + * Overall, carrying the list of methods and base classes has worked well. + * It allows me to give the Ocaml user introspection over their objects. + */ + + int classHandler(Node *n) { + String *name = Getattr(n, "name"); + classname = Getattr(n, "sym:name"); + + if (!name) + return SWIG_OK; + + String *mangled_name = mangleNameForCaml(name); + String *this_class_def = NewString(f_classtemplate); + String *name_normalized = normalizeTemplatedClassName(name); + String *old_class_ctors = f_class_ctors; + String *base_classes = NewString(""); + f_class_ctors = NewString(""); + bool sizeof_feature = generate_sizeof && isSimpleType(name); + + + classmode = true; + int rv = Language::classHandler(n); + classmode = false; + + if (sizeof_feature) { + Printf(f_wrappers, + "SWIGEXT CAML_VALUE _wrap_%s_sizeof( CAML_VALUE args ) {\n" + " CAMLparam1(args);\n" " CAMLreturn(Val_int(sizeof(%s)));\n" "}\n", mangled_name, name_normalized); + + Printf(f_mlbody, "external __%s_sizeof : unit -> int = " "\"_wrap_%s_sizeof\"\n", mangled_name, mangled_name); + } + + + /* Insert sizeof operator for concrete classes */ + if (sizeof_feature) { + Printv(f_class_ctors, "\"sizeof\" , (fun args -> C_int (__", mangled_name, "_sizeof ())) ;\n", NIL); + } + /* Handle up-casts in a nice way */ + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if (bname) { + String *base_create = NewString(""); + Printv(base_create, "(create_class \"", bname, "\")", NIL); + Printv(f_class_ctors, " \"::", bname, "\", (fun args -> ", base_create, " args) ;\n", NIL); + Printv(base_classes, base_create, " ;\n", NIL); + } + b = Next(b); + } + } + + Replaceall(this_class_def, "$classname", mangled_name); + Replaceall(this_class_def, "$normalized", name_normalized); + Replaceall(this_class_def, "$realname", name); + Replaceall(this_class_def, "$baselist", base_classes); + Replaceall(this_class_def, "$classbody", f_class_ctors); + + Delete(f_class_ctors); + f_class_ctors = old_class_ctors; + + // Actually write out the class definition + + Multiwrite(this_class_def); + + Setattr(n, "ocaml:ctor", mangled_name); + + return rv; + } + + String *normalizeTemplatedClassName(String *name) { + String *name_normalized = SwigType_typedef_resolve_all(name); + bool took_action; + + do { + took_action = false; + + if (is_a_pointer(name_normalized)) { + SwigType_del_pointer(name_normalized); + took_action = true; + } + + if (is_a_reference(name_normalized)) { + oc_SwigType_del_reference(name_normalized); + took_action = true; + } + + if (is_an_array(name_normalized)) { + oc_SwigType_del_array(name_normalized); + took_action = true; + } + } while (took_action); + + return SwigType_str(name_normalized, 0); + } + + /* + * Produce the symbol name that ocaml will use when referring to the + * target item. I wonder if there's a better way to do this: + * + * I shudder to think about doing it with a hash lookup, but that would + * make a couple of things easier: + */ + + String *mangleNameForCaml(String *s) { + String *out = Copy(s); + Replaceall(out, " ", "_xx"); + Replaceall(out, "::", "_xx"); + Replaceall(out, ",", "_x"); + Replaceall(out, "+", "_xx_plus"); + Replaceall(out, "-", "_xx_minus"); + Replaceall(out, "<", "_xx_ldbrace"); + Replaceall(out, ">", "_xx_rdbrace"); + Replaceall(out, "!", "_xx_not"); + Replaceall(out, "%", "_xx_mod"); + Replaceall(out, "^", "_xx_xor"); + Replaceall(out, "*", "_xx_star"); + Replaceall(out, "&", "_xx_amp"); + Replaceall(out, "|", "_xx_or"); + Replaceall(out, "(", "_xx_lparen"); + Replaceall(out, ")", "_xx_rparen"); + Replaceall(out, "[", "_xx_lbrace"); + Replaceall(out, "]", "_xx_rbrace"); + Replaceall(out, "~", "_xx_bnot"); + Replaceall(out, "=", "_xx_equals"); + Replaceall(out, "/", "_xx_slash"); + Replaceall(out, ".", "_xx_dot"); + return out; + } + + SwigType *fully_qualified_enum_type(Node *n) { + Node *parent = 0; + String *fully_qualified_name = NewString(""); + String *parent_type = 0; + + parent = parentNode(n); + while (parent) { + parent_type = nodeType(parent); + if (Getattr(parent, "name")) { + String *parent_copy = NewStringf("%s::", Getattr(parent, "name")); + if (Cmp(parent_type, "class") == 0 || Cmp(parent_type, "namespace") == 0) + Insert(fully_qualified_name, 0, parent_copy); + Delete(parent_copy); + } + if (!Cmp(parent_type, "class")) + break; + parent = parentNode(parent); + } + + return fully_qualified_name; + } + + /* Benedikt Grundmann inspired --> Enum wrap styles */ + + int enumvalueDeclaration(Node *n) { + String *name = Getattr(n, "name"); + SwigType *qtype = 0; + + if (name_qualifier_type) { + qtype = Copy(name_qualifier_type); + Printv(qtype, name, NIL); + } + + if (const_enum && qtype && name && !Getattr(seen_enumvalues, name)) { + Setattr(seen_enumvalues, name, "true"); + SetFlag(n, "feature:immutable"); + Setattr(n, "feature:enumvalue", "1"); // this does not appear to be used + + Setattr(n, "qualified:name", SwigType_namestr(qtype)); + + String *evname = SwigType_manglestr(qtype); + Insert(evname, 0, "SWIG_ENUM_"); + + Setattr(n, "feature:enumvname", name); + Setattr(n, "feature:symname", evname); + Delete(evname); + Printf(f_enumtypes_value, "| `%s\n", name); + + return Language::enumvalueDeclaration(n); + } else + return SWIG_OK; + } + + /* ------------------------------------------------------------------- + * This function is a bit uglier than it deserves. + * + * I used to direct lookup the name of the enum. Now that certain fixes + * have been made in other places, the names of enums are now fully + * qualified, which is a good thing, overall, but requires me to do + * some legwork. + * + * The other thing that uglifies this function is the varying way that + * typedef enum and enum are handled. I need to produce consistent names, + * which means looking up and registering by typedef and enum name. */ + int enumDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *name = Getattr(n, "name"); + if (name) { + String *oname = NewString(name); + /* name is now fully qualified */ + String *fully_qualified_name = NewString(name); + bool seen_enum = false; + if (name_qualifier_type) + Delete(name_qualifier_type); + char *strip_position; + name_qualifier_type = fully_qualified_enum_type(n); + + strip_position = strstr(Char(oname), "::"); + + while (strip_position) { + strip_position += 2; + oname = NewString(strip_position); + strip_position = strstr(Char(oname), "::"); + } + + seen_enum = (Getattr(seen_enums, fully_qualified_name) ? true : false); + + if (!seen_enum) { + const_enum = true; + Printf(f_enum_to_int, "| `%s -> (match y with\n", oname); + Printf(f_int_to_enum, "| `%s -> C_enum (\n", oname); + /* * * * A note about enum name resolution * * * * + * This code should now work, but I think we can do a bit better. + * The problem I'm having is that swig isn't very precise about + * typedef name resolution. My opinion is that SwigType_typedef + * resolve_all should *always* return the enum tag if one exists, + * rather than the admittedly friendlier enclosing typedef. + * + * This would make one of the cases below unnecessary. + * * * */ + Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", fully_qualified_name, oname); + if (!strncmp(Char(fully_qualified_name), "enum ", 5)) { + String *fq_noenum = NewString(Char(fully_qualified_name) + 5); + Printf(f_mlbody, + "let _ = Callback.register \"%s_marker\" (`%s)\n" "let _ = Callback.register \"%s_marker\" (`%s)\n", fq_noenum, oname, fq_noenum, name); + } + + Printf(f_enumtypes_type, "| `%s\n", oname); + Insert(fully_qualified_name, 0, "enum "); + Setattr(seen_enums, fully_qualified_name, n); + } + } + + int ret = Language::enumDeclaration(n); + + if (const_enum) { + Printf(f_int_to_enum, "`Int y)\n"); + Printf(f_enum_to_int, "| `Int x -> Swig.C_int x\n" "| _ -> raise (LabelNotFromThisEnum v))\n"); + } + + const_enum = false; + + return ret; + } + + /* ---------------------------------------------------------------------------- + * BEGIN C++ Director Class modifications + * ------------------------------------------------------------------------- */ + + /* + * Modified polymorphism code for Ocaml language module. + * + * TODO + * + * Move some boilerplate code generation to Swig_...() functions. + * + */ + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *returntype = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *symname = Getattr(n, "sym:name"); + String *declaration = NewString(""); + ParmList *l = Getattr(n, "parms"); + Wrapper *w = NewWrapper(); + String *tm; + String *wrap_args = NewString(""); + int status = SWIG_OK; + int idx; + bool pure_virtual = false; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + Printf(w->locals, "CAMLparam0();\n"); + + /* determine if the method returns a pointer */ + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(returntype, "void") && !is_pointer); + + /* virtual method definition */ + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + 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); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + ParmList *throw_parm_list = 0; + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + 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, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + Append(w->def, ")"); + Append(declaration, ")"); + } + Append(w->def, " {"); + Append(declaration, ";\n"); + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($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 { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(returntype, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + String *super_call = Swig_method_call(super, l); + if (is_void) + Printf(w->code, "%s;\n", super_call); + else + Printf(w->code, "CAMLreturn_type(%s);\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + Wrapper_add_local(w, "swig_result", "SWIG_CAMLlocal2(swig_result, args)"); + /* attach typemaps to arguments (C/C++ -> Ocaml) */ + String *arglist = NewString(""); + + Swig_director_parms_fixup(l); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + int num_arguments = emit_num_arguments(l); + int i; + char source[256]; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + for (i = 0, idx = 0, p = l; i < num_arguments; i++) { + + while (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + Putc(',', arglist); + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + Setattr(p, "emit:directorinput", pname); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + Printv(wrap_args, tm, "\n", NIL); + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + /* special handling for pointers to other C++ director classes. + * ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. in other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. we avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, ptype); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(ptype) + 2); + /* name as pointer */ + String *ppname = Copy(pname); + if (SwigType_isreference(ptype)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Python doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", pname); + String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(ptype, pname), + SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(ptype); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "CAML_VALUE", source, "= Val_unit", NIL); + Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Printf(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "}\n"); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "CAML_VALUE", source, "= Val_unit", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + Printv(w->code, "swig_result = Val_unit;\n", 0); + Printf(w->code, "args = Val_unit;\n"); + + /* wrap complex arguments to values */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the OCaml object */ + Printv(w->code, + "swig_result = caml_swig_alloc(1,C_list);\n" "SWIG_Store_field(swig_result,0,args);\n" "args = swig_result;\n" "swig_result = Val_unit;\n", 0); + Printf(w->code, "static const CAML_VALUE *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n"); + Printf(w->code, " swig_ocaml_func_val = caml_named_value(\"swig_runmethod\");\n }\n"); + Printf(w->code, "swig_result = caml_callback3(*swig_ocaml_func_val,swig_get_self(),caml_copy_string(\"%s\"),args);\n", Getattr(n, "name")); + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Printf(w->code, "if (!%s) {\n", Swig_cresult_name()); + Printf(w->code, " CAML_VALUE error = *caml_named_value(\"director_except\");\n"); + Replaceall(tm, "$error", "error"); + Printv(w->code, Str(tm), "\n", NIL); + Printf(w->code, "}\n"); + } + + /* + * Python method may return a simple object, or a tuple. + * for in/out arguments, we have to extract the appropriate values from the + * argument list, then marshal everything back to C/C++ (return value and + * output arguments). + */ + + /* marshal return value and other outputs (if any) from value to C/C++ + * type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + tm = Swig_typemap_lookup("directorout", n, "c_result", w); + if (tm != 0) { + Replaceall(tm, "$input", "swig_result"); + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + Replaceall(tm, "$result", "swig_result"); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(arglist); + Delete(cleanup); + Delete(outarg); + } + + /* any existing helper functions to handle this? */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + /* A little explanation: + * The director_enum test case makes a method whose return type + * is an enum type. returntype here is "int". gcc complains + * about an implicit enum conversion, and although i don't strictly + * agree with it, I'm working on fixing the error: + * + * Below is what I came up with. It's not great but it should + * always essentially work. + */ + if (!SwigType_isreference(returntype)) { + Printf(w->code, "CAMLreturn_type((%s)c_result);\n", SwigType_lstr(returntype, "")); + } else { + Printf(w->code, "CAMLreturn_type(*c_result);\n"); + } + } + } else { + Printf(w->code, "CAMLreturn0;\n"); + } + + Printf(w->code, "}\n"); + + // We expose 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) { + 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); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(pclassname); + DelWrapper(w); + return status; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p, *q; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("CAML_VALUE"); + p = NewParm(type, NewString("self"), n); + q = Copy(p); + set_nextSibling(q, superparms); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Setattr(n, "parms", q); + Language::classDirectorConstructor(n); + + Delete(sub); + Delete(classname); + Delete(supername); + //Delete(parms); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname; + classname = Swig_class_name(n); + + /* insert self parameter */ + Parm *p, *q; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("CAML_VALUE"); + p = NewParm(type, NewString("self"), n); + q = Copy(p); + set_nextSibling(p, parms); + + { + Wrapper *w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(CAML_VALUE self) : Swig::Director(self) { }", classname, classname); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " SwigDirector_%s(CAML_VALUE self);\n", classname); + Delete(classname); + Setattr(n, "parms", q); + return Language::classDirectorDefaultConstructor(n); + } + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n" "%s\n" "public:\n", declaration); + Delete(declaration); + return Language::classDirectorInit(n); + } + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + /* --------------------------------------------------------------------- + * typedefHandler + * + * This is here in order to maintain the correct association between + * typedef names and enum names. + * + * Since I implement enums as polymorphic variant tags, I need to call + * back into ocaml to evaluate them. This requires a string that can + * be generated in the typemaps, and also at SWIG time to be the same + * string. The problem that arises is that SWIG variously generates + * enum e_name_tag + * e_name_tag + * e_typedef_name + * for + * typedef enum e_name_tag { ... } e_typedef_name; + * + * Since I need these strings to be consistent, I must maintain a correct + * association list between typedef and enum names. + * --------------------------------------------------------------------- */ + int typedefHandler(Node *n) { + String *type = Getattr(n, "type"); + Node *enum_node = type ? Getattr(seen_enums, type) : 0; + if (enum_node) { + String *name = Getattr(enum_node, "name"); + + Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", Getattr(n, "name"), name); + + } + return SWIG_OK; + } + + String *runtimeCode() { + String *s = Swig_include_sys("ocamlrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'ocamlrun.swg'\n"); + s = NewString(""); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigocamlrun.h"); + } +}; + +/* ------------------------------------------------------------------------- + * swig_ocaml() - Instantiate module + * ------------------------------------------------------------------------- */ + +static Language *new_swig_ocaml() { + return new OCAML(); +} +extern "C" Language *swig_ocaml(void) { + return new_swig_ocaml(); +} diff --git a/contrib/tools/swig/Source/Modules/octave.cxx b/contrib/tools/swig/Source/Modules/octave.cxx new file mode 100644 index 00000000000..b1769e42a7b --- /dev/null +++ b/contrib/tools/swig/Source/Modules/octave.cxx @@ -0,0 +1,1590 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * octave.cxx + * + * Octave language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static String *global_name = 0; +static String *op_prefix = 0; + +static const char *usage = "\ +Octave Options (available with -octave)\n\ + -globals <name> - Set <name> used to access C global variables [default: 'cvar']\n\ + Use '.' to load C global variables into module namespace\n\ + -opprefix <str> - Prefix <str> for global operator functions [default: 'op_']\n\ +\n"; + + +class OCTAVE:public Language { +private: + File *f_begin; + File *f_runtime; + File *f_header; + File *f_doc; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + File *f_directors; + File *f_directors_h; + String *s_global_tab; + String *s_members_tab; + String *class_name; + + int have_constructor; + int have_destructor; + String *constructor_name; + + Hash *docs; + + void Octave_begin_function(Node *n, File *f, const_String_or_char_ptr cname, const_String_or_char_ptr wname, bool dld) { + if (dld) { + String *tname = texinfo_name(n, "std::string()"); + Printf(f, "SWIG_DEFUN( %s, %s, %s ) {", cname, wname, tname); + } + else { + Printf(f, "static octave_value_list %s (const octave_value_list& args, int nargout) {", wname); + } + } + +public: + OCTAVE(): + f_begin(0), + f_runtime(0), + f_header(0), + f_doc(0), + f_wrappers(0), + f_init(0), + f_initbeforefunc(0), + f_directors(0), + f_directors_h(0), + s_global_tab(0), + s_members_tab(0), + class_name(0), + have_constructor(0), + have_destructor(0), + constructor_name(0), + docs(0) + { + /* Add code to manage protected constructors and directors */ + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " error(\"accessing abstract class or protected constructor\"); \n", " SWIG_fail;\n", "}\n", NIL); + + enable_cplus_runtime_mode(); + allow_overloading(); + director_multiple_inheritance = 1; + director_language = 1; + docs = NewHash(); + } + + virtual void main(int argc, char *argv[]) { + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } else if (strcmp(argv[i], "-globals") == 0) { + if (argv[i + 1]) { + global_name = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-opprefix") == 0) { + if (argv[i + 1]) { + op_prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-cppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); + } + } + } + + if (!global_name) + global_name = NewString("cvar"); + if (!op_prefix) + op_prefix = NewString("op_"); + + SWIG_library_directory("octave"); + Preprocessor_define("SWIGOCTAVE 1", 0); + SWIG_config_file("octave.swg"); + SWIG_typemap_lang("octave"); + allow_overloading(); + + // Octave API is C++, so output must be C++ compatible even when wrapping C code + if (!cparse_cplusplus) + Swig_cparse_cplusplusout(1); + } + + virtual int top(Node *n) { + { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + int dirprot = 0; + if (Getattr(options, "dirprot")) { + dirprot = 1; + } + if (Getattr(options, "nodirprot")) { + dirprot = 0; + } + if (Getattr(options, "directors")) { + allow_directors(); + if (dirprot) + allow_dirprot(); + } + } + } + } + + String *module = Getattr(n, "name"); + String *outfile = Getattr(n, "outfile"); + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_header = NewString(""); + f_doc = NewString(""); + f_wrappers = NewString(""); + f_init = NewString(""); + f_initbeforefunc = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + s_global_tab = NewString(""); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("doc", f_doc); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGOCTAVE\n#define SWIGOCTAVE\n#endif\n\n"); + + Printf(f_runtime, "#define SWIG_name_d \"%s\"\n", module); + Printf(f_runtime, "#define SWIG_name %s\n", module); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIG_global_name \"%s\"\n", global_name); + Printf(f_runtime, "#define SWIG_op_prefix \"%s\"\n", op_prefix); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + Swig_banner(f_directors_h); + if (dirprot_mode()) { + // Printf(f_directors_h, "#include <map>\n"); + // Printf(f_directors_h, "#include <string>\n\n"); + } + } + + Printf(f_runtime, "\n"); + + Printf(s_global_tab, "\nstatic const struct swig_octave_member swig_globals[] = {\n"); + Printf(f_init, "static bool SWIG_init_user(octave_swig_type* module_ns)\n{\n"); + + if (!CPlusPlus) + Printf(f_header,"extern \"C\" {\n"); + + Language::top(n); + + if (!CPlusPlus) + Printf(f_header,"}\n"); + + if (Len(docs)) + emit_doc_texinfo(); + + if (directorsEnabled()) { + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + + Printf(f_init, "return true;\n}\n"); + Printf(s_global_tab, "{0,0,0,0,0,0}\n};\n"); + + Printv(f_wrappers, s_global_tab, NIL); + SwigType_emit_type_table(f_runtime, f_wrappers); + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_doc, f_begin); + if (directorsEnabled()) { + Dump(f_directors_h, f_begin); + Dump(f_directors, f_begin); + } + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(s_global_tab); + Delete(f_initbeforefunc); + Delete(f_init); + Delete(f_wrappers); + Delete(f_doc); + Delete(f_header); + Delete(f_directors); + Delete(f_directors_h); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + String *texinfo_escape(String *_s) { + const char* s=(const char*)Data(_s); + while (*s&&(*s=='\t'||*s=='\r'||*s=='\n'||*s==' ')) + ++s; + String *r = NewString(""); + for (int j=0;s[j];++j) { + if (s[j] == '\n') { + Append(r, "\\n\\\n"); + } else if (s[j] == '\r') { + Append(r, "\\r"); + } else if (s[j] == '\t') { + Append(r, "\\t"); + } else if (s[j] == '\\') { + Append(r, "\\\\"); + } else if (s[j] == '\'') { + Append(r, "\\\'"); + } else if (s[j] == '\"') { + Append(r, "\\\""); + } else + Putc(s[j], r); + } + return r; + } + void emit_doc_texinfo() { + for (Iterator it = First(docs); it.key; it = Next(it)) { + String *wrap_name = it.key; + + String *synopsis = Getattr(it.item, "synopsis"); + String *decl_info = Getattr(it.item, "decl_info"); + String *cdecl_info = Getattr(it.item, "cdecl_info"); + String *args_info = Getattr(it.item, "args_info"); + + String *doc_str = NewString(""); + Printv(doc_str, synopsis, decl_info, cdecl_info, args_info, NIL); + String *escaped_doc_str = texinfo_escape(doc_str); + + if (Len(doc_str)>0) { + Printf(f_doc,"static const char* %s_texinfo = ",wrap_name); + Printf(f_doc,"\"-*- texinfo -*-\\n\\\n%s", escaped_doc_str); + if (Len(decl_info)) + Printf(f_doc,"\\n\\\n@end deftypefn"); + Printf(f_doc,"\";\n"); + } + + Delete(escaped_doc_str); + Delete(doc_str); + Delete(wrap_name); + } + Printf(f_doc,"\n"); + } + bool is_empty_doc_node(Node* n) { + if (!n) + return true; + String *synopsis = Getattr(n, "synopsis"); + String *decl_info = Getattr(n, "decl_info"); + String *cdecl_info = Getattr(n, "cdecl_info"); + String *args_info = Getattr(n, "args_info"); + return !Len(synopsis) && !Len(decl_info) && + !Len(cdecl_info) && !Len(args_info); + } + String *texinfo_name(Node* n, const char* defval = "0") { + String *tname = NewString(""); + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(iname); + Node* d = Getattr(docs, wname); + + if (is_empty_doc_node(d)) + Printf(tname, defval); + else + Printf(tname, "%s_texinfo", wname); + + return tname; + } + void process_autodoc(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *name = Getattr(n, "name"); + String *wname = Swig_name_wrapper(iname); + String *str = Getattr(n, "feature:docstring"); + bool autodoc_enabled = !Cmp(Getattr(n, "feature:autodoc"), "1"); + Node* d = Getattr(docs, wname); + if (!d) { + d = NewHash(); + Setattr(d, "synopsis", NewString("")); + Setattr(d, "decl_info", NewString("")); + Setattr(d, "cdecl_info", NewString("")); + Setattr(d, "args_info", NewString("")); + Setattr(docs, wname, d); + } + + String *synopsis = Getattr(d, "synopsis"); + String *decl_info = Getattr(d, "decl_info"); + // String *cdecl_info = Getattr(d, "cdecl_info"); + String *args_info = Getattr(d, "args_info"); + + // * couldn't we just emit the docs here? + + if (autodoc_enabled) { + String *decl_str = NewString(""); + String *args_str = NewString(""); + make_autodocParmList(n, decl_str, args_str); + Append(decl_info, "@deftypefn {Loadable Function} "); + + SwigType *type = Getattr(n, "type"); + if (type && Strcmp(type, "void")) { + Node *nn = classLookup(Getattr(n, "type")); + String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); + Append(decl_info, "@var{retval} = "); + Printf(args_str, "%s@var{retval} is of type %s. ", args_str, type_str); + Delete(type_str); + } + + Append(decl_info, name); + Append(decl_info, " ("); + Append(decl_info, decl_str); + Append(decl_info, ")\n"); + Append(args_info, args_str); + Delete(decl_str); + Delete(args_str); + } + + if (str && Len(str) > 0) { + // strip off {} if necessary + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + + // emit into synopsis section + Append(synopsis, str); + } + } + + virtual int importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname) + Printf(f_init, "if (!SWIG_Octave_LoadModule(\"%s\")) return false;\n", modname); + return Language::importDirective(n); + } + + const char *get_implicitconv_flag(Node *n) { + int conv = 0; + if (n && GetFlag(n, "feature:implicitconv")) { + conv = 1; + } + return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0"; + } + + /* ----------------------------------------------------------------------------- + * addMissingParameterNames() + * For functions that have not had nameless parameters set in the Language class. + * + * Inputs: + * plist - entire parameter list + * arg_offset - argument number for first parameter + * Side effects: + * The "lname" attribute in each parameter in plist will be contain a parameter name + * ----------------------------------------------------------------------------- */ + + void addMissingParameterNames(Node* n, ParmList *plist, int arg_offset) { + Parm *p = plist; + int i = arg_offset; + while (p) { + if (!Getattr(p, "lname")) { + String *name = makeParameterName(n, p, i); + Setattr(p, "lname", name); + Delete(name); + } + i++; + p = nextSibling(p); + } + } + + void make_autodocParmList(Node *n, String *decl_str, String *args_str) { + String *pdocs = 0; + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + int arg_num = is_wrapping_class() ? 1 : 0; + + addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + for (p = plist; p; p = pnext, arg_num++) { + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + + String *name = 0; + String *type = 0; + String *value = 0; + String *pdoc = Getattr(p, "tmap:doc"); + if (pdoc) { + name = Getattr(p, "tmap:doc:name"); + type = Getattr(p, "tmap:doc:type"); + value = Getattr(p, "tmap:doc:value"); + } + + String *made_name = 0; + if (!name) { + name = made_name = makeParameterName(n, p, arg_num); + } + + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + if (SwigType_isvarargs(type)) + break; + + String *tex_name = NewString(""); + if (name) + Printf(tex_name, "@var{%s}", name); + else + Printf(tex_name, "@var{?}"); + + if (Len(decl_str)) + Append(decl_str, ", "); + Append(decl_str, tex_name); + + if (value) { + String *new_value = convertValue(value, Getattr(p, "type")); + if (new_value) { + value = new_value; + } else { + Node *lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(decl_str, " = %s", value); + } + + Node *nn = classLookup(Getattr(p, "type")); + String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); + Printf(args_str, "%s is of type %s. ", tex_name, type_str); + + Delete(type_str); + Delete(tex_name); + Delete(made_name); + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + } + + /* ------------------------------------------------------------ + * convertValue() + * Check if string v can be an Octave value literal, + * (eg. number or string), or translate it to an Octave literal. + * ------------------------------------------------------------ */ + String *convertValue(String *v, SwigType *t) { + if (v && Len(v) > 0) { + char fc = (Char(v))[0]; + if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) { + /* number or string (or maybe NULL pointer) */ + if (SwigType_ispointer(t) && Strcmp(v, "0") == 0) + return NewString("None"); + else + return v; + } + if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) + return SwigType_ispointer(t) ? NewString("nil") : NewString("0"); + if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0) + return NewString("true"); + if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0) + return NewString("false"); + } + return 0; + } + + virtual int functionWrapper(Node *n) { + Parm *p; + String *tm; + int j; + + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + int destructor = (!Cmp(nodeType, "destructor")); + String *storage = Getattr(n, "storage"); + + bool overloaded = !!Getattr(n, "sym:overloaded"); + bool last_overload = overloaded && !Getattr(n, "sym:nextSibling"); + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(iname); + String *overname = Copy(wname); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + if (!overloaded && !addSymbol(iname, n)) + return SWIG_ERROR; + + if (overloaded) + Append(overname, Getattr(n, "sym:overname")); + + if (!overloaded || last_overload) + process_autodoc(n); + + Wrapper *f = NewWrapper(); + Octave_begin_function(n, f->def, iname, overname, !overloaded); + + // Start default try block to execute + // cleanup code if exception is thrown + Printf(f->code, "try {\n"); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + int varargs = emit_isvarargs(l); + char source[64]; + + Printf(f->code, "if (!SWIG_check_num_args(\"%s\",args.length(),%i,%i,%i)) " + "{\n SWIG_fail;\n }\n", iname, num_arguments, num_required, varargs); + + if (constructor && num_arguments == 1 && num_required == 1) { + if (Cmp(storage, "explicit") == 0) { + Node *parent = Swig_methodclass(n); + if (GetFlag(parent, "feature:implicitconv")) { + String *desc = NewStringf("SWIGTYPE%s", SwigType_manglestr(Getattr(n, "type"))); + Printf(f->code, "if (SWIG_CheckImplicit(%s)) SWIG_fail;\n", desc); + Delete(desc); + } + } + } + + for (j = 0, p = l; j < num_arguments; ++j) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + if (!tm || checkAttribute(p, "tmap:in:numinputs", "0")) { + p = nextSibling(p); + continue; + } + + sprintf(source, "args(%d)", j); + Setattr(p, "emit:input", source); + + Replaceall(tm, "$source", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Replaceall(tm, "$target", Getattr(p, "lname")); + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + if (Getattr(p, "tmap:in:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p, "hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + Replaceall(tm, "$implicitconv", convflag); + Setattr(p, "implicitconv", convflag); + } + + String *getargs = NewString(""); + if (j >= num_required) + Printf(getargs, "if (%d<args.length()) {\n%s\n}", j, tm); + else + Printv(getargs, tm, NIL); + Printv(f->code, getargs, "\n", NIL); + Delete(getargs); + + p = Getattr(p, "tmap:in:next"); + continue; + } 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)); + break; + } + } + + // Check for trailing varargs + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + // Insert constraint checking code + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + // Insert cleanup code + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + if (Getattr(p, "tmap:freearg:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p, "hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + if (strcmp(convflag, "0") == 0) { + tm = 0; + } + } + if (tm && (Len(tm) != 0)) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + // Insert argument output code + String *outarg = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "_outp"); + Replaceall(tm, "$result", "_outp"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + int director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Append(f->code, "upcall = !!dynamic_cast<Swig::Director*>(arg1);\n"); + } + + Setattr(n, "wrap:name", overname); + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + Wrapper_add_local(f, "_out", "octave_value_list _out"); + Wrapper_add_local(f, "_outp", "octave_value_list *_outp=&_out"); + Wrapper_add_local(f, "_outv", "octave_value _outv"); + + // Return the function value + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$target", "_outv"); + Replaceall(tm, "$result", "_outv"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s\n", tm); + Printf(f->code, "if (_outv.is_defined()) _outp = " "SWIG_Octave_AppendOutput(_outp, _outv);\n"); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), iname); + } + emit_return_variable(n, d, f); + + Printv(f->code, outarg, NIL); + Printv(f->code, cleanup, NIL); + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$result", "_outv"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printf(f->code, "return _out;\n"); + + // Execute cleanup code if branched to fail: label + Printf(f->code, "fail:\n"); + Printv(f->code, cleanup, NIL); + Printf(f->code, "return octave_value_list();\n"); + + // Execute cleanup code if exception was thrown + Printf(f->code, "}\n"); + Printf(f->code, "catch(...) {\n"); + Printv(f->code, cleanup, NIL); + Printf(f->code, "throw;\n"); + Printf(f->code, "}\n"); + + // End wrapper function + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + Replaceall(f->code, "$symname", iname); + Wrapper_print(f, f_wrappers); + DelWrapper(f); + + if (last_overload) + dispatchFunction(n); + + if (!overloaded || last_overload) { + String *tname = texinfo_name(n); + Printf(s_global_tab, "{\"%s\",%s,0,0,2,%s},\n", iname, wname, tname); + Delete(tname); + } + + Delete(overname); + Delete(wname); + Delete(cleanup); + Delete(outarg); + + return SWIG_OK; + } + + void dispatchFunction(Node *n) { + Wrapper *f = NewWrapper(); + + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(iname); + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(args, nargout);", &maxargs); + String *tmp = NewString(""); + + Octave_begin_function(n, f->def, iname, wname, true); + Wrapper_add_local(f, "argc", "int argc = args.length()"); + Printf(tmp, "octave_value_ref argv[%d]={", maxargs); + for (int j = 0; j < maxargs; ++j) + Printf(tmp, "%soctave_value_ref(args,%d)", j ? "," : " ", j); + Printf(tmp, "}"); + Wrapper_add_local(f, "argv", tmp); + Printv(f->code, dispatch, "\n", NIL); + Printf(f->code, "error(\"No matching function for overload\");\n", iname); + Printf(f->code, "return octave_value_list();\n"); + Printv(f->code, "}\n", NIL); + + Wrapper_print(f, f_wrappers); + Delete(tmp); + DelWrapper(f); + Delete(dispatch); + Delete(wname); + } + + virtual int variableWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + String *tm; + Wrapper *getf = NewWrapper(); + Wrapper *setf = NewWrapper(); + + String *getname = Swig_name_get(NSPACE_TODO, iname); + String *setname = Swig_name_set(NSPACE_TODO, iname); + + String *getwname = Swig_name_wrapper(getname); + String *setwname = Swig_name_wrapper(setname); + + Octave_begin_function(n, setf->def, setname, setwname, true); + Printf(setf->code, "if (!SWIG_check_num_args(\"%s_set\",args.length(),1,1,0)) return octave_value_list();", iname); + if (is_assignable(n)) { + Setattr(n, "wrap:name", setname); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "args(0)"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "args(0)"); + if (Getattr(n, "tmap:varin:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + emit_action_code(n, setf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + } + Append(setf->code, "return octave_value_list();\n"); + Append(setf->code, "fail:\n"); + Append(setf->code, "return octave_value_list();\n"); + } else { + Printf(setf->code, "return octave_set_immutable(args,nargout);"); + } + Append(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + + Setattr(n, "wrap:name", getname); + int addfail = 0; + Octave_begin_function(n, getf->def, getname, getwname, true); + Wrapper_add_local(getf, "obj", "octave_value obj"); + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "obj"); + Replaceall(tm, "$result", "obj"); + addfail = emit_action_code(n, getf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + Append(getf->code, "return obj;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, "return octave_value_list();\n"); + } + Append(getf->code, "}\n"); + Wrapper_print(getf, f_wrappers); + + Printf(s_global_tab, "{\"%s\",0,%s,%s,2,0},\n", iname, getwname, setwname); + + Delete(getwname); + Delete(setwname); + DelWrapper(setf); + DelWrapper(getf); + + return SWIG_OK; + } + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *cppvalue = Getattr(n, "cppvalue"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + String *str = SwigType_str(type, wname); + Printf(f_header, "static %s = %s;\n", str, value); + Delete(str); + value = wname; + } + if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", cppvalue ? cppvalue : value); + Replaceall(tm, "$nsname", iname); + Printf(f_init, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + + return SWIG_OK; + } + + virtual int nativeWrapper(Node *n) { + return Language::nativeWrapper(n); + } + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + virtual int classHandler(Node *n) { + have_constructor = 0; + have_destructor = 0; + constructor_name = 0; + + class_name = Getattr(n, "sym:name"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + // This is a bug, due to the fact that swig_type -> octave_class mapping + // is 1-to-n. + static Hash *emitted = NewHash(); + String *mangled_classname = Swig_name_mangle(Getattr(n, "name")); + if (Getattr(emitted, mangled_classname)) { + Delete(mangled_classname); + return SWIG_NOWRAP; + } + Setattr(emitted, mangled_classname, "1"); + Delete(mangled_classname); + + assert(!s_members_tab); + s_members_tab = NewString(""); + Printv(s_members_tab, "static swig_octave_member swig_", class_name, "_members[] = {\n", NIL); + + Language::classHandler(n); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType_add_pointer(t); + + // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) + SwigType *smart = Swig_cparse_smartptr(n); + String *wrap_class = NewStringf("&_wrap_class_%s", class_name); + if (smart) { + SwigType_add_pointer(smart); + SwigType_remember_clientdata(smart, wrap_class); + } + //String *wrap_class = NewStringf("&_wrap_class_%s", class_name); + SwigType_remember_clientdata(t, wrap_class); + + int use_director = Swig_directorclass(n); + if (use_director) { + String *nspace = Getattr(n, "sym:nspace"); + String *cname = Swig_name_disown(nspace, class_name); + String *wcname = Swig_name_wrapper(cname); + String *cnameshdw = NewStringf("%s_shadow", cname); + String *wcnameshdw = Swig_name_wrapper(cnameshdw); + Octave_begin_function(n, f_wrappers, cnameshdw, wcnameshdw, true); + Printf(f_wrappers, " if (args.length()!=1) {\n"); + Printf(f_wrappers, " error(\"disown takes no arguments\");\n"); + Printf(f_wrappers, " return octave_value_list();\n"); + Printf(f_wrappers, " }\n"); + Printf(f_wrappers, " %s (args, nargout);\n", wcname); + Printf(f_wrappers, " return args;\n"); + Printf(f_wrappers, "}\n"); + Printf(s_members_tab, "{\"__disown\",%s,0,0,0,0},\n", wcnameshdw); + Delete(wcname); + Delete(cname); + Delete(wcnameshdw); + Delete(cnameshdw); + } + + Printf(s_members_tab, "{0,0,0,0,0,0}\n};\n"); + Printv(f_wrappers, s_members_tab, NIL); + + String *base_class_names = NewString(""); + String *base_class = NewString(""); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + + String *bname_mangled = SwigType_manglestr(SwigType_add_pointer(Copy(bname))); + Printf(base_class_names, "\"%s\",", bname_mangled); + Printf(base_class, "0,"); + b = Next(b); + index++; + Delete(bname_mangled); + } + } + + Printv(f_wrappers, "static const char *swig_", class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); + Printv(f_wrappers, "static const swig_type_info *swig_", class_name, "_base[] = {", base_class, "0};\n", NIL); + Printv(f_wrappers, "static swig_octave_class _wrap_class_", class_name, " = {\"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + Printv(f_wrappers, Swig_directorclass(n) ? "1," : "0,", NIL); + if (have_constructor) { + String *nspace = Getattr(n, "sym:nspace"); + String *cname = Swig_name_construct(nspace, constructor_name); + String *wcname = Swig_name_wrapper(cname); + String *tname = texinfo_name(n); + Printf(f_wrappers, "%s,%s,", wcname, tname); + Delete(tname); + Delete(wcname); + Delete(cname); + } else + Printv(f_wrappers, "0,0,", NIL); + if (have_destructor) { + String *nspace = Getattr(n, "sym:nspace"); + String *cname = Swig_name_destroy(nspace, class_name); + String *wcname = Swig_name_wrapper(cname); + Printf(f_wrappers, "%s,", wcname); + Delete(wcname); + Delete(cname); + } else + Printv(f_wrappers, "0", ",", NIL); + Printf(f_wrappers, "swig_%s_members,swig_%s_base_names,swig_%s_base };\n\n", class_name, class_name, class_name); + + Delete(base_class); + Delete(base_class_names); + Delete(smart); + Delete(t); + Delete(s_members_tab); + s_members_tab = 0; + class_name = 0; + + return SWIG_OK; + } + + virtual int memberfunctionHandler(Node *n) { + Language::memberfunctionHandler(n); + + assert(s_members_tab); + assert(class_name); + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + String *realname = iname ? iname : name; + String *wname = Getattr(n, "wrap:name"); + assert(wname); + + if (!Getattr(n, "sym:nextSibling")) { + String *tname = texinfo_name(n); + String *rname = Copy(wname); + bool overloaded = !!Getattr(n, "sym:overloaded"); + if (overloaded) + Delslice(rname, Len(rname) - Len(Getattr(n, "sym:overname")), DOH_END); + Printf(s_members_tab, "{\"%s\",%s,0,0,0,%s},\n", + realname, rname, tname); + Delete(rname); + Delete(tname); + } + + return SWIG_OK; + } + + virtual int membervariableHandler(Node *n) { + Setattr(n, "feature:autodoc", "0"); + + Language::membervariableHandler(n); + + assert(s_members_tab); + assert(class_name); + String *symname = Getattr(n, "sym:name"); + String *getname = Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); + String *setname = Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); + String *getwname = Swig_name_wrapper(getname); + String *setwname = GetFlag(n, "feature:immutable") ? NewString("octave_set_immutable") : Swig_name_wrapper(setname); + assert(s_members_tab); + + Printf(s_members_tab, "{\"%s\",0,%s,%s,0,0},\n", symname, getwname, setwname); + + Delete(getname); + Delete(setname); + Delete(getwname); + Delete(setwname); + return SWIG_OK; + } + + virtual int constructorHandler(Node *n) { + have_constructor = 1; + if (!constructor_name) + constructor_name = NewString(Getattr(n, "sym:name")); + + int use_director = Swig_directorclass(n); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("void"); + SwigType_add_pointer(type); + self = NewParm(type, name, n); + Delete(type); + Delete(name); + Setattr(self, "lname", "self_obj"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Setattr(n, "hidden", "1"); + Delete(self); + } + + return Language::constructorHandler(n); + } + + virtual int destructorHandler(Node *n) { + have_destructor = 1; + return Language::destructorHandler(n); + } + + virtual int staticmemberfunctionHandler(Node *n) { + Language::staticmemberfunctionHandler(n); + + assert(s_members_tab); + assert(class_name); + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + String *realname = iname ? iname : name; + String *wname = Getattr(n, "wrap:name"); + assert(wname); + + if (!Getattr(n, "sym:nextSibling")) { + String *tname = texinfo_name(n); + String *rname = Copy(wname); + bool overloaded = !!Getattr(n, "sym:overloaded"); + if (overloaded) + Delslice(rname, Len(rname) - Len(Getattr(n, "sym:overname")), DOH_END); + Printf(s_members_tab, "{\"%s\",%s,0,0,1,%s},\n", + realname, rname, tname); + Delete(rname); + Delete(tname); + } + + return SWIG_OK; + } + + virtual int memberconstantHandler(Node *n) { + return Language::memberconstantHandler(n); + } + + virtual int staticmembervariableHandler(Node *n) { + Setattr(n, "feature:autodoc", "0"); + + Language::staticmembervariableHandler(n); + + if (!GetFlag(n, "wrappedasconstant")) { + assert(s_members_tab); + assert(class_name); + String *symname = Getattr(n, "sym:name"); + String *getname = Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); + String *setname = Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)); + String *getwname = Swig_name_wrapper(getname); + String *setwname = GetFlag(n, "feature:immutable") ? NewString("octave_set_immutable") : Swig_name_wrapper(setname); + assert(s_members_tab); + + Printf(s_members_tab, "{\"%s\",0,%s,%s,1,0},\n", symname, getwname, setwname); + + Delete(getname); + Delete(setname); + Delete(getwname); + Delete(setwname); + } + return SWIG_OK; + } + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + // insert self parameter + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("void"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self"), n); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + // constructor + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s," "\nSwig::Director(static_cast<%s*>(this)) { \n", classname, target, call, basetype); + Append(w->def, "}\n"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + // constructor header + { + String *target = Swig_method_decl(0, decl, classname, parms, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + { + Wrapper *w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(void* self) :" + "\nSwig::Director((octave_swig_type*)self,static_cast<%s*>(this)) { \n", classname, classname, classname); + Append(w->def, "}\n"); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " SwigDirector_%s(octave_swig_type* self);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl = Getattr(n, "decl"); + String *returntype = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *symname = Getattr(n, "sym:name"); + String *declaration = NewString(""); + ParmList *l = Getattr(n, "parms"); + Wrapper *w = NewWrapper(); + String *tm; + String *wrap_args = NewString(""); + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + // determine if the method returns a pointer + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(returntype, "void") && !is_pointer); + + // virtual method definition + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + 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); + + // header declaration + target = Swig_method_decl(rtype, decl, name, l, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + 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, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + // declare method return value + // if the return value is a reference or const reference, a specialized typemap must + // handle it, including declaration of c_result ($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 { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(returntype, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + // attach typemaps to arguments (C/C++ -> Octave) + String *parse_args = NewString(""); + + Swig_director_parms_fixup(l); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + + int outputs = 0; + if (!is_void) + outputs++; + + // build argument list and type conversion string + p = l; + while (p) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + Wrapper_add_local(w, "tmpv", "octave_value tmpv"); + + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + String *parse = Getattr(p, "tmap:directorin:parse"); + if (!parse) { + Setattr(p, "emit:directorinput", "tmpv"); + Replaceall(tm, "$input", "tmpv"); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, tm, "\n", NIL); + Printf(wrap_args, "args.append(tmpv);\n"); + Putc('O', parse_args); + } else { + Append(parse_args, parse); + Setattr(p, "emit:directorinput", pname); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + } + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + p = nextSibling(p); + } + + String *method_name = Getattr(n, "sym:name"); + + Printv(w->code, wrap_args, NIL); + + // emit method invocation + Wrapper_add_local(w, "args", "octave_value_list args"); + Wrapper_add_local(w, "out", "octave_value_list out"); + Wrapper_add_local(w, "idx", "std::list<octave_value_list> idx"); + Printf(w->code, "idx.push_back(octave_value_list(\"%s\"));\n", method_name); + Printf(w->code, "idx.push_back(args);\n"); + Printf(w->code, "out=swig_get_self()->subsref(\".(\",idx,%d);\n", outputs); + + String *cleanup = NewString(""); + String *outarg = NewString(""); + idx = 0; + + // marshal return value + if (!is_void) { + Printf(w->code, "if (out.length()<%d) {\n", outputs); + Printf(w->code, "Swig::DirectorTypeMismatchException::raise(\"Octave " + "method %s.%s failed to return the required number " "of arguments.\");\n", classname, method_name); + Printf(w->code, "}\n"); + + tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); + if (tm != 0) { + char temp[24]; + sprintf(temp, "out(%d)", idx); + Replaceall(tm, "$input", temp); + // Replaceall(tm, "$argnum", temp); + Replaceall(tm, "$disown", Getattr(n, "wrap:disown") ? "SWIG_POINTER_DISOWN" : "0"); + if (Getattr(n, "tmap:directorout:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + idx++; + + // marshal outputs + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + char temp[24]; + sprintf(temp, "out(%d)", idx); + Replaceall(tm, "$result", temp); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(parse_args); + Delete(cleanup); + Delete(outarg); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(returntype, 0); + if (!SwigType_isreference(returntype)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Append(w->code, "}\n"); + + // We expose 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) { + 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); + } + } + // clean up + Delete(wrap_args); + Delete(pclassname); + DelWrapper(w); + return status; + } + + String *runtimeCode() { + String *s = NewString(""); + String *srun = Swig_include_sys("octrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'octrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigoctaverun.h"); + } +}; + +extern "C" Language *swig_octave(void) { + return new OCTAVE(); +} diff --git a/contrib/tools/swig/Source/Modules/overload.cxx b/contrib/tools/swig/Source/Modules/overload.cxx new file mode 100644 index 00000000000..5d278107cab --- /dev/null +++ b/contrib/tools/swig/Source/Modules/overload.cxx @@ -0,0 +1,866 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * overload.cxx + * + * This file is used to analyze overloaded functions and methods. + * It looks at signatures and tries to gather information for + * building a dispatch function. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +#define MAX_OVERLOAD 4096 + +/* Overload "argc" and "argv" */ +String *argv_template_string; +String *argc_template_string; + +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ + bool implicitconv_function; /* For ordering implicitconv functions*/ +}; + +static int fast_dispatch_mode = 0; +static int cast_dispatch_mode = 0; + +/* Set fast_dispatch_mode */ +void Wrapper_fast_dispatch_mode_set(int flag) { + fast_dispatch_mode = flag; +} + +void Wrapper_cast_dispatch_mode_set(int flag) { + cast_dispatch_mode = flag; +} + +/* ----------------------------------------------------------------------------- + * mark_implicitconv_function() + * + * Mark function if it contains an implicitconv type in the parameter list + * ----------------------------------------------------------------------------- */ +static void mark_implicitconv_function(Overloaded& onode) { + Parm *parms = onode.parms; + if (parms) { + bool is_implicitconv_function = false; + Parm *p = parms; + while (p) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + if (GetFlag(p, "implicitconv")) { + is_implicitconv_function = true; + break; + } + p = nextSibling(p); + } + if (is_implicitconv_function) + onode.implicitconv_function = true; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_rank() + * + * This function takes an overloaded declaration and creates a list that ranks + * all overloaded methods in an order that can be used to generate a dispatch + * function. + * Slight difference in the way this function is used by scripting languages and + * statically typed languages. The script languages call this method via + * Swig_overload_dispatch() - where wrappers for all overloaded methods are generated, + * however sometimes the code can never be executed. The non-scripting languages + * call this method via Swig_overload_check() for each overloaded method in order + * to determine whether or not the method should be wrapped. Note the slight + * difference when overloading methods that differ by const only. The + * scripting languages will ignore the const method, whereas the non-scripting + * languages ignore the first method parsed. + * ----------------------------------------------------------------------------- */ + +List *Swig_overload_rank(Node *n, bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n, "sym:overloaded"); + Node *c; + + if (!o) + return 0; + + c = o; + while (c) { + if (Getattr(c, "error")) { + c = Getattr(c, "sym:nextSibling"); + continue; + } + /* if (SmartPointer && Getattr(c,"cplus:staticbase")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } */ + + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + if (Getattr(c, "wrap:name")) { + assert(nnodes < MAX_OVERLOAD); + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c, "wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nodes[nnodes].implicitconv_function = false; + + mark_implicitconv_function(nodes[nnodes]); + nnodes++; + } + c = Getattr(c, "sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i, j; + for (i = 0; i < nnodes; i++) { + for (j = i + 1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i, j; + for (i = 0; i < nnodes - 1; i++) { + if (nodes[i].argc == nodes[i + 1].argc) { + for (j = i + 1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + // Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + if (checkAttribute(p1, "tmap:in:numinputs", "0")) { + p1 = Getattr(p1, "tmap:in:next"); + continue; + } + if (checkAttribute(p2, "tmap:in:numinputs", "0")) { + p2 = Getattr(p2, "tmap:in:next"); + continue; + } + String *t1 = Getattr(p1, "tmap:typecheck:precedence"); + String *t2 = Getattr(p2, "tmap:typecheck:precedence"); + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", + Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", + Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v - t2v; + } else if (!t1 && t2) + differ = 1; + else if (t1 && !t2) + differ = -1; + else if (!t1 && !t2) + differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1, "0") == 0)) { + t1 = Getattr(p1, "equivtype"); + t1 = t1 ? t1 : Getattr(p1, "ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1, "type")); + if (Getattr(p1, "tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1, "ltype", t1); + } + t2 = Getattr(p2, "equivtype"); + t2 = t2 ? t2 : Getattr(p2, "ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2, "type")); + if (Getattr(p2, "tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2, "ltype", t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2, t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1, t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1, "tmap:in:next")) { + p1 = Getattr(p1, "tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2, "tmap:in:next")) { + p2 = Getattr(p2, "tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *decl1 = Getattr(nodes[i].n, "decl"); + String *decl2 = Getattr(nodes[j].n, "decl"); + if (decl1 && decl2) { + /* Remove ref-qualifiers. Note that rvalue ref-qualifiers are already ignored and + * it is illegal to overload a function with and without ref-qualifiers. So with + * all the combinations of ref-qualifiers and cv-qualifiers, we just detect + * the cv-qualifier (const) overloading. */ + String *d1 = Copy(decl1); + String *d2 = Copy(decl2); + if (SwigType_isreference(d1) || SwigType_isrvalue_reference(d1)) { + Delete(SwigType_pop(d1)); + } + if (SwigType_isreference(d2) || SwigType_isrvalue_reference(d2)) { + Delete(SwigType_pop(d2)); + } + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1, dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), + "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), + "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s effectively ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[i].n), Getline(nodes[i].n), + "as it is shadowed by %s.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + int argc_changed_index = -1; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result, nodes[i].n); + // Printf(stdout,"[ %d ] %d %s\n", i, nodes[i].implicitconv_function, ParmList_errorstr(nodes[i].parms)); + // Swig_print_node(nodes[i].n); + if (i == nnodes-1 || nodes[i].argc != nodes[i+1].argc) { + if (argc_changed_index+2 < nnodes && (nodes[argc_changed_index+1].argc == nodes[argc_changed_index+2].argc)) { + // Add additional implicitconv functions in same order as already ranked. + // Consider overloaded functions by argument count... only add additional implicitconv functions if + // the number of functions with the same arg count > 1, ie, only if overloaded by same argument count. + int j; + for (j = argc_changed_index + 1; j <= i; j++) { + if (nodes[j].implicitconv_function) { + SetFlag(nodes[j].n, "implicitconvtypecheckoff"); + Append(result, nodes[j].n); + // Printf(stdout,"[ %d ] %d + %s\n", j, nodes[j].implicitconv_function, ParmList_errorstr(nodes[j].parms)); + // Swig_print_node(nodes[j].n); + } + } + } + argc_changed_index = i; + } + } + } + return result; +} + +// /* ----------------------------------------------------------------------------- +// * print_typecheck() +// * ----------------------------------------------------------------------------- */ + +static bool print_typecheck(String *f, int j, Parm *pj, bool implicitconvtypecheckoff) { + char tmp[256]; + sprintf(tmp, Char(argv_template_string), j); + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + tm = Copy(tm); + Replaceid(tm, Getattr(pj, "lname"), "_v"); + String *conv = Getattr(pj, "implicitconv"); + if (conv && !implicitconvtypecheckoff) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, tm, "\n", NIL); + Delete(tm); + return true; + } else + return false; +} + +/* ----------------------------------------------------------------------------- + * ReplaceFormat() + * ----------------------------------------------------------------------------- */ + +static String *ReplaceFormat(const_String_or_char_ptr fmt, int j) { + String *lfmt = NewString(fmt); + char buf[50]; + sprintf(buf, "%d", j); + Replaceall(lfmt, "$numargs", buf); + int i; + String *commaargs = NewString(""); + for (i = 0; i < j; i++) { + Printv(commaargs, ", ", NIL); + Printf(commaargs, Char(argv_template_string), i); + } + Replaceall(lfmt, "$commaargs", commaargs); + return lfmt; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_dispatch() + * + * Generate a dispatch function. argc is assumed to hold the argument count. + * argv is the argument vector. + * + * Note that for C++ class member functions, Swig_overload_dispatch() assumes + * that argc includes the "self" argument and that the first element of argv[] + * is the "self" argument. So for a member function: + * + * Foo::bar(int x, int y, int z); + * + * the argc should be 4 (not 3!) and the first element of argv[] would be + * the appropriate scripting language reference to "self". For regular + * functions (and static class functions) the argc and argv only include + * the regular function arguments. + * ----------------------------------------------------------------------------- */ + +/* + Cast dispatch mechanism. +*/ +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *maxargs) { + int i, j; + + *maxargs = 1; + + String *f = NewString(""); + String *sw = NewString(""); + Printf(f, "{\n"); + Printf(f, "unsigned long _index = 0;\n"); + Printf(f, "SWIG_TypeRank _rank = 0; \n"); + + /* Get a list of methods ranked by precedence values and argument count */ + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + + /* Loop over the functions */ + + bool emitcheck = true; + for (i = 0; i < nfunc; i++) { + int fn = 0; + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0; + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (num_arguments > *maxargs) + *maxargs = num_arguments; + + if (num_required == num_arguments) { + Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); + } else { + Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); + } + Printf(f, "SWIG_TypeRank _ranki = 0;\n"); + Printf(f, "SWIG_TypeRank _rankm = 0;\n"); + if (num_arguments) + Printf(f, "SWIG_TypeRank _pi = 1;\n"); + + /* create a list with the wrappers that collide with the + current one based on argument number */ + List *coll = NewList(); + for (int k = i + 1; k < nfunc; k++) { + Node *nk = Getitem(dispatch, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nrk = emit_num_required(pk); + int nak = emit_num_arguments(pk); + if ((nrk >= num_required && nrk <= num_arguments) || (nak >= num_required && nak <= num_arguments) || (nrk <= num_required && nak >= num_arguments)) + Append(coll, nk); + } + + // printf("overload: %s coll=%d\n", Char(Getattr(n, "sym:name")), Len(coll)); + + int num_braces = 0; + bool test = (num_arguments > 0); + if (test) { + int need_v = 1; + j = 0; + Parm *pj = pi; + while (pj) { + if (checkAttribute(pj, "tmap:in:numinputs", "0")) { + pj = Getattr(pj, "tmap:in:next"); + continue; + } + + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + tm = Copy(tm); + /* normalise for comparison later */ + Replaceid(tm, Getattr(pj, "lname"), "_v"); + + /* if all the wrappers have the same type check on this + argument we can optimize it out */ + for (int k = 0; k < Len(coll) && !emitcheck; k++) { + Node *nk = Getitem(coll, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nak = emit_num_arguments(pk); + if (nak <= j) + continue; + int l = 0; + Parm *pl = pk; + /* finds arg j on the collider wrapper */ + while (pl && l <= j) { + if (checkAttribute(pl, "tmap:in:numinputs", "0")) { + pl = Getattr(pl, "tmap:in:next"); + continue; + } + if (l == j) { + /* we are at arg j, so we compare the tmaps now */ + String *tml = Getattr(pl, "tmap:typecheck"); + /* normalise it before comparing */ + if (tml) + Replaceid(tml, Getattr(pl, "lname"), "_v"); + if (!tml || Cmp(tm, tml)) + emitcheck = true; + //printf("tmap: %s[%d] (%d) => %s\n\n", + // Char(Getattr(nk, "sym:name")), + // l, emitcheck, tml?Char(tml):0); + } + Parm *pl1 = Getattr(pl, "tmap:in:next"); + if (pl1) + pl = pl1; + else + pl = nextSibling(pl); + l++; + } + } + + if (emitcheck) { + if (need_v) { + Printf(f, "int _v = 0;\n"); + need_v = 0; + } + if (j >= num_required) { + Printf(f, "if (%s > %d) {\n", argc_template_string, j); + num_braces++; + } + String *tmp = NewStringf(argv_template_string, j); + + String *conv = Getattr(pj, "implicitconv"); + if (conv && !implicitconvtypecheckoff) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, "{\n", tm, "}\n", NIL); + Delete(tm); + fn = i + 1; + Printf(f, "if (!_v) goto check_%d;\n", fn); + Printf(f, "_ranki += _v*_pi;\n"); + Printf(f, "_rankm += _pi;\n"); + Printf(f, "_pi *= SWIG_MAXCASTRANK;\n"); + } + } + if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { + /* we emit a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ + Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), + "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", + Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); + } + Parm *pj1 = Getattr(pj, "tmap:in:next"); + if (pj1) + pj = pj1; + else + pj = nextSibling(pj); + j++; + } + } + + /* close braces */ + for ( /* empty */ ; num_braces > 0; num_braces--) + Printf(f, "}\n"); + + Printf(f, "if (!_index || (_ranki < _rank)) {\n"); + Printf(f, " _rank = _ranki; _index = %d;\n", i + 1); + Printf(f, " if (_rank == _rankm) goto dispatch;\n"); + Printf(f, "}\n"); + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(sw, "case %d:\n", i + 1); + Printf(sw, Char(lfmt), Getattr(ni, "wrap:name")); + Printf(sw, "\n"); + + Printf(f, "}\n"); /* braces closes "if" for this method */ + if (fn) + Printf(f, "check_%d:\n\n", fn); + + if (implicitconvtypecheckoff) + Delattr(ni, "implicitconvtypecheckoff"); + + Delete(lfmt); + Delete(coll); + } + Delete(dispatch); + Printf(f, "dispatch:\n"); + Printf(f, "switch(_index) {\n"); + Printf(f, "%s", sw); + Printf(f, "}\n"); + + Printf(f, "}\n"); + return f; +} + +/* + Fast dispatch mechanism, provided by Salvador Fandi~no Garc'ia (#930586). +*/ +static String *overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *maxargs, const_String_or_char_ptr fmt_fastdispatch) { + int i, j; + + *maxargs = 1; + + String *f = NewString(""); + + /* Get a list of methods ranked by precedence values and argument count */ + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + + /* Loop over the functions */ + + for (i = 0; i < nfunc; i++) { + int fn = 0; + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0; + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (num_arguments > *maxargs) + *maxargs = num_arguments; + + if (num_required == num_arguments) { + Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); + } else { + Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); + } + + /* create a list with the wrappers that collide with the + current one based on argument number */ + List *coll = NewList(); + for (int k = i + 1; k < nfunc; k++) { + Node *nk = Getitem(dispatch, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nrk = emit_num_required(pk); + int nak = emit_num_arguments(pk); + if ((nrk >= num_required && nrk <= num_arguments) || (nak >= num_required && nak <= num_arguments) || (nrk <= num_required && nak >= num_arguments)) + Append(coll, nk); + } + + // printf("overload: %s coll=%d\n", Char(Getattr(n, "sym:name")), Len(coll)); + + bool emitcheck = false; + int num_braces = 0; + bool test = (Len(coll) > 0 && num_arguments); + if (test) { + int need_v = 1; + j = 0; + Parm *pj = pi; + while (pj) { + if (checkAttribute(pj, "tmap:in:numinputs", "0")) { + pj = Getattr(pj, "tmap:in:next"); + continue; + } + + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + tm = Copy(tm); + /* normalise for comparison later */ + Replaceid(tm, Getattr(pj, "lname"), "_v"); + + /* if all the wrappers have the same type check on this + argument we can optimize it out */ + emitcheck = false; + for (int k = 0; k < Len(coll) && !emitcheck; k++) { + Node *nk = Getitem(coll, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nak = emit_num_arguments(pk); + if (nak <= j) + continue; + int l = 0; + Parm *pl = pk; + /* finds arg j on the collider wrapper */ + while (pl && l <= j) { + if (checkAttribute(pl, "tmap:in:numinputs", "0")) { + pl = Getattr(pl, "tmap:in:next"); + continue; + } + if (l == j) { + /* we are at arg j, so we compare the tmaps now */ + String *tml = Getattr(pl, "tmap:typecheck"); + /* normalise it before comparing */ + if (tml) + Replaceid(tml, Getattr(pl, "lname"), "_v"); + if (!tml || Cmp(tm, tml)) + emitcheck = true; + //printf("tmap: %s[%d] (%d) => %s\n\n", + // Char(Getattr(nk, "sym:name")), + // l, emitcheck, tml?Char(tml):0); + } + Parm *pl1 = Getattr(pl, "tmap:in:next"); + if (pl1) + pl = pl1; + else + pl = nextSibling(pl); + l++; + } + } + + if (emitcheck) { + if (need_v) { + Printf(f, "int _v = 0;\n"); + need_v = 0; + } + if (j >= num_required) { + Printf(f, "if (%s > %d) {\n", argc_template_string, j); + num_braces++; + } + String *tmp = NewStringf(argv_template_string, j); + + String *conv = Getattr(pj, "implicitconv"); + if (conv && !implicitconvtypecheckoff) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, "{\n", tm, "}\n", NIL); + Delete(tm); + fn = i + 1; + Printf(f, "if (!_v) goto check_%d;\n", fn); + } + } + if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { + /* we emit a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ + Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), + "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", + Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); + } + Parm *pj1 = Getattr(pj, "tmap:in:next"); + if (pj1) + pj = pj1; + else + pj = nextSibling(pj); + j++; + } + } + + /* close braces */ + for ( /* empty */ ; num_braces > 0; num_braces--) + Printf(f, "}\n"); + + // The language module may want to generate different code for last overloaded function called (with same number of arguments) + String *lfmt = ReplaceFormat(!emitcheck && fmt_fastdispatch ? fmt_fastdispatch : fmt, num_arguments); + Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + + Printf(f, "}\n"); /* braces closes "if" for this method */ + if (fn) + Printf(f, "check_%d:\n\n", fn); + + if (implicitconvtypecheckoff) + Delattr(ni, "implicitconvtypecheckoff"); + + Delete(lfmt); + Delete(coll); + } + Delete(dispatch); + return f; +} + +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxargs, const_String_or_char_ptr fmt_fastdispatch) { + + if (fast_dispatch_mode || GetFlag(n, "feature:fastdispatch")) { + return overload_dispatch_fast(n, fmt, maxargs, fmt_fastdispatch); + } + + int i, j; + + *maxargs = 1; + + String *f = NewString(""); + + /* Get a list of methods ranked by precedence values and argument count */ + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + + /* Loop over the functions */ + + for (i = 0; i < nfunc; i++) { + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0; + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (GetFlag(n, "wrap:this")) { + num_required++; + num_arguments++; + } + if (num_arguments > *maxargs) + *maxargs = num_arguments; + + if (num_required == num_arguments) { + Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); + } else { + Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); + } + + if (num_arguments) { + Printf(f, "int _v;\n"); + } + + int num_braces = 0; + j = 0; + Parm *pj = pi; + while (pj) { + if (checkAttribute(pj, "tmap:in:numinputs", "0")) { + pj = Getattr(pj, "tmap:in:next"); + continue; + } + if (j >= num_required) { + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(f, "if (%s <= %d) {\n", argc_template_string, j); + Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + Printf(f, "}\n"); + Delete(lfmt); + } + if (print_typecheck(f, (GetFlag(n, "wrap:this") ? j + 1 : j), pj, implicitconvtypecheckoff)) { + Printf(f, "if (_v) {\n"); + num_braces++; + } + if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { + /* we emit a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ + Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), + "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", + Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); + } + Parm *pk = Getattr(pj, "tmap:in:next"); + if (pk) + pj = pk; + else + pj = nextSibling(pj); + j++; + } + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + Delete(lfmt); + /* close braces */ + for ( /* empty */ ; num_braces > 0; num_braces--) + Printf(f, "}\n"); + Printf(f, "}\n"); /* braces closes "if" for this method */ + if (implicitconvtypecheckoff) + Delattr(ni, "implicitconvtypecheckoff"); + } + Delete(dispatch); + return f; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_check() + * ----------------------------------------------------------------------------- */ +void Swig_overload_check(Node *n) { + Swig_overload_rank(n, false); +} diff --git a/contrib/tools/swig/Source/Modules/perl5.cxx b/contrib/tools/swig/Source/Modules/perl5.cxx new file mode 100644 index 00000000000..dfa85f3c8ed --- /dev/null +++ b/contrib/tools/swig/Source/Modules/perl5.cxx @@ -0,0 +1,2528 @@ +/* ---------------------------------------------------------------------------- + * 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. + * + * perl5.cxx + * + * Perl5 language module for SWIG. + * ------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +static const char *usage = "\ +Perl 5 Options (available with -perl5)\n\ + -compat - Compatibility mode\n\ + -const - Wrap constants as constants and not variables (implies -proxy)\n\ + -nopm - Do not generate the .pm file\n\ + -noproxy - Don't create proxy classes\n\ + -proxy - Create proxy classes\n\ + -static - Omit code related to dynamic loading\n\ +\n"; + +static int compat = 0; + +static int no_pmfile = 0; + +static int export_all = 0; + +/* + * pmfile + * set by the -pm flag, overrides the name of the .pm file + */ +static String *pmfile = 0; + +/* + * module + * set by the %module directive, e.g. "Xerces". It will determine + * the name of the .pm file, and the dynamic library, and the name + * used by any module wanting to %import the module. + */ +static String *module = 0; + +/* + * namespace_module + * the fully namespace qualified name of the module. It will be used + * to set the package namespace in the .pm file, as well as the name + * of the initialization methods in the glue library. This will be + * the same as module, above, unless the %module directive is given + * the 'package' option, e.g. %module(package="Foo::Bar") "baz" + */ +static String *namespace_module = 0; + +/* + * cmodule + * the namespace of the internal glue code, set to the value of + * module with a 'c' appended + */ +static String *cmodule = 0; + +/* + * dest_package + * an optional namespace to put all classes into. Specified by using + * the %module(package="Foo::Bar") "baz" syntax + */ +static String *dest_package = 0; + +static String *command_tab = 0; +static String *constant_tab = 0; +static String *variable_tab = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_pm = 0; +static String *pm; /* Package initialization code */ +static String *magic; /* Magic variable wrappers */ + +static int staticoption = 0; + +// controlling verbose output +static int verbose = 0; + +/* The following variables are used to manage Perl5 classes */ + +static int blessed = 1; /* Enable object oriented features */ +static int do_constants = 0; /* Constant wrapping */ +static List *classlist = 0; /* List of classes */ +static int have_constructor = 0; +static int have_destructor = 0; +static int have_data_members = 0; +static String *class_name = 0; /* Name of the class (what Perl thinks it is) */ +static String *real_classname = 0; /* Real name of C/C++ class */ +static String *fullclassname = 0; + +static String *pcode = 0; /* Perl code associated with each class */ + /* static String *blessedmembers = 0; *//* Member data associated with each class */ +static int member_func = 0; /* Set to 1 when wrapping a member function */ +static String *func_stubs = 0; /* Function stubs */ +static String *const_stubs = 0; /* Constant stubs */ +static int num_consts = 0; /* Number of constants */ +static String *var_stubs = 0; /* Variable stubs */ +static String *exported = 0; /* Exported symbols */ +static String *pragma_include = 0; +static String *additional_perl_code = 0; /* Additional Perl code from %perlcode %{ ... %} */ +static Hash *operators = 0; +static int have_operators = 0; + +class PERL5:public Language { +public: + + PERL5():Language () { + Clear(argc_template_string); + Printv(argc_template_string, "items", NIL); + Clear(argv_template_string); + Printv(argv_template_string, "ST(%d)", NIL); + director_language = 1; + } + + /* Test to see if a type corresponds to something wrapped with a shadow class */ + Node *is_shadow(SwigType *t) { + Node *n; + n = classLookup(t); + /* Printf(stdout,"'%s' --> '%p'\n", t, n); */ + if (n) { + if (!Getattr(n, "perl5:proxy")) { + setclassname(n); + } + return Getattr(n, "perl5:proxy"); + } + return 0; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i = 1; + + SWIG_library_directory("perl5"); + + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-package") == 0) { + Printv(stderr, + "*** -package is no longer supported\n*** use the directive '%module A::B::C' in your interface file instead\n*** see the Perl section in the manual for details.\n", NIL); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-interface") == 0) { + Printv(stderr, + "*** -interface is no longer supported\n*** use the directive '%module A::B::C' in your interface file instead\n*** see the Perl section in the manual for details.\n", NIL); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-exportall") == 0) { + export_all = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-static") == 0) { + staticoption = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + blessed = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + blessed = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-const") == 0) { + do_constants = 1; + blessed = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nopm") == 0) { + no_pmfile = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-pm") == 0) { + Swig_mark_arg(i); + i++; + pmfile = NewString(argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i],"-v") == 0) { + Swig_mark_arg(i); + verbose++; + } else if (strcmp(argv[i], "-compat") == 0) { + compat = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } else if (strcmp(argv[i], "-cppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); + } + } + } + + Preprocessor_define("SWIGPERL 1", 0); + // SWIGPERL5 is deprecated, and no longer documented. + Preprocessor_define("SWIGPERL5 1", 0); + SWIG_typemap_lang("perl5"); + SWIG_config_file("perl5.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + * + * TODO: directors are disallowed in conjunction with many command + * line options. Some of them are probably safe, but it will take + * some effort to validate each one. + */ + { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + int dirprot = 0; + if (Getattr(options, "dirprot")) + dirprot = 1; + if (Getattr(options, "nodirprot")) + dirprot = 0; + if (Getattr(options, "directors")) { + int allow = 1; + if (export_all) { + Printv(stderr, "*** directors are not supported with -exportall\n", NIL); + allow = 0; + } + if (staticoption) { + Printv(stderr, "*** directors are not supported with -static\n", NIL); + allow = 0; + } + if (!blessed) { + Printv(stderr, "*** directors are not supported with -noproxy\n", NIL); + allow = 0; + } + if (no_pmfile) { + Printv(stderr, "*** directors are not supported with -nopm\n", NIL); + allow = 0; + } + if (compat) { + Printv(stderr, "*** directors are not supported with -compat\n", NIL); + allow = 0; + } + if (allow) { + allow_directors(); + if (dirprot) + allow_dirprot(); + } + } + } + } + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + + if (directorsEnabled()) { + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + /* 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); + + classlist = NewList(); + + pm = NewString(""); + func_stubs = NewString(""); + var_stubs = NewString(""); + const_stubs = NewString(""); + exported = NewString(""); + magic = NewString(""); + pragma_include = NewString(""); + additional_perl_code = NewString(""); + + command_tab = NewString("static swig_command_info swig_commands[] = {\n"); + constant_tab = NewString("static swig_constant_info swig_constants[] = {\n"); + variable_tab = NewString("static swig_variable_info swig_variables[] = {\n"); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGPERL\n#define SWIGPERL\n#endif\n\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + Printf(f_runtime, "#define SWIG_CASTRANK_MODE\n"); + Printf(f_runtime, "\n"); + + // Is the imported module in another package? (IOW, does it use the + // %module(package="name") option and it's different than the package + // of this module.) + Node *mod = Getattr(n, "module"); + Node *options = Getattr(mod, "options"); + module = Copy(Getattr(n,"name")); + + String *underscore_module = Copy(module); + Replaceall(underscore_module,":","_"); + + if (verbose > 0) { + fprintf(stdout, "top: using namespace_module: %s\n", Char(namespace_module)); + } + + if (directorsEnabled()) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", underscore_module); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", underscore_module); + if (dirprot_mode()) { + Printf(f_directors_h, "#include <map>\n"); + Printf(f_directors_h, "#include <string>\n\n"); + } + + 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(magic, "#include \"%s\"\n\n", filename); + Delete(filename); + } + } + + if (verbose > 0) { + fprintf(stdout, "top: using module: %s\n", Char(module)); + } + + dest_package = options ? Getattr(options, "package") : 0; + if (dest_package) { + namespace_module = Copy(dest_package); + if (verbose > 0) { + fprintf(stdout, "top: Found package: %s\n",Char(dest_package)); + } + } else { + namespace_module = Copy(module); + if (verbose > 0) { + fprintf(stdout, "top: No package found\n"); + } + } + /* If we're in blessed mode, change the package name to "packagec" */ + + if (blessed) { + cmodule = NewStringf("%sc",namespace_module); + } else { + cmodule = NewString(namespace_module); + } + + /* Create a .pm file + * Need to strip off any prefixes that might be found in + * the module name */ + + if (no_pmfile) { + f_pm = NewString(0); + } else { + if (!pmfile) { + char *m = Char(module) + Len(module); + while (m != Char(module)) { + if (*m == ':') { + m++; + break; + } + m--; + } + pmfile = NewStringf("%s.pm", m); + } + String *filen = NewStringf("%s%s", SWIG_output_directory(), pmfile); + if ((f_pm = NewFile(filen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Delete(filen); + filen = NULL; + Swig_register_filebyname("pm", f_pm); + Swig_register_filebyname("perl", f_pm); + } + { + String *boot_name = NewStringf("boot_%s", underscore_module); + Printf(f_header,"#define SWIG_init %s\n\n", boot_name); + Printf(f_header,"#define SWIG_name \"%s::%s\"\n", cmodule, boot_name); + Printf(f_header,"#define SWIG_prefix \"%s::\"\n", cmodule); + Delete(boot_name); + } + + Swig_banner_target_lang(f_pm, "#"); + Printf(f_pm, "\n"); + + Printf(f_pm, "package %s;\n", module); + + /* + * If the package option has been given we are placing our + * symbols into some other packages namespace, so we do not + * mess with @ISA or require for that package + */ + if (dest_package) { + Printf(f_pm,"use base qw(DynaLoader);\n"); + } else { + Printf(f_pm,"use base qw(Exporter);\n"); + if (!staticoption) { + Printf(f_pm,"use base qw(DynaLoader);\n"); + } + } + + /* Start creating magic code */ + + Printv(magic, + "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n", + "#ifdef PERL_OBJECT\n", + "#define MAGIC_CLASS _wrap_", underscore_module, "_var::\n", + "class _wrap_", underscore_module, "_var : public CPerlObj {\n", + "public:\n", + "#else\n", + "#define MAGIC_CLASS\n", + "#endif\n", + "SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {\n", + tab4, "MAGIC_PPERL\n", tab4, "croak(\"Value is read-only.\");\n", tab4, "return 0;\n", "}\n", NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* emit wrappers */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + + String *base = NewString(""); + + /* Dump out variable wrappers */ + + Printv(magic, "\n\n#ifdef PERL_OBJECT\n", "};\n", "#endif\n", NIL); + Printv(magic, "\n#ifdef __cplusplus\n}\n#endif\n", NIL); + + Printf(f_header, "%s\n", magic); + + String *type_table = NewString(""); + + /* Patch the type table to reflect the names used by shadow classes */ + if (blessed) { + Iterator cls; + for (cls = First(classlist); cls.item; cls = Next(cls)) { + String *pname = Getattr(cls.item, "perl5:proxy"); + if (pname) { + SwigType *type = Getattr(cls.item, "classtypeobj"); + if (!type) + continue; /* If unnamed class, no type will be found */ + type = Copy(type); + + SwigType_add_pointer(type); + String *mangled = SwigType_manglestr(type); + SwigType_remember_mangleddata(mangled, NewStringf("\"%s\"", pname)); + Delete(type); + Delete(mangled); + } + } + } + SwigType_emit_type_table(f_runtime, type_table); + + Printf(f_wrappers, "%s", type_table); + Delete(type_table); + + Printf(constant_tab, "{0,0,0,0,0,0}\n};\n"); + Printv(f_wrappers, constant_tab, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + Printf(f_init, "\t ST(0) = &PL_sv_yes;\n"); + Printf(f_init, "\t XSRETURN(1);\n"); + Printf(f_init, "}\n"); + + /* Finish off tables */ + Printf(variable_tab, "{0,0,0,0}\n};\n"); + Printv(f_wrappers, variable_tab, NIL); + + Printf(command_tab, "{0,0}\n};\n"); + Printv(f_wrappers, command_tab, NIL); + + + Printf(f_pm, "package %s;\n", cmodule); + + if (!staticoption) { + Printf(f_pm,"bootstrap %s;\n", module); + } else { + Printf(f_pm,"package %s;\n", cmodule); + Printf(f_pm,"boot_%s();\n", underscore_module); + } + + Printf(f_pm, "package %s;\n", module); + /* + * If the package option has been given we are placing our + * symbols into some other packages namespace, so we do not + * mess with @EXPORT + */ + if (!dest_package) { + Printf(f_pm,"@EXPORT = qw(%s);\n", exported); + } + + Printf(f_pm, "%s", pragma_include); + + if (blessed) { + + /* + * These methods will be duplicated if package + * has been specified, so we do not output them + */ + if (!dest_package) { + Printv(base, "\n# ---------- BASE METHODS -------------\n\n", "package ", namespace_module, ";\n\n", NIL); + + /* Write out the TIE method */ + + Printv(base, "sub TIEHASH {\n", tab4, "my ($classname,$obj) = @_;\n", tab4, "return bless $obj, $classname;\n", "}\n\n", NIL); + + /* Output a CLEAR method. This is just a place-holder, but by providing it we + * can make declarations such as + * %$u = ( x => 2, y=>3, z =>4 ); + * + * Where x,y,z are the members of some C/C++ object. */ + + Printf(base, "sub CLEAR { }\n\n"); + + /* Output default firstkey/nextkey methods */ + + Printf(base, "sub FIRSTKEY { }\n\n"); + Printf(base, "sub NEXTKEY { }\n\n"); + + /* Output a FETCH method. This is actually common to all classes */ + Printv(base, + "sub FETCH {\n", + tab4, "my ($self,$field) = @_;\n", tab4, "my $member_func = \"swig_${field}_get\";\n", tab4, "$self->$member_func();\n", "}\n\n", NIL); + + /* Output a STORE method. This is also common to all classes (might move to base class) */ + + Printv(base, + "sub STORE {\n", + tab4, "my ($self,$field,$newval) = @_;\n", + tab4, "my $member_func = \"swig_${field}_set\";\n", tab4, "$self->$member_func($newval);\n", "}\n\n", NIL); + + /* Output a 'this' method */ + + Printv(base, "sub this {\n", tab4, "my $ptr = shift;\n", tab4, "return tied(%$ptr);\n", "}\n\n", NIL); + + Printf(f_pm, "%s", base); + } + + /* Emit function stubs for stand-alone functions */ + Printf(f_pm, "\n# ------- FUNCTION WRAPPERS --------\n\n"); + Printf(f_pm, "package %s;\n\n", namespace_module); + Printf(f_pm, "%s", func_stubs); + + /* Emit package code for different classes */ + Printf(f_pm, "%s", pm); + + if (num_consts > 0) { + /* Emit constant stubs */ + Printf(f_pm, "\n# ------- CONSTANT STUBS -------\n\n"); + Printf(f_pm, "package %s;\n\n", namespace_module); + Printf(f_pm, "%s", const_stubs); + } + + /* Emit variable stubs */ + + Printf(f_pm, "\n# ------- VARIABLE STUBS --------\n\n"); + Printf(f_pm, "package %s;\n\n", namespace_module); + Printf(f_pm, "%s", var_stubs); + } + + /* Add additional Perl code at the end */ + Printf(f_pm, "%s", additional_perl_code); + + Printf(f_pm, "1;\n"); + Delete(f_pm); + Delete(base); + Delete(dest_package); + Delete(underscore_module); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + Dump(f_directors, f_begin); + } + + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_directors); + Delete(f_directors_h); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective(Node *n) + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + if (blessed) { + String *modname = Getattr(n, "module"); + if (modname) { + Printf(f_pm, "require %s;\n", modname); + } + } + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *overname = 0; + int director_method = 0; + + Parm *p; + int i; + Wrapper *f; + char source[256], temp[256]; + String *tm; + String *cleanup, *outarg; + int num_saved = 0; + int num_arguments, num_required; + int varargs = 0; + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + cleanup = NewString(""); + outarg = NewString(""); + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + Printv(f->def, "XS(", wname, ") {\n", "{\n", /* scope to destroy C++ objects before croaking */ + NIL); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + varargs = emit_isvarargs(l); + + Wrapper_add_local(f, "argvi", "int argvi = 0"); + + /* Check the number of arguments */ + if (!varargs) { + Printf(f->code, " if ((items < %d) || (items > %d)) {\n", num_required, num_arguments); + } else { + Printf(f->code, " if (items < %d) {\n", num_required); + } + Printf(f->code, " SWIG_croak(\"Usage: %s\");\n", usage_func(Char(iname), d, l)); + Printf(f->code, "}\n"); + + /* Write code to extract parameters. */ + for (i = 0, p = l; i < num_arguments; i++) { + + /* Skip ignored arguments */ + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + + /* Produce string representation of source and target arguments */ + sprintf(source, "ST(%d)", i); + String *target = Getattr(p, "lname"); + + if (i >= num_required) { + Printf(f->code, " if (items > %d) {\n", i); + } + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$target", target); + Replaceall(tm, "$source", source); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); /* Save input location */ + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + 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); + } + if (i >= num_required) { + Printf(f->code, " }\n"); + } + } + + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + sprintf(source, "ST(%d)", i); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printf(f->code, "if (items >= %d) {\n", i); + Printv(f->code, tm, "\n", NIL); + Printf(f->code, "}\n"); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + 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 */ + num_saved = 0; + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:argout"))) { + SwigType *t = Getattr(p, "type"); + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "ST(argvi)"); + Replaceall(tm, "$result", "ST(argvi)"); + if (is_shadow(t)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + + String *in = Getattr(p, "emit:input"); + if (in) { + sprintf(temp, "_saved[%d]", num_saved); + Replaceall(tm, "$arg", temp); + Replaceall(tm, "$input", temp); + Printf(f->code, "_saved[%d] = %s;\n", num_saved, in); + num_saved++; + } + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* If there were any saved arguments, emit a local variable for them */ + if (num_saved) { + sprintf(temp, "_saved[%d]", num_saved); + Wrapper_add_localv(f, "_saved", "SV *", temp, NIL); + } + + director_method = is_member_director(n) && !is_smart_pointer() && 0 != Cmp(nodeType(n), "destructor"); + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); + if (dirprot_mode() && !is_public(n)) { + Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name); + Printf(f->code, "SWIG_exception_fail(SWIG_RuntimeError, \"accessing protected member %s\");\n", name); + Append(f->code, "}\n"); + } + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Printf(f->code, "upcall = director && SvSTASH(SvRV(ST(0))) == gv_stashpv(director->swig_get_class(), 0);\n"); + } + + /* Emit the function call */ + if (director_method) { + Append(f->code, "try {\n"); + } + + /* Now write code to make the function call */ + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (director_method) { + Append(actioncode, "} catch (Swig::DirectorException& swig_err) {\n"); + Append(actioncode, " sv_setsv(ERRSV, swig_err.getNative());\n"); + Append(actioncode, " SWIG_fail;\n"); + Append(actioncode, "}\n"); + } + + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + SwigType *t = Getattr(n, "type"); + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$target", "ST(argvi)"); + Replaceall(tm, "$result", "ST(argvi)"); + if (is_shadow(t)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "SWIG_OWNER"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* If there were any output args, take care of them. */ + + Printv(f->code, outarg, NIL); + + /* If there was any cleanup, do that. */ + + Printv(f->code, cleanup, NIL); + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$result", "ST(argvi)"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + Printv(f->code, "XSRETURN(argvi);\n", "fail:\n", cleanup, "SWIG_croak_null();\n" "}\n" "}\n", NIL); + + /* Add the dXSARGS last */ + + Wrapper_add_local(f, "dXSARGS", "dXSARGS"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + /* Dump the wrapper function */ + + Wrapper_print(f, f_wrappers); + + /* Now register the function */ + + if (!Getattr(n, "sym:overloaded")) { + Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, iname, wname); + } else if (!Getattr(n, "sym:nextSibling")) { + /* Generate overloaded dispatch function */ + int maxargs; + String *dispatch = Swig_overload_dispatch_cast(n, "PUSHMARK(MARK); SWIG_CALLXS(%s); return;", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "XS(", dname, ") {\n", NIL); + + Wrapper_add_local(df, "dXSARGS", "dXSARGS"); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "croak(\"No matching function for overloaded '%s'\");\n", iname); + Printf(df->code, "XSRETURN(0);\n"); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, iname, dname); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + if (!Getattr(n, "sym:nextSibling")) { + if (export_all) { + Printf(exported, "%s ", iname); + } + + /* -------------------------------------------------------------------- + * Create a stub for this function, provided it's not a member function + * -------------------------------------------------------------------- */ + + if ((blessed) && (!member_func)) { + Printv(func_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); + } + + } + Delete(cleanup); + Delete(outarg); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + virtual int variableWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + Wrapper *getf, *setf; + String *tm; + String *getname = Swig_name_get(NSPACE_TODO, iname); + String *setname = Swig_name_set(NSPACE_TODO, iname); + + String *get_name = Swig_name_wrapper(getname); + String *set_name = Swig_name_wrapper(setname); + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + getf = NewWrapper(); + setf = NewWrapper(); + + /* Create a Perl function for setting the variable value */ + + if (!GetFlag(n, "feature:immutable")) { + Setattr(n, "wrap:name", set_name); + Printf(setf->def, "SWIGCLASS_STATIC int %s(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {\n", set_name); + Printv(setf->code, tab4, "MAGIC_PPERL\n", NIL); + + /* Check for a few typemaps */ + tm = Swig_typemap_lookup("varin", n, name, 0); + if (tm) { + Replaceall(tm, "$source", "sv"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "sv"); + /* Printf(setf->code,"%s\n", tm); */ + emit_action_code(n, setf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_NOWRAP; + } + Printf(setf->code, "fail:\n"); + Printf(setf->code, " return 1;\n}\n"); + Replaceall(setf->code, "$symname", iname); + Wrapper_print(setf, magic); + } + + /* Now write a function to evaluate the variable */ + Setattr(n, "wrap:name", get_name); + int addfail = 0; + Printf(getf->def, "SWIGCLASS_STATIC int %s(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {\n", get_name); + Printv(getf->code, tab4, "MAGIC_PPERL\n", NIL); + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$target", "sv"); + Replaceall(tm, "$result", "sv"); + Replaceall(tm, "$source", name); + if (is_shadow(t)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + /* Printf(getf->code,"%s\n", tm); */ + addfail = emit_action_code(n, getf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_NOWRAP; + } + Printf(getf->code, " return 1;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return 0;\n"); + } + Append(getf->code, "}\n"); + + + Replaceall(getf->code, "$symname", iname); + Wrapper_print(getf, magic); + + String *tt = Getattr(n, "tmap:varout:type"); + if (tt) { + tt = NewStringf("&%s", tt); + } else { + tt = NewString("0"); + } + /* Now add symbol to the PERL interpreter */ + if (GetFlag(n, "feature:immutable")) { + Printv(variable_tab, tab4, "{ \"", cmodule, "::", iname, "\", MAGIC_CLASS swig_magic_readonly, MAGIC_CLASS ", get_name, ",", tt, " },\n", NIL); + + } else { + Printv(variable_tab, tab4, "{ \"", cmodule, "::", iname, "\", MAGIC_CLASS ", set_name, ", MAGIC_CLASS ", get_name, ",", tt, " },\n", NIL); + } + + /* If we're blessed, try to figure out what to do with the variable + 1. If it's a Perl object of some sort, create a tied-hash + around it. + 2. Otherwise, just hack Perl's symbol table */ + + if (blessed) { + if (is_shadow(t)) { + Printv(var_stubs, + "\nmy %__", iname, "_hash;\n", + "tie %__", iname, "_hash,\"", is_shadow(t), "\", $", + cmodule, "::", iname, ";\n", "$", iname, "= \\%__", iname, "_hash;\n", "bless $", iname, ", ", is_shadow(t), ";\n", NIL); + } else { + Printv(var_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); + } + } + if (export_all) + Printf(exported, "$%s ", iname); + + Delete(tt); + DelWrapper(setf); + DelWrapper(getf); + Delete(getname); + Delete(setname); + Delete(set_name); + Delete(get_name); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + if (is_shadow(type)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + Printf(constant_tab, "%s,\n", tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + if (is_shadow(type)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + Printf(f_init, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + + if (blessed) { + if (is_shadow(type)) { + Printv(var_stubs, + "\nmy %__", iname, "_hash;\n", + "tie %__", iname, "_hash,\"", is_shadow(type), "\", $", + cmodule, "::", iname, ";\n", "$", iname, "= \\%__", iname, "_hash;\n", "bless $", iname, ", ", is_shadow(type), ";\n", NIL); + } else if (do_constants) { + Printv(const_stubs, "sub ", name, " () { $", cmodule, "::", name, " }\n", NIL); + num_consts++; + } else { + Printv(var_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); + } + } + if (export_all) { + if (do_constants && !is_shadow(type)) { + Printf(exported, "%s ", name); + } else { + Printf(exported, "$%s ", iname); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * usage_func() + * ------------------------------------------------------------ */ + char *usage_func(char *iname, SwigType *, ParmList *l) { + static String *temp = 0; + Parm *p; + int i; + + if (!temp) + temp = NewString(""); + Clear(temp); + Printf(temp, "%s(", iname); + + /* Now go through and print parameters */ + p = l; + i = 0; + while (p != 0) { + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + if (!checkAttribute(p,"tmap:in:numinputs","0")) { + /* If parameter has been named, use that. Otherwise, just print a type */ + if (SwigType_type(pt) != T_VOID) { + if (Len(pn) > 0) { + Printf(temp, "%s", pn); + } else { + Printf(temp, "%s", SwigType_str(pt, 0)); + } + } + i++; + p = nextSibling(p); + if (p) + if (!checkAttribute(p,"tmap:in:numinputs","0")) + Putc(',', temp); + } else { + p = nextSibling(p); + if (p) + if ((i > 0) && (!checkAttribute(p,"tmap:in:numinputs","0"))) + Putc(',', temp); + } + } + Printf(temp, ");"); + return Char(temp); + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + String *funcname = Getattr(n, "wrap:name"); + + if (!addSymbol(funcname, n)) + return SWIG_ERROR; + + Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, name, funcname); + if (export_all) + Printf(exported, "%s ", name); + if (blessed) { + Printv(func_stubs, "*", name, " = *", cmodule, "::", name, ";\n", NIL); + } + return SWIG_OK; + } + +/* ---------------------------------------------------------------------------- + * OBJECT-ORIENTED FEATURES + * + * These extensions provide a more object-oriented interface to C++ + * classes and structures. The code here is based on extensions + * provided by David Fletcher and Gary Holt. + * + * I have generalized these extensions to make them more general purpose + * and to resolve object-ownership problems. + * + * The approach here is very similar to the Python module : + * 1. All of the original methods are placed into a single + * package like before except that a 'c' is appended to the + * package name. + * + * 2. All methods and function calls are wrapped with a new + * perl function. While possibly inefficient this allows + * us to catch complex function arguments (which are hard to + * track otherwise). + * + * 3. Classes are represented as tied-hashes in a manner similar + * to Gary Holt's extension. This allows us to access + * member data. + * + * 4. Stand-alone (global) C functions are modified to take + * tied hashes as arguments for complex datatypes (if + * appropriate). + * + * 5. Global variables involving a class/struct is encapsulated + * in a tied hash. + * + * ------------------------------------------------------------------------- */ + + + void setclassname(Node *n) { + String *symname = Getattr(n, "sym:name"); + String *fullname; + String *actualpackage; + Node *clsmodule = Getattr(n, "module"); + + if (!clsmodule) { + /* imported module does not define a module name. Oh well */ + return; + } + + /* Do some work on the class name */ + if (verbose > 0) { + String *modulename = Getattr(clsmodule, "name"); + fprintf(stdout, "setclassname: Found sym:name: %s\n", Char(symname)); + fprintf(stdout, "setclassname: Found module: %s\n", Char(modulename)); + fprintf(stdout, "setclassname: No package found\n"); + } + + if (dest_package) { + fullname = NewStringf("%s::%s", namespace_module, symname); + } else { + actualpackage = Getattr(clsmodule,"name"); + + if (verbose > 0) { + fprintf(stdout, "setclassname: Found actualpackage: %s\n", Char(actualpackage)); + } + if ((!compat) && (!Strchr(symname,':'))) { + fullname = NewStringf("%s::%s",actualpackage,symname); + } else { + fullname = NewString(symname); + } + } + if (verbose > 0) { + fprintf(stdout, "setclassname: setting proxy: %s\n", Char(fullname)); + } + Setattr(n, "perl5:proxy", fullname); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + virtual int classDeclaration(Node *n) { + /* Do some work on the class name */ + if (!Getattr(n, "feature:onlychildren")) { + if (blessed) { + setclassname(n); + Append(classlist, n); + } + } + + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + + if (blessed) { + have_constructor = 0; + have_operators = 0; + have_destructor = 0; + have_data_members = 0; + operators = NewHash(); + + class_name = Getattr(n, "sym:name"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + /* Use the fully qualified name of the Perl class */ + if (!compat) { + fullclassname = NewStringf("%s::%s", namespace_module, class_name); + } else { + fullclassname = NewString(class_name); + } + real_classname = Getattr(n, "name"); + pcode = NewString(""); + // blessedmembers = NewString(""); + } + + /* Emit all of the members */ + Language::classHandler(n); + + + /* Finish the rest of the class */ + if (blessed) { + /* Generate a client-data entry */ + SwigType *ct = NewStringf("p.%s", real_classname); + Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", SwigType_manglestr(ct), ", (void*) \"", fullclassname, "\");\n", NIL); + SwigType_remember(ct); + Delete(ct); + + Printv(pm, "\n############# Class : ", fullclassname, " ##############\n", "\npackage ", fullclassname, ";\n", NIL); + + if (have_operators) { + Printf(pm, "use overload\n"); + Iterator ki; + for (ki = First(operators); ki.key; ki = Next(ki)) { + char *name = Char(ki.key); + // fprintf(stderr,"found name: <%s>\n", name); + if (strstr(name, "__eq__")) { + Printv(pm, tab4, "\"==\" => sub { $_[0]->__eq__($_[1])},\n",NIL); + } else if (strstr(name, "__ne__")) { + Printv(pm, tab4, "\"!=\" => sub { $_[0]->__ne__($_[1])},\n",NIL); + // there are no tests for this in operator_overload_runme.pl + // it is likely to be broken + // } else if (strstr(name, "__assign__")) { + // Printv(pm, tab4, "\"=\" => sub { $_[0]->__assign__($_[1])},\n",NIL); + } else if (strstr(name, "__str__")) { + Printv(pm, tab4, "'\"\"' => sub { $_[0]->__str__()},\n",NIL); + } else if (strstr(name, "__plusplus__")) { + Printv(pm, tab4, "\"++\" => sub { $_[0]->__plusplus__()},\n",NIL); + } else if (strstr(name, "__minmin__")) { + Printv(pm, tab4, "\"--\" => sub { $_[0]->__minmin__()},\n",NIL); + } else if (strstr(name, "__add__")) { + Printv(pm, tab4, "\"+\" => sub { $_[0]->__add__($_[1])},\n",NIL); + } else if (strstr(name, "__sub__")) { + Printv(pm, tab4, "\"-\" => sub { if( not $_[2] ) { $_[0]->__sub__($_[1]) }\n",NIL); + Printv(pm, tab8, "elsif( $_[0]->can('__rsub__') ) { $_[0]->__rsub__($_[1]) }\n",NIL); + Printv(pm, tab8, "else { die(\"reverse subtraction not supported\") }\n",NIL); + Printv(pm, tab8, "},\n",NIL); + } else if (strstr(name, "__mul__")) { + Printv(pm, tab4, "\"*\" => sub { $_[0]->__mul__($_[1])},\n",NIL); + } else if (strstr(name, "__div__")) { + Printv(pm, tab4, "\"/\" => sub { $_[0]->__div__($_[1])},\n",NIL); + } else if (strstr(name, "__mod__")) { + Printv(pm, tab4, "\"%\" => sub { $_[0]->__mod__($_[1])},\n",NIL); + // there are no tests for this in operator_overload_runme.pl + // it is likely to be broken + // } else if (strstr(name, "__and__")) { + // Printv(pm, tab4, "\"&\" => sub { $_[0]->__and__($_[1])},\n",NIL); + + // there are no tests for this in operator_overload_runme.pl + // it is likely to be broken + // } else if (strstr(name, "__or__")) { + // Printv(pm, tab4, "\"|\" => sub { $_[0]->__or__($_[1])},\n",NIL); + } else if (strstr(name, "__gt__")) { + Printv(pm, tab4, "\">\" => sub { $_[0]->__gt__($_[1])},\n",NIL); + } else if (strstr(name, "__ge__")) { + Printv(pm, tab4, "\">=\" => sub { $_[0]->__ge__($_[1])},\n",NIL); + } else if (strstr(name, "__not__")) { + Printv(pm, tab4, "\"!\" => sub { $_[0]->__not__()},\n",NIL); + } else if (strstr(name, "__lt__")) { + Printv(pm, tab4, "\"<\" => sub { $_[0]->__lt__($_[1])},\n",NIL); + } else if (strstr(name, "__le__")) { + Printv(pm, tab4, "\"<=\" => sub { $_[0]->__le__($_[1])},\n",NIL); + } else if (strstr(name, "__pluseq__")) { + Printv(pm, tab4, "\"+=\" => sub { $_[0]->__pluseq__($_[1])},\n",NIL); + } else if (strstr(name, "__mineq__")) { + Printv(pm, tab4, "\"-=\" => sub { $_[0]->__mineq__($_[1])},\n",NIL); + } else if (strstr(name, "__neg__")) { + Printv(pm, tab4, "\"neg\" => sub { $_[0]->__neg__()},\n",NIL); + } else { + fprintf(stderr,"Unknown operator: %s\n", name); + } + } + Printv(pm, tab4, + "\"=\" => sub { my $class = ref($_[0]); $class->new($_[0]) },\n", NIL); + Printv(pm, tab4, "\"fallback\" => 1;\n", NIL); + } + // make use strict happy + Printv(pm, "use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);\n", NIL); + + /* If we are inheriting from a base class, set that up */ + + Printv(pm, "@ISA = qw(", NIL); + + /* Handle inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "perl5:proxy"); + if (!bname) { + b = Next(b); + continue; + } + Printv(pm, " ", bname, NIL); + b = Next(b); + } + } + + /* Module comes last */ + if (!compat || Cmp(namespace_module, fullclassname)) { + Printv(pm, " ", namespace_module, NIL); + } + + Printf(pm, " );\n"); + + /* Dump out a hash table containing the pointers that we own */ + Printf(pm, "%%OWNER = ();\n"); + if (have_data_members || have_destructor) + Printf(pm, "%%ITERATORS = ();\n"); + + /* Dump out the package methods */ + + Printv(pm, pcode, NIL); + Delete(pcode); + + /* Output methods for managing ownership */ + + String *director_disown; + if (Getattr(n, "perl5:directordisown")) { + director_disown = NewStringf("%s%s($self);\n", tab4, Getattr(n, "perl5:directordisown")); + } else { + director_disown = NewString(""); + } + Printv(pm, + "sub DISOWN {\n", + tab4, "my $self = shift;\n", + director_disown, + tab4, "my $ptr = tied(%$self);\n", + tab4, "delete $OWNER{$ptr};\n", + "}\n\n", "sub ACQUIRE {\n", tab4, "my $self = shift;\n", tab4, "my $ptr = tied(%$self);\n", tab4, "$OWNER{$ptr} = 1;\n", "}\n\n", NIL); + Delete(director_disown); + + /* Only output the following methods if a class has member data */ + + Delete(operators); + operators = 0; + if (Swig_directorclass(n)) { + /* director classes need a way to recover subclass instance attributes */ + Node *get_attr = NewHash(); + String *mrename; + String *symname = Getattr(n, "sym:name"); + mrename = Swig_name_disown(NSPACE_TODO, symname); + Replaceall(mrename, "disown", "swig_get_attr"); + String *type = NewString(getClassType()); + String *name = NewString("self"); + SwigType_add_pointer(type); + Parm *p = NewParm(type, name, n); + Delete(name); + Delete(type); + type = NewString("SV"); + SwigType_add_pointer(type); + String *action = NewString(""); + Printv(action, "{\n", " Swig::Director *director = SWIG_DIRECTOR_CAST(arg1);\n", + " result = sv_newmortal();\n" " if (director) sv_setsv(result, director->swig_get_self());\n", "}\n", NIL); + Setfile(get_attr, Getfile(n)); + Setline(get_attr, Getline(n)); + Setattr(get_attr, "wrap:action", action); + Setattr(get_attr, "name", mrename); + Setattr(get_attr, "sym:name", mrename); + Setattr(get_attr, "type", type); + Setattr(get_attr, "parms", p); + Delete(action); + Delete(type); + Delete(p); + + member_func = 1; + functionWrapper(get_attr); + member_func = 0; + Delete(get_attr); + + Printv(pm, "sub FETCH {\n", tab4, "my ($self,$field) = @_;\n", tab4, "my $member_func = \"swig_${field}_get\";\n", tab4, + "if (not $self->can($member_func)) {\n", tab8, "my $h = ", cmodule, "::", mrename, "($self);\n", tab8, "return $h->{$field} if $h;\n", + tab4, "}\n", tab4, "return $self->$member_func;\n", "}\n", "\n", "sub STORE {\n", tab4, "my ($self,$field,$newval) = @_;\n", tab4, + "my $member_func = \"swig_${field}_set\";\n", tab4, "if (not $self->can($member_func)) {\n", tab8, "my $h = ", cmodule, "::", mrename, + "($self);\n", tab8, "return $h->{$field} = $newval if $h;\n", tab4, "}\n", tab4, "return $self->$member_func($newval);\n", "}\n", NIL); + + Delete(mrename); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + + member_func = 1; + Language::memberfunctionHandler(n); + member_func = 0; + + if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + + if (Strstr(symname, "__eq__")) { + DohSetInt(operators, "__eq__", 1); + have_operators = 1; + } else if (Strstr(symname, "__ne__")) { + DohSetInt(operators, "__ne__", 1); + have_operators = 1; + } else if (Strstr(symname, "__assign__")) { + DohSetInt(operators, "__assign__", 1); + have_operators = 1; + } else if (Strstr(symname, "__str__")) { + DohSetInt(operators, "__str__", 1); + have_operators = 1; + } else if (Strstr(symname, "__add__")) { + DohSetInt(operators, "__add__", 1); + have_operators = 1; + } else if (Strstr(symname, "__sub__")) { + DohSetInt(operators, "__sub__", 1); + have_operators = 1; + } else if (Strstr(symname, "__mul__")) { + DohSetInt(operators, "__mul__", 1); + have_operators = 1; + } else if (Strstr(symname, "__div__")) { + DohSetInt(operators, "__div__", 1); + have_operators = 1; + } else if (Strstr(symname, "__mod__")) { + DohSetInt(operators, "__mod__", 1); + have_operators = 1; + } else if (Strstr(symname, "__and__")) { + DohSetInt(operators, "__and__", 1); + have_operators = 1; + } else if (Strstr(symname, "__or__")) { + DohSetInt(operators, "__or__", 1); + have_operators = 1; + } else if (Strstr(symname, "__not__")) { + DohSetInt(operators, "__not__", 1); + have_operators = 1; + } else if (Strstr(symname, "__gt__")) { + DohSetInt(operators, "__gt__", 1); + have_operators = 1; + } else if (Strstr(symname, "__ge__")) { + DohSetInt(operators, "__ge__", 1); + have_operators = 1; + } else if (Strstr(symname, "__lt__")) { + DohSetInt(operators, "__lt__", 1); + have_operators = 1; + } else if (Strstr(symname, "__le__")) { + DohSetInt(operators, "__le__", 1); + have_operators = 1; + } else if (Strstr(symname, "__neg__")) { + DohSetInt(operators, "__neg__", 1); + have_operators = 1; + } else if (Strstr(symname, "__plusplus__")) { + DohSetInt(operators, "__plusplus__", 1); + have_operators = 1; + } else if (Strstr(symname, "__minmin__")) { + DohSetInt(operators, "__minmin__", 1); + have_operators = 1; + } else if (Strstr(symname, "__mineq__")) { + DohSetInt(operators, "__mineq__", 1); + have_operators = 1; + } else if (Strstr(symname, "__pluseq__")) { + DohSetInt(operators, "__pluseq__", 1); + have_operators = 1; + } + + if (Getattr(n, "feature:shadow")) { + String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); + String *plaction = NewStringf("%s::%s", cmodule, Swig_name_member(NSPACE_TODO, class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * + * Adds an instance member. + * ----------------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + + String *symname = Getattr(n, "sym:name"); + /* SwigType *t = Getattr(n,"type"); */ + + /* Emit a pair of get/set functions for the variable */ + + member_func = 1; + Language::membervariableHandler(n); + member_func = 0; + + if (blessed) { + + Printv(pcode, "*swig_", symname, "_get = *", cmodule, "::", Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)), ";\n", NIL); + Printv(pcode, "*swig_", symname, "_set = *", cmodule, "::", Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname)), ";\n", NIL); + + /* Now we need to generate a little Perl code for this */ + + /* if (is_shadow(t)) { + + *//* This is a Perl object that we have already seen. Add an + entry to the members list *//* + Printv(blessedmembers, + tab4, symname, " => '", is_shadow(t), "',\n", + NIL); + + } + */ + } + have_data_members++; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorDeclaration() + * + * Emits a blessed constructor for our class. In addition to our construct + * we manage a Perl hash table containing all of the pointers created by + * the constructor. This prevents us from accidentally trying to free + * something that wasn't necessarily allocated by malloc or new + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + + String *symname = Getattr(n, "sym:name"); + + member_func = 1; + + Swig_save("perl5:constructorHandler", n, "parms", NIL); + if (Swig_directorclass(n)) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("SV"); + SwigType_add_pointer(type); + self = NewParm(type, name, n); + Delete(type); + Delete(name); + Setattr(self, "lname", "O"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Setattr(n, "hidden", "1"); + Delete(self); + } + + String *saved_nc = none_comparison; + none_comparison = NewStringf("strcmp(SvPV_nolen(ST(0)), \"%s::%s\") != 0", module, class_name); + String *saved_director_prot_ctor_code = director_prot_ctor_code; + director_prot_ctor_code = NewStringf("if ($comparison) { /* subclassed */\n" " $director_new\n" "} else {\n" + "SWIG_exception_fail(SWIG_RuntimeError, \"accessing abstract class or protected constructor\");\n" "}\n"); + Language::constructorHandler(n); + Delete(none_comparison); + none_comparison = saved_nc; + Delete(director_prot_ctor_code); + director_prot_ctor_code = saved_director_prot_ctor_code; + Swig_restore(n); + + if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + if (Getattr(n, "feature:shadow")) { + String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); + String *plaction = NewStringf("%s::%s", module, Swig_name_member(NSPACE_TODO, class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + if ((Cmp(symname, class_name) == 0)) { + /* Emit a blessed constructor */ + Printf(pcode, "sub new {\n"); + } else { + /* Constructor doesn't match classname so we'll just use the normal name */ + Printv(pcode, "sub ", Swig_name_construct(NSPACE_TODO, symname), " {\n", NIL); + } + + const char *pkg = getCurrentClass() && Swig_directorclass(getCurrentClass())? "$_[0]" : "shift"; + Printv(pcode, + tab4, "my $pkg = ", pkg, ";\n", + tab4, "my $self = ", cmodule, "::", Swig_name_construct(NSPACE_TODO, symname), "(@_);\n", tab4, "bless $self, $pkg if defined($self);\n", "}\n\n", NIL); + + have_constructor = 1; + } + } + member_func = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + member_func = 1; + Language::destructorHandler(n); + if (blessed) { + if (Getattr(n, "feature:shadow")) { + String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); + String *plaction = NewStringf("%s::%s", module, Swig_name_member(NSPACE_TODO, class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + Printv(pcode, + "sub DESTROY {\n", + tab4, "return unless $_[0]->isa('HASH');\n", + tab4, "my $self = tied(%{$_[0]});\n", + tab4, "return unless defined $self;\n", + tab4, "delete $ITERATORS{$self};\n", + tab4, "if (exists $OWNER{$self}) {\n", + tab8, cmodule, "::", Swig_name_destroy(NSPACE_TODO, symname), "($self);\n", tab8, "delete $OWNER{$self};\n", tab4, "}\n}\n\n", NIL); + have_destructor = 1; + } + } + member_func = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + member_func = 1; + Language::staticmemberfunctionHandler(n); + member_func = 0; + if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + String *symname = Getattr(n, "sym:name"); + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + Language::staticmembervariableHandler(n); + if (blessed) { + String *symname = Getattr(n, "sym:name"); + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldblessed = blessed; + + /* Create a normal constant */ + blessed = 0; + Language::memberconstantHandler(n); + blessed = oldblessed; + + if (blessed) { + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(NSPACE_TODO, class_name, symname), ";\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * pragma() + * + * Pragma directive. + * + * %pragma(perl5) code="String" # Includes a string in the .pm file + * %pragma(perl5) include="file.pl" # Includes a file in the .pm file + * ------------------------------------------------------------ */ + + virtual int pragmaDirective(Node *n) { + String *lang; + String *code; + String *value; + if (!ImportMode) { + lang = Getattr(n, "lang"); + code = Getattr(n, "name"); + value = Getattr(n, "value"); + if (Strcmp(lang, "perl5") == 0) { + if (Strcmp(code, "code") == 0) { + /* Dump the value string into the .pm file */ + if (value) { + Printf(pragma_include, "%s\n", value); + } + } else if (Strcmp(code, "include") == 0) { + /* Include a file into the .pm file */ + if (value) { + FILE *f = Swig_include_open(value); + if (!f) { + Swig_error(input_file, line_number, "Unable to locate file %s\n", value); + } else { + char buffer[4096]; + while (fgets(buffer, 4095, f)) { + Printf(pragma_include, "%s", buffer); + } + fclose(f); + } + } + } else { + Swig_error(input_file, line_number, "Unrecognized pragma.\n"); + } + } + } + return Language::pragmaDirective(n); + } + + /* ------------------------------------------------------------ + * perlcode() - Output perlcode code into the shadow file + * ------------------------------------------------------------ */ + + String *perlcode(String *code, const String *indent) { + String *out = NewString(""); + String *temp; + char *t; + if (!indent) + indent = ""; + + temp = NewString(code); + + t = Char(temp); + if (*t == '{') { + Delitem(temp, 0); + Delitem(temp, DOH_END); + } + + /* Split the input text into lines */ + List *clist = SplitLines(temp); + Delete(temp); + int initial = 0; + String *s = 0; + Iterator si; + /* Get the initial indentation */ + + for (si = First(clist); si.item; si = Next(si)) { + s = si.item; + if (Len(s)) { + char *c = Char(s); + while (*c) { + if (!isspace(*c)) + break; + initial++; + c++; + } + if (*c && !isspace(*c)) + break; + else { + initial = 0; + } + } + } + while (si.item) { + s = si.item; + if (Len(s) > initial) { + char *c = Char(s); + c += initial; + Printv(out, indent, c, "\n", NIL); + } else { + Printv(out, "\n", NIL); + } + si = Next(si); + } + Delete(clist); + return out; + } + + /* ------------------------------------------------------------ + * insertDirective() + * + * Hook for %insert directive. + * ------------------------------------------------------------ */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + + if ((!ImportMode) && (Cmp(section, "perl") == 0)) { + Printv(additional_perl_code, code, NIL); + } else { + Language::insertDirective(n); + } + return SWIG_OK; + } + + String *runtimeCode() { + String *s = NewString(""); + String *shead = Swig_include_sys("perlhead.swg"); + if (!shead) { + Printf(stderr, "*** Unable to open 'perlhead.swg'\n"); + } else { + Append(s, shead); + Delete(shead); + } + String *serrors = Swig_include_sys("perlerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'perlerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *srun = Swig_include_sys("perlrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'perlrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigperlrun.h"); + } + + virtual int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + virtual int classDirectorEnd(Node *n) { + if (dirprot_mode()) { + /* + This implementation uses a std::map<std::string,int>. + + It should be possible to rewrite it using a more elegant way, + like copying the Java approach for the 'override' array. + + But for now, this seems to be the least intrusive way. + */ + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "/* Internal director utilities */\n"); + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_get_inner(const char *swig_protected_method_name) const {\n"); + Printf(f_directors_h, " std::map<std::string, bool>::const_iterator iv = swig_inner.find(swig_protected_method_name);\n"); + Printf(f_directors_h, " return (iv != swig_inner.end() ? iv->second : false);\n"); + Printf(f_directors_h, " }\n"); + + Printf(f_directors_h, " void swig_set_inner(const char *swig_protected_method_name, bool swig_val) const {\n"); + Printf(f_directors_h, " swig_inner[swig_protected_method_name] = swig_val;\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " mutable std::map<std::string, bool> swig_inner;\n"); + } + Printf(f_directors_h, "};\n"); + return Language::classDirectorEnd(n); + } + + virtual int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("SV"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self"), n); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { \n", classname, target, call); + Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); + Append(w->def, "}\n"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + virtual int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl = Getattr(n, "decl"); + String *name = Getattr(n, "name"); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *symname = Getattr(n, "sym:name"); + String *declaration = NewString(""); + ParmList *l = Getattr(n, "parms"); + Wrapper *w = NewWrapper(); + String *tm; + String *wrap_args = NewString(""); + String *returntype = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + /* determine if the method returns a pointer */ + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(returntype, "void") && !is_pointer); + + /* virtual method definition */ + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + 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); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + 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, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($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 { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(returntype, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (!is_void && !ignored_method) { + String *pres = NewStringf("SV *%s", Swig_cresult_name()); + Wrapper_add_local(w, Swig_cresult_name(), pres); + Delete(pres); + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> Perl) */ + String *parse_args = NewString(""); + String *pstack = NewString(""); + + Swig_director_parms_fixup(l); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("directorargout", l, w); + + Wrapper_add_local(w, "SP", "dSP"); + + { + String *ptype = Copy(getClassType()); + SwigType_add_pointer(ptype); + String *mangle = SwigType_manglestr(ptype); + + Wrapper_add_local(w, "swigself", "SV *swigself"); + Printf(w->code, "swigself = SWIG_NewPointerObj(SWIG_as_voidptr(this), SWIGTYPE%s, SWIG_SHADOW);\n", mangle); + Printf(w->code, "sv_bless(swigself, gv_stashpv(swig_get_class(), 0));\n"); + Delete(mangle); + Delete(ptype); + Append(pstack, "XPUSHs(swigself);\n"); + } + + Parm *p; + char source[256]; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; + p = l; + while (p) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* old style? caused segfaults without the p!=0 check + in the for() condition, and seems dangerous in the + while loop as well. + while (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + } + */ + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + sprintf(source, "obj%d", idx++); + String *input = NewString(source); + Setattr(p, "emit:directorinput", input); + Replaceall(tm, "$input", input); + Delete(input); + Replaceall(tm, "$owner", "0"); + Replaceall(tm, "$shadow", "0"); + /* Wrapper_add_localv(w, source, "SV *", source, "= 0", NIL); */ + Printv(wrap_args, "SV *", source, ";\n", NIL); + + Printv(wrap_args, tm, "\n", NIL); + Putc('O', parse_args); + Printv(pstack, "XPUSHs(", source, ");\n", NIL); + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + /* special handling for pointers to other C++ director classes. + * ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. in other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. we avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, ptype); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(ptype) + 2); + /* name as pointer */ + String *ppname = Copy(pname); + if (SwigType_isreference(ptype)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Perl doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", pname); + String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", + SwigType_str(ptype, pname), SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(ptype); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "SV *", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_DIRECTOR_CAST(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Append(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "SvREFCNT_inc((SV *)%s);\n", source); + Append(wrap_args, "}\n"); + Delete(director); + } else { + Wrapper_add_localv(w, source, "SV *", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Printf(pstack, "XPUSHs(sv_2mortal(%s));\n", source); + } + Putc('O', parse_args); + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + /* add the method name as a PyString */ + String *pyname = Getattr(n, "sym:name"); + + /* wrap complex arguments to PyObjects */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Python object */ + if (dirprot_mode() && !is_public(n)) { + Printf(w->code, "swig_set_inner(\"%s\", true);\n", name); + } + + Append(w->code, "ENTER;\n"); + Append(w->code, "SAVETMPS;\n"); + Append(w->code, "PUSHMARK(SP);\n"); + Append(w->code, pstack); + Delete(pstack); + Append(w->code, "PUTBACK;\n"); + Printf(w->code, "call_method(\"%s\", G_EVAL | G_SCALAR);\n", pyname); + + if (dirprot_mode() && !is_public(n)) + Printf(w->code, "swig_set_inner(\"%s\", false);\n", name); + + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + Append(w->code, "if (SvTRUE(ERRSV)) {\n"); + Append(w->code, " PUTBACK;\n FREETMPS;\n LEAVE;\n"); + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Replaceall(tm, "$error", "ERRSV"); + Printv(w->code, Str(tm), "\n", NIL); + } else { + Printf(w->code, " Swig::DirectorMethodException::raise(ERRSV);\n", classname, pyname); + } + Append(w->code, "}\n"); + Delete(tm); + + /* + * Python method may return a simple object, or a tuple. + * for in/out arguments, we have to extract the appropriate PyObjects from the tuple, + * then marshal everything back to C/C++ (return value and output arguments). + * + */ + + /* marshal return value and other outputs (if any) from PyObject to C/C++ type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + if (outputs > 1) { + Wrapper_add_local(w, "output", "SV *output"); + Printf(w->code, "if (count != %d) {\n", outputs); + Printf(w->code, " Swig::DirectorTypeMismatchException::raise(\"Perl method %s.%sfailed to return a list.\");\n", classname, pyname); + Append(w->code, "}\n"); + } + + idx = 0; + + /* marshal return value */ + if (!is_void) { + Append(w->code, "SPAGAIN;\n"); + Printf(w->code, "%s = POPs;\n", Swig_cresult_name()); + tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); + if (tm != 0) { + if (outputs > 1) { + Printf(w->code, "output = POPs;\n"); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", Swig_cresult_name()); + } + char temp[24]; + sprintf(temp, "%d", idx); + Replaceall(tm, "$argnum", temp); + + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + if (outputs > 1) { + Printf(w->code, "output = POPs;\n"); + Replaceall(tm, "$result", "output"); + } else { + Replaceall(tm, "$result", Swig_cresult_name()); + } + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(parse_args); + Delete(cleanup); + Delete(outarg); + } + + if (!ignored_method) { + Append(w->code, "PUTBACK;\n"); + Append(w->code, "FREETMPS;\n"); + Append(w->code, "LEAVE;\n"); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(returntype, 0); + if (!SwigType_isreference(returntype)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Append(w->code, "}\n"); + + // We expose 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) { + 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); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(pclassname); + DelWrapper(w); + return status; + } + int classDirectorDisown(Node *n) { + int rv; + member_func = 1; + rv = Language::classDirectorDisown(n); + member_func = 0; + if (rv == SWIG_OK && Swig_directorclass(n)) { + String *symname = Getattr(n, "sym:name"); + String *disown = Swig_name_disown(NSPACE_TODO, symname); + Setattr(n, "perl5:directordisown", NewStringf("%s::%s", cmodule, disown)); + } + return rv; + } + int classDirectorDestructor(Node *n) { + /* TODO: it would be nice if this didn't have to copy the body of Language::classDirectorDestructor() */ + String *DirectorClassName = directorClassName(getCurrentClass()); + String *body = NewString("\n"); + + String *ptype = Copy(getClassType()); + SwigType_add_pointer(ptype); + String *mangle = SwigType_manglestr(ptype); + + Printv(body, tab4, "dSP;\n", tab4, "SV *self = SWIG_NewPointerObj(SWIG_as_voidptr(this), SWIGTYPE", mangle, ", SWIG_SHADOW);\n", tab4, "\n", tab4, + "sv_bless(self, gv_stashpv(swig_get_class(), 0));\n", tab4, "ENTER;\n", tab4, "SAVETMPS;\n", tab4, "PUSHMARK(SP);\n", tab4, + "XPUSHs(self);\n", tab4, "XPUSHs(&PL_sv_yes);\n", tab4, "PUTBACK;\n", tab4, "call_method(\"DESTROY\", G_EVAL | G_VOID);\n", tab4, + "FREETMPS;\n", tab4, "LEAVE;\n", NIL); + + Delete(mangle); + Delete(ptype); + + if (Getattr(n, "noexcept")) { + Printf(f_directors_h, " virtual ~%s() noexcept;\n", DirectorClassName); + Printf(f_directors, "%s::~%s() noexcept {%s}\n\n", DirectorClassName, DirectorClassName, body); + } else if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~%s() throw();\n", DirectorClassName); + Printf(f_directors, "%s::~%s() throw() {%s}\n\n", DirectorClassName, DirectorClassName, body); + } else { + Printf(f_directors_h, " virtual ~%s();\n", DirectorClassName); + Printf(f_directors, "%s::~%s() {%s}\n\n", DirectorClassName, DirectorClassName, body); + } + return SWIG_OK; + } +}; + +/* ----------------------------------------------------------------------------- + * swig_perl5() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_perl5() { + return new PERL5(); +} +extern "C" Language *swig_perl5(void) { + return new_swig_perl5(); +} diff --git a/contrib/tools/swig/Source/Modules/php.cxx b/contrib/tools/swig/Source/Modules/php.cxx new file mode 100644 index 00000000000..1edbd874cc9 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/php.cxx @@ -0,0 +1,2876 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * php.cxx + * + * PHP language module for SWIG. + * ----------------------------------------------------------------------------- + */ + +/* FIXME: PHP OO wrapping TODO list: + * + * Medium term: + * + * Handle default parameters on overloaded methods in PHP where possible. + * (Mostly done - just need to handle cases of overloaded methods with + * default parameters...) + * This is an optimisation - we could handle this case using a PHP + * default value, but currently we treat it as we would for a default + * value which is a compound C++ expression (i.e. as if we had a + * method with two overloaded forms instead of a single method with + * a default parameter value). + * + * Long term: + * + * Sort out locale-dependent behaviour of strtod() - it's harmless unless + * SWIG ever sets the locale and DOH/base.c calls atof, so we're probably + * OK currently at least. + */ + +/* + * TODO: Replace remaining stderr messages with Swig_error or Swig_warning + * (may need to add more WARN_PHP_xxx codes...) + */ + +#include "swigmod.h" + +#include <ctype.h> +#include <errno.h> + +static const char *usage = "\ +PHP 7 Options (available with -php7)\n\ + -noproxy - Don't generate proxy classes.\n\ + -prefix <prefix> - Prepend <prefix> to all class names in PHP wrappers\n\ +\n"; + +/* The original class wrappers for PHP stored the pointer to the C++ class in + * the object property _cPtr. If we use the same name for the member variable + * which we put the pointer to the C++ class in, then the flat function + * wrappers will automatically pull it out without any changes being required. + * FIXME: Isn't using a leading underscore a bit suspect here? + */ +#define SWIG_PTR "_cPtr" + +/* This is the name of the hash where the variables existing only in PHP + * classes are stored. + */ +#define SWIG_DATA "_pData" + +static int constructors = 0; +static String *NOTCLASS = NewString("Not a class"); +static Node *classnode = 0; +static String *module = 0; +static String *cap_module = 0; +static String *prefix = 0; + +static String *shadow_classname = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_h = 0; +static File *f_phpcode = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static String *phpfilename = 0; + +static String *s_header; +static String *s_wrappers; +static String *s_init; +static String *r_init; // RINIT user code +static String *s_shutdown; // MSHUTDOWN user code +static String *r_shutdown; // RSHUTDOWN user code +static String *s_vinit; // varinit initialization code. +static String *s_vdecl; +static String *s_cinit; // consttab initialization code. +static String *s_oinit; +static String *s_arginfo; +static String *s_entry; +static String *cs_entry; +static String *all_cs_entry; +static String *pragma_incl; +static String *pragma_code; +static String *pragma_phpinfo; +static String *pragma_version; +static String *s_oowrappers; +static String *s_fakeoowrappers; +static String *s_phpclasses; + +/* To reduce code size (generated and compiled) we only want to emit each + * different arginfo once, so we need to track which have been used. + */ +static Hash *arginfo_used; + +/* Variables for using PHP classes */ +static Node *current_class = 0; + +static Hash *shadow_get_vars; +static Hash *shadow_set_vars; +static Hash *zend_types = 0; + +static int shadow = 1; + +static bool class_has_ctor = false; +static String *wrapping_member_constant = NULL; + +// These static variables are used to pass some state from Handlers into functionWrapper +static enum { + standard = 0, + memberfn, + staticmemberfn, + membervar, + staticmembervar, + constructor, + directorconstructor +} wrapperType = standard; + +extern "C" { + static void (*r_prevtracefunc) (const SwigType *t, String *mangled, String *clientdata) = 0; +} + +static void SwigPHP_emit_resource_registrations() { + Iterator ki; + bool emitted_default_dtor = false; + + if (!zend_types) + return; + + ki = First(zend_types); + if (ki.key) + Printf(s_oinit, "\n /* Register resource destructors for pointer types */\n"); + while (ki.key) { + DOH *key = ki.key; + Node *class_node = ki.item; + String *human_name = key; + String *rsrc_dtor_name = NULL; + + // write out body + if (class_node != NOTCLASS) { + String *destructor = Getattr(class_node, "destructor"); + human_name = Getattr(class_node, "sym:name"); + if (!human_name) + human_name = Getattr(class_node, "name"); + // Do we have a known destructor for this type? + if (destructor) { + rsrc_dtor_name = NewStringf("_wrap_destroy%s", key); + // Write out custom destructor function + Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(%s) {\n", rsrc_dtor_name); + Printf(s_wrappers, " %s(res, SWIGTYPE%s->name);\n", destructor, key); + Printf(s_wrappers, "}\n"); + } + } + + if (!rsrc_dtor_name) { + rsrc_dtor_name = NewString("_swig_default_rsrc_destroy"); + if (!emitted_default_dtor) { + // Write out custom destructor function + Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(%s) {\n", rsrc_dtor_name); + Printf(s_wrappers, " efree(res->ptr);\n"); + Printf(s_wrappers, "}\n"); + emitted_default_dtor = true; + } + } + + // declare le_swig_<mangled> to store php registration + Printf(s_vdecl, "static int le_swig_%s=0; /* handle for %s */\n", key, human_name); + + // register with php + Printf(s_oinit, " le_swig_%s=zend_register_list_destructors_ex" + "(%s, NULL, SWIGTYPE%s->name, module_number);\n", key, rsrc_dtor_name, key); + + // store php type in class struct + Printf(s_oinit, " SWIG_TypeClientData(SWIGTYPE%s,&le_swig_%s);\n", key, key); + + Delete(rsrc_dtor_name); + + ki = Next(ki); + } +} + +class PHP : public Language { +public: + PHP() { + director_language = 1; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + SWIG_library_directory("php"); + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-noshadow") == 0) || (strcmp(argv[i], "-noproxy") == 0)) { + shadow = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + + Preprocessor_define("SWIGPHP 1", 0); + Preprocessor_define("SWIGPHP7 1", 0); + SWIG_typemap_lang("php"); + SWIG_config_file("php.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + String *filen; + + /* Check if directors are enabled for this module. */ + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options && Getattr(options, "directors")) { + allow_directors(); + } + } + + /* Set comparison with null for ConstructorToFunction */ + setSubclassInstanceCheck(NewString("Z_TYPE_P($arg) != IS_NULL")); + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + /* main output file */ + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewStringEmpty(); + + /* sections of the output file */ + s_init = NewStringEmpty(); + r_init = NewStringEmpty(); + s_shutdown = NewStringEmpty(); + r_shutdown = NewStringEmpty(); + s_header = NewString("/* header section */\n"); + s_wrappers = NewString("/* wrapper section */\n"); + /* subsections of the init section */ + s_vinit = NewStringEmpty(); + s_vdecl = NewString("/* vdecl subsection */\n"); + s_cinit = NewString(" /* cinit subsection */\n"); + s_oinit = NewString(" /* oinit subsection */\n"); + pragma_phpinfo = NewStringEmpty(); + s_phpclasses = NewString("/* PHP Proxy Classes */\n"); + f_directors_h = NewStringEmpty(); + f_directors = NewStringEmpty(); + + if (directorsEnabled()) { + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", s_init); + Swig_register_filebyname("rinit", r_init); + Swig_register_filebyname("shutdown", s_shutdown); + Swig_register_filebyname("rshutdown", r_shutdown); + Swig_register_filebyname("header", s_header); + Swig_register_filebyname("wrapper", s_wrappers); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGPHP\n#define SWIGPHP\n#endif\n\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + /* Set the module name */ + module = Copy(Getattr(n, "name")); + cap_module = NewStringf("%(upper)s", module); + if (!prefix) + prefix = NewStringEmpty(); + + Printf(f_runtime, "#define SWIG_PREFIX \"%s\"\n", prefix); + Printf(f_runtime, "#define SWIG_PREFIX_LEN %lu\n", (unsigned long)Len(prefix)); + + if (directorsEnabled()) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", cap_module); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", cap_module); + + String *filename = Swig_file_filename(outfile_h); + Printf(f_directors, "\n#include \"%s\"\n\n", filename); + Delete(filename); + } + + /* PHP module file */ + filen = NewStringEmpty(); + Printv(filen, SWIG_output_directory(), module, ".php", NIL); + phpfilename = NewString(filen); + + f_phpcode = NewFile(filen, "w", SWIG_output_files()); + if (!f_phpcode) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_phpcode, "<?php\n\n"); + + Swig_banner(f_phpcode); + + Printf(f_phpcode, "\n"); + Printf(f_phpcode, "// Try to load our extension if it's not already loaded.\n"); + Printf(f_phpcode, "if (!extension_loaded('%s')) {\n", module); + Printf(f_phpcode, " if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {\n"); + Printf(f_phpcode, " if (!dl('php_%s.dll')) return;\n", module); + Printf(f_phpcode, " } else {\n"); + Printf(f_phpcode, " // PHP_SHLIB_SUFFIX gives 'dylib' on MacOS X but modules are 'so'.\n"); + Printf(f_phpcode, " if (PHP_SHLIB_SUFFIX === 'dylib') {\n"); + Printf(f_phpcode, " if (!dl('%s.so')) return;\n", module); + Printf(f_phpcode, " } else {\n"); + Printf(f_phpcode, " if (!dl('%s.'.PHP_SHLIB_SUFFIX)) return;\n", module); + Printf(f_phpcode, " }\n"); + Printf(f_phpcode, " }\n"); + Printf(f_phpcode, "}\n\n"); + + /* sub-sections of the php file */ + pragma_code = NewStringEmpty(); + pragma_incl = NewStringEmpty(); + pragma_version = NULL; + + /* Initialize the rest of the module */ + + Printf(s_oinit, " ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, NULL);\n", module, module); + + /* start the header section */ + Printf(s_header, "ZEND_BEGIN_MODULE_GLOBALS(%s)\n", module); + Printf(s_header, "const char *error_msg;\n"); + Printf(s_header, "int error_code;\n"); + Printf(s_header, "ZEND_END_MODULE_GLOBALS(%s)\n", module); + Printf(s_header, "ZEND_DECLARE_MODULE_GLOBALS(%s)\n", module); + Printf(s_header, "#define SWIG_ErrorMsg() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_msg)\n", module); + Printf(s_header, "#define SWIG_ErrorCode() ZEND_MODULE_GLOBALS_ACCESSOR(%s, error_code)\n", module); + + /* The following can't go in Lib/php/phprun.swg as it uses SWIG_ErrorMsg(), etc + * which has to be dynamically generated as it depends on the module name. + */ + Append(s_header, "#ifdef __GNUC__\n"); + Append(s_header, "static void SWIG_FAIL(void) __attribute__ ((__noreturn__));\n"); + Append(s_header, "#endif\n\n"); + Append(s_header, "static void SWIG_FAIL(void) {\n"); + Append(s_header, " zend_error(SWIG_ErrorCode(), \"%s\", SWIG_ErrorMsg());\n"); + // zend_error() should never return with the parameters we pass, but if it + // does, we really don't want to let SWIG_FAIL() return. This also avoids + // a warning about returning from a function marked as "__noreturn__". + Append(s_header, " abort();\n"); + Append(s_header, "}\n\n"); + + Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module); + Printf(s_header, " globals->error_msg = default_error_msg;\n"); + Printf(s_header, " globals->error_code = default_error_code;\n"); + Printf(s_header, "}\n"); + + Printf(s_header, "static void SWIG_ResetError(void) {\n"); + Printf(s_header, " SWIG_ErrorMsg() = default_error_msg;\n"); + Printf(s_header, " SWIG_ErrorCode() = default_error_code;\n"); + Printf(s_header, "}\n"); + + Append(s_header, "\n"); + Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_alter_newobject) {\n", module); + Append(s_header, " zval args[2];\n"); + Append(s_header, " swig_object_wrapper *value;\n"); + Append(s_header, "\n"); + Append(s_header, " SWIG_ResetError();\n"); + Append(s_header, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n"); + Append(s_header, " WRONG_PARAM_COUNT;\n"); + Append(s_header, " }\n"); + Append(s_header, "\n"); + Append(s_header, " value = (swig_object_wrapper *) Z_RES_VAL(args[0]);\n"); + Append(s_header, " value->newobject = zval_is_true(&args[1]);\n"); + Append(s_header, "\n"); + Append(s_header, " return;\n"); + Append(s_header, "}\n"); + Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_get_newobject) {\n", module); + Append(s_header, " zval args[1];\n"); + Append(s_header, " swig_object_wrapper *value;\n"); + Append(s_header, "\n"); + Append(s_header, " SWIG_ResetError();\n"); + Append(s_header, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n"); + Append(s_header, " WRONG_PARAM_COUNT;\n"); + Append(s_header, " }\n"); + Append(s_header, "\n"); + Append(s_header, " value = (swig_object_wrapper *) Z_RES_VAL(args[0]);\n"); + Append(s_header, " RETVAL_LONG(value->newobject);\n"); + Append(s_header, "\n"); + Append(s_header, " return;\n"); + Append(s_header, "}\n"); + + Printf(s_header, "#define SWIG_name \"%s\"\n", module); + Printf(s_header, "#ifdef __cplusplus\n"); + Printf(s_header, "extern \"C\" {\n"); + Printf(s_header, "#endif\n"); + Printf(s_header, "#include \"php.h\"\n"); + Printf(s_header, "#include \"php_ini.h\"\n"); + Printf(s_header, "#include \"ext/standard/info.h\"\n"); + Printf(s_header, "#include \"php_%s.h\"\n", module); + Printf(s_header, "#ifdef __cplusplus\n"); + Printf(s_header, "}\n"); + Printf(s_header, "#endif\n\n"); + + if (directorsEnabled()) { + // Insert director runtime + Swig_insert_file("director_common.swg", s_header); + Swig_insert_file("director.swg", s_header); + } + + /* Create the .h file too */ + filen = NewStringEmpty(); + Printv(filen, SWIG_output_directory(), "php_", module, ".h", NIL); + f_h = NewFile(filen, "w", SWIG_output_files()); + if (!f_h) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(f_h); + + Printf(f_h, "\n"); + Printf(f_h, "#ifndef PHP_%s_H\n", cap_module); + Printf(f_h, "#define PHP_%s_H\n\n", cap_module); + Printf(f_h, "extern zend_module_entry %s_module_entry;\n", module); + Printf(f_h, "#define phpext_%s_ptr &%s_module_entry\n\n", module, module); + Printf(f_h, "#ifdef PHP_WIN32\n"); + Printf(f_h, "# define PHP_%s_API __declspec(dllexport)\n", cap_module); + Printf(f_h, "#else\n"); + Printf(f_h, "# define PHP_%s_API\n", cap_module); + Printf(f_h, "#endif\n\n"); + + /* start the arginfo section */ + s_arginfo = NewString("/* arginfo subsection */\n"); + arginfo_used = NewHash(); + + /* start the function entry section */ + s_entry = NewString("/* entry subsection */\n"); + + /* holds all the per-class function entry sections */ + all_cs_entry = NewString("/* class entry subsection */\n"); + cs_entry = NULL; + + Printf(s_entry, "/* Every non-class user visible function must have an entry here */\n"); + Printf(s_entry, "static zend_function_entry %s_functions[] = {\n", module); + + /* Emit all of the code */ + Language::top(n); + + SwigPHP_emit_resource_registrations(); + + /* start the init section */ + { + String * s_init_old = s_init; + s_init = NewString("/* init section */\n"); + Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n", NIL); + Printf(s_init, " STANDARD_MODULE_HEADER,\n"); + Printf(s_init, " \"%s\",\n", module); + Printf(s_init, " %s_functions,\n", module); + Printf(s_init, " PHP_MINIT(%s),\n", module); + if (Len(s_shutdown) > 0) { + Printf(s_init, " PHP_MSHUTDOWN(%s),\n", module); + } else { + Printf(s_init, " NULL, /* No MSHUTDOWN code */\n"); + } + if (Len(r_init) > 0 || Len(s_vinit) > 0) { + Printf(s_init, " PHP_RINIT(%s),\n", module); + } else { + Printf(s_init, " NULL, /* No RINIT code */\n"); + } + if (Len(r_shutdown) > 0) { + Printf(s_init, " PHP_RSHUTDOWN(%s),\n", module); + } else { + Printf(s_init, " NULL, /* No RSHUTDOWN code */\n"); + } + if (Len(pragma_phpinfo) > 0) { + Printf(s_init, " PHP_MINFO(%s),\n", module); + } else { + Printf(s_init, " NULL, /* No MINFO code */\n"); + } + if (Len(pragma_version) > 0) { + Printf(s_init, " \"%s\",\n", pragma_version); + } else { + Printf(s_init, " NO_VERSION_YET,\n"); + } + Printf(s_init, " STANDARD_MODULE_PROPERTIES\n"); + Printf(s_init, "};\n"); + Printf(s_init, "zend_module_entry* SWIG_module_entry = &%s_module_entry;\n\n", module); + + Printf(s_init, "#ifdef __cplusplus\n"); + Printf(s_init, "extern \"C\" {\n"); + Printf(s_init, "#endif\n"); + // We want to write "SWIGEXPORT ZEND_GET_MODULE(%s)" but ZEND_GET_MODULE + // in PHP7 has "extern "C" { ... }" around it so we can't do that. + Printf(s_init, "SWIGEXPORT zend_module_entry *get_module(void) { return &%s_module_entry; }\n", module); + Printf(s_init, "#ifdef __cplusplus\n"); + Printf(s_init, "}\n"); + Printf(s_init, "#endif\n\n"); + + Printf(s_init, "#define SWIG_php_minit PHP_MINIT_FUNCTION(%s)\n\n", module); + + Printv(s_init, s_init_old, NIL); + Delete(s_init_old); + } + + /* We have to register the constants before they are (possibly) used + * by the pointer typemaps. This all needs re-arranging really as + * things are being called in the wrong order + */ + + // Printv(s_init,s_resourcetypes,NIL); + /* We need this after all classes written out by ::top */ + Printf(s_oinit, " CG(active_class_entry) = NULL;\n"); + Printf(s_oinit, " /* end oinit subsection */\n"); + Printf(s_init, "%s\n", s_oinit); + + /* Constants generated during top call */ + Printf(s_cinit, " /* end cinit subsection */\n"); + Printf(s_init, "%s\n", s_cinit); + Clear(s_cinit); + Delete(s_cinit); + + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + + // Now do REQUEST init which holds any user specified %rinit, and also vinit + if (Len(r_init) > 0 || Len(s_vinit) > 0) { + Printf(f_h, "PHP_RINIT_FUNCTION(%s);\n", module); + + Printf(s_init, "PHP_RINIT_FUNCTION(%s)\n{\n", module); + if (Len(r_init) > 0) { + Printv(s_init, + "/* rinit section */\n", + r_init, "\n", + NIL); + } + + if (Len(s_vinit) > 0) { + /* finish our init section which will have been used by class wrappers */ + Printv(s_init, + " /* vinit subsection */\n", + s_vinit, "\n" + " /* end vinit subsection */\n", + NIL); + Clear(s_vinit); + } + Delete(s_vinit); + + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + } + + Printf(f_h, "PHP_MINIT_FUNCTION(%s);\n", module); + + if (Len(s_shutdown) > 0) { + Printf(f_h, "PHP_MSHUTDOWN_FUNCTION(%s);\n", module); + + Printv(s_init, "PHP_MSHUTDOWN_FUNCTION(", module, ")\n" + "/* shutdown section */\n" + "{\n", + s_shutdown, + " return SUCCESS;\n" + "}\n\n", NIL); + } + + if (Len(r_shutdown) > 0) { + Printf(f_h, "PHP_RSHUTDOWN_FUNCTION(%s);\n", module); + + Printf(s_init, "PHP_RSHUTDOWN_FUNCTION(%s)\n{\n", module); + Printf(s_init, "/* rshutdown section */\n"); + Printf(s_init, "%s\n", r_shutdown); + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + } + + if (Len(pragma_phpinfo) > 0) { + Printf(f_h, "PHP_MINFO_FUNCTION(%s);\n", module); + + Printf(s_init, "PHP_MINFO_FUNCTION(%s)\n{\n", module); + Printf(s_init, "%s", pragma_phpinfo); + Printf(s_init, "}\n"); + } + + Printf(s_init, "/* end init section */\n"); + + Printf(f_h, "\n#endif /* PHP_%s_H */\n", cap_module); + + Delete(f_h); + + String *type_table = NewStringEmpty(); + SwigType_emit_type_table(f_runtime, type_table); + Printf(s_header, "%s", type_table); + Delete(type_table); + + /* Oh dear, more things being called in the wrong order. This whole + * function really needs totally redoing. + */ + + if (directorsEnabled()) { + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + Delete(f_runtime_h); + } + + Printf(s_header, "/* end header section */\n"); + Printf(s_wrappers, "/* end wrapper section */\n"); + Printf(s_vdecl, "/* end vdecl subsection */\n"); + + Dump(f_runtime, f_begin); + Printv(f_begin, s_header, NIL); + if (directorsEnabled()) { + Dump(f_directors, f_begin); + } + Printv(f_begin, s_vdecl, s_wrappers, NIL); + Printv(f_begin, all_cs_entry, "\n\n", s_arginfo, "\n\n", s_entry, + " SWIG_ZEND_NAMED_FE(swig_", module, "_alter_newobject,_wrap_swig_", module, "_alter_newobject,NULL)\n" + " SWIG_ZEND_NAMED_FE(swig_", module, "_get_newobject,_wrap_swig_", module, "_get_newobject,NULL)\n" + " ZEND_FE_END\n};\n\n", NIL); + Printv(f_begin, s_init, NIL); + Delete(s_header); + Delete(s_wrappers); + Delete(s_init); + Delete(s_vdecl); + Delete(all_cs_entry); + Delete(s_entry); + Delete(s_arginfo); + Delete(f_runtime); + Delete(f_begin); + Delete(arginfo_used); + + Printf(f_phpcode, "%s\n%s\n", pragma_incl, pragma_code); + if (s_fakeoowrappers) { + Printf(f_phpcode, "abstract class %s {", Len(prefix) ? prefix : module); + Printf(f_phpcode, "%s", s_fakeoowrappers); + Printf(f_phpcode, "}\n\n"); + Delete(s_fakeoowrappers); + s_fakeoowrappers = NULL; + } + Printf(f_phpcode, "%s\n", s_phpclasses); + Delete(f_phpcode); + + return SWIG_OK; + } + + /* Just need to append function names to function table to register with PHP. */ + void create_command(String *cname, String *iname, Node *n) { + // This is for the single main zend_function_entry record + Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname); + + // We want to only emit each different arginfo once, as that reduces the + // size of both the generated source code and the compiled extension + // module. To do this, we name the arginfo to encode the number of + // parameters and which (if any) are passed by reference by using a + // sequence of 0s (for non-reference) and 1s (for by references). + ParmList *l = Getattr(n, "parms"); + String * arginfo_code = NewStringEmpty(); + for (Parm *p = l; p; p = Getattr(p, "tmap:in:next")) { + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + Append(arginfo_code, GetFlag(p, "tmap:in:byref") ? "1" : "0"); + } + + if (!GetFlag(arginfo_used, arginfo_code)) { + // Not had this one before, so emit it. + SetFlag(arginfo_used, arginfo_code); + Printf(s_arginfo, "ZEND_BEGIN_ARG_INFO_EX(swig_arginfo_%s, 0, 0, 0)\n", arginfo_code); + for (const char * p = Char(arginfo_code); *p; ++p) { + Printf(s_arginfo, " ZEND_ARG_PASS_INFO(%c)\n", *p); + } + Printf(s_arginfo, "ZEND_END_ARG_INFO()\n"); + } + + String * s = cs_entry; + if (!s) s = s_entry; + Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,swig_arginfo_%s)\n", cname, iname, arginfo_code); + Delete(arginfo_code); + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewStringEmpty(); + if (Swig_directorclass(n) && wrapperType == directorconstructor) { + /* We have an extra 'this' parameter. */ + SetFlag(n, "wrap:this"); + } + String *dispatch = Swig_overload_dispatch(n, "%s(INTERNAL_FUNCTION_PARAM_PASSTHRU); return;", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + create_command(symname, wname, n); + Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + + Printf(tmp, "zval argv[%d]", maxargs); + Wrapper_add_local(f, "argv", tmp); + + Printf(f->code, "argc = ZEND_NUM_ARGS();\n"); + + Printf(f->code, "zend_get_parameters_array_ex(argc, argv);\n"); + + Replaceall(dispatch, "$args", "self,args"); + + Printv(f->code, dispatch, "\n", NIL); + + Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n"); + Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname); + Printv(f->code, "SWIG_FAIL();\n", NIL); + + Printv(f->code, "}\n", NIL); + Wrapper_print(f, s_wrappers); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + /* Helper method for PHP::functionWrapper */ + bool is_class(SwigType *t) { + Node *n = classLookup(t); + if (n) { + String *r = Getattr(n, "php:proxy"); // Set by classDeclaration() + if (!r) + r = Getattr(n, "sym:name"); // Not seen by classDeclaration yet, but this is the name + if (r) + return true; + } + return false; + } + + virtual int functionWrapper(Node *n) { + String *name = GetChar(n, "name"); + String *iname = GetChar(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *nodeType = Getattr(n, "nodeType"); + int newobject = GetFlag(n, "feature:new"); + int constructor = (Cmp(nodeType, "constructor") == 0); + + Parm *p; + int i; + int numopt; + String *tm; + Wrapper *f; + + String *wname; + int overloaded = 0; + String *overname = 0; + + if (Cmp(nodeType, "destructor") == 0) { + // We just generate the Zend List Destructor and let Zend manage the + // reference counting. There's no explicit destructor, but the user can + // just do `$obj = null;' to remove a reference to an object. + return CreateZendListDestructor(n); + } + // Test for overloading; + if (Getattr(n, "sym:overloaded")) { + overloaded = 1; + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + wname = Swig_name_wrapper(iname); + if (overname) { + Printf(wname, "%s", overname); + } + + f = NewWrapper(); + + String *outarg = NewStringEmpty(); + String *cleanup = NewStringEmpty(); + + Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL); + + emit_parameter_variables(l, f); + /* Attach standard typemaps */ + + emit_attach_parmmaps(l, f); + // Not issued for overloaded functions. + if (!overloaded) { + create_command(iname, wname, n); + } + + // wrap:parms is used by overload resolution. + Setattr(n, "wrap:parms", l); + + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + numopt = num_arguments - num_required; + + if (wrapperType == directorconstructor) + num_arguments++; + + if (num_arguments > 0) { + String *args = NewStringEmpty(); + if (wrapperType == directorconstructor) + Wrapper_add_local(f, "arg0", "zval * arg0"); + Printf(args, "zval args[%d]", num_arguments); + Wrapper_add_local(f, "args", args); + Delete(args); + args = NULL; + } + + // This generated code may be called: + // 1) as an object method, or + // 2) as a class-method/function (without a "this_ptr") + // Option (1) has "this_ptr" for "this", option (2) needs it as + // first parameter + + // NOTE: possible we ignore this_ptr as a param for native constructor + + Printf(f->code, "SWIG_ResetError();\n"); + + if (numopt > 0) { // membervariable wrappers do not have optional args + Wrapper_add_local(f, "arg_count", "int arg_count"); + Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n"); + Printf(f->code, "if(arg_count<%d || arg_count>%d ||\n", num_required, num_arguments); + Printf(f->code, " zend_get_parameters_array_ex(arg_count,args)!=SUCCESS)\n"); + Printf(f->code, "\tWRONG_PARAM_COUNT;\n\n"); + } else { + if (num_arguments == 0) { + Printf(f->code, "if(ZEND_NUM_ARGS() != 0) {\n"); + } else { + Printf(f->code, "if(ZEND_NUM_ARGS() != %d || zend_get_parameters_array_ex(%d, args) != SUCCESS) {\n", num_arguments, num_arguments); + } + Printf(f->code, "WRONG_PARAM_COUNT;\n}\n\n"); + } + if (wrapperType == directorconstructor) + Printf(f->code, "arg0 = &args[0];\n \n"); + + /* Now convert from PHP to C variables */ + // At this point, argcount if used is the number of deliberately passed args + // not including this_ptr even if it is used. + // It means error messages may be out by argbase with error + // reports. We can either take argbase into account when raising + // errors, or find a better way of dealing with _thisptr. + // I would like, if objects are wrapped, to assume _thisptr is always + // _this and not the first argument. + // This may mean looking at Language::memberfunctionHandler + + int limit = num_arguments; + if (wrapperType == directorconstructor) + limit--; + for (i = 0, p = l; i < limit; i++) { + String *source; + + /* Skip ignored arguments */ + //while (Getattr(p,"tmap:ignore")) { p = Getattr(p,"tmap:ignore:next");} + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + + if (wrapperType == directorconstructor) { + source = NewStringf("args[%d]", i+1); + } else { + source = NewStringf("args[%d]", i); + } + + String *ln = Getattr(p, "lname"); + + /* Check if optional */ + if (i >= num_required) { + Printf(f->code, "\tif(arg_count > %d) {\n", i); + } + + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", &source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printf(f->code, "%s\n", tm); + if (i == 0 && Getattr(p, "self")) { + Printf(f->code, "\tif(!arg1) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n"); + } + p = Getattr(p, "tmap:in:next"); + if (i >= num_required) { + Printf(f->code, "}\n"); + } + continue; + } 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)); + } + if (i >= num_required) { + Printf(f->code, "\t}\n"); + } + Delete(source); + } + + if (is_member_director(n)) { + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Printf(f->code, "upcall = !Swig::Director::swig_is_overridden_method(\"%s%s\", \"%s\");\n", + prefix, Swig_class_name(Swig_methodclass(n)), name); + } + + Swig_director_emit_dynamic_cast(n, f); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + bool hasargout = false; + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:argout")) && Len(tm)) { + hasargout = true; + Replaceall(tm, "$source", Getattr(p, "lname")); + // Replaceall(tm,"$input",Getattr(p,"lname")); + Replaceall(tm, "$target", "return_value"); + Replaceall(tm, "$result", "return_value"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + Setattr(n, "wrap:name", wname); + + /* emit function call */ + String *actioncode = emit_action(n); + + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$target", "return_value"); + Replaceall(tm, "$result", "return_value"); + Replaceall(tm, "$owner", newobject ? "1" : "0"); + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + if (outarg) { + Printv(f->code, outarg, NIL); + } + + if (cleanup) { + 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))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printf(f->code, "thrown:\n"); + Printf(f->code, "return;\n"); + + /* Error handling code */ + Printf(f->code, "fail:\n"); + Printv(f->code, cleanup, NIL); + Append(f->code, "SWIG_FAIL();\n"); + + Printf(f->code, "}\n"); + + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, s_wrappers); + DelWrapper(f); + f = NULL; + + if (overloaded && !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + Delete(wname); + wname = NULL; + + if (!shadow) { + return SWIG_OK; + } + + // Handle getters and setters. + if (wrapperType == membervar) { + const char *p = Char(iname); + if (strlen(p) > 4) { + p += strlen(p) - 4; + String *varname = Getattr(n, "membervariableHandler:sym:name"); + if (strcmp(p, "_get") == 0) { + Setattr(shadow_get_vars, varname, Getattr(n, "type")); + } else if (strcmp(p, "_set") == 0) { + Setattr(shadow_set_vars, varname, iname); + } + } + return SWIG_OK; + } + + // Only look at non-overloaded methods and the last entry in each overload + // chain (we check the last so that wrap:parms and wrap:name have been set + // for them all). + if (overloaded && Getattr(n, "sym:nextSibling") != 0) + return SWIG_OK; + + if (!s_oowrappers) + s_oowrappers = NewStringEmpty(); + + if (newobject || wrapperType == memberfn || wrapperType == staticmemberfn || wrapperType == standard || wrapperType == staticmembervar) { + bool handle_as_overload = false; + String **arg_names; + String **arg_values; + unsigned char * byref; + // Method or static method or plain function. + const char *methodname = 0; + String *output = s_oowrappers; + if (constructor) { + class_has_ctor = true; + // Skip the Foo:: prefix. + char *ptr = strrchr(GetChar(current_class, "sym:name"), ':'); + if (ptr) { + ptr++; + } else { + ptr = GetChar(current_class, "sym:name"); + } + if (strcmp(ptr, GetChar(n, "constructorHandler:sym:name")) == 0) { + methodname = "__construct"; + } else { + // The class has multiple constructors and this one is + // renamed, so this will be a static factory function + methodname = GetChar(n, "constructorHandler:sym:name"); + } + } else if (wrapperType == memberfn) { + methodname = Char(Getattr(n, "memberfunctionHandler:sym:name")); + } else if (wrapperType == staticmemberfn) { + methodname = Char(Getattr(n, "staticmemberfunctionHandler:sym:name")); + } else if (wrapperType == staticmembervar) { + // Static member variable, wrapped as a function due to PHP limitations. + methodname = Char(Getattr(n, "staticmembervariableHandler:sym:name")); + } else { // wrapperType == standard + methodname = Char(iname); + if (!s_fakeoowrappers) + s_fakeoowrappers = NewStringEmpty(); + output = s_fakeoowrappers; + } + + bool really_overloaded = overloaded ? true : false; + int min_num_of_arguments = emit_num_required(l); + int max_num_of_arguments = emit_num_arguments(l); + + Hash *ret_types = NewHash(); + Setattr(ret_types, d, d); + + bool non_void_return = (Cmp(d, "void") != 0); + + if (overloaded) { + // Look at all the overloaded versions of this method in turn to + // decide if it's really an overloaded method, or just one where some + // parameters have default values. + Node *o = Getattr(n, "sym:overloaded"); + while (o) { + if (o == n) { + o = Getattr(o, "sym:nextSibling"); + continue; + } + + SwigType *d2 = Getattr(o, "type"); + if (!d2) { + assert(constructor); + } else if (!Getattr(ret_types, d2)) { + Setattr(ret_types, d2, d2); + non_void_return = non_void_return || (Cmp(d2, "void") != 0); + } + + ParmList *l2 = Getattr(o, "wrap:parms"); + int num_arguments = emit_num_arguments(l2); + int num_required = emit_num_required(l2); + if (num_required < min_num_of_arguments) + min_num_of_arguments = num_required; + + if (num_arguments > max_num_of_arguments) { + max_num_of_arguments = num_arguments; + } + o = Getattr(o, "sym:nextSibling"); + } + + o = Getattr(n, "sym:overloaded"); + while (o) { + if (o == n) { + o = Getattr(o, "sym:nextSibling"); + continue; + } + + ParmList *l2 = Getattr(o, "wrap:parms"); + Parm *p = l, *p2 = l2; + if (wrapperType == memberfn) { + p = nextSibling(p); + p2 = nextSibling(p2); + } + while (p && p2) { + if (Cmp(Getattr(p, "type"), Getattr(p2, "type")) != 0) + break; + if (Cmp(Getattr(p, "name"), Getattr(p2, "name")) != 0) + break; + String *value = Getattr(p, "value"); + String *value2 = Getattr(p2, "value"); + if (value && !value2) + break; + if (!value && value2) + break; + if (value) { + if (Cmp(value, value2) != 0) + break; + } + p = nextSibling(p); + p2 = nextSibling(p2); + } + if (p && p2) + break; + // One parameter list is a prefix of the other, so check that all + // remaining parameters of the longer list are optional. + if (p2) + p = p2; + while (p && Getattr(p, "value")) + p = nextSibling(p); + if (p) + break; + o = Getattr(o, "sym:nextSibling"); + } + if (!o) { + // This "overloaded method" is really just one with default args. + really_overloaded = false; + } + } + + if (wrapperType == memberfn) { + // Allow for the "this" pointer. + --min_num_of_arguments; + --max_num_of_arguments; + } + + arg_names = (String **) malloc(max_num_of_arguments * sizeof(String *)); + if (!arg_names) { + /* FIXME: How should this be handled? The rest of SWIG just seems + * to not bother checking for malloc failing! */ + fprintf(stderr, "Malloc failed!\n"); + SWIG_exit(EXIT_FAILURE); + } + for (i = 0; i < max_num_of_arguments; ++i) { + arg_names[i] = NULL; + } + + arg_values = (String **) malloc(max_num_of_arguments * sizeof(String *)); + byref = (unsigned char *) malloc(max_num_of_arguments); + if (!arg_values || !byref) { + /* FIXME: How should this be handled? The rest of SWIG just seems + * to not bother checking for malloc failing! */ + fprintf(stderr, "Malloc failed!\n"); + SWIG_exit(EXIT_FAILURE); + } + for (i = 0; i < max_num_of_arguments; ++i) { + arg_values[i] = NULL; + byref[i] = false; + } + + Node *o; + if (overloaded) { + o = Getattr(n, "sym:overloaded"); + } else { + o = n; + } + while (o) { + int argno = 0; + Parm *p = Getattr(o, "wrap:parms"); + if (wrapperType == memberfn) + p = nextSibling(p); + while (p) { + if (GetInt(p, "tmap:in:numinputs") == 0) { + p = nextSibling(p); + continue; + } + assert(0 <= argno && argno < max_num_of_arguments); + byref[argno] = GetFlag(p, "tmap:in:byref"); + String *&pname = arg_names[argno]; + const char *pname_cstr = GetChar(p, "name"); + // Just get rid of the C++ namespace part for now. + const char *ptr = NULL; + if (pname_cstr && (ptr = strrchr(pname_cstr, ':'))) { + pname_cstr = ptr + 1; + } + if (!pname_cstr) { + // Unnamed parameter, e.g. int foo(int); + } else if (!pname) { + pname = NewString(pname_cstr); + } else { + size_t len = strlen(pname_cstr); + size_t spc = 0; + size_t len_pname = strlen(Char(pname)); + while (spc + len <= len_pname) { + if (strncmp(pname_cstr, Char(pname) + spc, len) == 0) { + char ch = ((char *) Char(pname))[spc + len]; + if (ch == '\0' || ch == ' ') { + // Already have this pname_cstr. + pname_cstr = NULL; + break; + } + } + char *p = strchr(Char(pname) + spc, ' '); + if (!p) + break; + spc = (p + 4) - Char(pname); + } + if (pname_cstr) { + Printf(pname, " or_%s", pname_cstr); + } + } + String *value = NewString(Getattr(p, "value")); + if (Len(value)) { + /* Check that value is a valid constant in PHP (and adjust it if + * necessary, or replace it with "?" if it's just not valid). */ + SwigType *type = Getattr(p, "type"); + switch (SwigType_type(type)) { + case T_BOOL: { + if (Strcmp(value, "true") == 0 || Strcmp(value, "false") == 0) + break; + char *p; + errno = 0; + long n = strtol(Char(value), &p, 0); + Clear(value); + if (errno || *p) { + Append(value, "?"); + } else if (n) { + Append(value, "true"); + } else { + Append(value, "false"); + } + break; + } + case T_CHAR: + case T_SCHAR: + case T_SHORT: + case T_INT: + case T_LONG: + case T_LONGLONG: { + char *p; + errno = 0; + long n = strtol(Char(value), &p, 0); + (void) n; + if (errno || *p) { + Clear(value); + Append(value, "?"); + } + break; + } + case T_UCHAR: + case T_USHORT: + case T_UINT: + case T_ULONG: + case T_ULONGLONG: { + char *p; + errno = 0; + unsigned int n = strtoul(Char(value), &p, 0); + (void) n; + if (errno || *p) { + Clear(value); + Append(value, "?"); + } + break; + } + case T_FLOAT: + case T_DOUBLE: + case T_LONGDOUBLE: { + char *p; + errno = 0; + /* FIXME: strtod is locale dependent... */ + double val = strtod(Char(value), &p); + if (errno || *p) { + Clear(value); + Append(value, "?"); + } else if (strchr(Char(value), '.') == 0) { + // Ensure value is a double constant, not an integer one. + Append(value, ".0"); + double val2 = strtod(Char(value), &p); + if (errno || *p || val != val2) { + Clear(value); + Append(value, "?"); + } + } + break; + } + case T_STRING: + if (Len(value) < 2) { + // How can a string (including "" be less than 2 characters?) + Clear(value); + Append(value, "?"); + } else { + const char *v = Char(value); + if (v[0] != '"' || v[Len(value) - 1] != '"') { + Clear(value); + Append(value, "?"); + } + // Strings containing "$" require special handling, but we do + // that later. + } + break; + case T_VOID: + assert(false); + break; + case T_POINTER: { + const char *v = Char(value); + if (v[0] == '(') { + // Handle "(void*)0", "(TYPE*)0", "(char*)NULL", etc. + v += strcspn(v + 1, "*()") + 1; + if (*v == '*') { + do { + v++; + v += strspn(v, " \t"); + } while (*v == '*'); + if (*v++ == ')') { + v += strspn(v, " \t"); + String * old = value; + value = NewString(v); + Delete(old); + } + } + } + if (Strcmp(value, "NULL") == 0 || + Strcmp(value, "nullptr") == 0 || + Strcmp(value, "0") == 0 || + Strcmp(value, "0L") == 0) { + Clear(value); + Append(value, "null"); + } else { + Clear(value); + Append(value, "?"); + } + break; + } + default: + /* Safe default */ + Clear(value); + Append(value, "?"); + break; + } + + if (!arg_values[argno]) { + arg_values[argno] = value; + value = NULL; + } else if (Cmp(arg_values[argno], value) != 0) { + // If a parameter has two different default values in + // different overloaded forms of the function, we can't + // set its default in PHP. Flag this by setting its + // default to `?'. + Delete(arg_values[argno]); + arg_values[argno] = NewString("?"); + } + } else if (arg_values[argno]) { + // This argument already has a default value in another overloaded + // form, but doesn't in this form. So don't try to do anything + // clever, just let the C wrappers resolve the overload and set the + // default values. + // + // This handling is safe, but I'm wondering if it may be overly + // conservative (FIXME) in some cases. It seems it's only bad when + // there's an overloaded form with the appropriate number of + // parameters which doesn't want the default value, but I need to + // think about this more. + Delete(arg_values[argno]); + arg_values[argno] = NewString("?"); + } + Delete(value); + p = nextSibling(p); + ++argno; + } + if (!really_overloaded) + break; + o = Getattr(o, "sym:nextSibling"); + } + + /* Clean up any parameters which haven't yet got names, or whose + * names clash. */ + Hash *seen = NewHash(); + /* We need $this to refer to the current class, so can't allow it + * to be used as a parameter. */ + Setattr(seen, "this", seen); + + for (int argno = 0; argno < max_num_of_arguments; ++argno) { + String *&pname = arg_names[argno]; + if (pname) { + Replaceall(pname, " ", "_"); + } else { + /* We get here if the SWIG .i file has "int foo(int);" */ + pname = NewStringEmpty(); + Printf(pname, "arg%d", argno + 1); + } + // Check if we've already used this parameter name. + while (Getattr(seen, pname)) { + // Append "_" to clashing names until they stop clashing... + Printf(pname, "_"); + } + Setattr(seen, Char(pname), seen); + + if (arg_values[argno] && Cmp(arg_values[argno], "?") == 0) { + handle_as_overload = true; + } + } + Delete(seen); + seen = NULL; + + String *invoke = NewStringEmpty(); + String *prepare = NewStringEmpty(); + String *args = NewStringEmpty(); + + if (!handle_as_overload && !(really_overloaded && max_num_of_arguments > min_num_of_arguments)) { + Printf(invoke, "%s(", iname); + if (wrapperType == memberfn) { + Printf(invoke, "$this->%s", SWIG_PTR); + } + for (int i = 0; i < max_num_of_arguments; ++i) { + if (i) + Printf(args, ","); + if (i || wrapperType == memberfn) + Printf(invoke, ","); + if (byref[i]) Printf(args, "&"); + String *value = arg_values[i]; + if (value) { + const char *v = Char(value); + if (v[0] == '"') { + /* In a PHP double quoted string, $ needs to be escaped as \$. */ + Replaceall(value, "$", "\\$"); + } + Printf(args, "$%s=%s", arg_names[i], value); + } else if (constructor && strcmp(methodname, "__construct") == 0 && i >= 1 && i < min_num_of_arguments) { + // We need to be able to call __construct($resource). + Printf(args, "$%s=null", arg_names[i]); + } else { + Printf(args, "$%s", arg_names[i]); + } + Printf(invoke, "$%s", arg_names[i]); + } + Printf(invoke, ")"); + } else { + int i; + for (i = 0; i < min_num_of_arguments; ++i) { + if (i) + Printf(args, ","); + Printf(args, "$%s", arg_names[i]); + } + String *invoke_args = NewStringEmpty(); + if (wrapperType == memberfn) { + Printf(invoke_args, "$this->%s", SWIG_PTR); + if (min_num_of_arguments > 0) + Printf(invoke_args, ","); + } + Printf(invoke_args, "%s", args); + if (constructor && min_num_of_arguments > 1) { + // We need to be able to call __construct($resource). + Clear(args); + Printf(args, "$%s", arg_names[0]); + for (i = 1; i < min_num_of_arguments; ++i) { + Printf(args, ","); + Printf(args, "$%s=null", arg_names[i]); + } + } + bool had_a_case = false; + int last_handled_i = i - 1; + for (; i < max_num_of_arguments; ++i) { + if (i) + Printf(args, ","); + const char *value = Char(arg_values[i]); + // FIXME: (really_overloaded && handle_as_overload) is perhaps a + // little conservative, but it doesn't hit any cases that it + // shouldn't for Xapian at least (and we need it to handle + // "Enquire::get_mset()" correctly). + bool non_php_default = ((really_overloaded && handle_as_overload) || + !value || strcmp(value, "?") == 0); + if (non_php_default) + value = "null"; + Printf(args, "$%s=%s", arg_names[i], value); + if (non_php_default) { + if (!had_a_case) { + Printf(prepare, "\t\tswitch (func_num_args()) {\n"); + had_a_case = true; + } + Printf(prepare, "\t\t"); + while (last_handled_i < i) { + Printf(prepare, "case %d: ", ++last_handled_i); + } + if (non_void_return) { + if ((!directorsEnabled() || !Swig_directorclass(n)) && !constructor) { + Append(prepare, "$r="); + } else if (wrapperType == staticmemberfn || wrapperType == staticmembervar) { + Append(prepare, "$r="); + } else { + Printf(prepare, "$this->%s=", SWIG_PTR); + } + } + if (!directorsEnabled() || !Swig_directorclass(n) || !constructor) { + Printf(prepare, "%s(%s); break;\n", iname, invoke_args); + } else if (!i) { + Printf(prepare, "%s($_this%s); break;\n", iname, invoke_args); + } else { + Printf(prepare, "%s($_this, %s); break;\n", iname, invoke_args); + } + } + if (i || wrapperType == memberfn) + Printf(invoke_args, ","); + Printf(invoke_args, "$%s", arg_names[i]); + } + Printf(prepare, "\t\t"); + if (had_a_case) + Printf(prepare, "default: "); + if (non_void_return) { + if ((!directorsEnabled() || !Swig_directorclass(n)) && !constructor) { + Append(prepare, "$r="); + } else if (wrapperType == staticmemberfn || wrapperType == staticmembervar) { + Append(prepare, "$r="); + } else { + Printf(prepare, "$this->%s=", SWIG_PTR); + } + } + + if (!directorsEnabled() || !Swig_directorclass(n) || !constructor) { + Printf(prepare, "%s(%s);\n", iname, invoke_args); + } else { + Printf(prepare, "%s($_this, %s);\n", iname, invoke_args); + } + if (had_a_case) + Printf(prepare, "\t\t}\n"); + Delete(invoke_args); + Printf(invoke, "$r"); + } + + Printf(output, "\n"); + // If it's a member function or a class constructor... + if (wrapperType == memberfn || (constructor && current_class)) { + String *acc = NewString(Getattr(n, "access")); + // If a base has the same method with public access, then PHP + // requires to have it here as public as well + Node *bases = Getattr(Swig_methodclass(n), "bases"); + if (bases && Strcmp(acc, "public") != 0) { + String *warnmsg = 0; + int haspublicbase = 0; + Iterator i = First(bases); + while (i.item) { + Node *j = firstChild(i.item); + while (j) { + String *jname = Getattr(j, "name"); + if (!jname || Strcmp(jname, Getattr(n, "name")) != 0) { + j = nextSibling(j); + continue; + } + if (Strcmp(nodeType(j), "cdecl") == 0) { + if (!Getattr(j, "access") || checkAttribute(j, "access", "public")) { + haspublicbase = 1; + } + } else if (Strcmp(nodeType(j), "using") == 0 && firstChild(j) && Strcmp(nodeType(firstChild(j)), "cdecl") == 0) { + if (!Getattr(firstChild(j), "access") || checkAttribute(firstChild(j), "access", "public")) { + haspublicbase = 1; + } + } + if (haspublicbase) { + warnmsg = NewStringf("Modifying the access of '%s::%s' to public, as the base '%s' has it as public as well.\n", Getattr(current_class, "classtype"), Getattr(n, "name"), Getattr(i.item, "classtype")); + break; + } + j = nextSibling(j); + } + i = Next(i); + if (haspublicbase) { + break; + } + } + if (Getattr(n, "access") && haspublicbase) { + Delete(acc); + acc = NewStringEmpty(); // implicitly public + Swig_warning(WARN_PHP_PUBLIC_BASE, input_file, line_number, Char(warnmsg)); + Delete(warnmsg); + } + } + + if (Cmp(acc, "public") == 0) { + // The default visibility for methods is public, so don't specify + // that explicitly to keep the wrapper size down. + Delete(acc); + acc = NewStringEmpty(); + } else if (Cmp(acc, "") != 0) { + Append(acc, " "); + } + + if (constructor) { + // Discriminate between the PHP constructor and a C++ constructor + // renamed to become a factory function in PHP. + bool php_constructor = (strcmp(methodname, "__construct") == 0); + const char * arg0 = NULL; + if (max_num_of_arguments > 0) { + arg0 = Char(arg_names[0]); + } else if (php_constructor) { + // The PHP constructor needs to be able to wrap a resource, but a + // renamed constructor doesn't. + arg0 = "res"; + Delete(args); + args = NewString("$res=null"); + } + String *mangled_type = SwigType_manglestr(Getattr(n, "type")); + if (!php_constructor) { + // A renamed constructor should be a static method. + Append(acc, "static "); + } + Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args); + if (php_constructor) { + // The PHP constructor needs to be able to wrap a resource, but a + // renamed constructor doesn't. + Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '%s') {\n", arg0, arg0, mangled_type); + Printf(output, "\t\t\t$this->%s=$%s;\n", SWIG_PTR, arg0); + Printf(output, "\t\t\treturn;\n"); + Printf(output, "\t\t}\n"); + } + } else { + Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args); + } + Delete(acc); + } else if (wrapperType == staticmembervar) { + // We're called twice for a writable static member variable - first + // with "foo_set" and then with "foo_get" - so generate half the + // wrapper function each time. + // + // For a const static member, we only get called once. + static bool started = false; + if (!started) { + Printf(output, "\tstatic function %s() {\n", methodname); + if (max_num_of_arguments) { + // Setter. + Printf(output, "\t\tif (func_num_args()) {\n"); + Printf(output, "\t\t\t%s(func_get_arg(0));\n", iname); + Printf(output, "\t\t\treturn;\n"); + Printf(output, "\t\t}\n"); + started = true; + goto done; + } + } + started = false; + } else { + Printf(output, "\tstatic function %s(%s) {\n", methodname, args); + } + + if (!constructor) + Printf(output, "%s", prepare); + if (constructor) { + if (!directorsEnabled() || !Swig_directorclass(n)) { + if (!Len(prepare)) { + if (strcmp(methodname, "__construct") == 0) { + Printf(output, "\t\t$this->%s=%s;\n", SWIG_PTR, invoke); + } else { + String *classname = Swig_class_name(current_class); + Printf(output, "\t\treturn new %s%s(%s);\n", prefix, classname, invoke); + } + } + } else { + Node *parent = Swig_methodclass(n); + String *classname = Swig_class_name(parent); + Printf(output, "\t\tif (get_class($this) === '%s%s') {\n", prefix, classname); + Printf(output, "\t\t\t$_this = null;\n"); + Printf(output, "\t\t} else {\n"); + Printf(output, "\t\t\t$_this = $this;\n"); + Printf(output, "\t\t}\n"); + if (!Len(prepare)) { + if (num_arguments > 1) { + Printf(output, "\t\t$this->%s=%s($_this, %s);\n", SWIG_PTR, iname, args); + } else { + Printf(output, "\t\t$this->%s=%s($_this);\n", SWIG_PTR, iname); + } + } + } + Printf(output, "%s", prepare); + } else if (!non_void_return && !hasargout) { + if (Cmp(invoke, "$r") != 0) + Printf(output, "\t\t%s;\n", invoke); + } else if (is_class(d)) { + if (Cmp(invoke, "$r") != 0) + Printf(output, "\t\t$r=%s;\n", invoke); + if (Len(ret_types) == 1) { + /* If d is abstract we can't create a new wrapper type d. */ + Node *d_class = classLookup(d); + int is_abstract = 0; + if (Getattr(d_class, "abstracts")) { + is_abstract = 1; + } + if (newobject || !is_abstract) { + Printf(output, "\t\tif (is_resource($r)) {\n"); + if (Getattr(classLookup(Getattr(n, "type")), "module")) { + /* + * _p_Foo -> Foo, _p_ns__Bar -> Bar + * TODO: do this in a more elegant way + */ + if (Len(prefix) == 0) { + Printf(output, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n"); + } else { + Printf(output, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix); + } + Printf(output, "\t\t\tif (class_exists($c)) return new $c($r);\n"); + Printf(output, "\t\t\treturn new %s%s($r);\n", prefix, Getattr(classLookup(d), "sym:name")); + } else { + Printf(output, "\t\t\t$c = new stdClass();\n"); + Printf(output, "\t\t\t$c->" SWIG_PTR " = $r;\n"); + Printf(output, "\t\t\treturn $c;\n"); + } + Printf(output, "\t\t}\n\t\treturn $r;\n"); + } else { + Printf(output, "\t\t$this->%s = $r;\n", SWIG_PTR); + Printf(output, "\t\treturn $this;\n"); + } + } else { + Printf(output, "\t\tif (!is_resource($r)) return $r;\n"); + String *wrapobj = NULL; + String *common = NULL; + Iterator i = First(ret_types); + while (i.item) { + SwigType *ret_type = i.item; + i = Next(i); + String *mangled = NewString("_p"); + Printf(mangled, "%s", SwigType_manglestr(ret_type)); + Node *class_node = Getattr(zend_types, mangled); + if (!class_node) { + /* This is needed when we're returning a pointer to a type + * rather than returning the type by value or reference. */ + Delete(mangled); + mangled = NewString(SwigType_manglestr(ret_type)); + class_node = Getattr(zend_types, mangled); + if (!class_node) { + // Return type isn't an object, so will be handled by the + // !is_resource() check before the switch. + continue; + } + } + const char *classname = GetChar(class_node, "sym:name"); + if (!classname) + classname = GetChar(class_node, "name"); + String * action = NewStringEmpty(); + if (classname) + Printf(action, "return new %s%s($r);\n", prefix, classname); + else + Printf(action, "return $r;\n"); + if (!wrapobj) { + wrapobj = NewString("\t\tswitch (get_resource_type($r)) {\n"); + common = action; + } else { + if (common && Cmp(common, action) != 0) { + Delete(common); + common = NULL; + } + } + Printf(wrapobj, "\t\t"); + if (i.item) { + Printf(wrapobj, "case '%s': ", mangled); + } else { + Printf(wrapobj, "default: "); + } + Printv(wrapobj, action, NIL); + if (action != common) Delete(action); + Delete(mangled); + } + Printf(wrapobj, "\t\t}\n"); + if (common) { + // All cases have the same action, so eliminate the switch + // wrapper. + Printf(output, "\t\t%s", common); + Delete(common); + } else { + Printv(output, wrapobj, NIL); + } + Delete(wrapobj); + } + } else { + if (non_void_return || hasargout) { + Printf(output, "\t\treturn %s;\n", invoke); + } else if (Cmp(invoke, "$r") != 0) { + Printf(output, "\t\t%s;\n", invoke); + } + } + Printf(output, "\t}\n"); + +done: + Delete(prepare); + Delete(invoke); + free(arg_values); + + Delete(args); + args = NULL; + + for (int i = 0; i < max_num_of_arguments; ++i) { + Delete(arg_names[i]); + } + free(arg_names); + arg_names = NULL; + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * globalvariableHandler() + * ------------------------------------------------------------ */ + + virtual int globalvariableHandler(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + String *tm; + + /* First do the wrappers such as name_set(), name_get() + * as provided by the baseclass's implementation of variableWrapper + */ + if (Language::globalvariableHandler(n) == SWIG_NOWRAP) { + return SWIG_NOWRAP; + } + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* First link C variables to PHP */ + + tm = Swig_typemap_lookup("varinit", n, name, 0); + if (tm) { + Replaceall(tm, "$target", name); + Printf(s_vinit, "%s\n", tm); + } else { + Swig_error(input_file, line_number, "Unable to link with type %s\n", SwigType_str(t, 0)); + } + + /* Now generate PHP -> C sync blocks */ + /* + tm = Swig_typemap_lookup("varin", n, name, 0); + if(tm) { + Replaceall(tm, "$symname", iname); + Printf(f_c->code, "%s\n", tm); + } else { + Swig_error(input_file, line_number, "Unable to link with type %s\n", SwigType_str(t, 0)); + } + */ + /* Now generate C -> PHP sync blocks */ + /* + if(!GetFlag(n,"feature:immutable")) { + + tm = Swig_typemap_lookup("varout", n, name, 0); + if(tm) { + Replaceall(tm, "$symname", iname); + Printf(f_php->code, "%s\n", tm); + } else { + Swig_error(input_file, line_number, "Unable to link with type %s\n", SwigType_str(t, 0)); + } + } + */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = GetChar(n, "name"); + String *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + SwigType_remember(type); + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Printf(s_cinit, "%s\n", tm); + } + + if (shadow) { + String *enumvalue = GetChar(n, "enumvalue"); + String *set_to = iname; + + if (!enumvalue) { + enumvalue = GetChar(n, "enumvalueex"); + } + + if (enumvalue && *Char(enumvalue)) { + // Check for a simple constant expression which is valid in PHP. + // If we find one, initialise the const member with it; otherwise + // we initialise it using the C/C++ wrapped constant. + const char *p; + for (p = Char(enumvalue); *p; ++p) { + if (!isdigit((unsigned char)*p) && !strchr(" +-", *p)) { + // FIXME: enhance to handle `<previous_enum> + 1' which is what + // we get for enums that don't have an explicit value set. + break; + } + } + if (!*p) + set_to = enumvalue; + } + + if (wrapping_member_constant) { + if (!s_oowrappers) + s_oowrappers = NewStringEmpty(); + Printf(s_oowrappers, "\n\tconst %s = %s;\n", wrapping_member_constant, set_to); + } else { + if (!s_fakeoowrappers) + s_fakeoowrappers = NewStringEmpty(); + Printf(s_fakeoowrappers, "\n\tconst %s = %s;\n", iname, set_to); + } + } + + return SWIG_OK; + } + + /* + * PHP::pragma() + * + * Pragma directive. + * + * %pragma(php) code="String" # Includes a string in the .php file + * %pragma(php) include="file.php" # Includes a file in the .php file + */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *type = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "php") == 0) { + if (Strcmp(type, "code") == 0) { + if (value) { + Printf(pragma_code, "%s\n", value); + } + } else if (Strcmp(type, "include") == 0) { + if (value) { + Printf(pragma_incl, "include '%s';\n", value); + } + } else if (Strcmp(type, "phpinfo") == 0) { + if (value) { + Printf(pragma_phpinfo, "%s\n", value); + } + } else if (Strcmp(type, "version") == 0) { + if (value) { + pragma_version = value; + } + } else { + Swig_warning(WARN_PHP_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", type); + } + } + } + return Language::pragmaDirective(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + if (!Getattr(n, "feature:onlychildren")) { + String *symname = Getattr(n, "sym:name"); + Setattr(n, "php:proxy", symname); + } + + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + constructors = 0; + current_class = n; + + if (shadow) { + char *rename = GetChar(n, "sym:name"); + + if (!addSymbol(rename, n)) + return SWIG_ERROR; + shadow_classname = NewString(rename); + + shadow_get_vars = NewHash(); + shadow_set_vars = NewHash(); + + /* Deal with inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + base = Next(base); + if (base.item) { + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_PHP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s, base %s ignored. Multiple inheritance is not supported in PHP.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + classnode = n; + Language::classHandler(n); + classnode = 0; + + if (shadow) { + List *baselist = Getattr(n, "bases"); + Iterator ki, base; + + if (baselist) { + base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + } else { + base.item = NULL; + } + + if (Getattr(n, "abstracts") && !GetFlag(n, "feature:notabstract")) { + Printf(s_phpclasses, "abstract "); + } + + Printf(s_phpclasses, "class %s%s ", prefix, shadow_classname); + String *baseclass = NULL; + if (base.item && Getattr(base.item, "module")) { + baseclass = Getattr(base.item, "sym:name"); + if (!baseclass) + baseclass = Getattr(base.item, "name"); + Printf(s_phpclasses, "extends %s%s ", prefix, baseclass); + } else if (GetFlag(n, "feature:exceptionclass")) { + Append(s_phpclasses, "extends Exception "); + } + { + Node *node = NewHash(); + Setattr(node, "type", Getattr(n, "name")); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + String * interfaces = Swig_typemap_lookup("phpinterfaces", node, "", 0); + if (interfaces) { + Printf(s_phpclasses, "implements %s ", interfaces); + } + Delete(node); + } + Printf(s_phpclasses, "{\n\tpublic $%s=null;\n", SWIG_PTR); + if (!baseclass) { + // Only store this in the base class (NB !baseclass means we *are* + // a base class...) + Printf(s_phpclasses, "\tprotected $%s=array();\n", SWIG_DATA); + } + + // Write property SET handlers + ki = First(shadow_set_vars); + if (ki.key) { + // This class has setters. + Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n"); + // FIXME: tune this threshold... + if (Len(shadow_set_vars) <= 2) { + // Not many setters, so avoid call_user_func. + for (; ki.key; ki = Next(ki)) { + DOH *key = ki.key; + String *iname = ki.item; + Printf(s_phpclasses, "\t\tif ($var === '%s') return %s($this->%s,$value);\n", key, iname, SWIG_PTR); + } + } else { + Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_set';\n", shadow_classname); + Printf(s_phpclasses, "\t\tif (function_exists($func)) return call_user_func($func,$this->%s,$value);\n", SWIG_PTR); + } + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } else { + Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } + + // Write property GET handlers + ki = First(shadow_get_vars); + if (ki.key) { + // This class has getters. + Printf(s_phpclasses, "\n\tfunction __get($var) {\n"); + int non_class_getters = 0; + for (; ki.key; ki = Next(ki)) { + DOH *key = ki.key; + SwigType *d = ki.item; + if (!is_class(d)) { + ++non_class_getters; + continue; + } + Printv(s_phpclasses, "\t\tif ($var === '", key, "') return new ", prefix, Getattr(classLookup(d), "sym:name"), "(", shadow_classname, "_", key, "_get($this->", SWIG_PTR, "));\n", NIL); + } + // FIXME: tune this threshold... + if (non_class_getters <= 2) { + // Not many non-class getters, so avoid call_user_func. + for (ki = First(shadow_get_vars); non_class_getters && ki.key; ki = Next(ki)) { + DOH *key = ki.key; + SwigType *d = ki.item; + if (is_class(d)) continue; + Printv(s_phpclasses, "\t\tif ($var === '", key, "') return ", shadow_classname, "_", key, "_get($this->", SWIG_PTR, ");\n", NIL); + --non_class_getters; + } + } else { + Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_get';\n", shadow_classname); + Printf(s_phpclasses, "\t\tif (function_exists($func)) return call_user_func($func,$this->%s);\n", SWIG_PTR); + } + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass); + } else { + // Reading an unknown property name gives null in PHP. + Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + + /* __isset() should return true for read-only properties, so check for + * *_get() not *_set(). */ + Printf(s_phpclasses, "\n\tfunction __isset($var) {\n"); + Printf(s_phpclasses, "\t\tif (function_exists('%s_'.$var.'_get')) return true;\n", shadow_classname); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n"); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } else { + Printf(s_phpclasses, "\n\tfunction __get($var) {\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + Printf(s_phpclasses, "\n\tfunction __isset($var) {\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n"); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } + + if (!class_has_ctor) { + Printf(s_phpclasses, "\tfunction __construct($h) {\n"); + Printf(s_phpclasses, "\t\t$this->%s=$h;\n", SWIG_PTR); + Printf(s_phpclasses, "\t}\n"); + } + + if (s_oowrappers) { + Printf(s_phpclasses, "%s", s_oowrappers); + Delete(s_oowrappers); + s_oowrappers = NULL; + } + class_has_ctor = false; + + Printf(s_phpclasses, "}\n\n"); + + Delete(shadow_classname); + shadow_classname = NULL; + + Delete(shadow_set_vars); + shadow_set_vars = NULL; + Delete(shadow_get_vars); + shadow_get_vars = NULL; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + wrapperType = memberfn; + Language::memberfunctionHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + wrapperType = membervar; + Language::membervariableHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + wrapperType = staticmembervar; + Language::staticmembervariableHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + wrapperType = staticmemberfn; + Language::staticmemberfunctionHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + int abstractConstructorHandler(Node *) { + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + constructors++; + if (Swig_directorclass(n)) { + String *name = GetChar(Swig_methodclass(n), "name"); + String *ctype = GetChar(Swig_methodclass(n), "classtype"); + String *sname = GetChar(Swig_methodclass(n), "sym:name"); + String *args = NewStringEmpty(); + ParmList *p = Getattr(n, "parms"); + int i; + + for (i = 0; p; p = nextSibling(p), i++) { + if (i) { + Printf(args, ", "); + } + if (Strcmp(GetChar(p, "type"), SwigType_str(GetChar(p, "type"), 0))) { + SwigType *t = Getattr(p, "type"); + Printf(args, "%s", SwigType_rcaststr(t, 0)); + if (SwigType_isreference(t)) { + Append(args, "*"); + } + } + Printf(args, "arg%d", i+1); + } + + /* director ctor code is specific for each class */ + Delete(director_ctor_code); + director_ctor_code = NewStringEmpty(); + director_prot_ctor_code = NewStringEmpty(); + Printf(director_ctor_code, "if (Z_TYPE_P(arg0) == IS_NULL) { /* not subclassed */\n"); + Printf(director_prot_ctor_code, "if (Z_TYPE_P(arg0) == IS_NULL) { /* not subclassed */\n"); + Printf(director_ctor_code, " %s = (%s *)new %s(%s);\n", Swig_cresult_name(), ctype, ctype, args); + Printf(director_prot_ctor_code, " SWIG_PHP_Error(E_ERROR, \"accessing abstract class or protected constructor\");\n", name, name, args); + if (i) { + Insert(args, 0, ", "); + } + Printf(director_ctor_code, "} else {\n %s = (%s *)new SwigDirector_%s(arg0%s);\n}\n", Swig_cresult_name(), ctype, sname, args); + Printf(director_prot_ctor_code, "} else {\n %s = (%s *)new SwigDirector_%s(arg0%s);\n}\n", Swig_cresult_name(), ctype, sname, args); + Delete(args); + + wrapperType = directorconstructor; + } else { + wrapperType = constructor; + } + Language::constructorHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * CreateZendListDestructor() + * ------------------------------------------------------------ */ + //virtual int destructorHandler(Node *n) { + //} + int CreateZendListDestructor(Node *n) { + String *name = GetChar(Swig_methodclass(n), "name"); + String *iname = GetChar(n, "sym:name"); + ParmList *l = Getattr(n, "parms"); + + String *destructorname = NewStringEmpty(); + Printf(destructorname, "_%s", Swig_name_wrapper(iname)); + Setattr(classnode, "destructor", destructorname); + + Wrapper *f = NewWrapper(); + Printf(f->def, "/* This function is designed to be called by the zend list destructors */\n"); + Printf(f->def, "/* to typecast and do the actual destruction */\n"); + Printf(f->def, "static void %s(zend_resource *res, const char *type_name) {\n", destructorname); + + Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) res->ptr", NIL); + Wrapper_add_localv(f, "ptr", "void *ptr=value->ptr", NIL); + Wrapper_add_localv(f, "newobject", "int newobject=value->newobject", NIL); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l, f); + + // Get type of first arg, thing to be destructed + // Skip ignored arguments + Parm *p = l; + //while (Getattr(p,"tmap:ignore")) {p = Getattr(p,"tmap:ignore:next");} + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + SwigType *pt = Getattr(p, "type"); + + Printf(f->code, " efree(value);\n"); + Printf(f->code, " if (! newobject) return; /* can't delete it! */\n"); + Printf(f->code, " arg1 = (%s)SWIG_ConvertResourceData(ptr, type_name, SWIGTYPE%s);\n", SwigType_lstr(pt, 0), SwigType_manglestr(pt)); + Printf(f->code, " if (! arg1) zend_error(E_ERROR, \"%s resource already free'd\");\n", Char(name)); + + Setattr(n, "wrap:name", destructorname); + + String *actioncode = emit_action(n); + Append(f->code, actioncode); + Delete(actioncode); + + Printf(f->code, "thrown:\n"); + Append(f->code, "return;\n"); + Append(f->code, "fail:\n"); + Append(f->code, "SWIG_FAIL();\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, s_wrappers); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + wrapping_member_constant = Getattr(n, "sym:name"); + Language::memberconstantHandler(n); + wrapping_member_constant = NULL; + return SWIG_OK; + } + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n"); + return Language::classDirectorEnd(n); + } + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewStringEmpty(); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("zval"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self"), n); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + // There should always be a "self" parameter first. + assert(ParmList_len(parms) > 0); + + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + + String *target = Swig_method_decl(0, decl, classname, parms, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) {", classname, target, call); + Append(w->def, "}"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + return Language::classDirectorConstructor(n); + } + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl = Getattr(n, "decl"); + String *returntype = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *symname = Getattr(n, "sym:name"); + String *declaration = NewStringEmpty(); + ParmList *l = Getattr(n, "parms"); + Wrapper *w = NewWrapper(); + String *tm; + String *wrap_args = NewStringEmpty(); + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + /* determine if the method returns a pointer */ + is_pointer = SwigType_ispointer_return(decl); + is_void = (Cmp(returntype, "void") == 0 && !is_pointer); + + /* virtual method definition */ + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + 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); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + 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, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($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 { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(returntype, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> PHP) */ + String *parse_args = NewStringEmpty(); + + Swig_director_parms_fixup(l); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; + p = l; + while (p) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + String *parse = Getattr(p, "tmap:directorin:parse"); + if (!parse) { + String *input = NewStringf("&args[%d]", idx++); + Setattr(p, "emit:directorinput", input); + Replaceall(tm, "$input", input); + Delete(input); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, tm, "\n", NIL); + Putc('O', parse_args); + } else { + Append(parse_args, parse); + Setattr(p, "emit:directorinput", pname); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + } + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + p = nextSibling(p); + } + + /* exception handling */ + bool error_used_in_typemap = false; + tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + if (Replaceall(tm, "$error", "error")) { + /* Only declare error if it is used by the typemap. */ + error_used_in_typemap = true; + Append(w->code, "int error;\n"); + } + } else { + Delete(tm); + tm = NULL; + } + + if (!idx) { + Printf(w->code, "zval *args = NULL;\n"); + } else { + Printf(w->code, "zval args[%d];\n", idx); + } + // typemap_directorout testcase requires that 0 can be assigned to the + // variable named after the result of Swig_cresult_name(), so that can't + // be a zval - make it a pointer to one instead. + Printf(w->code, "zval swig_zval_result, swig_funcname;\n", Swig_cresult_name()); + Printf(w->code, "zval * SWIGUNUSED %s = &swig_zval_result;\n", Swig_cresult_name()); + const char * funcname = GetChar(n, "sym:name"); + Printf(w->code, "ZVAL_STRINGL(&swig_funcname, \"%s\", %d);\n", funcname, strlen(funcname)); + + /* wrap complex arguments to zvals */ + Printv(w->code, wrap_args, NIL); + + if (error_used_in_typemap) { + Append(w->code, "error = "); + } + Append(w->code, "call_user_function(EG(function_table), &swig_self, &swig_funcname,"); + Printf(w->code, " &swig_zval_result, %d, args);\n", idx); + + if (tm) { + Printv(w->code, Str(tm), "\n", NIL); + Delete(tm); + } + + /* marshal return value from PHP to C/C++ type */ + + String *cleanup = NewStringEmpty(); + String *outarg = NewStringEmpty(); + + idx = 0; + + /* marshal return value */ + if (!is_void) { + tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); + if (tm != 0) { + Replaceall(tm, "$input", Swig_cresult_name()); + char temp[24]; + sprintf(temp, "%d", idx); + Replaceall(tm, "$argnum", temp); + + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), SwigType_namestr(c_classname), + SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + Replaceall(tm, "$result", Swig_cresult_name()); + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(parse_args); + Delete(cleanup); + Delete(outarg); + } + + Append(w->code, "thrown:\n"); + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(returntype, 0); + if (!SwigType_isreference(returntype)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } else { + Append(w->code, "return;\n"); + } + + Append(w->code, "fail:\n"); + Append(w->code, "SWIG_FAIL();\n"); + Append(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewStringEmpty(); + 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) { + 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); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(pclassname); + DelWrapper(w); + return status; + } + + int classDirectorDisown(Node *) { + return SWIG_OK; + } +}; /* class PHP */ + +static PHP *maininstance = 0; + +// We use this function to be able to write out zend_register_list_destructor_ex +// lines for most things in the type table +// NOTE: it's a function NOT A PHP::METHOD +extern "C" { +static void typetrace(const SwigType *ty, String *mangled, String *clientdata) { + Node *class_node; + if (!zend_types) { + zend_types = NewHash(); + } + // we want to know if the type which reduced to this has a constructor + if ((class_node = maininstance->classLookup(ty))) { + if (!Getattr(zend_types, mangled)) { + // OK it may have been set before by a different SwigType but it would + // have had the same underlying class node I think + // - it is certainly required not to have different originating class + // nodes for the same SwigType + Setattr(zend_types, mangled, class_node); + } + } else { // a non-class pointer + Setattr(zend_types, mangled, NOTCLASS); + } + if (r_prevtracefunc) + (*r_prevtracefunc) (ty, mangled, (String *) clientdata); +} +} + +/* ----------------------------------------------------------------------------- + * new_swig_php() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_php() { + maininstance = new PHP; + if (!r_prevtracefunc) { + r_prevtracefunc = SwigType_remember_trace(typetrace); + } else { + Printf(stderr, "php Typetrace vector already saved!\n"); + assert(0); + } + return maininstance; +} + +extern "C" Language *swig_php(void) { + return new_swig_php(); +} diff --git a/contrib/tools/swig/Source/Modules/python.cxx b/contrib/tools/swig/Source/Modules/python.cxx new file mode 100644 index 00000000000..c8c45df35c4 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/python.cxx @@ -0,0 +1,5718 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * python.cxx + * + * Python language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <limits.h> +#include "cparse.h" +#include <ctype.h> +#include <errno.h> +#include "pydoc.h" + +#include <stdint.h> + +#define PYSHADOW_MEMBER 0x2 +#define WARN_PYTHON_MULTIPLE_INH 405 + +#define PYTHON_INT_MAX (2147483647) +#define PYTHON_INT_MIN (-2147483647-1) + +static String *const_code = 0; +static String *module = 0; +static String *package = 0; +static String *mainmodule = 0; +static String *interface = 0; +static String *global_name = 0; +static int shadow = 1; +static int use_kw = 0; +static int director_method_index = 0; +static int builtin = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_shadow_py = 0; +static String *f_shadow = 0; +static String *f_shadow_begin = 0; +static Hash *f_shadow_imports = 0; +static String *f_shadow_after_begin = 0; +static String *f_shadow_stubs = 0; +static Hash *builtin_getset = 0; +static Hash *builtin_closures = 0; +static Hash *class_members = 0; +static File *f_builtins = 0; +static String *builtin_tp_init = 0; +static String *builtin_methods = 0; +static String *builtin_default_unref = 0; +static String *builtin_closures_code = 0; + +static String *methods; +static String *methods_proxydocs; +static String *class_name; +static String *shadow_indent = 0; +static int in_class = 0; +static int no_header_file = 0; +static int max_bases = 0; +static int builtin_bases_needed = 0; + +static int py3 = 0; + +/* C++ Support + Shadow Classes */ + +static int have_constructor; +static int have_repr; +static String *real_classname; + +/* Thread Support */ +static int threads = 0; +static int nothreads = 0; + +/* Other options */ +static int dirvtable = 0; +static int doxygen = 0; +static int fastunpack = 1; +static int fastproxy = 0; +static int olddefs = 0; +static int castmode = 0; +static int extranative = 0; +static int nortti = 0; +static int relativeimport = 0; + +/* flags for the make_autodoc function */ +enum autodoc_t { + AUTODOC_CLASS, + AUTODOC_CTOR, + AUTODOC_DTOR, + AUTODOC_STATICFUNC, + AUTODOC_FUNC, + AUTODOC_METHOD, + AUTODOC_CONST, + AUTODOC_VAR +}; + + +static const char *usage1 = "\ +Python Options (available with -python)\n\ + -builtin - Create Python built-in types rather than proxy classes, for better performance\n\ + -castmode - Enable the casting mode, which allows implicit cast between types in Python\n\ + -debug-doxygen-parser - Display doxygen parser module debugging information\n\ + -debug-doxygen-translator - Display doxygen translator module debugging information\n\ + -dirvtable - Generate a pseudo virtual table for directors for faster dispatch\n\ + -doxygen - Convert C++ doxygen comments to pydoc comments in proxy classes\n\ + -extranative - Return extra native wrappers for C++ std containers wherever possible\n\ + -fastproxy - Use fast proxy mechanism for member methods\n\ + -globals <name> - Set <name> used to access C global variable (default: 'cvar')\n\ + -interface <mod>- Set low-level C/C++ module name to <mod> (default: module name prefixed by '_')\n\ + -keyword - Use keyword arguments\n"; +static const char *usage2 = "\ + -nofastunpack - Use traditional UnpackTuple method to parse the argument functions\n\ + -noh - Don't generate the output header file\n"; +static const char *usage3 = "\ + -noproxy - Don't generate proxy classes\n\ + -nortti - Disable the use of the native C++ RTTI with directors\n\ + -nothreads - Disable thread support for the entire interface\n\ + -olddefs - Keep the old method definitions when using -fastproxy\n\ + -py3 - Generate code with Python 3 specific features and syntax\n\ + -relativeimport - Use relative Python imports\n\ + -threads - Add thread support for all the interface\n\ + -O - Enable the following optimization options:\n\ + -fastdispatch -fastproxy -fvirtual\n\ +\n"; + +static String *getSlot(Node *n = NULL, const char *key = NULL, String *default_slot = NULL) { + static String *zero = NewString("0"); + String *val = n && key && *key ? Getattr(n, key) : NULL; + return val ? val : default_slot ? default_slot : zero; +} + +static void printSlot(File *f, String *slotval, const char *slotname, const char *functype = NULL) { + String *slotval_override = 0; + if (functype && Strcmp(slotval, "0") == 0) + slotval = slotval_override = NewStringf("(%s) %s", functype, slotval); + int len = Len(slotval); + int fieldwidth = len > 41 ? (len > 61 ? 0 : 61 - len) : 41 - len; + Printf(f, " %s,%*s/* %s */\n", slotval, fieldwidth, "", slotname); + Delete(slotval_override); +} + +static String *getClosure(String *functype, String *wrapper, int funpack = 0) { + static const char *functypes[] = { + "unaryfunc", "SWIGPY_UNARYFUNC_CLOSURE", + "destructor", "SWIGPY_DESTRUCTOR_CLOSURE", + "inquiry", "SWIGPY_INQUIRY_CLOSURE", + "getiterfunc", "SWIGPY_GETITERFUNC_CLOSURE", + "binaryfunc", "SWIGPY_BINARYFUNC_CLOSURE", + "ternaryfunc", "SWIGPY_TERNARYFUNC_CLOSURE", + "ternarycallfunc", "SWIGPY_TERNARYCALLFUNC_CLOSURE", + "lenfunc", "SWIGPY_LENFUNC_CLOSURE", + "ssizeargfunc", "SWIGPY_SSIZEARGFUNC_CLOSURE", + "ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE", + "ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE", + "ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE", + "objobjproc", "SWIGPY_OBJOBJPROC_CLOSURE", + "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", + "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", + "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", + "iternextfunc", "SWIGPY_ITERNEXTFUNC_CLOSURE", + NULL + }; + + static const char *funpack_functypes[] = { + "unaryfunc", "SWIGPY_UNARYFUNC_CLOSURE", + "destructor", "SWIGPY_DESTRUCTOR_CLOSURE", + "inquiry", "SWIGPY_INQUIRY_CLOSURE", + "getiterfunc", "SWIGPY_GETITERFUNC_CLOSURE", + "ternaryfunc", "SWIGPY_TERNARYFUNC_CLOSURE", + "ternarycallfunc", "SWIGPY_TERNARYCALLFUNC_CLOSURE", + "lenfunc", "SWIGPY_LENFUNC_CLOSURE", + "ssizeargfunc", "SWIGPY_FUNPACK_SSIZEARGFUNC_CLOSURE", + "ssizessizeargfunc", "SWIGPY_SSIZESSIZEARGFUNC_CLOSURE", + "ssizeobjargproc", "SWIGPY_SSIZEOBJARGPROC_CLOSURE", + "ssizessizeobjargproc", "SWIGPY_SSIZESSIZEOBJARGPROC_CLOSURE", + "objobjproc", "SWIGPY_FUNPACK_OBJOBJPROC_CLOSURE", + "objobjargproc", "SWIGPY_OBJOBJARGPROC_CLOSURE", + "reprfunc", "SWIGPY_REPRFUNC_CLOSURE", + "hashfunc", "SWIGPY_HASHFUNC_CLOSURE", + "iternextfunc", "SWIGPY_ITERNEXTFUNC_CLOSURE", + NULL + }; + + if (!functype) + return NULL; + char *c = Char(functype); + int i; + if (funpack) { + for (i = 0; funpack_functypes[i] != NULL; i += 2) { + if (!strcmp(c, funpack_functypes[i])) + return NewStringf("%s(%s)", funpack_functypes[i + 1], wrapper); + } + } else { + for (i = 0; functypes[i] != NULL; i += 2) { + if (!strcmp(c, functypes[i])) + return NewStringf("%s(%s)", functypes[i + 1], wrapper); + } + } + return NULL; +} + +class PYTHON:public Language { +public: + PYTHON() { + /* Add code to manage protected constructors and directors */ + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing abstract class or protected constructor\"); \n", " SWIG_fail;\n", "}\n", NIL); + director_multiple_inheritance = 1; + director_language = 1; + } + + ~PYTHON() { + delete doxygenTranslator; + } + + /* ------------------------------------------------------------ + * Thread Implementation + * ------------------------------------------------------------ */ + int threads_enable(Node *n) const { + return threads && !GetFlagAttr(n, "feature:nothread"); + } + + int initialize_threads(String *f_init) { + if (!threads) { + return SWIG_OK; + } + Printf(f_init, "\n"); + Printf(f_init, "/* Initialize threading */\n"); + Printf(f_init, "SWIG_PYTHON_INITIALIZE_THREADS;\n"); + + return SWIG_OK; + } + + virtual void thread_begin_block(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadblock")) { + String *bb = Getattr(n, "feature:threadbeginblock"); + if (bb) { + Append(f, bb); + } else { + Append(f, "SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n"); + } + } + } + + virtual void thread_end_block(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadblock")) { + String *eb = Getattr(n, "feature:threadendblock"); + if (eb) { + Append(f, eb); + } else { + Append(f, "SWIG_PYTHON_THREAD_END_BLOCK;\n"); + } + } + } + + virtual void thread_begin_allow(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadallow")) { + String *bb = Getattr(n, "feature:threadbeginallow"); + Append(f, "{\n"); + if (bb) { + Append(f, bb); + } else { + Append(f, "SWIG_PYTHON_THREAD_BEGIN_ALLOW;\n"); + } + } + } + + virtual void thread_end_allow(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadallow")) { + String *eb = Getattr(n, "feature:threadendallow"); + Append(f, "\n"); + if (eb) { + Append(f, eb); + } else { + Append(f, "SWIG_PYTHON_THREAD_END_ALLOW;"); + } + Append(f, "\n}"); + } + } + + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("python"); + + int doxygen_translator_flags = 0; + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-interface") == 0) { + if (argv[i + 1]) { + interface = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + /* end added */ + } else if (strcmp(argv[i], "-globals") == 0) { + if (argv[i + 1]) { + global_name = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + shadow = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + shadow = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-keyword") == 0) { + use_kw = 1; + SWIG_cparse_set_compact_default_args(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nortti") == 0) { + nortti = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-threads") == 0) { + threads = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nothreads") == 0) { + /* Turn off thread support mode */ + nothreads = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dirvtable") == 0) { + dirvtable = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-doxygen") == 0) { + doxygen = 1; + scan_doxygen_comments = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-doxygen-translator") == 0) { + doxygen_translator_flags |= DoxygenTranslator::debug_translator; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-doxygen-parser") == 0) { + doxygen_translator_flags |= DoxygenTranslator::debug_parser; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastunpack") == 0) { + fastunpack = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastproxy") == 0) { + fastproxy = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-olddefs") == 0) { + olddefs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-castmode") == 0) { + castmode = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-extranative") == 0) { + extranative = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noh") == 0) { + no_header_file = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-newvwm") == 0) { + /* Turn on new value wrapper mode */ + /* Undocumented option, did have -help text: New value wrapper mode, use only when everything else fails */ + Swig_value_wrapper_mode(1); + no_header_file = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-O") == 0) { + fastproxy = 1; + Wrapper_fast_dispatch_mode_set(1); + Wrapper_virtual_elimination_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage1, stdout); + fputs(usage2, stdout); + fputs(usage3, stdout); + } else if (strcmp(argv[i], "-py3") == 0) { + py3 = 1; + Preprocessor_define("SWIGPYTHON_PY3", 0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-builtin") == 0) { + builtin = 1; + Preprocessor_define("SWIGPYTHON_BUILTIN", 0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-relativeimport") == 0) { + relativeimport = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0 || + strcmp(argv[i], "-fastinit") == 0 || + strcmp(argv[i], "-fastquery") == 0 || + strcmp(argv[i], "-fastunpack") == 0 || + strcmp(argv[i], "-modern") == 0 || + strcmp(argv[i], "-modernargs") == 0 || + strcmp(argv[i], "-noproxydel") == 0 || + strcmp(argv[i], "-safecstrings") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-aliasobj0") == 0 || + strcmp(argv[i], "-buildnone") == 0 || + strcmp(argv[i], "-classic") == 0 || + strcmp(argv[i], "-classptr") == 0 || + strcmp(argv[i], "-new_repr") == 0 || + strcmp(argv[i], "-new_vwm") == 0 || + strcmp(argv[i], "-newrepr") == 0 || + strcmp(argv[i], "-noaliasobj0") == 0 || + strcmp(argv[i], "-nobuildnone") == 0 || + strcmp(argv[i], "-nocastmode") == 0 || + strcmp(argv[i], "-nocppcast") == 0 || + strcmp(argv[i], "-nodirvtable") == 0 || + strcmp(argv[i], "-noextranative") == 0 || + strcmp(argv[i], "-nofastinit") == 0 || + strcmp(argv[i], "-nofastproxy") == 0 || + strcmp(argv[i], "-nofastquery") == 0 || + strcmp(argv[i], "-nomodern") == 0 || + strcmp(argv[i], "-nomodernargs") == 0 || + strcmp(argv[i], "-noolddefs") == 0 || + strcmp(argv[i], "-nooutputtuple") == 0 || + strcmp(argv[i], "-noproxyimport") == 0 || + strcmp(argv[i], "-nosafecstrings") == 0 || + strcmp(argv[i], "-old_repr") == 0 || + strcmp(argv[i], "-oldrepr") == 0 || + strcmp(argv[i], "-outputtuple") == 0 || + strcmp(argv[i], "-proxydel") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); + } + + } + } + + if (doxygen) + doxygenTranslator = new PyDocConverter(doxygen_translator_flags); + + if (!global_name) + global_name = NewString("cvar"); + Preprocessor_define("SWIGPYTHON 1", 0); + SWIG_typemap_lang("python"); + SWIG_config_file("python.swg"); + allow_overloading(); + } + + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + String *mod_docstring = NULL; + String *moduleimport = NULL; + { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + int dirprot = 0; + if (Getattr(options, "dirprot")) { + dirprot = 1; + } + if (Getattr(options, "nodirprot")) { + dirprot = 0; + } + if (Getattr(options, "directors")) { + allow_directors(); + if (dirprot) + allow_dirprot(); + } + if (Getattr(options, "threads")) { + threads = 1; + } + if (Getattr(options, "castmode")) { + castmode = 1; + } + if (Getattr(options, "nocastmode")) { + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nocastmode"); + SWIG_exit(EXIT_FAILURE); + } + if (Getattr(options, "extranative")) { + extranative = 1; + } + if (Getattr(options, "noextranative")) { + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "noextranative"); + SWIG_exit(EXIT_FAILURE); + } + if (Getattr(options, "outputtuple")) { + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "outputtuple"); + SWIG_exit(EXIT_FAILURE); + } + if (Getattr(options, "nooutputtuple")) { + Printf(stderr, "Deprecated module option: %s. This option is no longer supported.\n", "nooutputtuple"); + SWIG_exit(EXIT_FAILURE); + } + mod_docstring = Getattr(options, "docstring"); + package = Getattr(options, "package"); + moduleimport = Getattr(options, "moduleimport"); + } + } + } + + /* Set comparison with none for ConstructorToFunction */ + setSubclassInstanceCheck(NewString("$arg != Py_None")); + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = !no_header_file ? Getattr(n, "outfile_h") : 0; + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + builtin_getset = NewHash(); + builtin_closures = NewHash(); + builtin_closures_code = NewString(""); + class_members = NewHash(); + builtin_methods = NewString(""); + builtin_default_unref = NewString("delete $self;"); + + if (builtin) { + f_builtins = NewString(""); + } + + if (directorsEnabled()) { + if (!no_header_file) { + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } else { + f_runtime_h = f_runtime; + } + } + + /* 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); + + const_code = NewString(""); + methods = NewString(""); + methods_proxydocs = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGPYTHON\n#define SWIGPYTHON\n#endif\n\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + if (nothreads) { + Printf(f_runtime, "#define SWIG_PYTHON_NO_THREADS\n"); + } else if (threads) { + Printf(f_runtime, "#define SWIG_PYTHON_THREADS\n"); + } + + if (!dirvtable) { + Printf(f_runtime, "#define SWIG_PYTHON_DIRECTOR_NO_VTABLE\n"); + } + + if (nortti) { + Printf(f_runtime, "#ifndef SWIG_DIRECTOR_NORTTI\n"); + Printf(f_runtime, "#define SWIG_DIRECTOR_NORTTI\n"); + Printf(f_runtime, "#endif\n"); + } + + if (castmode) { + Printf(f_runtime, "#define SWIG_CASTRANK_MODE\n"); + Printf(f_runtime, "#define SWIG_PYTHON_CAST_MODE\n"); + } + + if (extranative) { + Printf(f_runtime, "#define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS\n"); + } + + if (builtin) { + Printf(f_runtime, "#define SWIGPYTHON_BUILTIN\n"); + } + + Printf(f_runtime, "\n"); + + Printf(f_header, "#ifdef SWIG_TypeQuery\n"); + Printf(f_header, "# undef SWIG_TypeQuery\n"); + Printf(f_header, "#endif\n"); + Printf(f_header, "#define SWIG_TypeQuery SWIG_Python_TypeQuery\n"); + + + /* Set module name */ + module = Copy(Getattr(n, "name")); + mainmodule = Getattr(n, "name"); + + if (directorsEnabled()) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module); + if (dirprot_mode()) { + Printf(f_directors_h, "#include <map>\n"); + Printf(f_directors_h, "#include <string>\n\n"); + } + + 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); + } + } + + /* If shadow classing is enabled, we're going to change the module name to "_module" */ + String *default_import_code = NewString(""); + if (shadow) { + String *filen = NewStringf("%s%s.py", SWIG_output_directory(), Char(module)); + // If we don't have an interface then change the module name X to _X + if (interface) + module = interface; + else + Insert(module, 0, "_"); + if ((f_shadow_py = NewFile(filen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Delete(filen); + filen = NULL; + + f_shadow = NewString(""); + f_shadow_begin = NewString(""); + f_shadow_imports = NewHash(); + f_shadow_after_begin = NewString(""); + f_shadow_stubs = NewString(""); + + Swig_register_filebyname("shadow", f_shadow); + Swig_register_filebyname("python", f_shadow); + + if (!builtin) { + /* Import the low-level C/C++ module. This should be a relative import, + * since the shadow module may also have been imported by a relative + * import, and there is thus no guarantee that the low-level C/C++ module is on + * sys.path. Relative imports must be explicitly specified from 2.6.0 + * onwards (implicit relative imports raised a DeprecationWarning in 2.6, + * and fail in 2.7 onwards). + * + * First check for __package__ which is available from 2.6 onwards, see PEP366. + * Next try determine the shadow wrapper's package based on the __name__ it + * was given by the importer that loaded it. + * If the module is in a package, load the low-level C/C++ module from the + * same package, otherwise load it as a global module. + */ + Printv(default_import_code, "# Import the low-level C/C++ module\n", NULL); + Printv(default_import_code, "if __package__ or \".\" in __name__:\n", NULL); + Printv(default_import_code, tab4, "from . import ", module, "\n", NULL); + Printv(default_import_code, "else:\n", NULL); + Printv(default_import_code, tab4, "import ", module, "\n", NULL); + } else { + Printv(default_import_code, "# Pull in all the attributes from the low-level C/C++ module\n", NULL); + Printv(default_import_code, "if __package__ or \".\" in __name__:\n", NULL); + Printv(default_import_code, tab4, "from .", module, " import *\n", NULL); + Printv(default_import_code, "else:\n", NULL); + Printv(default_import_code, tab4, "from ", module, " import *\n", NULL); + } + + /* Need builtins to qualify names like Exception that might also be + defined in this module (try both Python 3 and Python 2 names) */ + Printv(f_shadow, "try:\n", tab4, "import builtins as __builtin__\n", "except ImportError:\n", tab4, "import __builtin__\n", NULL); + + if (!builtin && fastproxy) { + Printf(f_shadow, "\n"); + Printf(f_shadow, "_swig_new_instance_method = %s.SWIG_PyInstanceMethod_New\n", module); + Printf(f_shadow, "_swig_new_static_method = %s.SWIG_PyStaticMethod_New\n", module); + } + + Printv(f_shadow, "\n", + "def _swig_repr(self):\n", + tab4, "try:\n", + tab4, tab4, "strthis = \"proxy of \" + self.this.__repr__()\n", + tab4, "except __builtin__.Exception:\n", + tab4, tab4, "strthis = \"\"\n", + tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); + + Printv(f_shadow, "\n", + "def _swig_setattr_nondynamic_instance_variable(set):\n", + tab4, "def set_instance_attr(self, name, value):\n", +#ifdef USE_THISOWN + tab4, tab4, "if name in (\"this\", \"thisown\"):\n", + tab4, tab4, tab4, "set(self, name, value)\n", +#else + tab4, tab4, "if name == \"thisown\":\n", + tab4, tab4, tab4, "self.this.own(value)\n", + tab4, tab4, "elif name == \"this\":\n", + tab4, tab4, tab4, "set(self, name, value)\n", +#endif + tab4, tab4, "elif hasattr(self, name) and isinstance(getattr(type(self), name), property):\n", + tab4, tab4, tab4, "set(self, name, value)\n", + tab4, tab4, "else:\n", + tab4, tab4, tab4, "raise AttributeError(\"You cannot add instance attributes to %s\" % self)\n", + tab4, "return set_instance_attr\n\n", NIL); + + Printv(f_shadow, "\n", + "def _swig_setattr_nondynamic_class_variable(set):\n", + tab4, "def set_class_attr(cls, name, value):\n", + tab4, tab4, "if hasattr(cls, name) and not isinstance(getattr(cls, name), property):\n", + tab4, tab4, tab4, "set(cls, name, value)\n", + tab4, tab4, "else:\n", + tab4, tab4, tab4, "raise AttributeError(\"You cannot add class attributes to %s\" % cls)\n", + tab4, "return set_class_attr\n\n", NIL); + + Printv(f_shadow, "\n", + "def _swig_add_metaclass(metaclass):\n", + tab4, "\"\"\"Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass\"\"\"\n", + tab4, "def wrapper(cls):\n", + tab4, tab4, "return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())\n", + tab4, "return wrapper\n\n", NIL); + + Printv(f_shadow, "\n", + "class _SwigNonDynamicMeta(type):\n", + tab4, "\"\"\"Meta class to enforce nondynamic attributes (no new attributes) for a class\"\"\"\n", + tab4, "__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)\n", + "\n", NIL); + + Printv(f_shadow, "\n", NIL); + + if (directorsEnabled()) { + Printv(f_shadow, "import weakref\n\n", NIL); + } + } + // Include some information in the code + Printf(f_header, "\n/*-----------------------------------------------\n @(target):= %s.so\n\ + ------------------------------------------------*/\n", module); + + Printf(f_header, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_header, "# define SWIG_init PyInit_%s\n\n", module); + Printf(f_header, "#else\n"); + Printf(f_header, "# define SWIG_init init%s\n\n", module); + Printf(f_header, "#endif\n"); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n"); + Append(const_code, "static swig_const_info swig_const_table[] = {\n"); + Append(methods, "static PyMethodDef SwigMethods[] = {\n"); + Append(methods_proxydocs, "static PyMethodDef SwigMethods_proxydocs[] = {\n"); + + /* the method exported for replacement of new.instancemethod in Python 3 */ + add_pyinstancemethod_new(); + add_pystaticmethod_new(); + + if (builtin) { + SwigType *s = NewString("SwigPyObject"); + SwigType_add_pointer(s); + SwigType_remember(s); + Delete(s); + } + + /* emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + + /* Close language module */ + Append(methods, "\t { NULL, NULL, 0, NULL }\n"); + Append(methods, "};\n"); + Printf(f_wrappers, "%s\n", methods); + Append(methods_proxydocs, "\t { NULL, NULL, 0, NULL }\n"); + Append(methods_proxydocs, "};\n"); + Printf(f_wrappers, "%s\n", methods_proxydocs); + + if (builtin) { + Dump(f_builtins, f_wrappers); + } + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Append(const_code, "{0, 0, 0, 0.0, 0, 0}};\n"); + Printf(f_wrappers, "%s\n", const_code); + initialize_threads(f_init); + + Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_init, " return m;\n"); + Printf(f_init, "#else\n"); + Printf(f_init, " return;\n"); + Printf(f_init, "#endif\n"); + Printf(f_init, "}\n"); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + if (shadow) { + Swig_banner_target_lang(f_shadow_py, "#"); + + if (mod_docstring) { + if (Len(mod_docstring)) { + const char *triple_double = "\"\"\""; + // follow PEP257 rules: https://www.python.org/dev/peps/pep-0257/ + // reported by pep257: https://github.com/GreenSteam/pep257 + bool multi_line_ds = Strchr(mod_docstring, '\n') != 0; + Printv(f_shadow_py, "\n", triple_double, multi_line_ds ? "\n":"", mod_docstring, multi_line_ds ? "\n":"", triple_double, "\n", NIL); + } + Delete(mod_docstring); + mod_docstring = NULL; + } + + if (Len(f_shadow_begin) > 0) + Printv(f_shadow_py, "\n", f_shadow_begin, "\n", NIL); + + Printv(f_shadow_py, "\nfrom sys import version_info as _swig_python_version_info\n", NULL); + Printv(f_shadow_py, "if _swig_python_version_info < (2, 7, 0):\n", NULL); + Printv(f_shadow_py, tab4, "raise RuntimeError(\"Python 2.7 or later required\")\n\n", NULL); + + if (Len(f_shadow_after_begin) > 0) + Printv(f_shadow_py, f_shadow_after_begin, "\n", NIL); + + if (moduleimport) { + Replaceall(moduleimport, "$module", module); + Printv(f_shadow_py, moduleimport, "\n", NIL); + } else { + Printv(f_shadow_py, default_import_code, NIL); + } + + Printv(f_shadow_py, "\n", f_shadow, "\n", NIL); + Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); + Delete(f_shadow_py); + } + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + if (f_runtime_h != f_begin) + Delete(f_runtime_h); + Dump(f_directors, f_begin); + } + + Dump(f_wrappers, f_begin); + if (builtin && builtin_bases_needed) + Printf(f_begin, "static PyTypeObject *builtin_bases[%d];\n\n", max_bases + 2); + Wrapper_pretty_print(f_init, f_begin); + + Delete(default_import_code); + Delete(f_shadow_after_begin); + Delete(f_shadow_imports); + Delete(f_shadow_begin); + Delete(f_shadow); + Delete(f_header); + Delete(f_wrappers); + Delete(f_builtins); + Delete(f_init); + Delete(f_directors); + Delete(f_directors_h); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * Emit the wrapper for PyInstanceMethod_New to MethodDef array. + * This wrapper is used to implement -fastproxy, + * as a replacement of new.instancemethod in Python 3. + * ------------------------------------------------------------ */ + int add_pyinstancemethod_new() { + String *name = NewString("SWIG_PyInstanceMethod_New"); + String *line = NewString(""); + Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); + Append(methods, line); + if (fastproxy) { + Append(methods_proxydocs, line); + } + Delete(line); + Delete(name); + return 0; + } + + /* ------------------------------------------------------------ + * Emit the wrapper for PyStaticMethod_New to MethodDef array. + * This wrapper is used to ensure the correct documentation is + * generated for static methods when using -fastproxy + * ------------------------------------------------------------ */ + int add_pystaticmethod_new() { + if (fastproxy) { + String *name = NewString("SWIG_PyStaticMethod_New"); + String *line = NewString(""); + Printf(line, "\t { \"%s\", %s, METH_O, NULL},\n", name, name); + Append(methods, line); + Append(methods_proxydocs, line); + Delete(line); + Delete(name); + } + return 0; + } + + /* ------------------------------------------------------------ + * subpkg_tail() + * + * Return the name of 'other' package relative to 'base'. + * + * 1. If 'other' is a sub-package of 'base', returns the 'other' relative to + * 'base'. + * 2. If 'other' and 'base' are equal, returns empty string "". + * 3. In any other case, NULL pointer is returned. + * + * The 'base' and 'other' are expected to be fully qualified names. + * + * NOTE: none of 'base' nor 'other' can be null. + * + * Examples: + * + * # base other tail + * -- ---- ----- ---- + * 1 "Foo" "Foo.Bar" -> "Bar" + * 2 "Foo" "Foo." -> "" + * 3 "Foo" "FooB.ar" -> NULL + * 4 "Foo.Bar" "Foo.Bar" -> "" + * 5 "Foo.Bar" "Foo" -> NULL + * 6 "Foo.Bar" "Foo.Gez" -> NULL + * + * NOTE: the example #2 is actually a syntax error (at input). I believe + * swig parser prevents us from this case happening here. + * ------------------------------------------------------------ */ + + static String *subpkg_tail(const String *base, const String *other) { + int baselen = Len(base); + int otherlen = Len(other); + + if (Strncmp(other, base, baselen) == 0) { + if ((baselen < otherlen) && (Char(other))[baselen] == '.') { + return NewString((Char(other)) + baselen + 1); + } else if (baselen == otherlen) { + return NewString(""); + } else { + return 0; + } + } else { + return 0; + } + } + + /* ------------------------------------------------------------ + * abs_import_directive_string() + * + * Return a string containing python code to import module. + * + * pkg package name or the module being imported + * mod module name of the module being imported + * pfx optional prefix to module name + * + * NOTE: keep this function consistent with abs_import_name_string(). + * ------------------------------------------------------------ */ + + static String *abs_import_directive_string(const String *pkg, const String *mod, const char *pfx = "") { + String *out = NewString(""); + + if (pkg && *Char(pkg)) { + Printf(out, "import %s.%s%s\n", pkg, pfx, mod); + } else { + Printf(out, "import %s%s\n", pfx, mod); + } + return out; + } + + /* ------------------------------------------------------------ + * rel_import_directive_string() + * + * Return a string containing python code to import module that + * is potentially within a package. + * + * mainpkg package name of the module which imports the other module + * pkg package name or the module being imported + * mod module name of the module being imported + * pfx optional prefix to module name + * + * NOTE: keep this function consistent with rel_import_name_string(). + * ------------------------------------------------------------ */ + + static String *rel_import_directive_string(const String *mainpkg, const String *pkg, const String *mod, const char *pfx = "") { + + /* NOTE: things are not so trivial. This is what we do here (by examples): + * + * 0. To import module 'foo', which is not in any package, we do absolute + * import: + * + * import foo + * + * 1. To import 'pkg1.pkg2.foo', when mainpkg != "pkg1" and + * mainpkg != "pkg1.pkg2" or when mainpkg is not given we do absolute + * import: + * + * import pkg1.pkg2.foo + * + * 2. To import module pkg1.foo, when mainpkg == "pkg1", we do: + * + * - for py3 = 0: + * + * import foo + * + * - for py3 = 1: + * + * from . import foo + * + * 3. To import "pkg1.pkg2.pkg3.foo", when mainpkg = "pkg1", we do: + * + * - for py3 == 0: + * + * import pkg2.pkg3.foo + * + * - for py3 == 1: + * + * from . import pkg2 # [1] + * import pkg1.pkg2.pkg3.foo + * + * NOTE: [1] is necessary for pkg2.foo to be present in the importing module + */ + + String *apkg = 0; // absolute (FQDN) package name of pkg + String *rpkg = 0; // relative package name + int py3_rlen1 = 0; // length of 1st level sub-package name, used by py3 + String *out = NewString(""); + + if (pkg && *Char(pkg)) { + if (mainpkg) { + String *tail = subpkg_tail(mainpkg, pkg); + if (tail) { + if (*Char(tail)) { + rpkg = NewString(tail); + const char *py3_end1 = Strchr(rpkg, '.'); + if (!py3_end1) + py3_end1 = (Char(rpkg)) + Len(rpkg); + py3_rlen1 = (int)(py3_end1 - Char(rpkg)); + } else { + rpkg = NewString(""); + } + Delete(tail); + } else { + apkg = NewString(pkg); + } + } else { + apkg = NewString(pkg); + } + } else { + apkg = NewString(""); + } + + if (apkg) { + Printf(out, "import %s%s%s%s\n", apkg, *Char(apkg) ? "." : "", pfx, mod); + Delete(apkg); + } else { + if (py3_rlen1) + Printf(out, "from . import %.*s\n", py3_rlen1, rpkg); + Printf(out, "from .%s import %s%s\n", rpkg, pfx, mod); + Delete(rpkg); + } + return out; + } + + /* ------------------------------------------------------------ + * import_directive_string() + * ------------------------------------------------------------ */ + + static String *import_directive_string(const String *mainpkg, const String *pkg, const String *mod, const char *pfx = "") { + if (!relativeimport) { + return abs_import_directive_string(pkg, mod, pfx); + } else { + return rel_import_directive_string(mainpkg, pkg, mod, pfx); + } + } + + /* ------------------------------------------------------------ + * abs_import_name_string() + * + * Return a string with the name of a symbol (perhaps imported + * from external module by absolute import directive). + * + * mainpkg package name of current module + * mainmod module name of current module + * pkg package name of (perhaps other) module + * mod module name of (perhaps other) module + * sym symbol name + * + * NOTE: mainmod, mod, and sym can't be NULL. + * NOTE: keep this function consistent with abs_import_directive_string() + * ------------------------------------------------------------ */ + + static String *abs_import_name_string(const String *mainpkg, const String *mainmod, const String *pkg, const String *mod, const String *sym) { + String *out = NewString(""); + if (pkg && *Char(pkg)) { + if (mainpkg && *Char(mainpkg)) { + if (Strcmp(mainpkg,pkg) != 0 || Strcmp(mainmod, mod) != 0) { + Printf(out, "%s.%s.", pkg, mod); + } + } else { + Printf(out, "%s.%s.", pkg, mod); + } + } else if ((mainpkg && *Char(mainpkg)) || Strcmp(mainmod, mod) != 0) { + Printf(out, "%s.", mod); + } + Append(out, sym); + return out; + } + + /* ------------------------------------------------------------ + * rel_import_name_string() + * + * Return a string with the name of a symbol (perhaps imported + * from external module by relative import directive). + * + * mainpkg package name of current module + * mainmod module name of current module + * pkg package name of (perhaps other) module + * mod module name of (perhaps other) module + * sym symbol name + * + * NOTE: mainmod, mod, and sym can't be NULL. + * NOTE: keep this function consistent with rel_import_directive_string() + * ------------------------------------------------------------ */ + + static String *rel_import_name_string(const String *mainpkg, const String *mainmod, const String *pkg, const String *mod, const String *sym) { + String *out = NewString(""); + if (pkg && *Char(pkg)) { + String *tail = 0; + if (mainpkg) + tail = subpkg_tail(mainpkg, pkg); + if (!tail) + tail = NewString(pkg); + if (*Char(tail)) { + Printf(out, "%s.%s.", tail, mod); + } else if (Strcmp(mainmod, mod) != 0) { + Printf(out, "%s.", mod); + } + Delete(tail); + } else if ((mainpkg && *Char(mainpkg)) || Strcmp(mainmod, mod) != 0) { + Printf(out, "%s.", mod); + } + Append(out, sym); + return out; + } + + /* ------------------------------------------------------------ + * import_name_string() + * ------------------------------------------------------------ */ + + static String *import_name_string(const String *mainpkg, const String *mainmod, const String *pkg, const String *mod, const String *sym) { + if (!relativeimport) { + return abs_import_name_string(mainpkg,mainmod,pkg,mod,sym); + } else { + return rel_import_name_string(mainpkg,mainmod,pkg,mod,sym); + } + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + if (shadow) { + String *modname = Getattr(n, "module"); + + if (modname) { + // Find the module node for this imported module. It should be the + // first child but search just in case. + Node *mod = firstChild(n); + while (mod && Strcmp(nodeType(mod), "module") != 0) + mod = nextSibling(mod); + + Node *options = Getattr(mod, "options"); + String *pkg = options ? Getattr(options, "package") : 0; + + if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) { + String *_import = import_directive_string(package, pkg, modname, "_"); + if (!GetFlagAttr(f_shadow_imports, _import)) { + String *import = import_directive_string(package, pkg, modname); + Printf(builtin ? f_shadow_after_begin : f_shadow, "%s", import); + Delete(import); + SetFlag(f_shadow_imports, _import); + } + Delete(_import); + } + + } + } + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * funcCall() + * + * Emit shadow code to call a function in the extension + * module. Using proper argument and calling style for + * given node n. + * ------------------------------------------------------------ */ + String *funcCall(String *name, String *parms) { + String *str = NewString(""); + + Printv(str, module, ".", name, "(", parms, ")", NIL); + return str; + } + + /* ------------------------------------------------------------ + * indent_pythoncode() + * + * Format (indent) Python code. + * Remove leading whitespace from 'code' and re-indent using + * the indentation string in 'indent'. + * ------------------------------------------------------------ */ + + String *indent_pythoncode(const String *code, const_String_or_char_ptr indent, String *file, int line, const char *directive_name) { + String *out = NewString(""); + String *temp; + char *t; + if (!indent) + indent = ""; + + temp = NewString(code); + + t = Char(temp); + if (*t == '{') { + Delitem(temp, 0); + Delitem(temp, DOH_END); + } + + /* Split the input text into lines */ + List *clist = SplitLines(temp); + Delete(temp); + + // Line number within the pythoncode. + int py_line = 0; + + String *initial = 0; + Iterator si; + + /* Get the initial indentation. Skip lines which only contain whitespace + * and/or a comment, as the indentation of those doesn't matter: + * + * A logical line that contains only spaces, tabs, formfeeds and + * possibly a comment, is ignored (i.e., no NEWLINE token is + * generated). + * + * see: + * https://docs.python.org/2/reference/lexical_analysis.html#blank-lines + * https://docs.python.org/3/reference/lexical_analysis.html#blank-lines + */ + for (si = First(clist); si.item; si = Next(si), ++py_line) { + const char *c = Char(si.item); + int i; + for (i = 0; isspace((unsigned char)c[i]); i++) { + // Scan forward until we find a non-space (which may be a null byte). + } + char ch = c[i]; + if (ch && ch != '#') { + // Found a line with actual content. + initial = NewStringWithSize(c, i); + break; + } + if (ch) { + Printv(out, indent, c, NIL); + } + Putc('\n', out); + } + + // Process remaining lines. + for ( ; si.item; si = Next(si), ++py_line) { + const char *c = Char(si.item); + // If no prefixed line was found, the above loop should have completed. + assert(initial); + + int i; + for (i = 0; isspace((unsigned char)c[i]); i++) { + // Scan forward until we find a non-space (which may be a null byte). + } + char ch = c[i]; + if (!ch) { + // Line is just whitespace - emit an empty line. + Putc('\n', out); + continue; + } + + if (ch == '#') { + // Comment - the indentation doesn't matter to python, but try to + // adjust the whitespace for the benefit of human readers (though SWIG + // currently seems to always remove any whitespace before a '#' before + // we get here, in which case we'll just leave the comment at the start + // of the line). + if (i >= Len(initial)) { + Printv(out, indent, NIL); + } + + Printv(out, c + i, "\n", NIL); + continue; + } + + if (i < Len(initial)) { + // There's non-whitespace in the initial prefix of this line. + Swig_error(file, line, "Line indented less than expected (line %d of %s) as no line should be indented less than the indentation in line 1\n", py_line, directive_name); + Printv(out, indent, c, "\n", NIL); + } else { + if (memcmp(c, Char(initial), Len(initial)) == 0) { + // Prefix matches initial, so just remove it. + Printv(out, indent, c + Len(initial), "\n", NIL); + continue; + } + Swig_warning(WARN_PYTHON_INDENT_MISMATCH, + file, line, "Whitespace indentation is inconsistent compared to earlier lines (line %d of %s)\n", py_line, directive_name); + // To avoid gratuitously breaking interface files which worked with + // SWIG <= 3.0.5, we remove a prefix of the same number of bytes for + // lines which start with different whitespace to the line we got + // 'initial' from. + Printv(out, indent, c + Len(initial), "\n", NIL); + } + } + Delete(clist); + return out; + } + + /* ------------------------------------------------------------ + * indent_docstring() + * + * Format (indent) a Python docstring. + * Remove leading whitespace from 'code' and re-indent using + * the indentation string in 'indent'. + * ------------------------------------------------------------ */ + + String *indent_docstring(const String *code, const_String_or_char_ptr indent) { + String *out = NewString(""); + String *temp; + char *t; + if (!indent) + indent = ""; + + temp = NewString(code); + + t = Char(temp); + if (*t == '{') { + Delitem(temp, 0); + Delitem(temp, DOH_END); + } + + /* Split the input text into lines */ + List *clist = SplitLines(temp); + Delete(temp); + + Iterator si; + + int truncate_characters_count = INT_MAX; + for (si = First(clist); si.item; si = Next(si)) { + const char *c = Char(si.item); + int i; + for (i = 0; isspace((unsigned char)c[i]); i++) { + // Scan forward until we find a non-space (which may be a null byte). + } + char ch = c[i]; + if (ch) { + // Found a line which isn't just whitespace + if (i < truncate_characters_count) + truncate_characters_count = i; + } + } + + if (truncate_characters_count == INT_MAX) + truncate_characters_count = 0; + + for (si = First(clist); si.item; si = Next(si)) { + const char *c = Char(si.item); + + int i; + for (i = 0; isspace((unsigned char)c[i]); i++) { + // Scan forward until we find a non-space (which may be a null byte). + } + char ch = c[i]; + if (!ch) { + // Line is just whitespace - emit an empty line. + Putc('\n', out); + continue; + } + + Printv(out, indent, c + truncate_characters_count, "\n", NIL); + } + Delete(clist); + return out; + } + + /* ------------------------------------------------------------ + * autodoc level declarations + * ------------------------------------------------------------ */ + + enum autodoc_l { + NO_AUTODOC = -2, // no autodoc + STRING_AUTODOC = -1, // use provided string + NAMES_AUTODOC = 0, // only parameter names + TYPES_AUTODOC = 1, // parameter names and types + EXTEND_AUTODOC = 2, // extended documentation and parameter names + EXTEND_TYPES_AUTODOC = 3 // extended documentation and parameter types + names + }; + + + autodoc_l autodoc_level(String *autodoc) { + autodoc_l dlevel = NO_AUTODOC; + char *c = Char(autodoc); + if (c) { + if (isdigit(c[0])) { + dlevel = (autodoc_l) atoi(c); + } else { + if (strcmp(c, "extended") == 0) { + dlevel = EXTEND_AUTODOC; + } else { + dlevel = STRING_AUTODOC; + } + } + } + return dlevel; + } + + + /* ------------------------------------------------------------ + * have_docstring() + * + * Check if there is a docstring directive and it has text, + * or there is an autodoc flag set + * ------------------------------------------------------------ */ + + bool have_docstring(Node *n) { + String *str = Getattr(n, "feature:docstring"); + return ((str && Len(str) > 0) + || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) + || (doxygen && doxygenTranslator->hasDocumentation(n)) + ); + } + + /* ------------------------------------------------------------ + * build_combined_docstring() + * + * Build the full docstring which may be a combination of the + * explicit docstring and autodoc string or, if none of them + * is specified, obtained by translating Doxygen comment to + * Python. + * + * Return new string to be deleted by caller (never NIL but + * may be empty if there is no docstring). + * ------------------------------------------------------------ */ + + String *build_combined_docstring(Node *n, autodoc_t ad_type, const String *indent = "", bool low_level = false) { + String *docstr = Getattr(n, "feature:docstring"); + if (docstr) { + // Simplify the code below by just ignoring empty docstrings. + if (!Len(docstr)) + docstr = NULL; + else + docstr = Copy(docstr); + } + + if (docstr) { + char *t = Char(docstr); + if (*t == '{') { + Delitem(docstr, 0); + Delitem(docstr, DOH_END); + } + } + + if (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")) { + String *autodoc = make_autodoc(n, ad_type, low_level); + if (autodoc && Len(autodoc) > 0) { + if (docstr) { + Append(autodoc, "\n"); + Append(autodoc, docstr); + } + + String *tmp = autodoc; + autodoc = docstr; + docstr = tmp; + } + + Delete(autodoc); + } + + if (!docstr) { + if (doxygen) { + docstr = Getattr(n, "python:docstring"); + if (!docstr && doxygenTranslator->hasDocumentation(n)) { + docstr = doxygenTranslator->getDocumentation(n, 0); + + // Avoid rebuilding it again the next time: notice that we can't do + // this for the combined doc string as autodoc part of it depends on + // the sym:name of the node and it is changed while handling it, so + // the cached results become incorrect. But Doxygen docstring only + // depends on the comment which is not going to change, so we can + // safely cache it. + Setattr(n, "python:docstring", Copy(docstr)); + } else { + // Must copy here since if the docstring is multi-line, the String* + // here will get Deleted below, which is bad if it is a pointer to + // the cached object! + docstr = Copy(docstr); + } + } + } + + if (!docstr) + docstr = NewString(""); + + // If there is more than one line then make docstrings like this: + // + // """ + // This is line1 + // And here is line2 followed by the rest of them + // """ + // + // otherwise, put it all on a single line + if (Strchr(docstr, '\n')) { + String *tmp = NewString(""); + Append(tmp, "\n"); + Append(tmp, indent_docstring(docstr, indent)); + Append(tmp, indent); + Delete(docstr); + docstr = tmp; + } + + return docstr; + } + + /* ------------------------------------------------------------ + * docstring() + * + * Get the docstring text, stripping off {} if necessary, + * and enclose in triple double quotes. If autodoc is also + * set then it will build a combined docstring. + * ------------------------------------------------------------ */ + + String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool low_level = false) { + String *docstr = build_combined_docstring(n, ad_type, indent, low_level); + const int len = Len(docstr); + if (!len) + return docstr; + + // Notice that all comments are created as raw strings (prefix "r"), + // because '\' is used often in comments, but may break Python module from + // loading. For example, in doxy comment one may write path in quotes: + // + // This is path to file "C:\x\file.txt" + // + // Python will not load the module with such comment because of illegal + // escape '\x'. '\' may additionally appear in verbatim or htmlonly sections + // of doxygen doc, Latex expressions, ... + String *doc = NewString(""); + + // Determine which kind of quotes to use as delimiters: for single line + // strings we can avoid problems with having a quote as the last character + // of the docstring by using different kind of quotes as delimiters. For + // multi-line strings this problem doesn't arise, as we always have a new + // line or spaces at the end of it, but it still does no harm to do it for + // them too. + // + // Note: we use double quotes by default, i.e. if there is no reason to + // prefer using single ones, for consistency with the older SWIG versions. + const bool useSingleQuotes = (Char(docstr))[len - 1] == '"'; + + Append(doc, useSingleQuotes ? "r'''" : "r\"\"\""); + + // We also need to avoid having triple quotes of whichever type we use, as + // this would break Python doc string syntax too. Unfortunately there is no + // way to have triple quotes inside of raw-triple-quoted string, so we have + // to break the string in parts and rely on concatenation of the adjacent + // string literals. + if (useSingleQuotes) + Replaceall(docstr, "'''", "''' \"'''\" '''"); + else + Replaceall(docstr, "\"\"\"", "\"\"\" '\"\"\"' \"\"\""); + + Append(doc, docstr); + Append(doc, useSingleQuotes ? "'''" : "\"\"\""); + Delete(docstr); + + return doc; + } + + /* ------------------------------------------------------------ + * cdocstring() + * + * Get the docstring text as it would appear in C-language + * source code (but without quotes around it). + * ------------------------------------------------------------ */ + + String *cdocstring(Node *n, autodoc_t ad_type, bool low_level = false) { + String *ds = build_combined_docstring(n, ad_type, "", low_level); + Replaceall(ds, "\\", "\\\\"); + Replaceall(ds, "\"", "\\\""); + Replaceall(ds, "\n", "\\n\"\n\t\t\""); + return ds; + } + + /* ----------------------------------------------------------------------------- + * addMissingParameterNames() + * + * For functions that have not had nameless parameters set in the Language class. + * + * Inputs: + * plist - entire parameter list + * arg_num - the number to start from when naming arguments + * Side effects: + * The "lname" attribute in each parameter in plist will be contain a parameter name + * ----------------------------------------------------------------------------- */ + + void addMissingParameterNames(Node *n, ParmList *plist, int arg_num) { + Parm *p = plist; + int i = arg_num; + while (p) { + if (!Getattr(p, "lname")) { + String *name = makeParameterName(n, p, i); + Setattr(p, "lname", name); + Delete(name); + } + i++; + p = nextSibling(p); + } + } + + /* ------------------------------------------------------------ + * make_autodocParmList() + * + * Generate the documentation for the function parameters + * Parameters: + * arg_num: The number to start assigning unnamed arguments from + * func_annotation: Function annotation support + * ------------------------------------------------------------ */ + + String *make_autodocParmList(Node *n, bool showTypes, int arg_num = 1, bool calling = false, bool func_annotation = false) { + + String *doc = NewString(""); + String *pdocs = 0; + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + + if (calling) + func_annotation = false; + + addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + if (Strcmp(ParmList_protostr(plist), "void") == 0) { + //No parameters actually + return doc; + } + + for (p = plist; p; p = pnext) { + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + + String *name = 0; + String *type = 0; + String *value = 0; + String *pdoc = Getattr(p, "tmap:doc"); + if (pdoc) { + name = Getattr(p, "tmap:doc:name"); + type = Getattr(p, "tmap:doc:type"); + value = Getattr(p, "tmap:doc:value"); + } + + // Skip the "self" argument - it is added to the parameter list automatically + // and shouldn't be included in the Parameters block + if (Getattr(p, "self")) { + continue; + } + + // Note: the generated name should be consistent with that in kwnames[] + String *made_name = 0; + if (!name) { + name = made_name = makeParameterName(n, p, arg_num); + } + + // Increment the argument number once we are sure this is a real argument to count + arg_num++; + + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + if (SwigType_isvarargs(type)) { + Delete(made_name); + break; + } + + if (Len(doc)) { + // add a comma to the previous one if any + Append(doc, ", "); + } + + // Do the param type too? + Node *nn = classLookup(Getattr(p, "type")); + String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); + if (showTypes) + Printf(doc, "%s ", type_str); + + Append(doc, name); + if (pdoc) { + if (!pdocs) + // numpydoc style: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt + pdocs = NewString("\nParameters\n----------\n"); + Printf(pdocs, "%s\n", pdoc); + } + // Write the function annotation + if (func_annotation) + Printf(doc, ": \"%s\"", type_str); + + // Write default value + if (value && !calling) { + String *new_value = convertValue(value, Getattr(p, "type")); + if (new_value) { + value = new_value; + } else { + // Even if the value is not representable in the target language, still use it in the documentation, for compatibility with the previous SWIG versions + // and because it can still be useful to see the C++ expression there. + Node *lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(doc, "=%s", value); + + if (new_value) + Delete(new_value); + } + Delete(type_str); + Delete(made_name); + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + return doc; + } + + /* ------------------------------------------------------------ + * make_autodoc() + * + * Build a docstring for the node, using parameter and other + * info in the parse tree. If the value of the autodoc + * attribute is "0" then do not include parameter types, if + * it is "1" (the default) then do. If it has some other + * value then assume it is supplied by the extension writer + * and use it directly. + * ------------------------------------------------------------ */ + + String *make_autodoc(Node *n, autodoc_t ad_type, bool low_level = false) { + int extended = 0; + bool first_func = true; + // If the function is overloaded then this function is called + // for the last one. Rewind to the first so the docstrings are + // in order. + while (Getattr(n, "sym:previousSibling")) + n = Getattr(n, "sym:previousSibling"); + + String *doc = NewString(""); + while (n) { + bool showTypes = false; + bool skipAuto = false; + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + switch (dlevel) { + case NO_AUTODOC: + break; + case NAMES_AUTODOC: + showTypes = false; + break; + case TYPES_AUTODOC: + showTypes = true; + break; + case EXTEND_AUTODOC: + extended = 1; + showTypes = false; + break; + case EXTEND_TYPES_AUTODOC: + extended = 1; + showTypes = true; + break; + case STRING_AUTODOC: + Append(doc, autodoc); + skipAuto = true; + break; + } + + if (!skipAuto) { + /* Check if a documentation name was given for either the low-level C API or high-level Python shadow API */ + String *symname = Getattr(n, low_level ? "doc:low:name" : "doc:high:name"); + if (!symname) { + symname = Getattr(n, "sym:name"); + } + + SwigType *type = Getattr(n, "type"); + String *type_str = NULL; + + // If the function has default arguments, then that documentation covers this version too + if (Getattr(n, "defaultargs") != NULL) { + n = Getattr(n, "sym:nextSibling"); + continue; + } + + if (!first_func) + Append(doc, "\n"); + + if (type) { + if (Strcmp(type, "void") == 0) { + type_str = NULL; + } else { + Node *nn = classLookup(type); + type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); + } + } + + /* Treat the low-level C API functions for getting/setting variables as methods for documentation purposes */ + String *kind = Getattr(n, "kind"); + if (kind && Strcmp(kind, "variable") == 0) { + if (ad_type == AUTODOC_FUNC) { + ad_type = AUTODOC_METHOD; + } + } + /* Treat destructors as methods for documentation purposes */ + String *nodeType = Getattr(n, "nodeType"); + if (nodeType && Strcmp(nodeType, "destructor") == 0) { + if (ad_type == AUTODOC_FUNC) { + ad_type = AUTODOC_METHOD; + } + } + + switch (ad_type) { + case AUTODOC_CLASS: + { + // Only do the autodoc if there isn't a docstring for the class + String *str = Getattr(n, "feature:docstring"); + if (!str || Len(str) == 0) { + if (builtin) { + String *name = Getattr(n, "name"); + String *rname = add_explicit_scope(SwigType_namestr(name)); + Printf(doc, "%s", rname); + Delete(rname); + } else { + if (CPlusPlus) { + Printf(doc, "Proxy of C++ %s class.", SwigType_namestr(real_classname)); + } else { + Printf(doc, "Proxy of C %s struct.", SwigType_namestr(real_classname)); + } + } + } + } + break; + case AUTODOC_CTOR: + if (Strcmp(class_name, symname) == 0) { + String *paramList = make_autodocParmList(n, showTypes, 2); + Printf(doc, "__init__("); + if (showTypes) + Printf(doc, "%s ", class_name); + if (Len(paramList)) + Printf(doc, "self, %s) -> %s", paramList, class_name); + else + Printf(doc, "self) -> %s", class_name); + } else + Printf(doc, "%s(%s) -> %s", symname, make_autodocParmList(n, showTypes), class_name); + break; + + case AUTODOC_DTOR: + if (showTypes) + Printf(doc, "__del__(%s self)", class_name); + else + Printf(doc, "__del__(self)"); + break; + + case AUTODOC_STATICFUNC: + Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); + if (type_str) + Printf(doc, " -> %s", type_str); + break; + + case AUTODOC_FUNC: + Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); + if (type_str) + Printf(doc, " -> %s", type_str); + break; + + case AUTODOC_METHOD: + { + String *paramList = make_autodocParmList(n, showTypes, 2); + Printf(doc, "%s(", symname); + if (showTypes) + Printf(doc, "%s ", class_name); + if (Len(paramList)) + Printf(doc, "self, %s)", paramList); + else + Printf(doc, "self)"); + if (type_str) + Printf(doc, " -> %s", type_str); + } + break; + + case AUTODOC_CONST: + // There is no autodoc support for constants currently, this enum + // element only exists to allow calling docstring() with it. + return NULL; + case AUTODOC_VAR: + // Variables can also be documented (e.g. through the property() function in python) + Printf(doc, "%s", symname); + if (showTypes) { + String *type = Getattr(n, "tmap:doc:type"); + if (!type) + type = Getattr(n, "membervariableHandler:type"); + if (!type) + type = Getattr(n, "type"); + Printf(doc, " : %s", type); + } + break; + } + Delete(type_str); + + // Special case: wrapper functions to get a variable should have no parameters. + // Because the node is re-used for the setter and getter, the feature:pdocs field will + // exist for the getter function, so explicitly avoid printing parameters in this case. + bool variable_getter = kind && Strcmp(kind, "variable") == 0 && Getattr(n, "memberget"); + if (extended && ad_type != AUTODOC_VAR && !variable_getter) { + String *pdocs = Getattr(n, "feature:pdocs"); + if (pdocs) { + Printv(doc, "\n", pdocs, NULL); + } + } + } + // if it's overloaded then get the next decl and loop around again + n = Getattr(n, "sym:nextSibling"); + if (n) + first_func = false; + } + + return doc; + } + + /* ------------------------------------------------------------ + * convertIntegerValue() + * + * Check if string v is an integer and can be represented in + * Python. If so, return an appropriate Python representation, + * otherwise (or if we are unsure), return NIL. + * ------------------------------------------------------------ */ + String *convertIntegerValue(String *v, SwigType *resolved_type) { + const char *const s = Char(v); + char *end; + String *result = NIL; + + // Check if this is an integer number in any base. + errno = 0; + long value = strtol(s, &end, 0); + if (errno == ERANGE || end == s) + return NIL; + + if (*end != '\0') { + // If there is a suffix after the number, we can safely ignore "l" + // and (provided the number is unsigned) "u", and also combinations of + // these, but not anything else. + for (char *p = end; *p != '\0'; ++p) { + switch (*p) { + case 'l': + case 'L': + break; + case 'u': + case 'U': + if (value < 0) + return NIL; + break; + default: + return NIL; + } + } + } + // So now we are certain that we are indeed dealing with an integer + // that has a representation as long given by value. + + // Restrict to guaranteed supported range in Python, see maxint docs: https://docs.python.org/2/library/sys.html#sys.maxint + // Don't do this pointless check when long is 32 bits or smaller as strtol will have already failed with ERANGE +#if LONG_MAX > PYTHON_INT_MAX || LONG_MIN < PYTHON_INT_MIN + if (value > PYTHON_INT_MAX || value < PYTHON_INT_MIN) { + return NIL; + } +#endif + + if (Cmp(resolved_type, "bool") == 0) + // Allow integers as the default value for a bool parameter. + return NewString(value ? "True" : "False"); + + if (value == 0) + return NewString(SwigType_ispointer(resolved_type) ? "None" : "0"); + + // v may still be octal or hexadecimal: + const char *p = s; + if (*p == '+' || *p == '-') + ++p; + if (*p == '0' && *(p+1) != 'x' && *(p+1) != 'X') { + // This must have been an octal number. This is the only case we + // cannot use in Python directly, since Python 2 and 3 use non- + // compatible representations. + result = NewString(*s == '-' ? "int(\"-" : "int(\""); + String *octal_string = NewStringWithSize(p, (int) (end - p)); + Append(result, octal_string); + Append(result, "\", 8)"); + Delete(octal_string); + return result; + } + result = *end == '\0' ? Copy(v) : NewStringWithSize(s, (int) (end - s)); + return result; + } + + /* ------------------------------------------------------------ + * convertDoubleValue() + * + * Check if the given string looks like a decimal floating point constant + * and return it if it does, otherwise return NIL. + * ------------------------------------------------------------ */ + String *convertDoubleValue(String *v) { + const char *const s = Char(v); + char *end; + + errno = 0; + double value = strtod(s, &end); + (void) value; + if (errno != ERANGE && end != s) { + // An added complication: at least some versions of strtod() recognize + // hexadecimal floating point numbers which don't exist in Python, so + // detect them ourselves and refuse to convert them (this can't be done + // without loss of precision in general). + // + // Also don't accept neither "NAN" nor "INFINITY" (both of which + // conveniently contain "n"). + if (strpbrk(s, "xXnN")) + return NIL; + + // Disregard optional "f" suffix, it can be just dropped in Python as it + // uses doubles for everything anyhow. + for (char * p = end; *p != '\0'; ++p) { + switch (*p) { + case 'f': + case 'F': + break; + + default: + return NIL; + } + } + + // Avoid unnecessary string allocation in the common case when we don't + // need to remove any suffix. + return *end == '\0' ? Copy(v) : NewStringWithSize(s, (int)(end - s)); + } + + return NIL; + } + + /* ------------------------------------------------------------ + * convertValue() + * + * Check if string v can be a Python value literal or a + * constant. Return an equivalent Python representation, + * or NIL if it isn't, or we are unsure. + * ------------------------------------------------------------ */ + String *convertValue(String *v, SwigType *type) { + const char *const s = Char(v); + String *result = NIL; + SwigType *resolved_type = SwigType_typedef_resolve_all(type); + + result = convertIntegerValue(v, resolved_type); + if (!result) { + result = convertDoubleValue(v); + if (!result) { + if (Strcmp(v, "true") == 0) + result = NewString("True"); + else if (Strcmp(v, "false") == 0) + result = NewString("False"); + else if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) + result = SwigType_ispointer(resolved_type) ? NewString("None") : NewString("0"); + // This could also be an enum type, default value of which could be + // representable in Python if it doesn't include any scope (which could, + // but currently is not, translated). + else if (!Strchr(s, ':')) { + Node *lookup = Swig_symbol_clookup(v, 0); + if (lookup) { + if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0) + result = Copy(Getattr(lookup, "sym:name")); + } + } + } + } + + Delete(resolved_type); + return result; + } + + /* ------------------------------------------------------------ + * is_representable_as_pyargs() + * + * Check if the function parameters default argument values + * can be represented in Python. + * + * If this method returns false, the parameters will be translated + * to a generic "*args" which allows us to deal with default values + * at C++ code level where they can always be handled. + * ------------------------------------------------------------ */ + bool is_representable_as_pyargs(Node *n) { + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Swig_typemap_attach_parms("default", plist, NULL); + + Parm *p; + Parm *pnext; + + for (p = plist; p; p = pnext) { + pnext = nextSibling(p); + String *tm = Getattr(p, "tmap:in"); + if (tm) { + Parm *in_next = Getattr(p, "tmap:in:next"); + if (in_next) + pnext = in_next; + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } + + // "default" typemap can contain arbitrary C++ code, so while it could, in + // principle, be possible to examine it and check if it's just something + // simple of the form "$1 = expression" and then use convertValue() to + // check if expression can be used in Python, but for now we just + // pessimistically give up and prefer to handle this at C++ level only. + if (Getattr(p, "tmap:default")) + return false; + + String *value = Getattr(p, "value"); + if (value) { + String *convertedValue = convertValue(value, Getattr(p, "type")); + if (!convertedValue) + return false; + Delete(convertedValue); + } + } + + return true; + } + + + /* ------------------------------------------------------------ + * is_real_overloaded() + * + * Check if the function is overloaded, but not just have some + * siblings generated due to the original function having + * default arguments. + * ------------------------------------------------------------ */ + bool is_real_overloaded(Node *n) { + Node *h = Getattr(n, "sym:overloaded"); + Node *i; + if (!h) + return false; + + i = Getattr(h, "sym:nextSibling"); + while (i) { + Node *nn = Getattr(i, "defaultargs"); + if (nn != h) { + /* Check if overloaded function has defaultargs and + * pointed to the first overloaded. */ + return true; + } + i = Getattr(i, "sym:nextSibling"); + } + + return false; + } + + /* ------------------------------------------------------------ + * make_pyParmList() + * + * Generate parameter list for Python functions or methods, + * reuse make_autodocParmList() to do so. + * ------------------------------------------------------------ */ + String *make_pyParmList(Node *n, bool in_class, bool is_calling, int kw, bool has_self_for_count = false) { + /* Get the original function for a defaultargs copy, + * see default_arguments() in parser.y. */ + Node *nn = Getattr(n, "defaultargs"); + if (nn) + n = nn; + + Parm *parms = Getattr(n, "parms"); + int varargs = parms ? emit_isvarargs(parms) : 0; + + /* We prefer to explicitly list all parameters of the C function in the + generated Python code as this makes the function more convenient to use, + however in some cases we must replace the real parameters list with just + the catch all "*args". This happens when: + + 1. The function is overloaded as Python doesn't support this. + 2. We were explicitly asked to use the "compact" arguments form. + 3. We were explicitly asked to use default args from C via the "python:cdefaultargs" feature. + 4. One of the default argument values can't be represented in Python. + 5. Varargs that haven't been forced to use a fixed number of arguments with %varargs. + */ + if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n) || varargs) { + String *parms = NewString(""); + if (in_class) + Printf(parms, "self, "); + Printf(parms, "*args"); + if (kw) + Printf(parms, ", **kwargs"); + return parms; + } + + bool funcanno = py3 ? true : false; + String *params = NewString(""); + String *_params = make_autodocParmList(n, false, ((in_class || has_self_for_count)? 2 : 1), is_calling, funcanno); + + if (in_class) { + Printf(params, "self"); + if (Len(_params) > 0) + Printf(params, ", "); + } + + Printv(params, _params, NULL); + + return params; + } + + /* ------------------------------------------------------------ + * have_pythonprepend() + * + * Check if there is a %pythonprepend directive and it has text + * ------------------------------------------------------------ */ + + bool have_pythonprepend(Node *n) { + String *str = Getattr(n, "feature:pythonprepend"); + return (str && Len(str) > 0); + } + + /* ------------------------------------------------------------ + * pythonprepend() + * + * Get the %pythonprepend code, stripping off {} if necessary + * ------------------------------------------------------------ */ + + String *pythonprepend(Node *n) { + String *str = Getattr(n, "feature:pythonprepend"); + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + return str; + } + + /* ------------------------------------------------------------ + * have_pythonappend() + * + * Check if there is a %pythonappend directive and it has text + * ------------------------------------------------------------ */ + + bool have_pythonappend(Node *n) { + String *str = Getattr(n, "feature:pythonappend"); + if (!str) + str = Getattr(n, "feature:addtofunc"); + return (str && Len(str) > 0); + } + + /* ------------------------------------------------------------ + * pythonappend() + * + * Get the %pythonappend code, stripping off {} if necessary + * ------------------------------------------------------------ */ + + String *pythonappend(Node *n) { + String *str = Getattr(n, "feature:pythonappend"); + if (!str) + str = Getattr(n, "feature:addtofunc"); + + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + return str; + } + + /* ------------------------------------------------------------ + * have_addtofunc() + * + * Check if there is a %addtofunc directive and it has text + * ------------------------------------------------------------ */ + + bool have_addtofunc(Node *n) { + return have_pythonappend(n) || have_pythonprepend(n); + } + + + /* ------------------------------------------------------------ + * returnTypeAnnotation() + * + * Helper function for constructing the function annotation + * of the returning type, return a empty string for Python 2.x + * ------------------------------------------------------------ */ + String *returnTypeAnnotation(Node *n) { + String *ret = 0; + Parm *p = Getattr(n, "parms"); + String *tm; + /* Try to guess the returning type by argout typemap, + * however the result may not accurate. */ + while (p) { + if ((tm = Getattr(p, "tmap:argout:match_type"))) { + tm = SwigType_str(tm, 0); + if (ret) + Printv(ret, ", ", tm, NULL); + else + ret = tm; + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + /* If no argout typemap, then get the returning type from + * the function prototype. */ + if (!ret) { + ret = Getattr(n, "type"); + if (ret) + ret = SwigType_str(ret, 0); + } + return (ret && py3) ? NewStringf(" -> \"%s\"", ret) + : NewString(""); + } + + /* ------------------------------------------------------------ + * emitFunctionShadowHelper() + * + * Refactoring some common code out of functionWrapper and + * dispatchFunction that writes the proxy code for non-member + * functions. + * ------------------------------------------------------------ */ + + void emitFunctionShadowHelper(Node *n, File *f_dest, String *name, int kw) { + String *parms = make_pyParmList(n, false, false, kw); + String *callParms = make_pyParmList(n, false, true, kw); + + // Callbacks need the C function in order to extract the pointer from the swig_ptr: string + bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback"); + + if (!fast || olddefs) { + /* Make a wrapper function to insert the code into */ + Printv(f_dest, "\n", "def ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4, true), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_dest, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_dest, tab4 "val = ", funcCall(name, callParms), "\n", NIL); + Printv(f_dest, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_dest, tab4 "return val\n", NIL); + } else { + Printv(f_dest, tab4 "return ", funcCall(name, callParms), "\n", NIL); + } + } + + // Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first. + if (fast) { + /* If there is no addtofunc directive then just assign from the extension module (for speed up) */ + Printv(f_dest, name, " = ", module, ".", name, "\n", NIL); + } + } + + + /* ------------------------------------------------------------ + * check_kwargs() + * + * check if using kwargs is allowed for this Node + * ------------------------------------------------------------ */ + + int check_kwargs(Node *n) const { + return (use_kw || GetFlag(n, "feature:kwargs")) + && !GetFlag(n, "memberset") && !GetFlag(n, "memberget"); + } + + + + /* ------------------------------------------------------------ + * add_method() + * ------------------------------------------------------------ */ + + void add_method(String *name, String *function, int kw, Node *n = 0, int funpack = 0, int num_required = -1, int num_arguments = -1) { + String * meth_str = NewString(""); + if (!kw) { + if (funpack) { + if (num_required == 0 && num_arguments == 0) { + Printf(meth_str, "\t { \"%s\", %s, METH_NOARGS, ", name, function); + } else if (num_required == 1 && num_arguments == 1) { + Printf(meth_str, "\t { \"%s\", %s, METH_O, ", name, function); + } else { + Printf(meth_str, "\t { \"%s\", %s, METH_VARARGS, ", name, function); + } + } else { + Printf(meth_str, "\t { \"%s\", %s, METH_VARARGS, ", name, function); + } + } else { + // Cast via void(*)(void) to suppress GCC -Wcast-function-type warning. + // Python should always call the function correctly, but the Python C API + // requires us to store it in function pointer of a different type. + Printf(meth_str, "\t { \"%s\", (PyCFunction)(void(*)(void))%s, METH_VARARGS|METH_KEYWORDS, ", name, function); + } + Append(methods, meth_str); + if (fastproxy) { + Append(methods_proxydocs, meth_str); + } + Delete(meth_str); + + if (!n) { + Append(methods, "NULL"); + if (fastproxy) { + Append(methods_proxydocs, "NULL"); + } + } else if (have_docstring(n)) { + /* Use the low-level docstring here since this is the docstring that will be used for the C API */ + String *ds = cdocstring(n, Getattr(n, "memberfunction") ? AUTODOC_METHOD : AUTODOC_FUNC, true); + Printf(methods, "\"%s\"", ds); + if (fastproxy) { + /* In the fastproxy case, we must also record the high-level docstring for use in the Python shadow API */ + Delete(ds); + ds = cdocstring(n, Getattr(n, "memberfunction") ? AUTODOC_METHOD : AUTODOC_FUNC); + Printf(methods_proxydocs, "\"%s\"", ds); + } + Delete(ds); + } else if (Getattr(n, "feature:callback")) { + Printf(methods, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + if (fastproxy) { + Printf(methods_proxydocs, "\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + } + } else { + Append(methods, "NULL"); + if (fastproxy) { + Append(methods_proxydocs, "NULL"); + } + } + + Append(methods, "},\n"); + if (fastproxy) { + Append(methods_proxydocs, "},\n"); + } + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + void dispatchFunction(Node *n, String *linkage, int funpack = 0, bool builtin_self = false, bool builtin_ctor = false, bool director_class = false) { + /* Last node in overloaded chain */ + + bool add_self = builtin_self && (!builtin_ctor || director_class); + + int maxargs; + + String *tmp = NewString(""); + String *dispatch; + + const char *dispatch_call = funpack ? "%s(self, argc, argv);" : (builtin_ctor ? "%s(self, args, NULL);" : "%s(self, args);"); + String *dispatch_code = NewStringf("return %s", dispatch_call); + + if (castmode) { + dispatch = Swig_overload_dispatch_cast(n, dispatch_code, &maxargs); + } else { + String *fastdispatch_code; + if (builtin_ctor) + fastdispatch_code = NewStringf("int retval = %s\nif (retval == 0 || !SWIG_Python_TypeErrorOccurred(NULL)) return retval;\nSWIG_fail;", dispatch_call); + else + fastdispatch_code = NewStringf("PyObject *retobj = %s\nif (!SWIG_Python_TypeErrorOccurred(retobj)) return retobj;\nSWIG_fail;", dispatch_call); + if (!CPlusPlus) { + Insert(fastdispatch_code, 0, "{\n"); + Append(fastdispatch_code, "\n}"); + } + dispatch = Swig_overload_dispatch(n, dispatch_code, &maxargs, fastdispatch_code); + Delete(fastdispatch_code); + } + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : ""; + Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL); + + Wrapper_add_local(f, "argc", "Py_ssize_t argc"); + Printf(tmp, "PyObject *argv[%d] = {0}", maxargs + 1); + Wrapper_add_local(f, "argv", tmp); + + if (!fastunpack) { + Wrapper_add_local(f, "ii", "Py_ssize_t ii"); + + if (builtin_ctor) + Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname); + + if (maxargs - (add_self ? 1 : 0) > 0) { + Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n"); + Append(f->code, "argc = PyObject_Length(args);\n"); + } else { + Append(f->code, "argc = args ? PyObject_Length(args) : 0;\n"); + } + + if (add_self) + Append(f->code, "argv[0] = self;\n"); + Printf(f->code, "for (ii = 0; (ii < %d) && (ii < argc); ii++) {\n", add_self ? maxargs - 1 : maxargs); + Printf(f->code, "argv[ii%s] = PyTuple_GET_ITEM(args,ii);\n", add_self ? " + 1" : ""); + Append(f->code, "}\n"); + if (add_self) + Append(f->code, "argc++;\n"); + } else { + if (builtin_ctor) + Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname); + Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", symname, maxargs, add_self ? "+1" : ""); + if (add_self) + Append(f->code, "argv[0] = self;\n"); + else + Append(f->code, "--argc;\n"); + } + + Replaceall(dispatch, "$args", "self, args"); + + Printv(f->code, dispatch, "\n", NIL); + + if (GetFlag(n, "feature:python:maybecall")) { + Append(f->code, "fail:\n"); + Append(f->code, " Py_INCREF(Py_NotImplemented);\n"); + Append(f->code, " return Py_NotImplemented;\n"); + } else { + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + String *fulldecl = Swig_name_decl(sibl); + Printf(protoTypes, "\n\" %s\\n\"", fulldecl); + Delete(fulldecl); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Append(f->code, "fail:\n"); + Printf(f->code, " SWIG_Python_RaiseOrModifyTypeError(" + "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); + Printf(f->code, "return %s;\n", builtin_ctor ? "-1" : "0"); + Delete(protoTypes); + } + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + Node *p = Getattr(n, "sym:previousSibling"); + if (!builtin_self) + add_method(symname, wname, 0, p); + + /* Create a shadow for this function (if enabled and not in a member function) */ + if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, symname, 0); + } + DelWrapper(f); + Delete(dispatch); + Delete(dispatch_code); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + /* + A note about argument marshalling with built-in types. + There are three distinct cases for member (non-static) methods: + + 1) An ordinary member function. In this case, the first param in + the param list is 'this'. For builtin types, 'this' is taken from + the first argument to the wrapper (usually called 'self); it's not + extracted from the second argument (which is usually a tuple). + + 2) A constructor for a non-director class. In this case, the + param list doesn't contain an entry for 'this', but the first ('self') + argument to the wrapper *does* contain the newly-allocated, + uninitialized object. + + 3) A constructor for a director class. In this case, the param + list contains a 'self' param, which comes from the first argument + to the wrapper function. + */ + + const char *get_implicitconv_flag(Node *klass) { + int conv = 0; + if (klass && GetFlag(klass, "feature:implicitconv")) { + conv = 1; + } + return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0"; + } + + + virtual int functionWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Node *parent = Swig_methodclass(n); + + int director_method = 0; + + Parm *p; + int i; + char source[64]; + Wrapper *f; + String *self_parse; + String *parse_args; + String *arglist; + String *get_pointers; + String *cleanup; + String *outarg; + String *kwargs; + String *tm; + String *overname = 0; + + int num_required; + int num_arguments; + int num_fixed_arguments; + int tuple_required; + int tuple_arguments; + int varargs = 0; + int allow_kwargs = check_kwargs(n); + + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + int destructor = (!Cmp(nodeType, "destructor")); + String *storage = Getattr(n, "storage"); + /* Only the first constructor is handled as init method. Others + constructor can be emitted via %rename */ + int handled_as_init = 0; + if (!have_constructor && (constructor || Getattr(n, "handled_as_constructor")) + && ((shadow & PYSHADOW_MEMBER))) { + String *nname = Getattr(n, "sym:name"); + String *sname = Getattr(getCurrentClass(), "sym:name"); + String *cname = Swig_name_construct(NSPACE_TODO, sname); + handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); + Delete(cname); + } + bool builtin_self = builtin && in_class && (constructor || (l && Getattr(l, "self"))); + bool builtin_ctor = false; + if (builtin_self && constructor) { + String *class_mname = Getattr(getCurrentClass(), "sym:name"); + String *mrename = Swig_name_construct(getNSpace(), class_mname); + if (Cmp(iname, mrename)) + builtin_self = false; + else + builtin_ctor = true; + Delete(mrename); + } + bool director_class = (getCurrentClass() && Swig_directorclass(getCurrentClass())); + bool add_self = builtin_self && (!builtin_ctor || director_class); + bool builtin_getter = (builtin && GetFlag(n, "memberget")); + bool builtin_setter = (builtin && GetFlag(n, "memberset") && !builtin_getter); + char const *self_param = builtin ? "self" : "SWIGUNUSEDPARM(self)"; + char const *wrap_return = builtin_ctor ? "int " : "PyObject *"; + String *linkage = NewString("SWIGINTERN "); + String *wrapper_name = Swig_name_wrapper(iname); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + self_parse = NewString(""); + parse_args = NewString(""); + arglist = NewString(""); + get_pointers = NewString(""); + cleanup = NewString(""); + outarg = NewString(""); + kwargs = NewString(""); + + int allow_thread = threads_enable(n); + + Wrapper_add_local(f, "resultobj", "PyObject *resultobj = 0"); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + /* Get number of required and total arguments */ + tuple_arguments = num_arguments = emit_num_arguments(l); + tuple_required = num_required = emit_num_required(l); + if (add_self) { + --tuple_arguments; + --tuple_required; + } + num_fixed_arguments = tuple_required; + + // builtin handles/checks kwargs by default except in constructor wrappers so we need to explicitly handle them in the C constructor wrapper + // The check below is for zero arguments. Sometimes (eg directors) self is the first argument for a method with zero arguments. + if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self"))) + if (!builtin_ctor) + allow_kwargs = 0; + varargs = emit_isvarargs(l); + + String *wname = Copy(wrapper_name); + if (overname) { + Append(wname, overname); + } + + const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : ""; + if (!allow_kwargs || overname) { + if (!varargs) { + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); + } else { + Printv(f->def, linkage, wrap_return, wname, "__varargs__", "(PyObject *", self_param, ", PyObject *args, PyObject *varargs) {", NIL); + } + if (allow_kwargs) { + Swig_warning(WARN_LANG_OVERLOAD_KEYWORD, input_file, line_number, "Can't use keyword arguments with overloaded functions (%s).\n", Swig_name_decl(n)); + allow_kwargs = 0; + } + } else { + if (varargs) { + Swig_warning(WARN_LANG_VARARGS_KEYWORD, input_file, line_number, "Can't wrap varargs with keyword arguments enabled\n"); + varargs = 0; + } + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args, PyObject *kwargs) {", NIL); + } + if (!builtin || !in_class || tuple_arguments > 0 || builtin_ctor) { + if (!allow_kwargs) { + Append(parse_args, " if (!PyArg_ParseTuple(args, \""); + } else { + Append(parse_args, " if (!PyArg_ParseTupleAndKeywords(args, kwargs, \""); + Append(arglist, ", kwnames"); + } + } + + bool over_varargs = emit_isvarargs_function(n); + + int funpack = fastunpack && !varargs && !over_varargs && !allow_kwargs; + int noargs = funpack && (tuple_required == 0 && tuple_arguments == 0); + int onearg = funpack && (tuple_required == 1 && tuple_arguments == 1); + + if (builtin && funpack && !overname && !builtin_ctor) { + int compactdefargs = ParmList_is_compactdefargs(l); + if (!(compactdefargs && (tuple_arguments > tuple_required || varargs))) { + String *argattr = NewStringf("%d", tuple_arguments); + Setattr(n, "python:argcount", argattr); + Delete(argattr); + } + } + + /* Generate code for argument marshalling */ + if (funpack) { + if (num_arguments > 0 && !overname) { + sprintf(source, "PyObject *swig_obj[%d]", num_arguments); + Wrapper_add_localv(f, "swig_obj", source, NIL); + } + } + + + if (constructor && num_arguments == 1 && num_required == 1) { + if (Cmp(storage, "explicit") == 0) { + if (GetFlag(parent, "feature:implicitconv")) { + String *desc = NewStringf("SWIGTYPE%s", SwigType_manglestr(Getattr(n, "type"))); + Printf(f->code, "if (SWIG_CheckImplicit(%s)) SWIG_fail;\n", desc); + Delete(desc); + } + } + } + + if (builtin_ctor && checkAttribute(n, "access", "protected")) { + String *tmp_none_comparison = Copy(none_comparison); + Replaceall(tmp_none_comparison, "$arg", "self"); + Printf(self_parse, "if (!(%s)) {\n", tmp_none_comparison); + Printv(self_parse, " SWIG_SetErrorMsg(PyExc_RuntimeError, \"accessing abstract class or protected constructor\");\n SWIG_fail;\n}\n", NIL); + Delete(tmp_none_comparison); + } + + int use_parse = 0; + Append(kwargs, "{"); + 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"); + bool parse_from_tuple = (i > 0 || !add_self); + if (SwigType_type(pt) == T_VARARGS) { + parse_from_tuple = false; + num_fixed_arguments -= atoi(Char(Getattr(p, "tmap:in:numinputs"))); + } + if (!parse_from_tuple) + sprintf(source, "self"); + else if (funpack) + sprintf(source, "swig_obj[%d]", add_self && !overname ? i - 1 : i); + else + sprintf(source, "obj%d", builtin_ctor ? i + 1 : i); + + if (parse_from_tuple) { + Printf(arglist, ", "); + if (i == num_required) + Putc('|', parse_args); /* Optional argument separator */ + } + + /* Keyword argument handling */ + if (allow_kwargs && parse_from_tuple) { + String *name = makeParameterName(n, p, i + 1); + Printf(kwargs, " (char *)\"%s\", ", name); + Delete(name); + } + + /* Look for an input typemap */ + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + if (builtin_self) { + Replaceall(tm, "$self", "self"); + } else if (funpack) { + Replaceall(tm, "$self", "swig_obj[0]"); + } else { + Replaceall(tm, "$self", "obj0"); + } + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); /* Save the location of the object */ + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + if (Getattr(p, "tmap:in:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p, "hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + Replaceall(tm, "$implicitconv", convflag); + Setattr(p, "implicitconv", convflag); + } + + if (parse_from_tuple) + Putc('O', parse_args); + if (!funpack && parse_from_tuple) { + Wrapper_add_localv(f, source, "PyObject *", source, "= 0", NIL); + Printf(arglist, "&%s", source); + } + if (i >= num_required) + Printv(get_pointers, "if (", source, ") {\n", NIL); + Printv(get_pointers, tm, "\n", NIL); + if (i >= num_required) + Printv(get_pointers, "}\n", NIL); + + } else { + use_parse = 1; + Append(parse_args, parse); + if (parse_from_tuple) + Printf(arglist, "&%s", ln); + } + p = Getattr(p, "tmap:in:next"); + continue; + } 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)); + break; + } + } + + /* finish argument marshalling */ + Append(kwargs, " NULL }"); + if (allow_kwargs) { + Printv(f->locals, " char * kwnames[] = ", kwargs, ";\n", NIL); + } + + if (use_parse || allow_kwargs) { + Printf(parse_args, ":%s\"", iname); + Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + funpack = 0; + } else { + Clear(parse_args); + + if (funpack) { + Clear(f->def); + if (overname) { + if (noargs) { + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); + } else { + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); + } + Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); + } else { + int is_tp_call = Equal(Getattr(n, "feature:python:slot"), "tp_call"); + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); + if (builtin_ctor) + Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname); + if (onearg && !builtin_ctor && !is_tp_call) { + Printf(parse_args, "if (!args) SWIG_fail;\n"); + Append(parse_args, "swig_obj[0] = args;\n"); + } else if (!noargs) { + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args, \"%s\", %d, %d, swig_obj)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); + } else if (noargs) { + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args, \"%s\", %d, %d, 0)) SWIG_fail;\n", iname, num_fixed_arguments, tuple_arguments); + } + } + } else { + if (builtin_ctor) + Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname); + if (builtin && in_class && tuple_arguments == 0) { + Printf(parse_args, " if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname); + } else { + Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments); + Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + } + } + } + + /* Now piece together the first part of the wrapper function */ + Printv(f->code, self_parse, parse_args, get_pointers, NIL); + + /* Check for trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if (!Getattr(p, "tmap:in:parse") && (tm = Getattr(p, "tmap:freearg"))) { + if (Getattr(p, "tmap:freearg:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p, "hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + if (strcmp(convflag, "0") == 0) { + tm = 0; + } + } + if (tm && (Len(tm) != 0)) { + Replaceall(tm, "$source", Getattr(p, "lname")); + 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"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* if the object is a director, and the method call originated from its + * underlying python object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in python. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); + if (dirprot_mode() && !is_public(n)) { + Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name); + Printf(f->code, "SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing protected member %s\");\n", name); + Append(f->code, "SWIG_fail;\n"); + Append(f->code, "}\n"); + } + Wrapper_add_local(f, "upcall", "bool upcall = false"); + if (funpack) { + const char *self_parm = builtin_self ? "self" : "swig_obj[0]"; + Printf(f->code, "upcall = (director && (director->swig_get_self()==%s));\n", self_parm); + } else { + const char *self_parm = builtin_self ? "self" : "obj0"; + Printf(f->code, "upcall = (director && (director->swig_get_self()==%s));\n", self_parm); + } + } + + /* Emit the function call */ + if (director_method) { + Append(f->code, "try {\n"); + } else { + if (allow_thread) { + String *preaction = NewString(""); + thread_begin_allow(n, preaction); + Setattr(n, "wrap:preaction", preaction); + + String *postaction = NewString(""); + thread_end_allow(n, postaction); + Setattr(n, "wrap:postaction", postaction); + } + } + + Setattr(n, "wrap:name", wname); + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (director_method) { + Append(actioncode, "} catch (Swig::DirectorException&) {\n"); + Append(actioncode, " SWIG_fail;\n"); + Append(actioncode, "}\n"); + } + + /* This part below still needs cleanup */ + + /* Return the function value */ + tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode); + + if (tm) { + if (builtin_self) { + Replaceall(tm, "$self", "self"); + } else if (funpack) { + Replaceall(tm, "$self", "swig_obj[0]"); + } else { + Replaceall(tm, "$self", "obj0"); + } + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + if (builtin_ctor) { + Replaceall(tm, "$owner", "SWIG_BUILTIN_INIT"); + } else if (handled_as_init) { + Replaceall(tm, "$owner", "SWIG_POINTER_NEW"); + } else { + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm, "$owner", "0"); + } + } + // FIXME: this will not try to unwrap directors returned as non-director + // base class pointers! + + /* New addition to unwrap director return values so that the original + * python object is returned instead. + */ +#if 1 + int unwrap = 0; + String *decl = Getattr(n, "decl"); + int is_pointer = SwigType_ispointer_return(decl); + int is_reference = SwigType_isreference_return(decl); + if (is_pointer || is_reference) { + String *type = Getattr(n, "type"); + //Node *classNode = Swig_methodclass(n); + //Node *module = Getattr(classNode, "module"); + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, type); + if (target) + unwrap = 1; + } + if (unwrap) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = SWIG_DIRECTOR_CAST(%s);\n", Swig_cresult_name()); + Append(f->code, "if (director) {\n"); + Append(f->code, " resultobj = director->swig_get_self();\n"); + Append(f->code, " Py_INCREF(resultobj);\n"); + Append(f->code, "} else {\n"); + Printf(f->code, "%s\n", tm); + Append(f->code, "}\n"); + } else { + Printf(f->code, "%s\n", tm); + } +#else + Printf(f->code, "%s\n", tm); +#endif + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + int need_cleanup = Len(cleanup) != 0; + if (need_cleanup) { + 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))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$result", "resultobj"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + if (builtin_ctor) + Append(f->code, " return resultobj == Py_None ? -1 : 0;\n"); + else + Append(f->code, " return resultobj;\n"); + + /* Error handling code */ + + Append(f->code, "fail:\n"); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + if (builtin_ctor) { + Printv(f->code, " return -1;\n", NIL); + } else { + if (GetFlag(n, "feature:python:maybecall")) { + Append(f->code, " PyErr_Clear();\n"); + Append(f->code, " Py_INCREF(Py_NotImplemented);\n"); + Append(f->code, " return Py_NotImplemented;\n"); + } else { + Printv(f->code, " return NULL;\n", NIL); + } + } + + Append(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", "resultobj"); + + if (builtin_self) { + Replaceall(f->code, "$self", "self"); + } else if (funpack) { + Replaceall(f->code, "$self", "swig_obj[0]"); + } else { + Replaceall(f->code, "$self", "obj0"); + } + + /* Dump the function out */ + Wrapper_print(f, f_wrappers); + + /* If varargs. Need to emit a varargs stub */ + if (varargs) { + DelWrapper(f); + f = NewWrapper(); + if (funpack) { + // Note: funpack is currently always false for varargs + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", Py_ssize_t nobjs, PyObject **swig_obj) {", NIL); + } else { + Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL); + } + Wrapper_add_local(f, "resultobj", builtin_ctor ? "int resultobj" : "PyObject *resultobj"); + Wrapper_add_local(f, "varargs", "PyObject *varargs"); + Wrapper_add_local(f, "newargs", "PyObject *newargs"); + if (funpack) { + Wrapper_add_local(f, "i", "int i"); + Printf(f->code, "newargs = PyTuple_New(%d);\n", num_fixed_arguments); + Printf(f->code, "for (i = 0; i < %d; ++i) {\n", num_fixed_arguments); + Printf(f->code, " PyTuple_SET_ITEM(newargs, i, swig_obj[i]);\n"); + Printf(f->code, " Py_XINCREF(swig_obj[i]);\n"); + Printf(f->code, "}\n"); + Printf(f->code, "varargs = PyTuple_New(nobjs > %d ? nobjs - %d : 0);\n", num_fixed_arguments, num_fixed_arguments); + Printf(f->code, "for (i = 0; i < nobjs - %d; ++i) {\n", num_fixed_arguments); + Printf(f->code, " PyTuple_SET_ITEM(newargs, i, swig_obj[i + %d]);\n", num_fixed_arguments); + Printf(f->code, " Py_XINCREF(swig_obj[i + %d]);\n", num_fixed_arguments); + Printf(f->code, "}\n"); + } else { + Printf(f->code, "newargs = PyTuple_GetSlice(args,0,%d);\n", num_fixed_arguments); + Printf(f->code, "varargs = PyTuple_GetSlice(args,%d,PyTuple_Size(args));\n", num_fixed_arguments); + } + Printf(f->code, "resultobj = %s__varargs__(%s,newargs,varargs);\n", wname, builtin ? "self" : "NULL"); + Append(f->code, "Py_XDECREF(newargs);\n"); + Append(f->code, "Py_XDECREF(varargs);\n"); + Append(f->code, "return resultobj;\n"); + Append(f->code, "}\n"); + Wrapper_print(f, f_wrappers); + } + + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + if (!builtin_self) + add_method(iname, wname, allow_kwargs, n, funpack, num_required, num_arguments); + + /* Create a shadow for this function (if enabled and not in a member function) */ + if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, iname, allow_kwargs); + } + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n, linkage, funpack, builtin_self, builtin_ctor, director_class); + } + } + + // Put this in tp_init of the PyTypeObject + if (builtin_ctor) { + if ((director_method || !is_private(n)) && !Getattr(class_members, iname)) { + Setattr(class_members, iname, n); + if (!builtin_tp_init) + builtin_tp_init = Swig_name_wrapper(iname); + } + } + + /* If this is a builtin type, create a PyGetSetDef entry for this member variable. */ + if (builtin) { + const char *memname = "__dict__"; + Hash *h = Getattr(builtin_getset, memname); + if (!h) { + h = NewHash(); + Setattr(builtin_getset, memname, h); + Delete(h); + } + Setattr(h, "getter", "SwigPyObject_get___dict__"); + if (!Getattr(h, "doc")) { + Setattr(n, "doc:high:name", Getattr(n, "name")); + Setattr(h, "doc", cdocstring(n, AUTODOC_VAR)); + } + } + + if (builtin_getter) { + String *memname = Getattr(n, "membervariableHandler:sym:name"); + if (!memname) + memname = iname; + Hash *h = Getattr(builtin_getset, memname); + if (!h) { + h = NewHash(); + Setattr(builtin_getset, memname, h); + Delete(h); + } + Setattr(h, "getter", wrapper_name); + Delattr(n, "memberget"); + if (!Getattr(h, "doc")) { + Setattr(n, "doc:high:name", Getattr(n, "name")); + String *ds = cdocstring(n, AUTODOC_VAR); + Setattr(h, "doc", ds); + Delete(ds); + } + } + if (builtin_setter) { + String *memname = Getattr(n, "membervariableHandler:sym:name"); + if (!memname) + memname = iname; + Hash *h = Getattr(builtin_getset, memname); + if (!h) { + h = NewHash(); + Setattr(builtin_getset, memname, h); + Delete(h); + } + Setattr(h, "setter", wrapper_name); + Delattr(n, "memberset"); + if (!Getattr(h, "doc")) { + Setattr(n, "doc:high:name", Getattr(n, "name")); + String *ds = cdocstring(n, AUTODOC_VAR); + Setattr(h, "doc", ds); + Delete(ds); + } + } + + if (in_class && builtin) { + /* Handle operator overloads for builtin types */ + String *slot = Getattr(n, "feature:python:slot"); + if (slot) { + String *func_type = Getattr(n, "feature:python:slot:functype"); + String *closure_decl = getClosure(func_type, wrapper_name, overname ? 0 : funpack); + String *feature_name = NewStringf("feature:python:%s", slot); + String *closure_name = 0; + if (closure_decl) { + closure_name = NewStringf("%s_%s_closure", wrapper_name, func_type); + if (!GetFlag(builtin_closures, closure_name)) + Printf(builtin_closures_code, "%s /* defines %s */\n\n", closure_decl, closure_name); + SetFlag(builtin_closures, closure_name); + Delete(closure_decl); + } else { + closure_name = Copy(wrapper_name); + } + if (func_type) { + String *s = NewStringf("%s", closure_name); + Delete(closure_name); + closure_name = s; + } + Setattr(parent, feature_name, closure_name); + Delete(feature_name); + Delete(closure_name); + } + + /* Handle comparison operators for builtin types */ + String *compare = Getattr(n, "feature:python:compare"); + if (compare) { + Hash *richcompare = Getattr(parent, "python:richcompare"); + assert(richcompare); + Setattr(richcompare, compare, wrapper_name); + } + } + + Delete(self_parse); + Delete(parse_args); + Delete(linkage); + Delete(arglist); + Delete(get_pointers); + Delete(cleanup); + Delete(outarg); + Delete(kwargs); + Delete(wname); + DelWrapper(f); + Delete(wrapper_name); + return SWIG_OK; + } + + + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + static int have_globals = 0; + String *tm; + Wrapper *getf, *setf; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + getf = NewWrapper(); + setf = NewWrapper(); + + /* If this is our first call, add the globals variable to the + Python dictionary. */ + + if (!have_globals) { + Printf(f_init, "\t globals = SWIG_globals();\n"); + Printf(f_init, "\t if (!globals) {\n"); + Printf(f_init, " PyErr_SetString(PyExc_TypeError, \"Failure to create SWIG globals.\");\n"); + Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_init, "\t return NULL;\n"); + Printf(f_init, "#else\n"); + Printf(f_init, "\t return;\n"); + Printf(f_init, "#endif\n"); + Printf(f_init, "\t }\n"); + Printf(f_init, "\t PyDict_SetItemString(md, \"%s\", globals);\n", global_name); + Printf(f_init, "\t Py_DECREF(globals);\n"); + if (builtin) + Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", global_name); + have_globals = 1; + if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + Printf(f_shadow_stubs, "%s = %s.%s\n", global_name, module, global_name); + } + } + int assignable = is_assignable(n); + + if (!builtin && shadow && !assignable && !in_class) + Printf(f_shadow_stubs, "%s = %s.%s\n", iname, global_name, iname); + + String *getname = Swig_name_get(NSPACE_TODO, iname); + String *setname = Swig_name_set(NSPACE_TODO, iname); + String *vargetname = NewStringf("Swig_var_%s", getname); + String *varsetname = NewStringf("Swig_var_%s", setname); + + /* Create a function for setting the value of the variable */ + if (assignable) { + Setattr(n, "wrap:name", varsetname); + if (builtin && in_class) { + String *set_wrapper = Swig_name_wrapper(setname); + Setattr(n, "pybuiltin:setter", set_wrapper); + Delete(set_wrapper); + } + Printf(setf->def, "SWIGINTERN int %s(PyObject *_val) {", varsetname); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "_val"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "_val"); + if (Getattr(n, "tmap:varin:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + emit_action_code(n, setf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + } + Printv(setf->code, " return 0;\n", NULL); + Append(setf->code, "fail:\n"); + Printv(setf->code, " return 1;\n", NULL); + } else { + /* Is a readonly variable. Issue an error */ + if (CPlusPlus) { + Printf(setf->def, "SWIGINTERN int %s(PyObject *) {", varsetname); + } else { + Printf(setf->def, "SWIGINTERN int %s(PyObject *_val SWIGUNUSED) {", varsetname); + } + Printv(setf->code, " SWIG_Error(SWIG_AttributeError,\"Variable ", iname, " is read-only.\");\n", " return 1;\n", NIL); + } + + Append(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + + /* Create a function for getting the value of a variable */ + Setattr(n, "wrap:name", vargetname); + if (builtin && in_class) { + String *get_wrapper = Swig_name_wrapper(getname); + Setattr(n, "pybuiltin:getter", get_wrapper); + Delete(get_wrapper); + } + int addfail = 0; + Printf(getf->def, "SWIGINTERN PyObject *%s(void) {", vargetname); + Wrapper_add_local(getf, "pyobj", "PyObject *pyobj = 0"); + if (builtin) { + Wrapper_add_local(getf, "self", "PyObject *self = 0"); + Append(getf->code, " (void)self;\n"); + } + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "pyobj"); + Replaceall(tm, "$result", "pyobj"); + addfail = emit_action_code(n, getf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + Append(getf->code, " return pyobj;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return NULL;\n"); + } + Append(getf->code, "}\n"); + + Wrapper_print(getf, f_wrappers); + + /* Now add this to the variable linking mechanism */ + Printf(f_init, "\t SWIG_addvarlink(globals, \"%s\", %s, %s);\n", iname, vargetname, varsetname); + if (builtin && shadow && !assignable && !in_class) { + Printf(f_init, "\t PyDict_SetItemString(md, \"%s\", PyObject_GetAttrString(globals, \"%s\"));\n", iname, iname); + Printf(f_init, "\t SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", iname); + } + Delete(vargetname); + Delete(varsetname); + Delete(getname); + Delete(setname); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + /* Determine if the node requires the _swigconstant code to be generated */ + bool needs_swigconstant(Node *n) { + SwigType *type = Getattr(n, "type"); + SwigType *qtype = SwigType_typedef_resolve_all(type); + SwigType *uqtype = SwigType_strip_qualifiers(qtype); + bool result = false; + + /* Note, that we need special handling for function pointers, as + * SwigType_base(fptr) does not return the underlying pointer-to-function + * type but the return-type of function. */ + if (!SwigType_isfunction(uqtype) && !SwigType_isfunctionpointer(uqtype)) { + SwigType *basetype = SwigType_base(uqtype); + result = SwigType_isclass(basetype) != 0; + Delete(basetype); + } + + Delete(qtype); + Delete(uqtype); + + return result; + } + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + int have_tm = 0; + int have_builtin_symname = 0; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + String *str = SwigType_str(type, wname); + Printf(f_header, "static %s = %s;\n", str, value); + Delete(str); + value = wname; + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Printf(const_code, "%s,\n", tm); + Delete(tm); + have_tm = 1; + } + + + if (builtin && in_class && Getattr(n, "pybuiltin:symname")) { + have_builtin_symname = 1; + Swig_require("builtin_constantWrapper", n, "*sym:name", "pybuiltin:symname", NIL); + Setattr(n, "sym:name", Getattr(n, "pybuiltin:symname")); + } + + if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + if (needs_swigconstant(n) && !builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER)) && (!in_class || !Getattr(n, "feature:python:callback"))) { + // Generate `*_swigconstant()` method which registers the new constant. + // + // *_swigconstant methods are required for constants of class type. + // Class types are registered in shadow file (see *_swigregister). The + // instances of class must be created (registered) after the type is + // registered, so we can't let SWIG_init() to register constants of + // class type (the SWIG_init() is called before shadow classes are + // defined and registered). + Printf(f_wrappers, "SWIGINTERN PyObject *%s_swigconstant(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", iname); + Printf(f_wrappers, tab2 "PyObject *module;\n", tm); + Printf(f_wrappers, tab2 "PyObject *d;\n"); + Printf(f_wrappers, tab2 "if (!SWIG_Python_UnpackTuple(args, \"swigconstant\", 1, 1, &module)) return NULL;\n"); + Printf(f_wrappers, tab2 "d = PyModule_GetDict(module);\n"); + Printf(f_wrappers, tab2 "if (!d) return NULL;\n"); + Printf(f_wrappers, tab2 "%s\n", tm); + Printf(f_wrappers, tab2 "return SWIG_Py_Void();\n"); + Printf(f_wrappers, "}\n\n\n"); + + // Register the method in SwigMethods array + String *cname = NewStringf("%s_swigconstant", iname); + add_method(cname, cname, 0, 0, 1, 1, 1); + Delete(cname); + } else { + Printf(f_init, "%s\n", tm); + } + Delete(tm); + have_tm = 1; + } + + if (have_builtin_symname) + Swig_restore(n); + + if (!have_tm) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + + if (!builtin && (shadow) && (!(shadow & PYSHADOW_MEMBER))) { + String *f_s; + if (!in_class) { + f_s = f_shadow; + } else { + f_s = Getattr(n, "feature:python:callback") ? NIL : f_shadow_stubs; + } + + if (f_s) { + if (needs_swigconstant(n)) { + Printv(f_s, "\n",NIL); + Printv(f_s, module, ".", iname, "_swigconstant(",module,")\n", NIL); + } + Printv(f_s, iname, " = ", module, ".", iname, "\n", NIL); + if (have_docstring(n)) + Printv(f_s, docstring(n, AUTODOC_CONST, tab4), "\n", NIL); + } + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + add_method(name, wrapname, 0); + if (!builtin && shadow) { + Printv(f_shadow_stubs, name, " = ", module, ".", name, "\n", NIL); + } + return SWIG_OK; + } + + + + /* ---------------------------------------------------------------------------- + * BEGIN C++ Director Class modifications + * ------------------------------------------------------------------------- */ + + /* C++/Python polymorphism demo code + * + * TODO + * + * Move some boilerplate code generation to Swig_...() functions. + * + */ + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * ** Moved down due to gcc-2.96 internal error ** + * --------------------------------------------------------------- */ + + int classDirectorMethods(Node *n); + + int classDirectorMethod(Node *n, Node *parent, String *super); + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("PyObject"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self"), n); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { \n", classname, target, call); + Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); + Append(w->def, "}\n"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + { + Node *parent = Swig_methodclass(n); + String *basetype = Getattr(parent, "classtype"); + Wrapper *w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(PyObject *self) : Swig::Director(self) { \n", classname, classname); + Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); + Append(w->def, "}\n"); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " SwigDirector_%s(PyObject *self);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + String *classname = Swig_class_name(n); + + if (dirprot_mode()) { + /* + This implementation uses a std::map<std::string,int>. + + It should be possible to rewrite it using a more elegant way, + like copying the Java approach for the 'override' array. + + But for now, this seems to be the least intrusive way. + */ + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "/* Internal director utilities */\n"); + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_get_inner(const char *swig_protected_method_name) const {\n"); + Printf(f_directors_h, " std::map<std::string, bool>::const_iterator iv = swig_inner.find(swig_protected_method_name);\n"); + Printf(f_directors_h, " return (iv != swig_inner.end() ? iv->second : false);\n"); + Printf(f_directors_h, " }\n"); + + Printf(f_directors_h, " void swig_set_inner(const char *swig_protected_method_name, bool swig_val) const {\n"); + Printf(f_directors_h, " swig_inner[swig_protected_method_name] = swig_val;\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " mutable std::map<std::string, bool> swig_inner;\n"); + + } + if (director_method_index) { + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); + Printf(f_directors_h, "/* VTable implementation */\n"); + Printf(f_directors_h, " PyObject *swig_get_method(size_t method_index, const char *method_name) const {\n"); + Printf(f_directors_h, " PyObject *method = vtable[method_index];\n"); + Printf(f_directors_h, " if (!method) {\n"); + Printf(f_directors_h, " swig::SwigVar_PyObject name = SWIG_Python_str_FromChar(method_name);\n"); + Printf(f_directors_h, " method = PyObject_GetAttr(swig_get_self(), name);\n"); + Printf(f_directors_h, " if (!method) {\n"); + Printf(f_directors_h, " std::string msg = \"Method in class %s doesn't exist, undefined \";\n", classname); + Printf(f_directors_h, " msg += method_name;\n"); + Printf(f_directors_h, " Swig::DirectorMethodException::raise(msg.c_str());\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, " vtable[method_index] = method;\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, " return method;\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " mutable swig::SwigVar_PyObject vtable[%d];\n", director_method_index); + Printf(f_directors_h, "#endif\n\n"); + } + + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + + /* ------------------------------------------------------------ + * classDirectorDisown() + * ------------------------------------------------------------ */ + + int classDirectorDisown(Node *n) { + int result; + int oldshadow = shadow; + /* disable shadowing */ + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + result = Language::classDirectorDisown(n); + shadow = oldshadow; + if (shadow) { + if (builtin) { + String *rname = SwigType_namestr(real_classname); + Printf(builtin_methods, " { \"__disown__\", Swig::Director::swig_pyobj_disown< %s >, METH_NOARGS, \"\" },\n", rname); + Delete(rname); + } else { + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_disown(NSPACE_TODO, symname); //Getattr(n, "name")); + Printv(f_shadow, tab4, "def __disown__(self):\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow, tab8, "self.thisown = 0\n", NIL); +#else + Printv(f_shadow, tab8, "self.this.disown()\n", NIL); +#endif + Printv(f_shadow, tab8, module, ".", mrename, "(self)\n", NIL); + Printv(f_shadow, tab8, "return weakref.proxy(self)\n", NIL); + Delete(mrename); + } + } + return result; + } + + /* ---------------------------------------------------------------------------- + * END of C++ Director Class modifications + * ------------------------------------------------------------------------- */ + + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + if (shadow && !Getattr(n, "feature:onlychildren")) { + Node *mod = Getattr(n, "module"); + if (mod) { + String *modname = Getattr(mod, "name"); + Node *options = Getattr(mod, "options"); + String *pkg = options ? Getattr(options, "package") : 0; + String *sym = Getattr(n, "sym:name"); + String *importname = import_name_string(package, mainmodule, pkg, modname, sym); + Setattr(n, "python:proxy", importname); + Delete(importname); + } + } + int result = Language::classDeclaration(n); + return result; + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + String *add_explicit_scope(String *s) { + if (!Strstr(s, "::")) { + String *ss = NewStringf("::%s", s); + Delete(s); + s = ss; + } + return s; + } + + void builtin_pre_decl(Node *n) { + String *name = Getattr(n, "name"); + String *rname = add_explicit_scope(SwigType_namestr(name)); + String *mname = SwigType_manglestr(rname); + + Printf(f_init, "\n/* type '%s' */\n", rname); + Printf(f_init, " builtin_pytype = (PyTypeObject *)&SwigPyBuiltin_%s_type;\n", mname); + Printf(f_init, " builtin_pytype->tp_dict = d = PyDict_New();\n"); + + Delete(rname); + Delete(mname); + } + + void builtin_post_decl(File *f, Node *n) { + String *name = Getattr(n, "name"); + String *pname = Copy(name); + SwigType_add_pointer(pname); + String *symname = Getattr(n, "sym:name"); + String *rname = add_explicit_scope(SwigType_namestr(name)); + String *mname = SwigType_manglestr(rname); + String *pmname = SwigType_manglestr(pname); + String *templ = NewStringf("SwigPyBuiltin_%s", mname); + int funpack = fastunpack; + static String *tp_new = NewString("PyType_GenericNew"); + + Printv(f_init, " SwigPyBuiltin_SetMetaType(builtin_pytype, metatype);\n", NIL); + + // We can’t statically initialize a structure member with a function defined in another C module + // So this is done in the initialization function instead, see https://docs.python.org/2/extending/newtypes.html + Printf(f_init, " builtin_pytype->tp_new = %s;\n", getSlot(n, "feature:python:tp_new", tp_new)); + + Printv(f_init, " builtin_base_count = 0;\n", NIL); + List *baselist = Getattr(n, "bases"); + if (baselist) { + int base_count = 0; + for (Iterator b = First(baselist); b.item; b = Next(b)) { + String *bname = Getattr(b.item, "name"); + if (!bname || GetFlag(b.item, "feature:ignore")) + continue; + base_count++; + String *base_name = Copy(bname); + SwigType_add_pointer(base_name); + String *base_mname = SwigType_manglestr(base_name); + Printf(f_init, " builtin_basetype = SWIG_MangledTypeQuery(\"%s\");\n", base_mname); + Printv(f_init, " if (builtin_basetype && builtin_basetype->clientdata && ((SwigPyClientData *) builtin_basetype->clientdata)->pytype) {\n", NIL); + Printv(f_init, " builtin_bases[builtin_base_count++] = ((SwigPyClientData *) builtin_basetype->clientdata)->pytype;\n", NIL); + Printv(f_init, " } else {\n", NIL); + Printf(f_init, " PyErr_SetString(PyExc_TypeError, \"Could not create type '%s' as base '%s' has not been initialized.\\n\");\n", symname, bname); + Printv(f_init, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + Printv(f_init, " return NULL;\n", NIL); + Printv(f_init, "#else\n", NIL); + Printv(f_init, " return;\n", NIL); + Printv(f_init, "#endif\n", NIL); + Printv(f_init, " }\n", NIL); + Delete(base_name); + Delete(base_mname); + } + if (base_count > max_bases) + max_bases = base_count; + } + Printv(f_init, " builtin_bases[builtin_base_count] = NULL;\n", NIL); + Printv(f_init, " SwigPyBuiltin_InitBases(builtin_pytype, builtin_bases);\n", NIL); + builtin_bases_needed = 1; + + // Check for non-public destructor, in which case tp_dealloc will issue + // a warning and allow the memory to leak. Any class that doesn't explicitly + // have a private/protected destructor has an implicit public destructor. + static String *tp_dealloc_bad = NewString("SwigPyBuiltin_BadDealloc"); + + String *getset_name = NewStringf("%s_getset", templ); + String *methods_name = NewStringf("%s_methods", templ); + String *getset_def = NewString(""); + Printf(getset_def, "SWIGINTERN PyGetSetDef %s[] = {\n", getset_name); + + // All objects have 'this' and 'thisown' attributes + Printv(f_init, "PyDict_SetItemString(d, \"this\", this_descr);\n", NIL); + Printv(f_init, "PyDict_SetItemString(d, \"thisown\", thisown_descr);\n", NIL); + + // Now, the rest of the attributes + for (Iterator member_iter = First(builtin_getset); member_iter.item; member_iter = Next(member_iter)) { + String *memname = member_iter.key; + Hash *mgetset = member_iter.item; + String *getter = Getattr(mgetset, "getter"); + String *setter = Getattr(mgetset, "setter"); + const char *getter_closure = getter ? funpack ? "SwigPyBuiltin_FunpackGetterClosure" : "SwigPyBuiltin_GetterClosure" : "0"; + const char *setter_closure = setter ? funpack ? "SwigPyBuiltin_FunpackSetterClosure" : "SwigPyBuiltin_SetterClosure" : "0"; + String *gspair = NewStringf("%s_%s_getset", symname, memname); + Printf(f, "static SwigPyGetSet %s = { %s, %s };\n", gspair, getter ? getter : "0", setter ? setter : "0"); + String *doc = Getattr(mgetset, "doc"); + if (!doc) + doc = NewStringf("%s.%s", name, memname); + String *entry = NewStringf("{ (char *)\"%s\", %s, %s, (char *)\"%s\", &%s }", memname, getter_closure, setter_closure, doc, gspair); + if (GetFlag(mgetset, "static")) { + Printf(f, "static PyGetSetDef %s_def = %s;\n", gspair, entry); + Printf(f_init, "static_getset = SwigPyStaticVar_new_getset(metatype, &%s_def);\n", gspair); + Printf(f_init, "PyDict_SetItemString(d, static_getset->d_getset->name, (PyObject *) static_getset);\n", memname); + Printf(f_init, "Py_DECREF(static_getset);\n"); + } else { + Printf(getset_def, " %s,\n", entry); + } + Delete(gspair); + Delete(entry); + } + Printv(f, getset_def, " { NULL, NULL, NULL, NULL, NULL } /* Sentinel */\n", "};\n\n", NIL); + + // Rich compare function + Hash *richcompare = Getattr(n, "python:richcompare"); + String *richcompare_func = NewStringf("%s_richcompare", templ); + assert(richcompare); + Printf(f, "SWIGINTERN PyObject *\n"); + Printf(f, "%s(PyObject *self, PyObject *other, int op) {\n", richcompare_func); + Printf(f, " PyObject *result = NULL;\n"); + if (!funpack) { + Printf(f, " PyObject *tuple = PyTuple_New(1);\n"); + Printf(f, " assert(tuple);\n"); + Printf(f, " PyTuple_SET_ITEM(tuple, 0, other);\n"); + Printf(f, " Py_XINCREF(other);\n"); + } + Iterator rich_iter = First(richcompare); + if (rich_iter.item) { + Printf(f, " switch (op) {\n"); + for (; rich_iter.item; rich_iter = Next(rich_iter)) + Printf(f, " case %s : result = %s(self, %s); break;\n", rich_iter.key, rich_iter.item, funpack ? "other" : "tuple"); + Printv(f, " default : break;\n", NIL); + Printf(f, " }\n"); + } + Printv(f, " if (!result) {\n", NIL); + Printv(f, " if (SwigPyObject_Check(self) && SwigPyObject_Check(other)) {\n", NIL); + Printv(f, " result = SwigPyObject_richcompare((SwigPyObject *)self, (SwigPyObject *)other, op);\n", NIL); + Printv(f, " } else {\n", NIL); + Printv(f, " result = Py_NotImplemented;\n", NIL); + Printv(f, " Py_INCREF(result);\n", NIL); + Printv(f, " }\n", NIL); + Printv(f, " }\n", NIL); + if (!funpack) + Printf(f, " Py_DECREF(tuple);\n"); + Printf(f, " return result;\n"); + Printf(f, "}\n\n"); + + // Methods + Printf(f, "SWIGINTERN PyMethodDef %s_methods[] = {\n", templ); + Dump(builtin_methods, f); + Printf(f, " { NULL, NULL, 0, NULL } /* Sentinel */\n};\n\n"); + + // No instance dict for nondynamic objects + if (GetFlag(n, "feature:python:nondynamic")) + Setattr(n, "feature:python:tp_setattro", "SWIG_Python_NonDynamicSetAttr"); + + Node *mod = Getattr(n, "module"); + String *modname = mod ? Getattr(mod, "name") : 0; + String *quoted_symname; + if (package) { + if (modname) + quoted_symname = NewStringf("\"%s.%s.%s\"", package, modname, symname); + else + quoted_symname = NewStringf("\"%s.%s\"", package, symname); + } else { + if (modname) + quoted_symname = NewStringf("\"%s.%s\"", modname, symname); + else + quoted_symname = NewStringf("\"%s\"", symname); + } + String *quoted_tp_doc_str = NewStringf("\"%s\"", getSlot(n, "feature:python:tp_doc")); + String *tp_init = NewString(builtin_tp_init ? Char(builtin_tp_init) : Swig_directorclass(n) ? "0" : "SwigPyBuiltin_BadInit"); + String *tp_flags = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); + String *tp_flags_py3 = NewString("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE"); + + static String *tp_basicsize = NewStringf("sizeof(SwigPyObject)"); + static String *tp_dictoffset_default = NewString("offsetof(SwigPyObject, dict)"); + static String *tp_hash = NewString("SwigPyObject_hash"); + String *tp_as_number = NewStringf("&%s_type.as_number", templ); + String *tp_as_sequence = NewStringf("&%s_type.as_sequence", templ); + String *tp_as_mapping = NewStringf("&%s_type.as_mapping", templ); + String *tp_as_buffer = NewStringf("&%s_type.as_buffer", templ); + + Printf(f, "static PyHeapTypeObject %s_type = {\n", templ); + + // PyTypeObject ht_type + Printf(f, " {\n"); + Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + Printv(f, " PyVarObject_HEAD_INIT(NULL, 0)\n", NIL); + Printv(f, "#else\n", NIL); + Printf(f, " PyObject_HEAD_INIT(NULL)\n"); + printSlot(f, getSlot(), "ob_size"); + Printv(f, "#endif\n", NIL); + printSlot(f, quoted_symname, "tp_name"); + printSlot(f, getSlot(n, "feature:python:tp_basicsize", tp_basicsize), "tp_basicsize"); + printSlot(f, getSlot(n, "feature:python:tp_itemsize"), "tp_itemsize"); + printSlot(f, getSlot(n, "feature:python:tp_dealloc", tp_dealloc_bad), "tp_dealloc", "destructor"); + printSlot(f, getSlot(n, "feature:python:tp_print"), "tp_print", "printfunc"); + printSlot(f, getSlot(n, "feature:python:tp_getattr"), "tp_getattr", "getattrfunc"); + printSlot(f, getSlot(n, "feature:python:tp_setattr"), "tp_setattr", "setattrfunc"); + Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_compare"), "tp_compare"); + Printv(f, "#else\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_compare"), "tp_compare", "cmpfunc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_repr"), "tp_repr", "reprfunc"); + printSlot(f, getSlot(n, "feature:python:tp_as_number", tp_as_number), "tp_as_number"); + printSlot(f, getSlot(n, "feature:python:tp_as_sequence", tp_as_sequence), "tp_as_sequence"); + printSlot(f, getSlot(n, "feature:python:tp_as_mapping", tp_as_mapping), "tp_as_mapping"); + printSlot(f, getSlot(n, "feature:python:tp_hash", tp_hash), "tp_hash", "hashfunc"); + printSlot(f, getSlot(n, "feature:python:tp_call"), "tp_call", "ternaryfunc"); + printSlot(f, getSlot(n, "feature:python:tp_str"), "tp_str", "reprfunc"); + printSlot(f, getSlot(n, "feature:python:tp_getattro"), "tp_getattro", "getattrofunc"); + printSlot(f, getSlot(n, "feature:python:tp_setattro"), "tp_setattro", "setattrofunc"); + printSlot(f, getSlot(n, "feature:python:tp_as_buffer", tp_as_buffer), "tp_as_buffer"); + Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags_py3), "tp_flags"); + Printv(f, "#else\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_flags", tp_flags), "tp_flags"); + Printv(f, "#endif\n", NIL); + if (have_docstring(n)) { + String *ds = cdocstring(n, AUTODOC_CLASS); + String *tp_doc = NewString(""); + Printf(tp_doc, "\"%s\"", ds); + Delete(ds); + printSlot(f, tp_doc, "tp_doc"); + Delete(tp_doc); + } else { + printSlot(f, quoted_tp_doc_str, "tp_doc"); + } + printSlot(f, getSlot(n, "feature:python:tp_traverse"), "tp_traverse", "traverseproc"); + printSlot(f, getSlot(n, "feature:python:tp_clear"), "tp_clear", "inquiry"); + printSlot(f, getSlot(n, "feature:python:tp_richcompare", richcompare_func), "tp_richcompare", "richcmpfunc"); + printSlot(f, getSlot(n, "feature:python:tp_weaklistoffset"), "tp_weaklistoffset"); + printSlot(f, getSlot(n, "feature:python:tp_iter"), "tp_iter", "getiterfunc"); + printSlot(f, getSlot(n, "feature:python:tp_iternext"), "tp_iternext", "iternextfunc"); + printSlot(f, getSlot(n, "feature:python:tp_methods", methods_name), "tp_methods"); + printSlot(f, getSlot(n, "feature:python:tp_members"), "tp_members"); + printSlot(f, getSlot(n, "feature:python:tp_getset", getset_name), "tp_getset"); + printSlot(f, getSlot(n, "feature:python:tp_base"), "tp_base"); + printSlot(f, getSlot(n, "feature:python:tp_dict"), "tp_dict"); + printSlot(f, getSlot(n, "feature:python:tp_descr_get"), "tp_descr_get", "descrgetfunc"); + printSlot(f, getSlot(n, "feature:python:tp_descr_set"), "tp_descr_set", "descrsetfunc"); + printSlot(f, getSlot(n, "feature:python:tp_dictoffset", tp_dictoffset_default), "tp_dictoffset", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_init", tp_init), "tp_init", "initproc"); + printSlot(f, getSlot(n, "feature:python:tp_alloc"), "tp_alloc", "allocfunc"); + printSlot(f, getSlot(), "tp_new", "newfunc"); + printSlot(f, getSlot(n, "feature:python:tp_free"), "tp_free", "freefunc"); + printSlot(f, getSlot(n, "feature:python:tp_is_gc"), "tp_is_gc", "inquiry"); + printSlot(f, getSlot(n, "feature:python:tp_bases"), "tp_bases", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_mro"), "tp_mro", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_cache"), "tp_cache", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_subclasses"), "tp_subclasses", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_weaklist"), "tp_weaklist", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:tp_del"), "tp_del", "destructor"); + printSlot(f, getSlot(n, "feature:python:tp_version_tag"), "tp_version_tag", "int"); + Printv(f, "#if PY_VERSION_HEX >= 0x03040000\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_finalize"), "tp_finalize", "destructor"); + Printv(f, "#endif\n", NIL); + Printv(f, "#if PY_VERSION_HEX >= 0x03080000\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_vectorcall"), "tp_vectorcall", "vectorcallfunc"); + Printv(f, "#endif\n", NIL); + Printv(f, "#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)\n", NIL); + printSlot(f, getSlot(), "tp_print"); + Printv(f, "#endif\n", NIL); + + Printv(f, "#ifdef COUNT_ALLOCS\n", NIL); + printSlot(f, getSlot(n, "feature:python:tp_allocs"), "tp_allocs", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_maxalloc"), "tp_maxalloc", "Py_ssize_t"); + printSlot(f, getSlot(n, "feature:python:tp_prev"), "tp_prev"); + printSlot(f, getSlot(n, "feature:python:tp_next"), "tp_next"); + Printv(f, "#endif\n", NIL); + Printf(f, " },\n"); + + // PyAsyncMethods as_async + Printv(f, "#if PY_VERSION_HEX >= 0x03050000\n", NIL); + Printf(f, " {\n"); + printSlot(f, getSlot(n, "feature:python:am_await"), "am_await", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:am_aiter"), "am_aiter", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:am_anext"), "am_anext", "unaryfunc"); + Printf(f, " },\n"); + Printv(f, "#endif\n", NIL); + + // PyNumberMethods as_number + Printf(f, " {\n"); + printSlot(f, getSlot(n, "feature:python:nb_add"), "nb_add", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_subtract"), "nb_subtract", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_multiply"), "nb_multiply", "binaryfunc"); + Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_divide"), "nb_divide", "binaryfunc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_remainder"), "nb_remainder", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_divmod"), "nb_divmod", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_power"), "nb_power", "ternaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_negative"), "nb_negative", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_positive"), "nb_positive", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_absolute"), "nb_absolute", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_nonzero"), "nb_nonzero", "inquiry"); + printSlot(f, getSlot(n, "feature:python:nb_invert"), "nb_invert", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_lshift"), "nb_lshift", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_rshift"), "nb_rshift", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_and"), "nb_and", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_xor"), "nb_xor", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_or"), "nb_or", "binaryfunc"); + Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_coerce"), "nb_coerce", "coercion"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_int"), "nb_int", "unaryfunc"); + Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_reserved"), "nb_reserved", "void *"); + Printv(f, "#else\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_long"), "nb_long", "unaryfunc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_float"), "nb_float", "unaryfunc"); + Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_oct"), "nb_oct", "unaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_hex"), "nb_hex", "unaryfunc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_inplace_add"), "nb_inplace_add", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_subtract"), "nb_inplace_subtract", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_multiply"), "nb_inplace_multiply", "binaryfunc"); + Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_inplace_divide"), "nb_inplace_divide", "binaryfunc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_inplace_remainder"), "nb_inplace_remainder", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_power"), "nb_inplace_power", "ternaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_lshift"), "nb_inplace_lshift", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_rshift"), "nb_inplace_rshift", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_and"), "nb_inplace_and", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_xor"), "nb_inplace_xor", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_or"), "nb_inplace_or", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_floor_divide"), "nb_floor_divide", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_divide"), "nb_true_divide", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_floor_divide"), "nb_inplace_floor_divide", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_divide"), "nb_inplace_true_divide", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_index"), "nb_index", "unaryfunc"); + Printv(f, "#if PY_VERSION_HEX >= 0x03050000\n", NIL); + printSlot(f, getSlot(n, "feature:python:nb_matrix_multiply"), "nb_matrix_multiply", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:nb_inplace_matrix_multiply"), "nb_inplace_matrix_multiply", "binaryfunc"); + Printv(f, "#endif\n", NIL); + Printf(f, " },\n"); + + // PyMappingMethods as_mapping; + Printf(f, " {\n"); + printSlot(f, getSlot(n, "feature:python:mp_length"), "mp_length", "lenfunc"); + printSlot(f, getSlot(n, "feature:python:mp_subscript"), "mp_subscript", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:mp_ass_subscript"), "mp_ass_subscript", "objobjargproc"); + Printf(f, " },\n"); + + // PySequenceMethods as_sequence; + Printf(f, " {\n"); + printSlot(f, getSlot(n, "feature:python:sq_length"), "sq_length", "lenfunc"); + printSlot(f, getSlot(n, "feature:python:sq_concat"), "sq_concat", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:sq_repeat"), "sq_repeat", "ssizeargfunc"); + printSlot(f, getSlot(n, "feature:python:sq_item"), "sq_item", "ssizeargfunc"); + Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:was_sq_slice"), "was_sq_slice", "void *"); + Printv(f, "#else\n", NIL); + printSlot(f, getSlot(n, "feature:python:sq_slice"), "sq_slice", "ssizessizeargfunc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:sq_ass_item"), "sq_ass_item", "ssizeobjargproc"); + Printv(f, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:was_sq_ass_slice"), "was_sq_ass_slice", "void *"); + Printv(f, "#else\n", NIL); + printSlot(f, getSlot(n, "feature:python:sq_ass_slice"), "sq_ass_slice", "ssizessizeobjargproc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:sq_contains"), "sq_contains", "objobjproc"); + printSlot(f, getSlot(n, "feature:python:sq_inplace_concat"), "sq_inplace_concat", "binaryfunc"); + printSlot(f, getSlot(n, "feature:python:sq_inplace_repeat"), "sq_inplace_repeat", "ssizeargfunc"); + Printf(f, " },\n"); + + // PyBufferProcs as_buffer; + Printf(f, " {\n"); + Printv(f, "#if PY_VERSION_HEX < 0x03000000\n", NIL); + printSlot(f, getSlot(n, "feature:python:bf_getreadbuffer"), "bf_getreadbuffer", "readbufferproc"); + printSlot(f, getSlot(n, "feature:python:bf_getwritebuffer"), "bf_getwritebuffer", "writebufferproc"); + printSlot(f, getSlot(n, "feature:python:bf_getsegcount"), "bf_getsegcount", "segcountproc"); + printSlot(f, getSlot(n, "feature:python:bf_getcharbuffer"), "bf_getcharbuffer", "charbufferproc"); + Printv(f, "#endif\n", NIL); + printSlot(f, getSlot(n, "feature:python:bf_getbuffer"), "bf_getbuffer", "getbufferproc"); + printSlot(f, getSlot(n, "feature:python:bf_releasebuffer"), "bf_releasebuffer", "releasebufferproc"); + Printf(f, " },\n"); + + // PyObject *ht_name, *ht_slots, *ht_qualname; + printSlot(f, getSlot(n, "feature:python:ht_name"), "ht_name", "PyObject *"); + printSlot(f, getSlot(n, "feature:python:ht_slots"), "ht_slots", "PyObject *"); + Printv(f, "#if PY_VERSION_HEX >= 0x03030000\n", NIL); + printSlot(f, getSlot(n, "feature:python:ht_qualname"), "ht_qualname", "PyObject *"); + + // struct _dictkeysobject *ht_cached_keys; + printSlot(f, getSlot(n, "feature:python:ht_cached_keys"), "ht_cached_keys"); + Printv(f, "#endif\n", NIL); + Printf(f, "};\n\n"); + + String *clientdata = NewString(""); + Printf(clientdata, "&%s_clientdata", templ); + SwigType_remember_mangleddata(pmname, clientdata); + + SwigType *smart = Swig_cparse_smartptr(n); + if (smart) { + SwigType_add_pointer(smart); + String *smart_pmname = SwigType_manglestr(smart); + SwigType_remember_mangleddata(smart_pmname, clientdata); + Delete(smart_pmname); + } + + String *clientdata_klass = NewString("0"); + if (GetFlag(n, "feature:implicitconv")) { + Clear(clientdata_klass); + Printf(clientdata_klass, "(PyObject *) &%s_type", templ); + } + + Printf(f, "SWIGINTERN SwigPyClientData %s_clientdata = {%s, 0, 0, 0, 0, 0, (PyTypeObject *)&%s_type};\n\n", templ, clientdata_klass, templ); + + Printv(f_init, " if (PyType_Ready(builtin_pytype) < 0) {\n", NIL); + Printf(f_init, " PyErr_SetString(PyExc_TypeError, \"Could not create type '%s'.\");\n", symname); + Printv(f_init, "#if PY_VERSION_HEX >= 0x03000000\n", NIL); + Printv(f_init, " return NULL;\n", NIL); + Printv(f_init, "#else\n", NIL); + Printv(f_init, " return;\n", NIL); + Printv(f_init, "#endif\n", NIL); + Printv(f_init, " }\n", NIL); + Printv(f_init, " Py_INCREF(builtin_pytype);\n", NIL); + Printf(f_init, " PyModule_AddObject(m, \"%s\", (PyObject *)builtin_pytype);\n", symname); + Printf(f_init, " SwigPyBuiltin_AddPublicSymbol(public_interface, \"%s\");\n", symname); + Printv(f_init, " d = md;\n", NIL); + + Delete(clientdata); + Delete(smart); + Delete(rname); + Delete(pname); + Delete(mname); + Delete(pmname); + Delete(templ); + Delete(tp_flags); + Delete(tp_flags_py3); + Delete(tp_as_buffer); + Delete(tp_as_mapping); + Delete(tp_as_sequence); + Delete(tp_as_number); + Delete(quoted_symname); + Delete(quoted_tp_doc_str); + Delete(tp_init); + Delete(clientdata_klass); + Delete(richcompare_func); + Delete(getset_name); + Delete(methods_name); + } + + virtual int classHandler(Node *n) { + File *f_shadow_file = f_shadow; + Node *base_node = NULL; + + if (shadow) { + + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + have_repr = 0; + + class_name = Getattr(n, "sym:name"); + real_classname = Getattr(n, "name"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + if (builtin) { + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist) > 0) { + Iterator b = First(baselist); + base_node = b.item; + } + } + + shadow_indent = (String *) tab4; + + /* Handle inheritance */ + String *base_class = NewString(""); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "python:proxy"); + bool ignore = GetFlag(b.item, "feature:ignore") ? true : false; + if (!bname || ignore) { + if (!bname && !ignore) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(n), Getline(n), + "Base class '%s' ignored - unknown module name for base. Either import the appropriate module interface file or specify the name of the module in the %%import directive.\n", + SwigType_namestr(Getattr(b.item, "name"))); + } + b = Next(b); + continue; + } + Printv(base_class, bname, NIL); + b = Next(b); + if (b.item) { + Printv(base_class, ", ", NIL); + } + } + } + + if (builtin) { + Hash *base_richcompare = NULL; + Hash *richcompare = NULL; + if (base_node) + base_richcompare = Getattr(base_node, "python:richcompare"); + if (base_richcompare) + richcompare = Copy(base_richcompare); + else + richcompare = NewHash(); + Setattr(n, "python:richcompare", richcompare); + } + + /* dealing with abstract base class */ + String *abcs = Getattr(n, "feature:python:abc"); + if (py3 && abcs) { + if (Len(base_class)) { + Printv(base_class, ", ", NIL); + } + Printv(base_class, abcs, NIL); + } + + if (builtin) { + if (have_docstring(n)) { + String *ds = cdocstring(n, AUTODOC_CLASS); + Setattr(n, "feature:python:tp_doc", ds); + Delete(ds); + } else { + String *name = Getattr(n, "name"); + String *rname = add_explicit_scope(SwigType_namestr(name)); + Setattr(n, "feature:python:tp_doc", rname); + Delete(rname); + } + } else { + if (!py3) { + if (GetFlag(n, "feature:python:nondynamic")) + Printv(f_shadow, "@_swig_add_metaclass(_SwigNonDynamicMeta)\n", NIL); + } + Printv(f_shadow, "class ", class_name, NIL); + + if (Len(base_class)) { + Printf(f_shadow, "(%s)", base_class); + } else { + if (GetFlag(n, "feature:exceptionclass")) { + Printf(f_shadow, "(Exception)"); + } else { + Printf(f_shadow, "(object"); + Printf(f_shadow, py3 && GetFlag(n, "feature:python:nondynamic") ? ", metaclass=_SwigNonDynamicMeta" : "", ")"); + Printf(f_shadow, ")"); + } + } + + Printf(f_shadow, ":\n"); + + // write docstrings if requested + if (have_docstring(n)) { + String *str = docstring(n, AUTODOC_CLASS, tab4); + if (str && Len(str)) + Printv(f_shadow, tab4, str, "\n\n", NIL); + } + + Printv(f_shadow, tab4, "thisown = property(lambda x: x.this.own(), ", "lambda x, v: x.this.own(v), doc=\"The membership flag\")\n", NIL); + /* Add static attribute */ + if (GetFlag(n, "feature:python:nondynamic")) { + Printv(f_shadow_file, tab4, "__setattr__ = _swig_setattr_nondynamic_instance_variable(object.__setattr__)\n", NIL); + } + } + } + + /* Emit all of the members */ + + in_class = 1; + if (builtin) + builtin_pre_decl(n); + + /* Override the shadow file so we can capture its methods */ + f_shadow = NewString(""); + + // Set up type check for director class constructor + Clear(none_comparison); + if (builtin && Swig_directorclass(n)) { + String *p_real_classname = Copy(real_classname); + SwigType_add_pointer(p_real_classname); + String *mangle = SwigType_manglestr(p_real_classname); + String *descriptor = NewStringf("SWIGTYPE%s", mangle); + Printv(none_comparison, "self->ob_type != ((SwigPyClientData *)(", descriptor, ")->clientdata)->pytype", NIL); + Delete(descriptor); + Delete(mangle); + Delete(p_real_classname); + } else { + Printv(none_comparison, "$arg != Py_None", NIL); + } + + Language::classHandler(n); + + in_class = 0; + + /* Complete the class */ + if (shadow) { + /* Generate a class registration function */ + // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) + SwigType *smart = Swig_cparse_smartptr(n); + SwigType *ct = Copy(smart ? smart : real_classname); + SwigType_add_pointer(ct); + SwigType *realct = Copy(real_classname); + SwigType_add_pointer(realct); + SwigType_remember(realct); + if (builtin) { + Printv(f_wrappers, builtin_closures_code, NIL); + Delete(builtin_closures_code); + builtin_closures_code = NewString(""); + Clear(builtin_closures); + } else { + Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); + Printv(f_wrappers, " PyObject *obj;\n", NIL); + Printv(f_wrappers, " if (!SWIG_Python_UnpackTuple(args, \"swigregister\", 1, 1, &obj)) return NULL;\n", NIL); + + Printv(f_wrappers, + " SWIG_TypeNewClientData(SWIGTYPE", SwigType_manglestr(ct), ", SWIG_NewClientData(obj));\n", " return SWIG_Py_Void();\n", "}\n\n", NIL); + String *cname = NewStringf("%s_swigregister", class_name); + add_method(cname, cname, 0, 0, 1, 1, 1); + Delete(cname); + } + Delete(smart); + Delete(ct); + Delete(realct); + if (!have_constructor) { + if (!builtin) + Printv(f_shadow_file, "\n", tab4, "def __init__(self, *args, **kwargs):\n", tab8, "raise AttributeError(\"", "No constructor defined", + (Getattr(n, "abstracts") ? " - class is abstract" : ""), "\")\n", NIL); + } else if (!builtin) { + + Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); + Printv(f_wrappers, " return SWIG_Python_InitShadowInstance(args);\n", "}\n\n", NIL); + String *cname = NewStringf("%s_swiginit", class_name); + add_method(cname, cname, 0); + Delete(cname); + } + if (!have_repr && !builtin) { + /* Supply a repr method for this class */ + String *rname = SwigType_namestr(real_classname); + Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL); + Delete(rname); + } + + if (builtin) + builtin_post_decl(f_builtins, n); + + if (builtin_tp_init) { + Delete(builtin_tp_init); + builtin_tp_init = 0; + } + + if (!builtin) { + /* Now emit methods */ + Printv(f_shadow_file, f_shadow, NIL); + Printf(f_shadow_file, "\n"); + Printf(f_shadow_file, "# Register %s in %s:\n", class_name, module); + Printf(f_shadow_file, "%s.%s_swigregister(%s)\n", module, class_name, class_name); + } + + shadow_indent = 0; + Printf(f_shadow_file, "%s\n", f_shadow_stubs); + Clear(f_shadow_stubs); + } + + if (builtin) { + Clear(class_members); + Clear(builtin_getset); + Clear(builtin_methods); + } + + /* Restore shadow file back to original version */ + Delete(f_shadow); + f_shadow = f_shadow_file; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * functionHandler() - Mainly overloaded for callback handling + * ------------------------------------------------------------ */ + + virtual int functionHandler(Node *n) { + String *pcb = GetFlagAttr(n, "feature:python:callback"); + if (pcb) { + if (Strcmp(pcb, "1") == 0) { + SetFlagAttr(n, "feature:callback", "%s_cb_ptr"); + } else { + SetFlagAttr(n, "feature:callback", pcb); + } + autodoc_l dlevel = autodoc_level(Getattr(n, "feature:autodoc")); + if (dlevel != NO_AUTODOC && dlevel > TYPES_AUTODOC) { + Setattr(n, "feature:autodoc", "1"); + } + } + return Language::functionHandler(n); + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow; + + if (builtin) + Swig_save("builtin_memberfunc", n, "python:argcount", NIL); + + /* Create the default member function */ + oldshadow = shadow; /* Disable shadowing when wrapping member functions */ + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::memberfunctionHandler(n); + shadow = oldshadow; + + if (builtin && in_class) { + // Can't use checkAttribute(n, "access", "public") because + // "access" attr isn't set on %extend methods + if (!checkAttribute(n, "access", "private") && strncmp(Char(symname), "operator ", 9) && !Getattr(class_members, symname)) { + String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); + String *wname = Swig_name_wrapper(fullname); + Setattr(class_members, symname, n); + int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; + String *ds = have_docstring(n) ? cdocstring(n, AUTODOC_METHOD) : NewString(""); + if (check_kwargs(n)) { + // Cast via void(*)(void) to suppress GCC -Wcast-function-type + // warning. Python should always call the function correctly, but + // the Python C API requires us to store it in function pointer of a + // different type. + Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, METH_VARARGS|METH_KEYWORDS, \"%s\" },\n", symname, wname, ds); + } else if (argcount == 0) { + Printf(builtin_methods, " { \"%s\", %s, METH_NOARGS, \"%s\" },\n", symname, wname, ds); + } else if (argcount == 1) { + Printf(builtin_methods, " { \"%s\", %s, METH_O, \"%s\" },\n", symname, wname, ds); + } else { + Printf(builtin_methods, " { \"%s\", %s, METH_VARARGS, \"%s\" },\n", symname, wname, ds); + } + Delete(fullname); + Delete(wname); + Delete(ds); + } + } + + if (builtin) + Swig_restore(n); + + if (!Getattr(n, "sym:nextSibling")) { + if (shadow && !builtin) { + int fproxy = fastproxy; + String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); + if (Strcmp(symname, "__repr__") == 0) { + have_repr = 1; + } + if (Getattr(n, "feature:shadow")) { + String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); + String *pyaction = NewStringf("%s.%s", module, fullname); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + fproxy = 0; + } else { + int allow_kwargs = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; + String *parms = make_pyParmList(n, true, false, allow_kwargs); + String *callParms = make_pyParmList(n, true, true, allow_kwargs); + if (!have_addtofunc(n)) { + if (!fastproxy || olddefs) { + Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); + Printv(f_shadow, tab8, "return ", funcCall(fullname, callParms), "\n", NIL); + } + } else { + Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); + if (have_pythonprepend(n)) { + fproxy = 0; + Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + } + if (have_pythonappend(n)) { + fproxy = 0; + Printv(f_shadow, tab8, "val = ", funcCall(fullname, callParms), "\n", NIL); + Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_shadow, tab8, "return val\n\n", NIL); + } else { + Printv(f_shadow, tab8, "return ", funcCall(fullname, callParms), "\n\n", NIL); + } + } + } + if (fproxy) { + Printf(f_shadow, tab4); + Printf(f_shadow, "%s = _swig_new_instance_method(%s.%s)\n", symname, module, Swig_name_member(NSPACE_TODO, class_name, symname)); + } + Delete(fullname); + } + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + if (builtin && in_class) { + Swig_save("builtin_memberconstantHandler", n, "pybuiltin:symname", NIL); + Setattr(n, "pybuiltin:symname", symname); + } + Language::staticmemberfunctionHandler(n); + if (builtin && in_class) { + Swig_restore(n); + } + + if (builtin && in_class) { + if ((GetFlagAttr(n, "feature:extend") || checkAttribute(n, "access", "public")) + && !Getattr(class_members, symname)) { + String *fullname = Swig_name_member(NSPACE_TODO, class_name, symname); + String *wname = Swig_name_wrapper(fullname); + Setattr(class_members, symname, n); + int funpack = fastunpack && !Getattr(n, "sym:overloaded"); + String *pyflags = NewString("METH_STATIC|"); + int argcount = Getattr(n, "python:argcount") ? atoi(Char(Getattr(n, "python:argcount"))) : 2; + if (funpack && argcount == 0) + Append(pyflags, "METH_NOARGS"); + else if (funpack && argcount == 1) + Append(pyflags, "METH_O"); + else + Append(pyflags, "METH_VARARGS"); + // Cast via void(*)(void) to suppress GCC -Wcast-function-type warning. + // Python should always call the function correctly, but the Python C + // API requires us to store it in function pointer of a different type. + if (have_docstring(n)) { + String *ds = cdocstring(n, AUTODOC_STATICFUNC); + Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"%s\" },\n", symname, wname, pyflags, ds); + Delete(ds); + } else { + Printf(builtin_methods, " { \"%s\", (PyCFunction)(void(*)(void))%s, %s, \"\" },\n", symname, wname, pyflags); + } + Delete(fullname); + Delete(wname); + Delete(pyflags); + } + return SWIG_OK; + } + + if (Getattr(n, "sym:nextSibling")) { + return SWIG_OK; + } + + if (shadow) { + String *staticfunc_name = NewString(fastproxy ? "_swig_new_static_method" : "staticmethod"); + bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback"); + if (!fast || olddefs) { + int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; + String *parms = make_pyParmList(n, false, false, kw); + String *callParms = make_pyParmList(n, false, true, kw); + Printv(f_shadow, "\n", tab4, "@staticmethod", NIL); + Printv(f_shadow, "\n", tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_STATICFUNC, tab8), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL); + Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_shadow, tab8, "return val\n", NIL); + } else { + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(NSPACE_TODO, class_name, symname), callParms), "\n", NIL); + } + } + + // Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first. + if (fast) { + Printv(f_shadow, tab4, symname, " = ", staticfunc_name, "(", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), + ")\n", NIL); + } + Delete(staticfunc_name); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow = shadow; + int use_director = Swig_directorclass(n); + + /* + * If we're wrapping the constructor of a C++ director class, prepend a new parameter + * to receive the scripting language object (e.g. 'self') + * + */ + Swig_save("python:constructorHandler", n, "parms", NIL); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("PyObject"); + SwigType_add_pointer(type); + self = NewParm(type, name, n); + Delete(type); + Delete(name); + Setattr(self, "lname", "O"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Setattr(n, "hidden", "1"); + Delete(self); + } + + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::constructorHandler(n); + shadow = oldshadow; + + Delattr(n, "wrap:self"); + Swig_restore(n); + + if (!Getattr(n, "sym:nextSibling")) { + if (shadow) { + int allow_kwargs = (check_kwargs(n) && (!Getattr(n, "sym:overloaded"))) ? 1 : 0; + int handled_as_init = 0; + if (!have_constructor) { + String *nname = Getattr(n, "sym:name"); + String *sname = Getattr(getCurrentClass(), "sym:name"); + String *cname = Swig_name_construct(NSPACE_TODO, sname); + handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); + Delete(cname); + } + + String *subfunc = Swig_name_construct(NSPACE_TODO, symname); + if (!have_constructor && handled_as_init) { + if (!builtin) { + if (Getattr(n, "feature:shadow")) { + String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); + String *pyaction = NewStringf("%s.%s", module, subfunc); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + } else { + String *pass_self = NewString(""); + Node *parent = Swig_methodclass(n); + String *classname = Swig_class_name(parent); + String *rclassname = Swig_class_name(getCurrentClass()); + assert(rclassname); + + String *parms = make_pyParmList(n, true, false, allow_kwargs); + /* Pass 'self' only if using director */ + String *callParms = make_pyParmList(n, false, true, allow_kwargs, true); + + if (use_director) { + Insert(callParms, 0, "_self, "); + Printv(pass_self, tab8, NIL); + Printf(pass_self, "if self.__class__ == %s:\n", classname); + //Printv(pass_self, tab8, tab4, "args = (None,) + args\n", tab8, "else:\n", tab8, tab4, "args = (self,) + args\n", NIL); + Printv(pass_self, tab8, tab4, "_self = None\n", tab8, "else:\n", tab8, tab4, "_self = self\n", NIL); + } + + Printv(f_shadow, "\n", tab4, "def __init__(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_CTOR, tab8), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + Printv(f_shadow, pass_self, NIL); + Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self, ", funcCall(subfunc, callParms), ")\n", NIL); + if (have_pythonappend(n)) + Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n\n", NIL); + Delete(pass_self); + } + have_constructor = 1; + } + } else { + /* Hmmm. We seem to be creating a different constructor. We're just going to create a + function for it. */ + if (!builtin) { + if (Getattr(n, "feature:shadow")) { + String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), "", Getfile(n), Getline(n), "%feature(\"shadow\")"); + String *pyaction = NewStringf("%s.%s", module, subfunc); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow_stubs, pycode, "\n", NIL); + Delete(pycode); + } else { + String *parms = make_pyParmList(n, false, false, allow_kwargs); + String *callParms = make_pyParmList(n, false, true, allow_kwargs); + + Printv(f_shadow_stubs, "\ndef ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow_stubs, tab4, docstring(n, AUTODOC_CTOR, tab4), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow_stubs, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); + Printv(f_shadow_stubs, tab4, "val = ", funcCall(subfunc, callParms), "\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL); +#endif + if (have_pythonappend(n)) + Printv(f_shadow_stubs, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_shadow_stubs, tab4, "return val\n", NIL); + } + } else { + Printf(f_shadow_stubs, "%s = %s\n", symname, subfunc); + } + } + Delete(subfunc); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow = shadow; + + if (builtin && in_class) { + Node *cls = Swig_methodclass(n); + // Use the destructor for the tp_dealloc slot unless a user overrides it with another method + if (!Getattr(cls, "feature:python:tp_dealloc")) { + Setattr(n, "feature:python:slot", "tp_dealloc"); + Setattr(n, "feature:python:slot:functype", "destructor"); + } + } + + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + //Setattr(n,"emit:dealloc","1"); + Language::destructorHandler(n); + shadow = oldshadow; + + if (shadow) { + if (Getattr(n, "feature:shadow")) { + String *pycode = indent_pythoncode(Getattr(n, "feature:shadow"), tab4, Getfile(n), Getline(n), "%feature(\"shadow\")"); + String *pyaction = NewStringf("%s.%s", module, Swig_name_destroy(NSPACE_TODO, symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + } else { + Printv(f_shadow, tab4, "__swig_destroy__ = ", module, ".", Swig_name_destroy(NSPACE_TODO, symname), "\n", NIL); + if (!have_pythonprepend(n) && !have_pythonappend(n)) { + return SWIG_OK; + } + Printv(f_shadow, tab4, "def __del__(self):\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_DTOR, tab8), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow, indent_pythoncode(pythonprepend(n), tab8, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow, tab8, "try:\n", NIL); + Printv(f_shadow, tab8, tab4, "if self.thisown:", module, ".", Swig_name_destroy(NSPACE_TODO, symname), "(self)\n", NIL); + Printv(f_shadow, tab8, "except __builtin__.Exception: pass\n", NIL); +#else +#endif + if (have_pythonappend(n)) + Printv(f_shadow, indent_pythoncode(pythonappend(n), tab8, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL); + Printv(f_shadow, tab8, "pass\n", NIL); + Printv(f_shadow, "\n", NIL); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + + int oldshadow = shadow; + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::membervariableHandler(n); + shadow = oldshadow; + + if (shadow && !builtin) { + String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); + String *setname = Swig_name_set(NSPACE_TODO, mname); + String *getname = Swig_name_get(NSPACE_TODO, mname); + int assignable = is_assignable(n); + Printv(f_shadow, tab4, symname, " = property(", module, ".", getname, NIL); + if (assignable) + Printv(f_shadow, ", ", module, ".", setname, NIL); + if (have_docstring(n)) + Printv(f_shadow, ", doc=", docstring(n, AUTODOC_VAR, tab4), NIL); + Printv(f_shadow, ")\n", NIL); + Delete(mname); + Delete(setname); + Delete(getname); + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + Swig_save("builtin_staticmembervariableHandler", n, "builtin_symname", NIL); + Language::staticmembervariableHandler(n); + Swig_restore(n); + + if (GetFlag(n, "wrappedasconstant")) + return SWIG_OK; + + String *symname = Getattr(n, "sym:name"); + + if (shadow) { + if (!builtin && GetFlag(n, "hasconsttype")) { + String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); + Printf(f_shadow_stubs, "%s.%s = %s.%s.%s\n", class_name, symname, module, global_name, mname); + Delete(mname); + } else { + String *mname = Swig_name_member(NSPACE_TODO, class_name, symname); + String *getname = Swig_name_get(NSPACE_TODO, mname); + String *wrapgetname = Swig_name_wrapper(getname); + String *vargetname = NewStringf("Swig_var_%s", getname); + String *setname = Swig_name_set(NSPACE_TODO, mname); + String *wrapsetname = Swig_name_wrapper(setname); + String *varsetname = NewStringf("Swig_var_%s", setname); + + Wrapper *f = NewWrapper(); + Printv(f->def, "SWIGINTERN PyObject *", wrapgetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(args)) {", NIL); + Printv(f->code, " return ", vargetname, "();\n", NIL); + Append(f->code, "}\n"); + add_method(getname, wrapgetname, 0); + Wrapper_print(f, f_wrappers); + DelWrapper(f); + int assignable = is_assignable(n); + if (assignable) { + int funpack = fastunpack; + Wrapper *f = NewWrapper(); + Printv(f->def, "SWIGINTERN PyObject *", wrapsetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + Wrapper_add_local(f, "res", "int res"); + if (!funpack) { + Wrapper_add_local(f, "value", "PyObject *value"); + Append(f->code, "if (!PyArg_ParseTuple(args, \"O:set\", &value)) return NULL;\n"); + } + Printf(f->code, "res = %s(%s);\n", varsetname, funpack ? "args" : "value"); + Append(f->code, "return !res ? SWIG_Py_Void() : NULL;\n"); + Append(f->code, "}\n"); + Wrapper_print(f, f_wrappers); + add_method(setname, wrapsetname, 0, 0, funpack, 1, 1); + DelWrapper(f); + } + if (!builtin) { + Printv(f_shadow, tab4, symname, " = property(", module, ".", getname, NIL); + if (assignable) + Printv(f_shadow, ", ", module, ".", setname, NIL); + if (have_docstring(n)) + Printv(f_shadow, ", doc=", docstring(n, AUTODOC_VAR, tab4), NIL); + Printv(f_shadow, ")\n", NIL); + } + String *getter = Getattr(n, "pybuiltin:getter"); + String *setter = Getattr(n, "pybuiltin:setter"); + Hash *h = NULL; + if (getter || setter) { + h = Getattr(builtin_getset, symname); + if (!h) { + h = NewHash(); + Setattr(h, "static", "1"); + Setattr(builtin_getset, symname, h); + } + } + if (getter) + Setattr(h, "getter", getter); + if (setter) + Setattr(h, "setter", setter); + if (h) + Delete(h); + Delete(mname); + Delete(getname); + Delete(wrapgetname); + Delete(vargetname); + Delete(setname); + Delete(wrapsetname); + Delete(varsetname); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + if (builtin && in_class) { + Swig_save("builtin_memberconstantHandler", n, "pybuiltin:symname", NIL); + Setattr(n, "pybuiltin:symname", symname); + } + int oldshadow = shadow; + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::memberconstantHandler(n); + shadow = oldshadow; + + if (builtin && in_class) { + Swig_restore(n); + } else if (shadow) { + Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(NSPACE_TODO, class_name, symname), "\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab4, docstring(n, AUTODOC_CONST, tab4), "\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * insertDirective() + * + * Hook for %insert directive. We're going to look for special %shadow inserts + * as a special case so we can do indenting correctly + * ------------------------------------------------------------ */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + + if (!ImportMode && (Cmp(section, "python") == 0 || Cmp(section, "shadow") == 0)) { + if (shadow) { + String *pycode = indent_pythoncode(code, shadow_indent, Getfile(n), Getline(n), "%pythoncode or %insert(\"python\") block"); + Printv(f_shadow, pycode, NIL); + Delete(pycode); + } + } else if (!ImportMode && (Cmp(section, "pythonbegin") == 0)) { + if (shadow) { + String *pycode = indent_pythoncode(code, "", Getfile(n), Getline(n), "%pythonbegin or %insert(\"pythonbegin\") block"); + Printv(f_shadow_begin, pycode, NIL); + Delete(pycode); + } + } else { + Language::insertDirective(n); + } + return SWIG_OK; + } + + virtual String *runtimeCode() { + String *s = NewString(""); + String *shead = Swig_include_sys("pyhead.swg"); + if (!shead) { + Printf(stderr, "*** Unable to open 'pyhead.swg'\n"); + } else { + Append(s, shead); + Delete(shead); + } + String *serrors = Swig_include_sys("pyerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'pyerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *sthread = Swig_include_sys("pythreads.swg"); + if (!sthread) { + Printf(stderr, "*** Unable to open 'pythreads.swg'\n"); + } else { + Append(s, sthread); + Delete(sthread); + } + String *sapi = Swig_include_sys("pyapi.swg"); + if (!sapi) { + Printf(stderr, "*** Unable to open 'pyapi.swg'\n"); + } else { + Append(s, sapi); + Delete(sapi); + } + String *srun = Swig_include_sys("pyrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'pyrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + virtual String *defaultExternalRuntimeFilename() { + return NewString("swigpyrun.h"); + } + + /*---------------------------------------------------------------------- + * kwargsSupport() + *--------------------------------------------------------------------*/ + + bool kwargsSupport() const { + return true; + } +}; + +/* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * + * ** Moved it here due to internal error on gcc-2.96 ** + * --------------------------------------------------------------- */ +int PYTHON::classDirectorMethods(Node *n) { + director_method_index = 0; + return Language::classDirectorMethods(n); +} + + +int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl = Getattr(n, "decl"); + String *name = Getattr(n, "name"); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *symname = Getattr(n, "sym:name"); + String *declaration = NewString(""); + ParmList *l = Getattr(n, "parms"); + Wrapper *w = NewWrapper(); + String *tm; + String *wrap_args = NewString(""); + String *returntype = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (builtin) { + // Rename any wrapped parameters called 'self' as the generated code contains a variable with same name + Parm *p; + for (p = l; p; p = nextSibling(p)) { + String *arg = Getattr(p, "name"); + if (arg && Cmp(arg, "self") == 0) + Delattr(p, "name"); + } + } + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + /* determine if the method returns a pointer */ + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(returntype, "void") && !is_pointer); + + /* virtual method definition */ + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + 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); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + ParmList *throw_parm_list = 0; + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + 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, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($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 { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(returntype, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (builtin) { + Printv(w->code, "PyObject *self = NULL;\n", NIL); + Printv(w->code, "(void)self;\n", NIL); + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> Python) */ + String *arglist = NewString(""); + String *parse_args = NewString(""); + + Swig_director_parms_fixup(l); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + char source[256]; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; + p = l; + int use_parse = 0; + while (p) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* old style? caused segfaults without the p!=0 check + in the for() condition, and seems dangerous in the + while loop as well. + while (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + } + */ + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + Putc(',', arglist); + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + String *parse = Getattr(p, "tmap:directorin:parse"); + if (!parse) { + sprintf(source, "obj%d", idx++); + String *input = NewString(source); + Setattr(p, "emit:directorinput", input); + Replaceall(tm, "$input", input); + Delete(input); + Replaceall(tm, "$owner", "0"); + /* Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); */ + Printv(wrap_args, "swig::SwigVar_PyObject ", source, ";\n", NIL); + + Printv(wrap_args, tm, "\n", NIL); + Printv(arglist, "(PyObject *)", source, NIL); + Putc('O', parse_args); + } else { + use_parse = 1; + Append(parse_args, parse); + Setattr(p, "emit:directorinput", pname); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + Append(arglist, tm); + } + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + /* special handling for pointers to other C++ director classes. + * ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. in other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. we avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, ptype); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(ptype) + 2); + /* name as pointer */ + String *ppname = Copy(pname); + if (SwigType_isreference(ptype)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Python doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", pname); + String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(ptype, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", + SwigType_str(ptype, pname), SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(ptype); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_DIRECTOR_CAST(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_InternalNewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Append(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "Py_INCREF((PyObject *)%s);\n", source); + Append(wrap_args, "}\n"); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_InternalNewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Putc('O', parse_args); + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + /* add the method name as a PyString */ + String *pyname = Getattr(n, "sym:name"); + + int allow_thread = threads_enable(n); + + if (allow_thread) { + thread_begin_block(n, w->code); + Append(w->code, "{\n"); + } + + /* wrap complex arguments to PyObjects */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Python object */ + if (dirprot_mode() && !is_public(n)) { + Printf(w->code, "swig_set_inner(\"%s\", true);\n", name); + } + + + Append(w->code, "if (!swig_get_self()) {\n"); + Printf(w->code, " Swig::DirectorException::raise(\"'self' uninitialized, maybe you forgot to call %s.__init__.\");\n", classname); + Append(w->code, "}\n"); + Append(w->code, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); + Printf(w->code, "const size_t swig_method_index = %d;\n", director_method_index++); + Printf(w->code, "const char *const swig_method_name = \"%s\";\n", pyname); + + Append(w->code, "PyObject *method = swig_get_method(swig_method_index, swig_method_name);\n"); + if (Len(parse_args) > 0) { + if (use_parse) { + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", Swig_cresult_name(), parse_args, arglist); + } else { + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallFunctionObjArgs(method %s, NULL);\n", Swig_cresult_name(), arglist); + } + } else { + Append(w->code, "swig::SwigVar_PyObject args = PyTuple_New(0);\n"); + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_Call(method, (PyObject *) args, NULL);\n", Swig_cresult_name()); + } + Append(w->code, "#else\n"); + if (Len(parse_args) > 0) { + if (use_parse) { + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", Swig_cresult_name(), pyname, parse_args, arglist); + } else { + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar(\"%s\");\n", pyname); + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", Swig_cresult_name(), arglist); + } + } else { + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar(\"%s\");\n", pyname); + Printf(w->code, "swig::SwigVar_PyObject %s = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n", Swig_cresult_name()); + } + Append(w->code, "#endif\n"); + + if (dirprot_mode() && !is_public(n)) + Printf(w->code, "swig_set_inner(\"%s\", false);\n", name); + + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + Printf(w->code, "if (!%s) {\n", Swig_cresult_name()); + Append(w->code, " PyObject *error = PyErr_Occurred();\n"); + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Replaceall(tm, "$error", "error"); + Printv(w->code, Str(tm), "\n", NIL); + } else { + Append(w->code, " if (error) {\n"); + Printf(w->code, " Swig::DirectorMethodException::raise(\"Error detected when calling '%s.%s'\");\n", classname, pyname); + Append(w->code, " }\n"); + } + Append(w->code, "}\n"); + Delete(tm); + + /* + * Python method may return a simple object, or a tuple. + * for in/out arguments, we have to extract the appropriate PyObjects from the tuple, + * then marshal everything back to C/C++ (return value and output arguments). + * + */ + + /* marshal return value and other outputs (if any) from PyObject to C/C++ type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + if (outputs > 1) { + Wrapper_add_local(w, "output", "PyObject *output"); + Printf(w->code, "if (!PyTuple_Check(%s)) {\n", Swig_cresult_name()); + Printf(w->code, " Swig::DirectorTypeMismatchException::raise(\"Python method %s.%sfailed to return a tuple.\");\n", classname, pyname); + Append(w->code, "}\n"); + } + + idx = 0; + + /* marshal return value */ + if (!is_void) { + tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); + if (tm != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(%s, %d);\n", Swig_cresult_name(), idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", Swig_cresult_name()); + } + char temp[24]; + sprintf(temp, "%d", idx); + Replaceall(tm, "$argnum", temp); + + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + if (Getattr(n, "tmap:directorout:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), SwigType_namestr(c_classname), + SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(%s, %d);\n", Swig_cresult_name(), idx++); + Replaceall(tm, "$result", "output"); + } else { + Replaceall(tm, "$result", Swig_cresult_name()); + } + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + /* any existing helper functions to handle this? */ + if (allow_thread) { + Append(w->code, "}\n"); + thread_end_block(n, w->code); + } + + Delete(parse_args); + Delete(arglist); + Delete(cleanup); + Delete(outarg); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(returntype, 0); + if (!SwigType_isreference(returntype)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Append(w->code, "}\n"); + + // We expose 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) { + 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); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(pclassname); + DelWrapper(w); + return status; +} + +/* ----------------------------------------------------------------------------- + * swig_python() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_python() { + return new PYTHON(); +} +extern "C" Language *swig_python(void) { + return new_swig_python(); +} diff --git a/contrib/tools/swig/Source/Modules/r.cxx b/contrib/tools/swig/Source/Modules/r.cxx new file mode 100644 index 00000000000..3e3c23e44ec --- /dev/null +++ b/contrib/tools/swig/Source/Modules/r.cxx @@ -0,0 +1,2897 @@ + +/* ----------------------------------------------------------------------------- + * 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. + * + * r.cxx + * + * R language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static String* replaceInitialDash(const String *name) +{ + String *retval; + if (!Strncmp(name, "_", 1)) { + retval = Copy(name); + Insert(retval, 0, "s"); + } else { + retval = Copy(name); + } + return retval; +} + +static String * getRTypeName(SwigType *t, int *outCount = NULL) { + String *b = SwigType_base(t); + List *els = SwigType_split(t); + int count = 0; + int i; + + if(Strncmp(b, "struct ", 7) == 0) + Replace(b, "struct ", "", DOH_REPLACE_FIRST); + + for(i = 0; i < Len(els); i++) { + String *el = Getitem(els, i); + if(Strcmp(el, "p.") == 0 || Strncmp(el, "a(", 2) == 0) { + count++; + Append(b, "Ref"); + } + } + if(outCount) + *outCount = count; + + String *tmp = NewString(""); + char *retName = Char(SwigType_manglestr(t)); + Insert(tmp, 0, retName); + return tmp; + +} + +/* -------------------------------------------------------------- + * Tries to get the resolved name, with options of adding + * or removing a layer of references. Take care not + * to request both + * --------------------------------------------------------------*/ + +static String *getRClassName(String *retType, int deRef=0, int upRef=0) { + SwigType *resolved = SwigType_typedef_resolve_all(retType); + int ispointer = SwigType_ispointer(resolved); + int isreference = SwigType_isreference(resolved); + if (upRef) { + SwigType_add_pointer(resolved); + } + if (deRef) { + if (ispointer) { + SwigType_del_pointer(resolved); + } + if (isreference) { + SwigType_del_reference(resolved); + } + } + String *tmp = NewString(""); + Insert(tmp, 0, Char(SwigType_manglestr(resolved))); + return(tmp); +} + +/* -------------------------------------------------------------- + * Tries to get the name of the R class corresponding to the given type + * e.g. struct A * is ARef, struct A** is ARefRef. + * Now handles arrays, i.e. struct A[2] + * --------------------------------------------------------------*/ + + +static String * getRClassNameCopyStruct(String *retType, int addRef) { + String *tmp = NewString(""); + + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + Printf(stdout, "SwigType_split return an empty list for %s\n", retType); +#endif + return(tmp); + } + + + String *el = Getitem(l, n-1); + char *ptr = Char(el); + if(strncmp(ptr, "struct ", 7) == 0) + ptr += 7; + + Printf(tmp, "%s", ptr); + + if(addRef) { + for(int i = 0; i < n; i++) { + if(Strcmp(Getitem(l, i), "p.") == 0 || + Strncmp(Getitem(l, i), "a(", 2) == 0) + Printf(tmp, "Ref"); + } + } + + return tmp; +} + + +/* ------------------------------------------------------------- + * Write the elements of a list to the File*, one element per line. + * If quote is true, surround the element with "element". + * This takes care of inserting a tab in front of each line and also + * a comma after each element, except the last one. + * --------------------------------------------------------------*/ + + +static void writeListByLine(List *l, File *out, bool quote = 0) { + int i, n = Len(l); + for(i = 0; i < n; i++) + Printf(out, "%s%s%s%s%s\n", tab8, + quote ? "\"" :"", + Getitem(l, i), + quote ? "\"" :"", i < n-1 ? "," : ""); +} + + +static const char *usage = "\ +R Options (available with -r)\n\ + -copystruct - Emit R code to copy C structs (on by default)\n\ + -debug - Output debug\n\ + -dll <name> - Name of the DLL (without the .dll or .so suffix).\n\ + Default is the module name.\n\ + -gc - Aggressive garbage collection\n\ + -memoryprof - Add memory profile\n\ + -namespace - Output NAMESPACE file\n\ + -no-init-code - Turn off the generation of the R_init_<pkgname> code\n\ + (registration information still generated)\n\ + -package <name> - Package name for the PACKAGE argument of the R .Call()\n\ + invocations. Default is the module name.\n\ +"; + + + +/* ------------------------------------------------------------- + * Display the help for this module on the screen/console. + * --------------------------------------------------------------*/ + +static void showUsage() { + fputs(usage, stdout); +} + +static bool expandTypedef(SwigType *t) { + if (SwigType_isenum(t)) return false; + String *prefix = SwigType_prefix(t); + if (Strncmp(prefix, "f", 1)) return false; + if (Strncmp(prefix, "p.f", 3)) return false; + return true; +} + + +/* ------------------------------------------------------------- + * Determine whether we should add a .copy argument to the S function + * that wraps/interfaces to the routine that returns the given type. + * --------------------------------------------------------------*/ + +static int addCopyParameter(SwigType *type) { + int ok = 0; + ok = Strncmp(type, "struct ", 7) == 0 || Strncmp(type, "p.struct ", 9) == 0; + if(!ok) { + ok = Strncmp(type, "p.", 2); + } + + return(ok); +} + +static void replaceRClass(String *tm, SwigType *type) { + String *tmp = getRClassName(type, 0, 0); + String *tmp_base = getRClassName(type, 1, 0); + String *tmp_ref = getRClassName(type, 0, 1); + Replaceall(tm, "$R_class", tmp); + Replaceall(tm, "$*R_class", tmp_base); + Replaceall(tm, "$&R_class", tmp_ref); + Delete(tmp); Delete(tmp_base); Delete(tmp_ref); +} + +class R : public Language { +public: + R(); + void registerClass(Node *n); + void main(int argc, char *argv[]); + int top(Node *n); + + void dispatchFunction(Node *n); + int functionWrapper(Node *n); + int constantWrapper(Node *n); + int variableWrapper(Node *n); + + int classDeclaration(Node *n); + int enumDeclaration(Node *n); + String *enumValue(Node *n); + virtual int enumvalueDeclaration(Node *n); + int membervariableHandler(Node *n); + + int typedefHandler(Node *n); + + static List *Swig_overload_rank(Node *n, + bool script_lang_wrapping); + + int memberfunctionHandler(Node *n) { + if (debugMode) + Printf(stdout, "<memberfunctionHandler> %s %s\n", + Getattr(n, "name"), + Getattr(n, "type")); + member_name = Getattr(n, "sym:name"); + processing_class_member_function = 1; + int status = Language::memberfunctionHandler(n); + processing_class_member_function = 0; + return status; + } + + /* Grab the name of the current class being processed so that we can + deal with members of that class. */ + int classHandler(Node *n){ + if(!ClassMemberTable) + ClassMemberTable = NewHash(); + + class_name = Getattr(n, "name"); + int status = Language::classHandler(n); + + class_name = NULL; + return status; + } + + // Not used: + String *runtimeCode(); + +protected: + int addRegistrationRoutine(String *rname, int nargs); + int outputRegistrationRoutines(File *out); + + int outputCommandLineArguments(File *out); + int generateCopyRoutines(Node *n); + int DumpCode(Node *n); + + int OutputMemberReferenceMethod(String *className, int isSet, List *memberList, List *nameList, List *typeList, File *out); + int defineArrayAccessors(SwigType *type); + + void addNamespaceFunction(String *name) { + if(!namespaceFunctions) + namespaceFunctions = NewList(); + Append(namespaceFunctions, name); + } + + void addNamespaceMethod(String *name) { + if(!namespaceMethods) + namespaceMethods = NewList(); + Append(namespaceMethods, name); + } + + String* processType(SwigType *t, Node *n, int *nargs = NULL); + String *createFunctionPointerHandler(SwigType *t, Node *n, int *nargs); + int addFunctionPointerProxy(String *name, Node *n, SwigType *t, String *s_paramTypes) { + /*XXX Do we need to put the t in there to get the return type later. */ + if(!functionPointerProxyTable) + functionPointerProxyTable = NewHash(); + + Setattr(functionPointerProxyTable, name, n); + + Setattr(SClassDefs, name, name); + Printv(s_classes, "setClass('", + name, + "',\n", tab8, + "prototype = list(parameterTypes = c(", s_paramTypes, "),\n", + tab8, tab8, tab8, + "returnType = '", SwigType_manglestr(t), "'),\n", tab8, + "contains = 'CRoutinePointer')\n\n##\n", NIL); + + return SWIG_OK; + } + + + void addSMethodInfo(String *name, + String *argType, int nargs); + // Simple initialization such as constant strings that can be reused. + void init(); + + + void addAccessor(String *memberName, Wrapper *f, + String *name, String *methodSetGet); + + static int getFunctionPointerNumArgs(Node *n, SwigType *tt); + + // filtering of class member lists by function type. Used in constructing accessors + // are we allowed to use stl style functors to customise this? + List* filterMemberList(List *class_member_function_types, List *class_member_other, String *R_MEMBER, bool equal); + +protected: + bool copyStruct; + bool memoryProfile; + bool aggressiveGc; + + // Strings into which we cumulate the generated code that is to be written + //vto the files. + String *enum_values; + String *enum_def_calls; + String *sfile; + String *f_init; + String *s_classes; + String *f_begin; + String *f_runtime; + String *f_wrapper; + String *s_header; + String *f_wrappers; + String *s_init; + String *s_init_routine; + String *s_namespace; + + // State variables that carry information across calls to functionWrapper() + // from member accessors and class declarations. + String *opaqueClassDeclaration; + int processing_variable; + int processing_member_access_function; + String *member_name; + String *class_name; + + String *R_MEMBER_NORMAL; + String *R_MEMBER_SET; + String *R_MEMBER_GET; + + int processing_class_member_function; + // Spread out the lists so that they are simpler to process + // by storing the type of the method (i.e. set, get or nothing) + // and having separate lists for name, membername and wrapper + List *class_member_function_types; + List *class_member_function_names; + List *class_member_function_membernames; + List *class_member_function_wrappernames; + /* */ + Hash *ClassMemberTable; + Hash *ClassMethodsTable; + Hash *SClassDefs; + Hash *SMethodInfo; + + // Information about routines that are generated and to be registered with + // R for dynamic lookup. + Hash *registrationTable; + Hash *functionPointerProxyTable; + + List *namespaceFunctions; + List *namespaceMethods; + List *namespaceClasses; // Probably can do this from ClassMemberTable. + + + // Store a copy of the command line. + // Need only keep a string that has it formatted. + char **Argv; + int Argc; + bool inCPlusMode; + + // State variables that we remember from the command line settings + // potentially that govern the code we generate. + String *DllName; + String *Rpackage; + bool noInitializationCode; + bool outputNamespaceInfo; + + String *UnProtectWrapupCode; + + // Static members + static bool debugMode; +}; + +R::R() : + copyStruct(false), + memoryProfile(false), + aggressiveGc(false), + enum_values(0), + enum_def_calls(0), + sfile(0), + f_init(0), + s_classes(0), + f_begin(0), + f_runtime(0), + f_wrapper(0), + s_header(0), + f_wrappers(0), + s_init(0), + s_init_routine(0), + s_namespace(0), + opaqueClassDeclaration(0), + processing_variable(0), + processing_member_access_function(0), + member_name(0), + class_name(0), + R_MEMBER_NORMAL(NewString("normal")), + R_MEMBER_SET(NewString("set")), + R_MEMBER_GET(NewString("get")), + processing_class_member_function(0), + class_member_function_types(0), + class_member_function_names(0), + class_member_function_membernames(0), + class_member_function_wrappernames(0), + ClassMemberTable(0), + ClassMethodsTable(0), + SClassDefs(0), + SMethodInfo(0), + registrationTable(0), + functionPointerProxyTable(0), + namespaceFunctions(0), + namespaceMethods(0), + namespaceClasses(0), + Argv(0), + Argc(0), + inCPlusMode(false), + DllName(0), + Rpackage(0), + noInitializationCode(false), + outputNamespaceInfo(false), + UnProtectWrapupCode(0) { +} + +bool R::debugMode = false; + +int R::getFunctionPointerNumArgs(Node *n, SwigType *tt) { + (void) tt; + n = Getattr(n, "type"); + if (debugMode) + Printf(stdout, "type: %s\n", n); + + ParmList *parms = Getattr(n, "parms"); + if (debugMode) + Printf(stdout, "parms = %p\n", parms); + return ParmList_len(parms); +} + + +void R::addSMethodInfo(String *name, String *argType, int nargs) { + (void) argType; + + if(!SMethodInfo) + SMethodInfo = NewHash(); + if (debugMode) + Printf(stdout, "[addMethodInfo] %s\n", name); + + Hash *tb = Getattr(SMethodInfo, name); + + if(!tb) { + tb = NewHash(); + Setattr(SMethodInfo, name, tb); + } + + String *str = Getattr(tb, "max"); + int max = -1; + if(str) + max = atoi(Char(str)); + if(max < nargs) { + if(str) Delete(str); + str = NewStringf("%d", max); + Setattr(tb, "max", str); + } +} + +/* ---------------------------------------- + * Returns the name of the new routine. + * ------------------------------------------ */ + +String * R::createFunctionPointerHandler(SwigType *t, Node *n, int *numArgs) { + String *funName = SwigType_manglestr(t); + + /* See if we have already processed this one. */ + if(functionPointerProxyTable && Getattr(functionPointerProxyTable, funName)) + return funName; + + if (debugMode) + Printf(stdout, "<createFunctionPointerHandler> Defining %s\n", t); + + SwigType *rettype = Copy(Getattr(n, "type")); + SwigType *funcparams = SwigType_functionpointer_decompose(rettype); + String *rtype = SwigType_str(rettype, 0); + + // ParmList *parms = Getattr(n, "parms"); + // memory leak + ParmList *parms = SwigType_function_parms(SwigType_del_pointer(Copy(t)), n); + + + if (debugMode) { + Printf(stdout, "Type: %s\n", t); + Printf(stdout, "Return type: %s\n", SwigType_base(t)); + } + + bool isVoidType = Strcmp(rettype, "void") == 0; + if (debugMode) + Printf(stdout, "%s is void ? %s (%s)\n", funName, isVoidType ? "yes" : "no", rettype); + + Wrapper *f = NewWrapper(); + + /* Go through argument list, attach lnames for arguments */ + int i = 0; + Parm *p = parms; + for (i = 0; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname; + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i+1); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + Swig_typemap_attach_parms("out", parms, f); + Swig_typemap_attach_parms("scoerceout", parms, f); + Swig_typemap_attach_parms("scheck", parms, f); + + Printf(f->def, "%s %s(", rtype, funName); + + emit_parameter_variables(parms, f); + emit_return_variable(n, rettype, f); + // emit_attach_parmmaps(parms,f); + + /* Using weird name and struct to avoid potential conflicts. */ + Wrapper_add_local(f, "r_swig_cb_data", "RCallbackFunctionData *r_swig_cb_data = R_SWIG_getCallbackFunctionData()"); + String *lvar = NewString("r_swig_cb_data"); + + Wrapper_add_local(f, "r_tmp", "SEXP r_tmp"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_nprotect", "int r_nprotect = 0"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_vmax", "char * r_vmax= 0"); // for use in converting arguments to R objects for call. + + // Add local for error code in return value. This is not in emit_return_variable because that assumes an out typemap + // whereas the type makes are reverse + Wrapper_add_local(f, "ecode", "int ecode = 0"); + + p = parms; + int nargs = ParmList_len(parms); + if(numArgs) { + *numArgs = nargs; + if (debugMode) + Printf(stdout, "Setting number of parameters to %d\n", *numArgs); + } + String *setExprElements = NewString(""); + + String *s_paramTypes = NewString(""); + for(i = 0; p; i++) { + SwigType *tt = Getattr(p, "type"); + SwigType *name = Getattr(p, "name"); + SwigType *swig_parm_name = NewStringf("swigarg_%s", name); + String *tm = Getattr(p, "tmap:out"); + bool isVoidParm = Strcmp(tt, "void") == 0; + if (isVoidParm) + Printf(f->def, "%s", SwigType_str(tt, 0)); + else + Printf(f->def, "%s %s", SwigType_str(tt, 0), swig_parm_name); + if (tm) { + String *lstr = SwigType_lstr(tt, 0); + if (SwigType_isreference(tt) || SwigType_isrvalue_reference(tt)) { + Printf(f->code, "%s = (%s) &%s;\n", Getattr(p, "lname"), lstr, swig_parm_name); + } else if (!isVoidParm) { + Printf(f->code, "%s = (%s) %s;\n", Getattr(p, "lname"), lstr, swig_parm_name); + } + Replaceall(tm, "$1", name); + Replaceall(tm, "$result", "r_tmp"); + if (debugMode) { + Printf(stdout, "Calling Replace A: %s\n", Getattr(p,"type")); + } + replaceRClass(tm, Getattr(p,"type")); + Replaceall(tm,"$owner", "0"); + Delete(lstr); + } + + Printf(setExprElements, "%s\n", tm); + Printf(setExprElements, "SETCAR(r_swig_cb_data->el, %s);\n", "r_tmp"); + Printf(setExprElements, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + + Printf(s_paramTypes, "'%s'", SwigType_manglestr(tt)); + + + p = nextSibling(p); + if(p) { + Printf(f->def, ", "); + Printf(s_paramTypes, ", "); + } + } + + Printf(f->def, ") {\n"); + + Printf(f->code, "Rf_protect(%s->expr = Rf_allocVector(LANGSXP, %d));\n", lvar, nargs + 1); + Printf(f->code, "r_nprotect++;\n"); + Printf(f->code, "r_swig_cb_data->el = r_swig_cb_data->expr;\n\n"); + + Printf(f->code, "SETCAR(r_swig_cb_data->el, r_swig_cb_data->fun);\n"); + Printf(f->code, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + + Printf(f->code, "%s\n\n", setExprElements); + + Printv(f->code, "r_swig_cb_data->retValue = R_tryEval(", + "r_swig_cb_data->expr,", + " R_GlobalEnv,", + " &r_swig_cb_data->errorOccurred", + ");\n", + NIL); + + Printv(f->code, "\n", + "if(r_swig_cb_data->errorOccurred) {\n", + "R_SWIG_popCallbackFunctionData(1);\n", + "Rf_error(\"error in calling R function as a function pointer (", + funName, + ")\");\n", + "}\n", + NIL); + + + + if(!isVoidType) { + /* Need to deal with the return type of the function pointer, not the function pointer itself. + So build a new node that has the relevant pieces. + XXX Have to be a little more clever so that we can deal with struct A * - the * is getting lost. + Is this still true? If so, will a SwigType_push() solve things? + */ + Parm *bbase = NewParmNode(rettype, n); + String *returnTM = Swig_typemap_lookup("in", bbase, Swig_cresult_name(), f); + if(returnTM) { + String *tm = returnTM; + Replaceall(tm,"$input", "r_swig_cb_data->retValue"); + Replaceall(tm,"$target", Swig_cresult_name()); + replaceRClass(tm, rettype); + Replaceall(tm,"$owner", "0"); + Replaceall(tm,"$disown","0"); + Printf(f->code, "%s\n", tm); + } + Delete(bbase); + } + + Printv(f->code, "R_SWIG_popCallbackFunctionData(1);\n", NIL); + Printv(f->code, "\n", UnProtectWrapupCode, NIL); + + if (SwigType_isreference(rettype)) { + Printv(f->code, "return *", Swig_cresult_name(), ";\n", NIL); + } else if (SwigType_isrvalue_reference(rettype)) { + Printv(f->code, "return std::move(*", Swig_cresult_name(), ");\n", NIL); + } else if (!isVoidType) { + Printv(f->code, "return ", Swig_cresult_name(), ";\n", NIL); + } + + Printv(f->code, "\n}\n", NIL); + Replaceall(f->code, "SWIG_exception_fail", "SWIG_exception_noreturn"); + + /* To coerce correctly in S, we really want to have an extra/intermediate + function that handles the scoerceout. + We need to check if any of the argument types have an entry in + that map. If none do, the ignore and call the function straight. + Otherwise, generate a marshalling function. + Need to be able to find it in S. Or use an entirely generic one + that evaluates the expressions. + Handle errors in the evaluation of the function by restoring + the stack, if there is one in use for this function (i.e. no + userData). + */ + + Wrapper_print(f, f_wrapper); + + addFunctionPointerProxy(funName, n, t, s_paramTypes); + Delete(s_paramTypes); + Delete(rtype); + Delete(rettype); + Delete(funcparams); + DelWrapper(f); + + return funName; +} + +void R::init() { + UnProtectWrapupCode = + NewStringf("%s", "vmaxset(r_vmax);\nif(r_nprotect) Rf_unprotect(r_nprotect);\n\n"); + + SClassDefs = NewHash(); + + sfile = NewString(""); + f_init = NewString(""); + s_header = NewString(""); + f_begin = NewString(""); + f_runtime = NewString(""); + f_wrapper = NewString(""); + s_classes = NewString(""); + s_init = NewString(""); + s_init_routine = NewString(""); + enum_def_calls = NewString(""); +} + + +/* ------------------------------------------------------------- + * Method from Language that is called to start the entire + * processing off, i.e. the generation of the code. + * It is called after the input has been read and parsed. + * Here we open the output streams and generate the code. + * ------------------------------------------------------------- */ +int R::top(Node *n) { + String *module = Getattr(n, "name"); + + if (debugMode) { + Printf(stdout, "<Top> %s\n", module); + } + + if(!Rpackage) + Rpackage = Copy(module); + if(!DllName) + DllName = Copy(module); + + if(outputNamespaceInfo) { + s_namespace = NewString(""); + Swig_register_filebyname("snamespace", s_namespace); + Printf(s_namespace, "useDynLib(%s)\n", DllName); + } + // Register the naming functions + Swig_name_register("wrapper", "R_swig_%f"); + + /* Associate the different streams with names so that they can be used in %insert directives by the + typemap code. */ + Swig_register_filebyname("sinit", s_init); + Swig_register_filebyname("sinitroutine", s_init_routine); + + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("header", s_header); + Swig_register_filebyname("wrapper", f_wrapper); + Swig_register_filebyname("s", sfile); + Swig_register_filebyname("sclasses", s_classes); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGR\n#define SWIGR\n#endif\n\n"); + + + Swig_banner_target_lang(s_init, "#"); + outputCommandLineArguments(s_init); + + Printf(f_wrapper, "#ifdef __cplusplus\n"); + Printf(f_wrapper, "extern \"C\" {\n"); + Printf(f_wrapper, "#endif\n\n"); + + Language::top(n); + + Printf(f_wrapper, "#ifdef __cplusplus\n"); + Printf(f_wrapper, "}\n"); + Printf(f_wrapper, "#endif\n"); + + String *type_table = NewString(""); + SwigType_emit_type_table(f_runtime,f_wrapper); + Delete(type_table); + + if(ClassMemberTable) { + //XXX OutputClassAccessInfo(ClassMemberTable, sfile); + Delete(ClassMemberTable); + ClassMemberTable = NULL; + } + + Printf(f_init,"}\n"); + if(registrationTable) + outputRegistrationRoutines(f_init); + + /* Now arrange to write the 2 files - .S and .c. */ + + DumpCode(n); + + Delete(sfile); + Delete(s_classes); + Delete(s_init); + Delete(f_wrapper); + Delete(f_init); + + Delete(s_header); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; +} + + +/* ------------------------------------------------------------- + * Write the generated code to the .S and the .c files. + * ------------------------------------------------------------- */ +int R::DumpCode(Node *n) { + String *output_filename = NewString(""); + + + /* The name of the file in which we will generate the S code. */ + Printf(output_filename, "%s%s.R", SWIG_output_directory(), Rpackage); + +#ifdef R_SWIG_VERBOSE + Printf(stdout, "Writing S code to %s\n", output_filename); +#endif + + File *scode = NewFile(output_filename, "w", SWIG_output_files()); + if (!scode) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(output_filename); + + + Printf(scode, "%s\n\n", s_init); + Printf(scode, "%s\n\n", s_classes); + Printf(scode, "%s\n", sfile); + Printf(scode, "%s\n", enum_def_calls); + + Delete(scode); + String *outfile = Getattr(n,"outfile"); + File *runtime = NewFile(outfile,"w", SWIG_output_files()); + if (!runtime) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + Printf(runtime, "%s", f_begin); + Printf(runtime, "%s\n", f_runtime); + Printf(runtime, "%s\n", s_header); + Printf(runtime, "%s\n", f_wrapper); + Printf(runtime, "%s\n", f_init); + + Delete(runtime); + + if(outputNamespaceInfo) { + output_filename = NewString(""); + Printf(output_filename, "%sNAMESPACE", SWIG_output_directory()); + File *ns = NewFile(output_filename, "w", SWIG_output_files()); + if (!ns) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(output_filename); + + Printf(ns, "%s\n", s_namespace); + + Printf(ns, "\nexport(\n"); + writeListByLine(namespaceFunctions, ns); + Printf(ns, ")\n"); + Printf(ns, "\nexportMethods(\n"); + writeListByLine(namespaceMethods, ns, 1); + Printf(ns, ")\n"); + Delete(ns); + Delete(s_namespace); + } + + return SWIG_OK; +} + + +List *R::filterMemberList(List *class_member_types, + List *class_member_other, + String *R_MEMBER, bool equal) { + // filters class_member_other based on whether corresponding elements of + // class_member_function_types are equal or notequal to R_MEMBER + List *CM = NewList(); + Iterator ftype, other; + + for (ftype = First(class_member_types), other = First(class_member_other); + ftype.item; + ftype=Next(ftype), other=Next(other)) { + // verbose, clean up later if the overall structure works + if (equal) { + if (ftype.item == R_MEMBER) { + Append(CM, other.item); + } + } else { + if (ftype.item != R_MEMBER) { + Append(CM, other.item); + } + } + } + return(CM); +} + +# if 0 +// not called +/* ------------------------------------------------------------- + * We may need to do more.... so this is left as a + * stub for the moment. + * -------------------------------------------------------------*/ +int R::OutputClassAccessInfo(Hash *tb, File *out) { + int n = OutputClassMemberTable(tb, out); + OutputClassMethodsTable(out); + return n; +} + +/* ------------------------------------------------------------- + * Currently this just writes the information collected about the + * different methods of the C++ classes that have been processed + * to the console. + * This will be used later to define S4 generics and methods. + * --------------------------------------------------------------*/ + +int R::OutputClassMethodsTable(File *) { + Hash *tb = ClassMethodsTable; + + if(!tb) + return SWIG_OK; + + List *keys = Keys(tb); + String *key; + int i, n = Len(keys); + if (debugMode) { + for(i = 0; i < n ; i++ ) { + key = Getitem(keys, i); + Printf(stdout, "%d) %s\n", i, key); + List *els = Getattr(tb, key); + int nels = Len(els); + Printf(stdout, "\t"); + for(int j = 0; j < nels; j+=2) { + Printf(stdout, "%s%s", Getitem(els, j), j < nels - 1 ? ", " : ""); + Printf(stdout, "%s\n", Getitem(els, j+1)); + } + Printf(stdout, "\n"); + } + } + + return SWIG_OK; +} + + +/* -------------------------------------------------------------- + * Iterate over the <class name>_set and <>_get + * elements and generate the $ and $<- functions + * that provide constrained access to the member + * fields in these elements. + + * tb - a hash table that is built up in functionWrapper + * as we process each membervalueHandler. + * The entries are indexed by <class name>_set and + * <class_name>_get. Each entry is a List *. + + * out - the stram where the code is to be written. This is the S + * code stream as we generate only S code here. + * --------------------------------------------------------------*/ + +int R::OutputClassMemberTable(Hash *tb, File *out) { + List *keys = Keys(tb), *el; + + String *key; + int i, n = Len(keys); + /* Loop over all the <Class>_set and <Class>_get entries in the table. */ + /* This function checks for names ending in _set - perhaps it should */ + /* use attributes of some other form, as it potentially clashes with */ + /* methods ending in _set */ + + if(n && outputNamespaceInfo) { + Printf(s_namespace, "exportClasses("); + } + for(i = 0; i < n; i++) { + key = Getitem(keys, i); + el = Getattr(tb, key); + + String *className = Getitem(el, 0); + char *ptr = Char(key); + int klen = Len(key); + int isSet = 0; + if (klen > 4) { + ptr = &ptr[klen - 4]; + isSet = strcmp(ptr, "_set") == 0; + } + + if(outputNamespaceInfo) + Printf(s_namespace, "\"%s\"%s", className, i < n-1 ? "," : ""); + } + if(n && outputNamespaceInfo) { + Printf(s_namespace, ")\n"); + } + + return n; +} + +// end not used +#endif +/* -------------------------------------------------------------- + * Write the methods for $ or $<- for accessing a member field in an + * struct or union (or class). + * className - the name of the struct or union (e.g. Bar for struct Bar) + * isSet - a logical value indicating whether the method is for + * modifying ($<-) or accessing ($) the member field. + * el - a list of length 2 * # accessible member elements + 1. + * The first element is the name of the class. + * The other pairs are member name and the name of the R function to access it. + * out - the stream where we write the code. + * --------------------------------------------------------------*/ + +int R::OutputMemberReferenceMethod(String *className, int isSet, + List *memberList, List *nameList, + List *typeList, File *out) { + int numMems = Len(memberList), j; + int varaccessor = 0; + if (numMems == 0) + return SWIG_OK; + + Wrapper *f = NewWrapper(), *attr = NewWrapper(); + + Printf(f->def, "function(x, name%s)", isSet ? ", value" : ""); + Printf(attr->def, "function(x, i, j, ...%s)", isSet ? ", value" : ""); + + Printf(f->code, "{\n"); + Printf(f->code, "%saccessorFuns = list(", tab8); + + Node *itemList = NewHash(); + bool has_prev = false; + for(j = 0; j < numMems; j++) { + String *item = Getitem(memberList, j); + String *dup = Getitem(nameList, j); + String *setgetmethod = Getitem(typeList, j); + + if (setgetmethod == R_MEMBER_GET) + varaccessor++; + + if (Getattr(itemList, item)) + continue; + Setattr(itemList, item, "1"); + + String *pitem; + if (!Strcmp(item, "operator ()")) { + pitem = NewString("call"); + } else if (!Strcmp(item, "operator ->")) { + pitem = NewString("deref"); + } else if (!Strcmp(item, "operator +")) { + pitem = NewString("add"); + } else if (!Strcmp(item, "operator -")) { + pitem = NewString("sub"); + } else { + pitem = Copy(item); + } + if (has_prev) + Printf(f->code, ", "); + Printf(f->code, "'%s' = %s", pitem, dup); + has_prev = true; + Delete(pitem); + } + Delete(itemList); + Printf(f->code, ");\n"); + + if (!isSet && varaccessor > 0) { + Printf(f->code, "%svaccessors = c(", tab8); + bool first = true; + for(j = 0; j < numMems; j++) { + String *item = Getitem(memberList, j); + String *setgetmethod = Getitem(typeList, j); + + // Check the type here instead of the name + if (setgetmethod == R_MEMBER_GET) { + Printf(f->code, "%s'%s'", first ? "" : ", ", item); + first = false; + } + } + Printf(f->code, ");\n"); + } + + Printv(f->code, ";", tab8, + "idx = pmatch(name, names(accessorFuns));\n", + tab8, + "if(is.na(idx)) \n", + tab8, tab4, NIL); + Printf(f->code, "return(callNextMethod(x, name%s));\n", + isSet ? ", value" : ""); + Printv(f->code, tab8, "f = accessorFuns[[idx]];\n", NIL); + if(isSet) { + Printv(f->code, tab8, "f(x, value);\n", NIL); + Printv(f->code, tab8, "x;\n", NIL); // make certain to return the S value. + } else { + if (varaccessor) { + Printv(f->code, tab8, + "if (is.na(match(name, vaccessors))) function(...){f(x, ...)} else f(x);\n", NIL); + } else { + Printv(f->code, tab8, "function(...){f(x, ...)};\n", NIL); + } + } + Printf(f->code, "}\n"); + + String *classname_str = SwigType_namestr(className); + Printf(out, "# Start of accessor method for %s\n", classname_str); + Printf(out, "setMethod('$%s', '_p%s', ", + isSet ? "<-" : "", + getRClassName(className)); + Wrapper_print(f, out); + Printf(out, ");\n"); + + if(isSet) { + Printf(out, "setMethod('[[<-', c('_p%s', 'character'),", + getRClassName(className)); + Insert(f->code, 2, "name = i;\n"); + Printf(attr->code, "%s", f->code); + Wrapper_print(attr, out); + Printf(out, ");\n"); + } + + Printf(out, "# end of accessor method for %s\n", classname_str); + + Delete(classname_str); + DelWrapper(attr); + DelWrapper(f); + + return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Called when a enumeration is to be processed. + * We want to call the R function defineEnumeration(). + * tdname is the typedef of the enumeration, i.e. giving its name. + * --------------------------------------------------------------*/ + +int R::enumDeclaration(Node *n) { + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + String *symname = Getattr(n, "sym:name"); + + // TODO - deal with anonymous enumerations + // Previous enum code for R didn't wrap them + if (!symname || Getattr(n, "unnamedinstance")) + return SWIG_NOWRAP; + + // create mangled name for the enum + // This will have content if the %nspace feature is set on + // the input file + String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call + String *ename; + + String *name = Getattr(n, "name"); + ename = getRClassName(name); + if (debugMode) { + Node *current_class = getCurrentClass(); + String *cl = NewString(""); + if (current_class) { + cl = getEnumClassPrefix(); + } + Printf(stdout, "enumDeclaration: %s, %s, %s, %s, %s\n", name, symname, nspace, ename, cl); + } + Delete(name); + // set up a call to create the R enum structure. The list of + // individual elements will be built in enum_code + enum_values = 0; + // Emit each enum item + Language::enumDeclaration(n); + + Printf(enum_def_calls, "defineEnumeration(\"%s\",\n .values=c(%s))\n\n", ename, enum_values); + Delete(enum_values); + Delete(ename); + } + return SWIG_OK; +} + +/* ------------------------------------------------------------- +* --------------------------------------------------------------*/ + +int R::enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) { + Printf(stdout, "evd: Not public\n"); + return SWIG_NOWRAP; + } + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + Node *parent = parentNode(n); + String *parent_name = Getattr(parent, "name"); + String *newsymname = 0; + String *tmpValue; + + // Strange hack from parent method + 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("'%s'", Getattr(n, "enumvalue")); + Setattr(n, "enumvalue", val); + Delete(val); + } + + if (GetFlag(parent, "scopedenum")) { + newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + symname = newsymname; + } + + { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum "); + if (debugMode) { + Printf(stdout, "Setting type: %s\n", Copy(typemap_lookup_type)); + } + Setattr(n, "type", typemap_lookup_type); + + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + + String *value = enumValue(n); + if (enum_values) { + Printf(enum_values, ",\n\"%s\" = %s", name, value); + } else { + enum_values = NewString(""); + Printf(enum_values, "\"%s\" = %s", name, value); + } + + Delete(value); + } + + return SWIG_OK; +} + + +/* ------------------------------------------------------------- + * Create accessor functions for variables. + * Does not create equivalent wrappers for enumerations, + * which are handled differently + * --------------------------------------------------------------*/ + +int R::variableWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + if (debugMode) { + Printf(stdout, "variableWrapper %s\n", n); + } + processing_variable = 1; + Language::variableWrapper(n); // Force the emission of the _set and _get function wrappers. + processing_variable = 0; + + + SwigType *ty = Getattr(n, "type"); + String *nodeType = nodeType(n); + int addCopyParam = addCopyParameter(ty); + + //XXX + processType(ty, n); + + if (nodeType && !Strcmp(nodeType, "enumitem")) { + /* special wrapper for enums - don't want the R _set, _get functions*/ + if (debugMode) { + Printf(stdout, "variableWrapper enum branch\n"); + } + } else if(!SwigType_isconst(ty)) { + Wrapper *f = NewWrapper(); + Printf(f->def, "%s = \nfunction(value%s)\n{\n", + name, addCopyParam ? ", .copy = FALSE" : ""); + Printv(f->code, "if(missing(value)) {\n", + name, "_get(", addCopyParam ? ".copy" : "", ")\n}", NIL); + Printv(f->code, " else {\n", + name, "_set(value)\n}\n}", NIL); + + Wrapper_print(f, sfile); + DelWrapper(f); + } else { + Printf(sfile, "%s = %s_get\n", name, name); + } + + return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Creates accessor functions for class members. + + * ToDo - this version depends on naming conventions and needs + * to be replaced. + * --------------------------------------------------------------*/ + +void R::addAccessor(String *memberName, Wrapper *wrapper, String *name, + String *methodSetGet) { + + if (!class_member_function_names) { + class_member_function_names = NewList(); + class_member_function_membernames = NewList(); + class_member_function_wrappernames = NewList(); + class_member_function_types = NewList(); + } + Append(class_member_function_types, methodSetGet); + Append(class_member_function_names, name); + Append(class_member_function_membernames, memberName); + + String *tmp = NewString(""); + Wrapper_print(wrapper, tmp); + Append(class_member_function_wrappernames, tmp); + // if we could put the wrapper in directly: Append(l, Copy(sfun)); + if (debugMode) + Printf(stdout, "Adding accessor: %s (%s) => %s\n", memberName, name, tmp); +} + +#define MAX_OVERLOAD 256 + +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ +}; + + +List * R::Swig_overload_rank(Node *n, + bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n,"sym:overloaded"); + + + if (!o) return 0; + + Node *c = o; + while (c) { + if (Getattr(c,"error")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + + if (Getattr(c,"wrap:name")) { + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c,"wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nnodes++; + } + c = Getattr(c,"sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i,j; + for (i = 0; i < nnodes; i++) { + for (j = i+1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i,j; + for (i = 0; i < nnodes-1; i++) { + if (nodes[i].argc == nodes[i+1].argc) { + for (j = i+1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + if (debugMode) { + Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + } + if (checkAttribute(p1,"tmap:in:numinputs","0")) { + p1 = Getattr(p1,"tmap:in:next"); + continue; + } + if (checkAttribute(p2,"tmap:in:numinputs","0")) { + p2 = Getattr(p2,"tmap:in:next"); + continue; + } + String *t1 = Getattr(p1,"tmap:typecheck:precedence"); + String *t2 = Getattr(p2,"tmap:typecheck:precedence"); + if (debugMode) { + Printf(stdout,"t1 = '%s', t2 = '%s'\n", t1, t2); + } + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", + Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s not supported (incomplete type checking rule - no precedence level in typecheck typemap for '%s').\n", + Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v-t2v; + } + else if (!t1 && t2) differ = 1; + else if (t1 && !t2) differ = -1; + else if (!t1 && !t2) differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1,"0") == 0)) { + t1 = Getattr(p1,"ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1,"type")); + if (Getattr(p1,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1,"ltype",t1); + } + t2 = Getattr(p2,"ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2,"type")); + if (Getattr(p2,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2,"ltype",t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2,t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1,t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1,"tmap:in:next")) { + p1 = Getattr(p1,"tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2,"tmap:in:next")) { + p2 = Getattr(p2,"tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *d1 = Getattr(nodes[i].n, "decl"); + String *d2 = Getattr(nodes[j].n, "decl"); + if (d1 && d2) { + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1, dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), + "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n), + "using non-const method %s instead.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s effectively ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[i].n), Getline(nodes[i].n), + "as it is shadowed by %s.\n", Swig_name_decl(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) { + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored,\n", Swig_name_decl(nodes[j].n)); + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n), + "using %s instead.\n", Swig_name_decl(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result,nodes[i].n); + // Printf(stdout,"[ %d ] %s\n", i, ParmList_errorstr(nodes[i].parms)); + // Swig_print_node(nodes[i].n); + } + } + return result; +} + +void R::dispatchFunction(Node *n) { + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + + String *sfname = NewString(symname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + Printf(f->def, + "`%s` <- function(...) {", sfname); + if (debugMode) { + Swig_print_node(n); + } + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + Printv(f->code, + "argtypes <- mapply(class, list(...));\n", + "argv <- list(...);\n", + "argc <- length(argtypes);\n", NIL ); + + Printf(f->code, "# dispatch functions %d\n", nfunc); + int cur_args = -1; + bool first_compare = true; + for (int i=0; i < nfunc; i++) { + Node *ni = Getitem(dispatch,i); + Parm *pi = Getattr(ni,"wrap:parms"); + int num_arguments = emit_num_arguments(pi); + + String *overname = Getattr(ni,"sym:overname"); + if (cur_args != num_arguments) { + if (cur_args != -1) { + Printv(f->code, "} else ", NIL); + } + Printf(f->code, "if (argc == %d) {", num_arguments); + cur_args = num_arguments; + first_compare = true; + } + Parm *p; + int j; + if (num_arguments > 0) { + if (!first_compare) { + Printv(f->code, " else ", NIL); + } else { + first_compare = false; + } + Printv(f->code, "if (", NIL); + for (p =pi, j = 0 ; j < num_arguments ; j++) { + if (debugMode) { + Swig_print_node(p); + } + String *tm = Swig_typemap_lookup("rtype", p, "", 0); + if(tm) { + replaceRClass(tm, Getattr(p, "type")); + } + + String *tmcheck = Swig_typemap_lookup("rtypecheck", p, "", 0); + if (tmcheck) { + String *tmp = NewString(""); + Printf(tmp, "argv[[%d]]", j+1); + Replaceall(tmcheck, "$arg", tmp); + Printf(tmp, "argtype[%d]", j+1); + Replaceall(tmcheck, "$argtype", tmp); + if (tm) { + Replaceall(tmcheck, "$rtype", tm); + } + if (debugMode) { + Printf(stdout, "<rtypecheck>%s\n", tmcheck); + } + Printf(f->code, "%s(%s)", + j == 0 ? "" : " && ", + tmcheck); + p = Getattr(p, "tmap:in:next"); + continue; + } + // Below should be migrated into rtypecheck typemaps + if (tm) { + Printf(f->code, "%s", j == 0 ? "" : " && "); + if (Strcmp(tm, "numeric") == 0) { + Printf(f->code, "is.numeric(argv[[%d]])", j+1); + } else if (Strcmp(tm, "integer") == 0) { + Printf(f->code, "(is.integer(argv[[%d]]) || is.numeric(argv[[%d]]))", j+1, j+1); + } else if (Strcmp(tm, "character") == 0) { + Printf(f->code, "is.character(argv[[%d]])", j+1); + } else { + if (SwigType_ispointer(Getattr(p, "type"))) + Printf(f->code, "(extends(argtypes[%d], '%s') || is.null(argv[[%d]]))", j+1, tm, j+1); + else + Printf(f->code, "extends(argtypes[%d], '%s')", j+1, tm); + } + } + if (!SwigType_ispointer(Getattr(p, "type"))) { + Printf(f->code, " && length(argv[[%d]]) == 1", j+1); + } + p = Getattr(p, "tmap:in:next"); + } + Printf(f->code, ") { f <- %s%s; }\n", sfname, overname); + } else { + Printf(f->code, "f <- %s%s; ", sfname, overname); + } + } + if (cur_args != -1) { + Printf(f->code, "} else {\n" + "stop(\"cannot find overloaded function for %s with argtypes (\"," + "toString(argtypes),\")\");\n" + "}", sfname); + } + Printv(f->code, ";\nf(...)", NIL); + Printv(f->code, ";\n}", NIL); + Wrapper_print(f, sfile); + Printv(sfile, "# Dispatch function\n", NIL); + DelWrapper(f); +} + +/*-------------------------------------------------------------- + +* --------------------------------------------------------------*/ + +int R::functionWrapper(Node *n) { + String *fname = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *type = Getattr(n, "type"); + + if (debugMode) { + Printf(stdout, + "<functionWrapper> %s %s %s\n", fname, iname, type); + } + String *overname = 0; + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + bool destructor = (!Cmp(nodeType, "destructor")); + + String *sfname = NewString(iname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + if (Getattr(n,"sym:overloaded")) { + overname = Getattr(n,"sym:overname"); + Append(sfname, overname); + } + + if (debugMode) + Printf(stdout, + "<functionWrapper> processing parameters\n"); + + + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *tm; + + p = l; + while(p) { + SwigType *resultType = Getattr(p, "type"); + if (expandTypedef(resultType) && + SwigType_istypedef(resultType)) { + SwigType *resolved = + SwigType_typedef_resolve_all(resultType); + if (expandTypedef(resolved)) { + if (debugMode) { + Printf(stdout, "Setting type: %s\n", resolved); + } + Setattr(p, "type", Copy(resolved)); + } + } + p = nextSibling(p); + } + + String *unresolved_return_type = + Copy(type); + if (expandTypedef(type) && + SwigType_istypedef(type)) { + SwigType *resolved = + SwigType_typedef_resolve_all(type); + if (debugMode) + Printf(stdout, "<functionWrapper> resolved %s\n", Copy(unresolved_return_type)); + if (expandTypedef(resolved)) { + type = Copy(resolved); + Setattr(n, "type", type); + } + } + if (debugMode) + Printf(stdout, "<functionWrapper> unresolved_return_type %s\n", unresolved_return_type); + if(processing_member_access_function) { + if (debugMode) + Printf(stdout, "<functionWrapper memberAccess> '%s' '%s' '%s' '%s'\n", fname, iname, member_name, class_name); + + if(opaqueClassDeclaration) + return SWIG_OK; + + + /* Add the name of this member to a list for this class_name. + We will dump all these at the end. */ + + bool isSet(GetFlag(n, "memberset")); + + String *tmp = NewString(isSet ? Swig_name_set(NSPACE_TODO, class_name) : Swig_name_get(NSPACE_TODO, class_name)); + + List *memList = Getattr(ClassMemberTable, tmp); + if(!memList) { + memList = NewList(); + Append(memList, class_name); + Setattr(ClassMemberTable, tmp, memList); + } + Delete(tmp); + Append(memList, member_name); + Append(memList, iname); + } + + int i; + int nargs; + + String *wname = Swig_name_wrapper(iname); + + if(overname) + Append(wname, overname); + Setattr(n,"wrap:name", wname); + + Wrapper *f = NewWrapper(); + Wrapper *sfun = NewWrapper(); + + int isVoidReturnType = (Strcmp(type, "void") == 0); + // Need to use the unresolved return type since + // typedef resolution removes the const which causes a + // mismatch with the function action + emit_return_variable(n, unresolved_return_type, f); + + SwigType *rtype = Getattr(n, "type"); + int addCopyParam = 0; + + if(!isVoidReturnType) + addCopyParam = addCopyParameter(rtype); + + if (debugMode) + Printf(stdout, "Adding a .copy argument to %s for %s = %s\n", + iname, type, addCopyParam ? "yes" : "no"); + + Printv(f->def, "SWIGEXPORT SEXP\n", wname, " ( ", NIL); + + Printf(sfun->def, "# Start of %s\n", iname); + Printv(sfun->def, "\n`", sfname, "` = function(", NIL); + + if(outputNamespaceInfo) {//XXX Need to be a little more discriminating + if (constructor) { + String *niname = Copy(iname); + Replace(niname, "new_", "", DOH_REPLACE_FIRST); + addNamespaceFunction(niname); + Delete(niname); + } else { + addNamespaceFunction(iname); + } + } + + Swig_typemap_attach_parms("scoercein", l, f); + Swig_typemap_attach_parms("scoerceout", l, f); + Swig_typemap_attach_parms("scheck", l, f); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l,f); + Setattr(n,"wrap:parms",l); + + nargs = emit_num_arguments(l); + + Wrapper_add_local(f, "r_nprotect", "unsigned int r_nprotect = 0"); + Wrapper_add_localv(f, "r_ans", "SEXP", "r_ans = R_NilValue", NIL); + Wrapper_add_localv(f, "r_vmax", "VMAXTYPE", "r_vmax = vmaxget()", NIL); + + String *sargs = NewString(""); + + + String *s_inputTypes = NewString(""); + String *s_inputMap = NewString(""); + bool inFirstArg = true; + bool inFirstType = true; + Parm *curP; + for (p =l, i = 0 ; i < nargs ; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *tt = Getattr(p, "type"); + int nargs = -1; + String *funcptr_name = processType(tt, p, &nargs); + + // SwigType *tp = Getattr(p, "type"); + String *name = Getattr(p,"name"); + String *lname = Getattr(p,"lname"); + + // R keyword renaming + if (name) { + if (Swig_name_warning(p, 0, name, 0)) { + name = 0; + } else { + /* If we have a :: in the parameter name because we are accessing a static member of a class, say, then + we need to remove that prefix. */ + while (Strstr(name, "::")) { + //XXX need to free. + name = NewStringf("%s", Strchr(name, ':') + 2); + if (debugMode) + Printf(stdout, "+++ parameter name with :: in it %s\n", name); + } + } + } + if (!name || Len(name) == 0) + name = NewStringf("s_arg%d", i+1); + + name = replaceInitialDash(name); + + if (!Strncmp(name, "arg", 3)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(processing_variable) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(!Strcmp(name, fname)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + Printf(sargs, "%s, ", name); + + String *tm; + if((tm = Getattr(p, "tmap:scoercein"))) { + Replaceall(tm, "$input", name); + replaceRClass(tm, Getattr(p, "type")); + + if(funcptr_name) { + //XXX need to get this to return non-zero + if(nargs == -1) + nargs = getFunctionPointerNumArgs(p, tt); + + String *snargs = NewStringf("%d", nargs); + Printv(sfun->code, "if(is.function(", name, ")) {", "\n", + "assert('...' %in% names(formals(", name, + ")) || length(formals(", name, ")) >= ", snargs, ");\n} ", NIL); + Delete(snargs); + + Printv(sfun->code, "else {\n", + "if(is.character(", name, ")) {\n", + name, " = getNativeSymbolInfo(", name, ");", + "\n};\n", + "if(is(", name, ", \"NativeSymbolInfo\")) {\n", + name, " = ", name, "$address", ";\n};\n", + "if(is(", name, ", \"ExternalReference\")) {\n", + name, " = ", name, "@ref;\n}\n", + "}; \n", + NIL); + } else { + Printf(sfun->code, "%s\n", tm); + } + } + + Printv(sfun->def, inFirstArg ? "" : ", ", name, NIL); + + if ((tm = Getattr(p,"tmap:scheck"))) { + + Replaceall(tm,"$target", lname); + Replaceall(tm,"$source", name); + Replaceall(tm,"$input", name); + replaceRClass(tm, Getattr(p, "type")); + Printf(sfun->code,"%s\n",tm); + } + + + + curP = p; + if ((tm = Getattr(p,"tmap:in"))) { + + Replaceall(tm,"$target", lname); + Replaceall(tm,"$source", name); + Replaceall(tm,"$input", name); + + if (Getattr(p,"wrap:disown") || (Getattr(p,"tmap:in:disown"))) { + Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm,"$disown","0"); + } + + if(funcptr_name) { + /* have us a function pointer */ + Printf(f->code, "if(TYPEOF(%s) != CLOSXP) {\n", name); + Replaceall(tm,"$R_class", ""); + } else { + replaceRClass(tm, Getattr(p, "type")); + } + + + Printf(f->code,"%s\n",tm); + if(funcptr_name) + Printf(f->code, "} else {\n%s = %s;\nR_SWIG_pushCallbackFunctionData(%s, NULL);\n}\n", + lname, funcptr_name, name); + Printv(f->def, inFirstArg ? "" : ", ", "SEXP ", name, NIL); + if (Len(name) != 0) + inFirstArg = false; + p = Getattr(p,"tmap:in:next"); + + } else { + p = nextSibling(p); + } + + + tm = Swig_typemap_lookup("rtype", curP, "", 0); + if(tm) { + replaceRClass(tm, Getattr(curP, "type")); + } + Printf(s_inputTypes, "%s'%s'", inFirstType ? "" : ", ", tm); + Printf(s_inputMap, "%s%s='%s'", inFirstType ? "" : ", ", name, tm); + inFirstType = false; + + if(funcptr_name) + Delete(funcptr_name); + } /* end of looping over parameters. */ + + if(addCopyParam) { + Printf(sfun->def, "%s.copy = FALSE", nargs > 0 ? ", " : ""); + Printf(f->def, "%sSEXP s_swig_copy", nargs > 0 ? ", " : ""); + + Printf(sargs, "as.logical(.copy), "); + } + + Printv(f->def, ")\n{\n", NIL); + Printv(sfun->def, ")\n{\n", NIL); + + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + if (tm && (Len(tm) != 0)) { + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + String *outargs = NewString(""); + int numOutArgs = isVoidReturnType ? -1 : 0; + for(p = l, i = 0; p; i++) { + if((tm = Getattr(p, "tmap:argout"))) { + // String *lname = Getattr(p, "lname"); + numOutArgs++; + String *pos = NewStringf("%d", numOutArgs); + Replaceall(tm,"$source", Getattr(p, "lname")); + Replaceall(tm,"$result", "r_ans"); + Replaceall(tm,"$n", pos); // The position into which to store the answer. + Replaceall(tm,"$arg", Getattr(p, "emit:input")); + Replaceall(tm,"$input", Getattr(p, "emit:input")); + Replaceall(tm,"$owner", "0"); + + + Printf(outargs, "%s\n", tm); + p = Getattr(p,"tmap:argout:next"); + } else + p = nextSibling(p); + } + + String *actioncode = emit_action(n); + + /* Deal with the explicit return value. */ + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + SwigType *retType = Getattr(n, "type"); + + Replaceall(tm,"$1", Swig_cresult_name()); + Replaceall(tm,"$result", "r_ans"); + if (debugMode){ + Printf(stdout, "Calling replace D: %s, %s, %s\n", retType, n, tm); + } + replaceRClass(tm, retType); + + if (GetFlag(n,"feature:new")) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm,"$owner", "0"); + } + + Printf(f->code, "%s\n", tm); + + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, + "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), fname); + } + + + if(Len(outargs)) { + Wrapper_add_local(f, "R_OutputValues", "SEXP R_OutputValues"); + + String *tmp = NewString(""); + if(!isVoidReturnType) + Printf(tmp, "Rf_protect(r_ans);\n"); + + Printf(tmp, "Rf_protect(R_OutputValues = Rf_allocVector(VECSXP,%d));\nr_nprotect += %d;\n", + numOutArgs + !isVoidReturnType, + isVoidReturnType ? 1 : 2); + + if(!isVoidReturnType) + Printf(tmp, "SET_VECTOR_ELT(R_OutputValues, 0, r_ans);\n"); + Printf(tmp, "r_ans = R_OutputValues;\n"); + + Insert(outargs, 0, tmp); + Delete(tmp); + + + + Printv(f->code, outargs, NIL); + Delete(outargs); + + } + + /* Output cleanup code */ + int need_cleanup = Len(cleanup) != 0; + if (need_cleanup) { + 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))) { + Replaceall(tm, "$source", Swig_cresult_name()); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printv(f->code, UnProtectWrapupCode, NIL); + + /*If the user gave us something to convert the result in */ + if ((tm = Swig_typemap_lookup("scoerceout", n, Swig_cresult_name(), sfun))) { + Replaceall(tm,"$source","ans"); + Replaceall(tm,"$result","ans"); + if (constructor) { + Node * parent = Getattr(n, "parentNode"); + String * smartname = Getattr(parent, "feature:smartptr"); + if (smartname) { + smartname = getRClassName(smartname, 1, 1); + Replaceall(tm, "$R_class", smartname); + Delete(smartname); + } + } + if (debugMode) { + Printf(stdout, "Calling replace B: %s, %s, %s\n", Getattr(n, "type"), Getattr(n, "sym:name"), getNSpace()); + } + replaceRClass(tm, Getattr(n, "type")); + Chop(tm); + } + + + Printv(sfun->code, ";", (Len(tm) ? "ans = " : ""), ".Call('", wname, + "', ", sargs, "PACKAGE='", Rpackage, "');\n", NIL); + if(Len(tm)) + { + Printf(sfun->code, "%s\n\n", tm); + if (constructor) + { + String *finalizer = NewString(iname); + Replace(finalizer, "new_", "", DOH_REPLACE_FIRST); + Printf(sfun->code, "reg.finalizer(ans@ref, delete_%s);\n", finalizer); + } + Printf(sfun->code, "ans\n"); + } + + if (destructor) + Printv(f->code, "R_ClearExternalPtr(self);\n", NIL); + + Printv(f->code, "return r_ans;\n", NIL); + + /* Error handling code */ + Printv(f->code, "fail: SWIGUNUSED;\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, " Rf_error(\"%s %s\", SWIG_ErrorType(SWIG_lasterror_code), SWIG_lasterror_msg);\n", NIL); + Printv(f->code, " return R_NilValue;\n", NIL); + Delete(cleanup); + + Printv(f->code, "}\n", NIL); + Printv(sfun->code, "\n}", NIL); + + /* Substitute the function name */ + Replaceall(f->code,"$symname",iname); + + Wrapper_print(f, f_wrapper); + Wrapper_print(sfun, sfile); + + Printf(sfun->code, "\n# End of %s\n", iname); + tm = Swig_typemap_lookup("rtype", n, "", 0); + if(tm) { + SwigType *retType = Getattr(n, "type"); + if (debugMode) { + Printf(stdout, "Calling replace C: %s\n", Copy(retType)); + } + replaceRClass(tm, retType); + } + + Printv(sfile, "attr(`", sfname, "`, 'returnType') = '", + isVoidReturnType ? "void" : (tm ? tm : ""), + "'\n", NIL); + + if(nargs > 0) + Printv(sfile, "attr(`", sfname, "`, \"inputTypes\") = c(", + s_inputTypes, ")\n", NIL); + Printv(sfile, "class(`", sfname, "`) = c(\"SWIGFunction\", class('", + sfname, "'))\n\n", NIL); + + if (memoryProfile) { + Printv(sfile, "memory.profile()\n", NIL); + } + if (aggressiveGc) { + Printv(sfile, "gc()\n", NIL); + } + + // Printv(sfile, "setMethod('", name, "', '", name, "', ", iname, ")\n\n\n"); + + + + /* If we are dealing with a method in an C++ class, then + add the name of the R function and its definition. + XXX need to figure out how to store the Wrapper if possible in the hash/list. + Would like to be able to do this so that we can potentially insert + */ + if(processing_member_access_function || processing_class_member_function) { + String *method_type = R_MEMBER_NORMAL; + if (GetFlag(n, "memberset")) { + method_type = R_MEMBER_SET; + } else if (GetFlag(n, "memberget")) { + method_type = R_MEMBER_GET; + } + addAccessor(member_name, sfun, iname, method_type); + } + + if (Getattr(n, "sym:overloaded") && + !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + addRegistrationRoutine(wname, addCopyParam ? nargs +1 : nargs); + + DelWrapper(f); + DelWrapper(sfun); + + Delete(sargs); + Delete(sfname); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * R::constantWrapper() + * ---------------------------------------------------------------------- */ + +int R::constantWrapper(Node *n) { + (void) n; + // TODO + return SWIG_OK; +} + +/*-------------------------------------------------------------- + * Add the specified routine name to the collection of + * generated routines that are called from R functions. + * This is used to register the routines with R for + * resolving symbols. + + * rname - the name of the routine + * nargs - the number of arguments it expects. + * --------------------------------------------------------------*/ + +int R::addRegistrationRoutine(String *rname, int nargs) { + if(!registrationTable) + registrationTable = NewHash(); + + String *el = + NewStringf("{\"%s\", (DL_FUNC) &%s, %d}", rname, rname, nargs); + + Setattr(registrationTable, rname, el); + + return SWIG_OK; +} + +/* ------------------------------------------------------------- + * Write the registration information to an array and + * create the initialization routine for registering + * these. + * --------------------------------------------------------------*/ + +int R::outputRegistrationRoutines(File *out) { + int i, n; + if(!registrationTable) + return(0); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + + Printf(out, "#include <R_ext/Rdynload.h>\n\n"); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\n}\n#endif\n\n"); + + Printf(out, "SWIGINTERN R_CallMethodDef CallEntries[] = {\n"); + + List *keys = Keys(registrationTable); + n = Len(keys); + for(i = 0; i < n; i++) + Printf(out, " %s,\n", Getattr(registrationTable, Getitem(keys, i))); + + Printf(out, " {NULL, NULL, 0}\n};\n\n"); + + if(!noInitializationCode) { + if (inCPlusMode) + Printv(out, "extern \"C\" ", NIL); + { /* R allows pckage names to have '.' in the name, which is not allowed in C++ var names + we simply replace all occurrences of '.' with '_' to construct the var name */ + String * Rpackage_sane = Copy(Rpackage); + Replace(Rpackage_sane, ".", "_", DOH_REPLACE_ANY); + Printf(out, "SWIGEXPORT void R_init_%s(DllInfo *dll) {\n", Rpackage_sane); + Delete(Rpackage_sane); + } + Printf(out, "%sR_registerRoutines(dll, NULL, CallEntries, NULL, NULL);\n", tab4); + if(Len(s_init_routine)) { + Printf(out, "\n%s\n", s_init_routine); + } + Printf(out, "}\n"); + } + + return n; +} + + + +/* ------------------------------------------------------------- + * Process a struct, union or class declaration in the source code, + * or an anonymous typedef struct + * --------------------------------------------------------------*/ + +//XXX What do we need to do here - +// Define an S4 class to refer to this. + +void R::registerClass(Node *n) { + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + String *sname = NewStringf("_p%s", SwigType_manglestr(name)); + if(!Getattr(SClassDefs, sname)) { + Setattr(SClassDefs, sname, sname); + String *base; + + if(Strcmp(kind, "class") == 0) { + base = NewString(""); + List *l = Getattr(n, "bases"); + if(Len(l)) { + Printf(base, "c("); + for(int i = 0; i < Len(l); i++) { + registerClass(Getitem(l, i)); + Printf(base, "'_p%s'%s", + SwigType_manglestr(Getattr(Getitem(l, i), "name")), + i < Len(l)-1 ? ", " : ""); + } + Printf(base, ")"); + } else { + base = NewString("'C++Reference'"); + } + } else + base = NewString("'ExternalReference'"); + + Printf(s_classes, "setClass('%s', contains = %s)\n", sname, base); + Delete(base); + String *smartptr = Getattr(n, "feature:smartptr"); + if (smartptr) { + List *l = Getattr(n, "bases"); + SwigType *spt = Swig_cparse_type(smartptr); + String *smart = SwigType_typedef_resolve_all(spt); + String *smart_rname = SwigType_manglestr(smart); + Printf(s_classes, "setClass('_p%s', contains = c('%s'", smart_rname, sname); + Delete(spt); + Delete(smart); + Delete(smart_rname); + for(int i = 0; i < Len(l); i++) { + Node * b = Getitem(l, i); + smartptr = Getattr(b, "feature:smartptr"); + if (smartptr) { + spt = Swig_cparse_type(smartptr); + smart = SwigType_typedef_resolve_all(spt); + smart_rname = SwigType_manglestr(smart); + Printf(s_classes, ", '_p%s'", smart_rname); + Delete(spt); + Delete(smart); + Delete(smart_rname); + } + } + Printf(s_classes, "))\n"); + } + } +} + +int R::classDeclaration(Node *n) { + + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + registerClass(n); + + + /* If we have a typedef union { ... } U, then we never get to see the typedef + via a regular call to typedefHandler. Instead, */ + if(Getattr(n, "unnamed") && Getattr(n, "storage") && Strcmp(Getattr(n, "storage"), "typedef") == 0 + && Getattr(n, "tdname") && Strcmp(Getattr(n, "tdname"), name) == 0) { + if (debugMode) + Printf(stdout, "Typedef in the class declaration for %s\n", name); + // typedefHandler(n); + } + + bool opaque = GetFlag(n, "feature:opaque") ? true : false; + + if(opaque) + opaqueClassDeclaration = name; + + int status = Language::classDeclaration(n); + + opaqueClassDeclaration = NULL; + + + if (class_member_function_types) { + + // collect the "set" methods + List *class_set_membernames = filterMemberList(class_member_function_types, + class_member_function_membernames, R_MEMBER_SET, true); + List *class_set_functionnames = filterMemberList(class_member_function_types, + class_member_function_names, R_MEMBER_SET, true); + // this one isn't used - collecting to keep code simpler + List *class_set_functiontypes = filterMemberList(class_member_function_types, + class_member_function_types, R_MEMBER_SET, true); + + // collect the others + List *class_other_membernames = filterMemberList(class_member_function_types, + class_member_function_membernames, R_MEMBER_SET, false); + List *class_other_functionnames = filterMemberList(class_member_function_types, + class_member_function_names, R_MEMBER_SET, false); + List *class_other_functiontypes = filterMemberList(class_member_function_types, + class_member_function_types, R_MEMBER_SET, false); + + if (Len(class_other_membernames) > 0) { + OutputMemberReferenceMethod(name, 0, class_other_membernames, class_other_functionnames, class_other_functiontypes, sfile); + } + if (Len(class_set_membernames) > 0) { + OutputMemberReferenceMethod(name, 1, class_set_membernames, class_set_functionnames, class_set_functiontypes, sfile); + } + Delete(class_set_membernames); + Delete(class_set_functionnames); + Delete(class_set_functiontypes); + Delete(class_other_membernames); + Delete(class_other_functionnames); + Delete(class_other_functiontypes); + } + + if (class_member_function_types) { + Delete(class_member_function_types); + class_member_function_types = NULL; + Delete(class_member_function_names); + class_member_function_names = NULL; + Delete(class_member_function_membernames); + class_member_function_membernames = NULL; + Delete(class_member_function_wrappernames); + class_member_function_wrappernames = NULL; + } + if (Getattr(n, "has_destructor")) { + Printf(sfile, "setMethod('delete', '_p%s', function(obj) {delete%s(obj)})\n", getRClassName(name), getRClassName(name)); + + } + if(!opaque && !Strcmp(kind, "struct") && copyStruct) { + + String *def = + NewStringf("setClass(\"%s\",\n%srepresentation(\n", name, tab4); + bool firstItem = true; + + for(Node *c = firstChild(n); c; ) { + String *elName; + String *tp; + + elName = Getattr(c, "name"); + + String *elKind = Getattr(c, "kind"); + if (!Equal(elKind, "variable")) { + c = nextSibling(c); + continue; + } + if (!Len(elName)) { + c = nextSibling(c); + continue; + } + tp = Swig_typemap_lookup("rtype", c, "", 0); + if(!tp) { + c = nextSibling(c); + continue; + } + if (Strstr(tp, "R_class")) { + c = nextSibling(c); + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + c = nextSibling(c); + continue; + } + + if (!firstItem) { + Printf(def, ",\n"); + } + // else + //XXX How can we tell if this is already done. + // SwigType_push(elType, elDecl); + + + // returns "" tp = processType(elType, c, NULL); + // Printf(stdout, "<classDeclaration> elType %p\n", elType); + // tp = getRClassNameCopyStruct(Getattr(c, "type"), 1); + + String *elNameT = replaceInitialDash(elName); + Printf(def, "%s%s = \"%s\"", tab8, elNameT, tp); + firstItem = false; + Delete(tp); + Delete(elNameT); + c = nextSibling(c); + } + Printf(def, "),\n%scontains = \"RSWIGStruct\")\n", tab8); + Printf(s_classes, "%s\n\n# End class %s\n\n", def, name); + + generateCopyRoutines(n); + + Delete(def); + } + + return status; +} + + + +/* ------------------------------------------------------------- + * Create the C routines that copy an S object of the class given + * by the given struct definition in Node *n to the C value + * and also the routine that goes from the C routine to an object + * of this S class. + * --------------------------------------------------------------*/ + +/*XXX + Clean up the toCRef - make certain the names are correct for the types, etc. + in all cases. +*/ + +int R::generateCopyRoutines(Node *n) { + Wrapper *copyToR = NewWrapper(); + Wrapper *copyToC = NewWrapper(); + + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *kind = Getattr(n, "kind"); + String *type; + + if(Len(tdname)) { + type = Copy(tdname); + } else { + type = NewStringf("%s %s", kind, name); + } + + String *mangledName = SwigType_manglestr(name); + + if (debugMode) + Printf(stdout, "generateCopyRoutines: name = %s, %s\n", name, type); + + Printf(copyToR->def, "CopyToR%s = function(value, obj = new(\"%s\"))\n{\n", + mangledName, name); + Printf(copyToC->def, "CopyToC%s = function(value, obj)\n{\n", + mangledName); + + Node *c = firstChild(n); + + for(; c; c = nextSibling(c)) { + String *elName = Getattr(c, "name"); + if (!Len(elName)) { + continue; + } + String *elKind = Getattr(c, "kind"); + if (!Equal(elKind, "variable")) { + continue; + } + + String *tp = Swig_typemap_lookup("rtype", c, "", 0); + if(!tp) { + continue; + } + if (Strstr(tp, "R_class")) { + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + continue; + } + + + /* The S functions to get and set the member value. */ + String *elNameT = replaceInitialDash(elName); + Printf(copyToR->code, "obj@%s = value$%s;\n", elNameT, elNameT); + Printf(copyToC->code, "obj$%s = value@%s;\n", elNameT, elNameT); + Delete(elNameT); + } + Printf(copyToR->code, "obj;\n}\n\n"); + String *rclassName = getRClassNameCopyStruct(type, 0); // without the Ref. + Printf(sfile, "# Start definition of copy functions & methods for %s\n", rclassName); + + Wrapper_print(copyToR, sfile); + Printf(copyToC->code, "obj\n}\n\n"); + Wrapper_print(copyToC, sfile); + + + Printf(sfile, "# Start definition of copy methods for %s\n", rclassName); + Printf(sfile, "setMethod('copyToR', '_p_%s', CopyToR%s);\n", rclassName, + mangledName); + Printf(sfile, "setMethod('copyToC', '%s', CopyToC%s);\n\n", rclassName, + mangledName); + + Printf(sfile, "# End definition of copy methods for %s\n", rclassName); + Printf(sfile, "# End definition of copy functions & methods for %s\n", rclassName); + + String *m = NewStringf("%sCopyToR", name); + addNamespaceMethod(m); + char *tt = Char(m); tt[Len(m)-1] = 'C'; + addNamespaceMethod(m); + Delete(m); + Delete(rclassName); + Delete(mangledName); + DelWrapper(copyToR); + DelWrapper(copyToC); + + return SWIG_OK; +} + + + +/* ------------------------------------------------------------- + * Called when there is a typedef to be invoked. + * + * XXX Needs to be enhanced or split to handle the case where we have a + * typedef within a classDeclaration emission because the struct/union/etc. + * is anonymous. + * --------------------------------------------------------------*/ + +int R::typedefHandler(Node *n) { + SwigType *tp = Getattr(n, "type"); + String *type = Getattr(n, "type"); + if (debugMode) + Printf(stdout, "<typedefHandler> %s\n", Getattr(n, "name")); + + processType(tp, n); + + if(Strncmp(type, "struct ", 7) == 0) { + String *name = Getattr(n, "name"); + char *trueName = Char(type); + trueName += 7; + if (debugMode) + Printf(stdout, "<typedefHandler> Defining S class %s\n", trueName); + Printf(s_classes, "setClass('_p%s', contains = 'ExternalReference')\n", + SwigType_manglestr(name)); + } + + return Language::typedefHandler(n); +} + + + +/* -------------------------------------------------------------- + * Called when processing a field in a "class", i.e. struct, union or + * actual class. We set a state variable so that we can correctly + * interpret the resulting functionWrapper() call and understand that + * it is for a field element. + * --------------------------------------------------------------*/ + +int R::membervariableHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + processType(t, n, NULL); + processing_member_access_function = 1; + member_name = Getattr(n,"sym:name"); + if (debugMode) + Printf(stdout, "<membervariableHandler> name = %s, sym:name = %s\n", + Getattr(n, "name"), member_name); + + int status(Language::membervariableHandler(n)); + + if(!opaqueClassDeclaration && debugMode) + Printf(stdout, "<membervariableHandler> %s %s\n", Getattr(n, "name"), Getattr(n, "type")); + + processing_member_access_function = 0; + member_name = NULL; + + return status; +} + + +/* + This doesn't seem to get used so leave it out for the moment. +*/ +String * R::runtimeCode() { + String *s = Swig_include_sys("rrun.swg"); + if (!s) { + Printf(stdout, "*** Unable to open 'rrun.swg'\n"); + s = NewString(""); + } + return s; +} + + +/* ----------------------------------------------------------------------- + * Called when SWIG wants to initialize this + * We initialize anythin we want here. + * Most importantly, tell SWIG where to find the files (e.g. r.swg) for this module. + * Use Swig_mark_arg() to tell SWIG that it is understood and not to + * throw an error. + * --------------------------------------------------------------*/ + +void R::main(int argc, char *argv[]) { + init(); + Preprocessor_define("SWIGR 1", 0); + SWIG_library_directory("r"); + SWIG_config_file("r.swg"); + debugMode = false; + copyStruct = true; + memoryProfile = false; + aggressiveGc = false; + inCPlusMode = false; + outputNamespaceInfo = false; + noInitializationCode = false; + + this->Argc = argc; + this->Argv = argv; + + allow_overloading();// can we support this? + + for(int i = 0; i < argc; i++) { + if(strcmp(argv[i], "-package") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + Rpackage = argv[i]; + } else if(strcmp(argv[i], "-dll") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + DllName = argv[i]; + } else if(strcmp(argv[i], "-help") == 0) { + showUsage(); + } else if(strcmp(argv[i], "-namespace") == 0) { + outputNamespaceInfo = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-no-init-code")) { + noInitializationCode = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-c++")) { + inCPlusMode = true; + Swig_mark_arg(i); + Printf(s_classes, "setClass('C++Reference', contains = 'ExternalReference')\n"); + } else if(!strcmp(argv[i], "-debug")) { + debugMode = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-copystruct")) { + copyStruct = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocopystruct")) { + copyStruct = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-memoryprof")) { + memoryProfile = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nomemoryprof")) { + memoryProfile = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-aggressivegc")) { + aggressiveGc = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-noaggressivegc")) { + aggressiveGc = false; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); + } + + if (debugMode) { + Swig_typemap_search_debug_set(); + Swig_typemap_used_debug_set(); + Swig_typemap_register_debug_set(); + Swig_file_debug_set(); + } + /// copyToR copyToC functions. + + } +} + +/* ----------------------------------------------------------------------- + * Could make this work for String or File and then just store the resulting string + * rather than the collection of arguments and argc. + * ----------------------------------------------------------------------- */ +int R::outputCommandLineArguments(File *out) +{ + if(Argc < 1 || !Argv || !Argv[0]) + return(-1); + + Printf(out, "\n## Generated via the command line invocation:\n##\t"); + for(int i = 0; i < Argc ; i++) { + Printf(out, " %s", Argv[i]); + } + Printf(out, "\n\n\n"); + + return Argc; +} + + + +/* How SWIG instantiates an object from this module. + See swigmain.cxx */ +extern "C" +Language *swig_r(void) { + return new R(); +} + + + + +/* ----------------------------------------------------------------------- + * Needs to be reworked. + *----------------------------------------------------------------------- */ +String * R::processType(SwigType *t, Node *n, int *nargs) { + //XXX Need to handle typedefs, e.g. + // a type which is a typedef to a function pointer. + + SwigType *tmp = Getattr(n, "tdname"); + if (debugMode) + Printf(stdout, "processType %s (tdname = %s)(SwigType = %s)\n", Getattr(n, "name"), tmp, Copy(t)); + + SwigType *td = t; + if (expandTypedef(t) && + SwigType_istypedef(t)) { + SwigType *resolved = + SwigType_typedef_resolve_all(t); + if (expandTypedef(resolved)) { + td = Copy(resolved); + } + } + + if(!td) { + int count = 0; + String *b = getRTypeName(t, &count); + if(count && b && !Getattr(SClassDefs, b)) { + if (debugMode) + Printf(stdout, "<processType> Defining class %s\n", b); + + Printf(s_classes, "setClass('%s', contains = 'ExternalReference')\n", b); + Setattr(SClassDefs, b, b); + } + + } + + + if(td) + t = td; + + if(SwigType_isfunctionpointer(t)) { + if (debugMode) + Printf(stdout, + "<processType> Defining pointer handler %s\n", t); + + String *tmp = createFunctionPointerHandler(t, n, nargs); + return tmp; + } + + return NULL; +} + + +/* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in from R when + * setting up an enum variable + * ------------------------------------------------------------------------ */ + +String *R::enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *newsymname = 0; + + Node *parent = parentNode(n); + symname = Getattr(n, "sym:name"); + + // parent enumtype has namespace mangled in + String *etype = Getattr(parent, "enumtype"); + // we have to directly call the c wrapper function, as the + // R wrapper to the enum is designed to be used after the enum + // structures have been created on the R side. This means + // that we'll need to construct a .Call expression + + // change the type for variableWrapper + if (debugMode) { + Printf(stdout, "<enumValue> type set: %s\n", etype); + } + + Setattr(n, "type", etype); + + if (!getCurrentClass()) { + newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); + Setattr(n, "sym:name", newsymname); + variableWrapper(n); + value = Swig_name_get(NSPACE_TODO, newsymname); + } else { + String *enumClassPrefix = getEnumClassPrefix(); + newsymname = Swig_name_member(0, enumClassPrefix, symname); + Setattr(n, "name", Getattr(n, "value")); + Setattr(n, "sym:name", newsymname); + variableWrapper(n); + value = Swig_name_get(NSPACE_TODO, newsymname); + } + value = Swig_name_wrapper(value); + Replace(value, "_wrap", "R_swig", DOH_REPLACE_FIRST); + + String *valuecall=NewString(""); + Printv(valuecall, ".Call('", value, "',FALSE, PACKAGE='", Rpackage, "')", NIL); + Delete(value); + return valuecall; +} diff --git a/contrib/tools/swig/Source/Modules/ruby.cxx b/contrib/tools/swig/Source/Modules/ruby.cxx new file mode 100644 index 00000000000..48b0efab36c --- /dev/null +++ b/contrib/tools/swig/Source/Modules/ruby.cxx @@ -0,0 +1,3511 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * ruby.cxx + * + * Ruby language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> +#include <string.h> +#include <limits.h> /* for INT_MAX */ + +#define SWIG_PROTECTED_TARGET_METHODS 1 + +class RClass { +private: + String *temp; + +public: + String *name; /* class name (renamed) */ + String *cname; /* original C class/struct name */ + String *mname; /* Mangled name */ + + /** + * The C variable name used in the SWIG-generated wrapper code to refer to + * this class; usually it is of the form "SwigClassXXX.klass", where SwigClassXXX + * is a swig_class struct instance and klass is a member of that struct. + */ + String *vname; + + /** + * The C variable name used in the SWIG-generated wrapper code to refer to + * the module that implements this class's methods (when we're trying to + * support C++ multiple inheritance). Usually it is of the form + * "SwigClassClassName.mImpl", where SwigClassXXX is a swig_class struct instance + * and mImpl is a member of that struct. + */ + String *mImpl; + + String *type; + String *prefix; + String *init; + + + int constructor_defined; + int destructor_defined; + + RClass() { + temp = NewString(""); + name = NewString(""); + cname = NewString(""); + mname = NewString(""); + vname = NewString(""); + mImpl = NewString(""); + type = NewString(""); + prefix = NewString(""); + init = NewString(""); + constructor_defined = 0; + destructor_defined = 0; + } + + ~RClass() { + Delete(name); + Delete(cname); + Delete(vname); + Delete(mImpl); + Delete(mname); + Delete(type); + Delete(prefix); + Delete(init); + Delete(temp); + } + + void set_name(const_String_or_char_ptr cn, const_String_or_char_ptr rn, const_String_or_char_ptr valn) { + /* Original C/C++ class (or struct) name */ + Clear(cname); + Append(cname, cn); + + /* Mangled name */ + Delete(mname); + mname = Swig_name_mangle(cname); + + /* Renamed class name */ + Clear(name); + Append(name, valn); + + /* Variable name for the VALUE that refers to the Ruby Class object */ + Clear(vname); + Printf(vname, "SwigClass%s.klass", name); + + /* Variable name for the VALUE that refers to the Ruby Class object */ + Clear(mImpl); + Printf(mImpl, "SwigClass%s.mImpl", name); + + /* Prefix */ + Clear(prefix); + Printv(prefix, (rn ? rn : cn), "_", NIL); + } + + char *strip(const_String_or_char_ptr s) { + Clear(temp); + Append(temp, s); + if (Strncmp(s, prefix, Len(prefix)) == 0) { + Replaceall(temp, prefix, ""); + } + return Char(temp); + } +}; + + +/* flags for the make_autodoc function */ +enum autodoc_t { + AUTODOC_CLASS, + AUTODOC_CTOR, + AUTODOC_DTOR, + AUTODOC_STATICFUNC, + AUTODOC_FUNC, + AUTODOC_METHOD, + AUTODOC_GETTER, + AUTODOC_SETTER, + AUTODOC_NONE +}; + +static const char *usage = "\ +Ruby Options (available with -ruby)\n\ + -autorename - Enable renaming of classes and methods to follow Ruby coding standards\n\ + -globalmodule - Wrap everything into the global module\n\ + -initname <name>- Set entry function to Init_<name> (used by `require')\n\ + -minherit - Attempt to support multiple inheritance\n\ + -noautorename - Disable renaming of classes and methods (default)\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ +"; + + +#define RCLASS(hash, name) (RClass*)(Getattr(hash, name) ? Data(Getattr(hash, name)) : 0) +#define SET_RCLASS(hash, name, klass) Setattr(hash, name, NewVoid(klass, 0)) + + +class RUBY:public Language { +private: + + String *module; + String *modvar; + String *feature; + String *prefix; + int current; + Hash *classes; /* key=cname val=RClass */ + RClass *klass; /* Currently processing class */ + Hash *special_methods; /* Python style special method name table */ + + File *f_directors; + File *f_directors_h; + File *f_directors_helpers; + File *f_begin; + File *f_runtime; + File *f_runtime_h; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + + bool useGlobalModule; + bool multipleInheritance; + + // Wrap modes + enum WrapperMode { + NO_CPP, + MEMBER_FUNC, + CONSTRUCTOR_ALLOCATE, + CONSTRUCTOR_INITIALIZE, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }; + + /* ------------------------------------------------------------ + * autodoc level declarations + * ------------------------------------------------------------ */ + + enum autodoc_l { + NO_AUTODOC = -2, // no autodoc + STRING_AUTODOC = -1, // use provided string + NAMES_AUTODOC = 0, // only parameter names + TYPES_AUTODOC = 1, // parameter names and types + EXTEND_AUTODOC = 2, // extended documentation and parameter names + EXTEND_TYPES_AUTODOC = 3 // extended documentation and parameter types + names + }; + + autodoc_t last_mode; + String* last_autodoc; + + autodoc_l autodoc_level(String *autodoc) { + autodoc_l dlevel = NO_AUTODOC; + char *c = Char(autodoc); + if (c) { + if (isdigit(c[0])) { + dlevel = (autodoc_l) atoi(c); + } else { + if (strcmp(c, "extended") == 0) { + dlevel = EXTEND_AUTODOC; + } else { + dlevel = STRING_AUTODOC; + } + } + } + return dlevel; + } + + + + /* ------------------------------------------------------------ + * have_docstring() + * Check if there is a docstring directive and it has text, + * or there is an autodoc flag set + * ------------------------------------------------------------ */ + + bool have_docstring(Node *n) { + String *str = Getattr(n, "feature:docstring"); + return (str && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + } + + /* ------------------------------------------------------------ + * docstring() + * Get the docstring text, stripping off {} if necessary, + * and enclose in triple double quotes. If autodoc is also + * set then it will build a combined docstring. + * ------------------------------------------------------------ */ + + String *docstring(Node *n, autodoc_t ad_type) { + + String *str = Getattr(n, "feature:docstring"); + bool have_ds = (str && Len(str) > 0); + bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + String *autodoc = NULL; + String *doc = NULL; + + if (have_ds) { + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + } + + if (have_auto) { + autodoc = make_autodoc(n, ad_type); + have_auto = (autodoc && Len(autodoc) > 0); + } + + if (have_auto || have_ds) + doc = NewString("/*"); + + if (have_auto && have_ds) { // Both autodoc and docstring are present + Printv(doc, "\n", autodoc, "\n", str, "\n", NIL); + } else if (!have_auto && have_ds) { // only docstring + Printv(doc, str, NIL); + } else if (have_auto && !have_ds) { // only autodoc + Printv(doc, "\n", autodoc, "\n", NIL); + } else { + doc = NewString(""); + } + + if (have_auto || have_ds) + Append(doc, "*/\n"); + + // Save the generated strings in the parse tree in case they are used later + // by post processing tools + Setattr(n, "ruby:docstring", doc); + Setattr(n, "ruby:autodoc", autodoc); + return doc; + } + + /* ----------------------------------------------------------------------------- + * addMissingParameterNames() + * For functions that have not had nameless parameters set in the Language class. + * + * Inputs: + * plist - entire parameter list + * arg_offset - argument number for first parameter + * Side effects: + * The "lname" attribute in each parameter in plist will be contain a parameter name + * ----------------------------------------------------------------------------- */ + + void addMissingParameterNames(Node* n, ParmList *plist, int arg_offset) { + Parm *p = plist; + int i = arg_offset; + while (p) { + if (!Getattr(p, "lname")) { + String *name = makeParameterName(n, p, i); + Setattr(p, "lname", name); + Delete(name); + } + i++; + p = nextSibling(p); + } + } + + /* ------------------------------------------------------------ + * make_autodocParmList() + * Generate the documentation for the function parameters + * ------------------------------------------------------------ */ + + String *make_autodocParmList(Node *n, bool showTypes) { + String *doc = NewString(""); + String *pdocs = 0; + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + int lines = 0; + int arg_num = is_wrapping_class() ? 1 : 0; + const int maxwidth = 80; + + addMissingParameterNames(n, plist, arg_num); // for $1_name substitutions done in Swig_typemap_attach_parms + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + if (Strcmp(ParmList_protostr(plist), "void") == 0) { + //No parameters actually + return doc; + } + + for (p = plist; p; p = pnext, arg_num++) { + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + + String *name = 0; + String *type = 0; + String *value = 0; + String *pdoc = Getattr(p, "tmap:doc"); + if (pdoc) { + name = Getattr(p, "tmap:doc:name"); + type = Getattr(p, "tmap:doc:type"); + value = Getattr(p, "tmap:doc:value"); + } + + // Note: the generated name should be consistent with that in kwnames[] + String *made_name = 0; + if (!name) { + name = made_name = makeParameterName(n, p, arg_num); + } + + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + if (SwigType_isvarargs(type)) + break; + + // Skip the 'self' parameter which in ruby is implicit + if ( Cmp(name, "self") == 0 ) + continue; + + // Make __p parameters just p (as used in STL) + Replace( name, "__", "", DOH_REPLACE_FIRST ); + + if (Len(doc)) { + // add a comma to the previous one if any + Append(doc, ", "); + + // Do we need to wrap a long line? + if ((Len(doc) - lines * maxwidth) > maxwidth) { + Printf(doc, "\n%s", tab4); + lines += 1; + } + } + + // Do the param type too? + Node *nn = classLookup(Getattr(p, "type")); + String *type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); + if (showTypes) + Printf(doc, "%s ", type_str); + + Append(doc, name); + if (pdoc) { + if (!pdocs) + pdocs = NewString("Parameters:\n"); + Printf(pdocs, " %s.\n", pdoc); + } + + if (value) { + String *new_value = convertValue(value, Getattr(p, "type")); + if (new_value) { + value = new_value; + } else { + Node *lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(doc, "=%s", value); + } + Delete(type_str); + Delete(made_name); + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + return doc; + } + + /* ------------------------------------------------------------ + * make_autodoc() + * Build a docstring for the node, using parameter and other + * info in the parse tree. If the value of the autodoc + * attribute is "0" then do not include parameter types, if + * it is "1" (the default) then do. If it has some other + * value then assume it is supplied by the extension writer + * and use it directly. + * ------------------------------------------------------------ */ + + String *make_autodoc(Node *n, autodoc_t ad_type) { + int extended = 0; + // If the function is overloaded then this function is called + // for the last one. Rewind to the first so the docstrings are + // in order. + while (Getattr(n, "sym:previousSibling")) + n = Getattr(n, "sym:previousSibling"); + + Node *pn = Swig_methodclass(n); + String* super_names = NewString(""); + String* class_name = Getattr(pn, "sym:name") ; + + if ( !class_name ) { + class_name = NewString(""); + } else { + class_name = Copy(class_name); + List *baselist = Getattr(pn, "bases"); + if (baselist && Len(baselist)) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + + int count = 0; + for ( ;base.item; ++count) { + if ( count ) Append(super_names, ", "); + String *basename = Getattr(base.item, "sym:name"); + + String* basenamestr = NewString(basename); + Node* parent = parentNode(base.item); + while (parent) + { + String *parent_name = Copy( Getattr(parent, "sym:name") ); + if ( !parent_name ) { + Node* mod = Getattr(parent, "module"); + if ( mod ) + parent_name = Copy( Getattr(mod, "name") ); + if ( parent_name ) + (Char(parent_name))[0] = (char)toupper((Char(parent_name))[0]); + } + if ( parent_name ) { + Insert(basenamestr, 0, "::"); + Insert(basenamestr, 0, parent_name); + Delete(parent_name); + } + parent = parentNode(parent); + } + + Append(super_names, basenamestr ); + Delete(basenamestr); + base = Next(base); + } + } + } + String* full_name; + if ( module ) { + full_name = NewString(module); + if (Len(class_name) > 0) + Append(full_name, "::"); + } + else + full_name = NewString(""); + Append(full_name, class_name); + + String* symname = Getattr(n, "sym:name"); + if ( Getattr( special_methods, symname ) ) + symname = Getattr( special_methods, symname ); + + String* methodName = NewString(full_name); + Append(methodName, symname); + + + // Each overloaded function will try to get documented, + // so we keep the name of the last overloaded function and its type. + // Documenting just from functionWrapper() is not possible as + // sym:name has already been changed to include the class name + if ( last_mode == ad_type && Cmp(methodName, last_autodoc) == 0 ) { + Delete(full_name); + Delete(class_name); + Delete(super_names); + Delete(methodName); + return NewString(""); + } + + + last_mode = ad_type; + last_autodoc = Copy(methodName); + + String *doc = NewString(""); + int counter = 0; + bool skipAuto = false; + Node* on = n; + for ( ; n; ++counter ) { + String *type_str = NULL; + skipAuto = false; + bool showTypes = false; + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + switch (dlevel) { + case NO_AUTODOC: + break; + case NAMES_AUTODOC: + showTypes = false; + break; + case TYPES_AUTODOC: + showTypes = true; + break; + case EXTEND_AUTODOC: + extended = 1; + showTypes = false; + break; + case EXTEND_TYPES_AUTODOC: + extended = 1; + showTypes = true; + break; + case STRING_AUTODOC: + skipAuto = true; + break; + } + + SwigType *type = Getattr(n, "type"); + + if (type) { + if (Strcmp(type, "void") == 0) { + type_str = NULL; + } else { + SwigType *qt = SwigType_typedef_resolve_all(type); + if (SwigType_isenum(qt)) { + type_str = NewString("int"); + } else { + Node *nn = classLookup(type); + type_str = nn ? Copy(Getattr(nn, "sym:name")) : SwigType_str(type, 0); + } + } + } + + if (counter == 0) { + switch (ad_type) { + case AUTODOC_CLASS: + Printf(doc, " Document-class: %s", full_name); + if ( Len(super_names) > 0 ) + Printf( doc, " < %s", super_names); + Append(doc, "\n\n"); + break; + case AUTODOC_CTOR: + Printf(doc, " Document-method: %s.new\n\n", full_name); + break; + + case AUTODOC_DTOR: + break; + + case AUTODOC_STATICFUNC: + Printf(doc, " Document-method: %s.%s\n\n", full_name, symname); + break; + + case AUTODOC_FUNC: + case AUTODOC_METHOD: + case AUTODOC_GETTER: + Printf(doc, " Document-method: %s.%s\n\n", full_name, symname); + break; + case AUTODOC_SETTER: + Printf(doc, " Document-method: %s.%s=\n\n", full_name, symname); + break; + case AUTODOC_NONE: + break; + } + } + + if (skipAuto) { + if ( counter == 0 ) Printf(doc, " call-seq:\n"); + switch( ad_type ) + { + case AUTODOC_STATICFUNC: + case AUTODOC_FUNC: + case AUTODOC_METHOD: + case AUTODOC_GETTER: + { + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, " %s(%s)", symname, paramList); + else + Printf(doc, " %s", symname); + if (type_str) + Printf(doc, " -> %s", type_str); + break; + } + case AUTODOC_SETTER: + { + Printf(doc, " %s=(x)", symname); + if (type_str) + Printf(doc, " -> %s", type_str); + break; + } + default: + break; + } + } else { + switch (ad_type) { + case AUTODOC_CLASS: + { + // Only do the autodoc if there isn't a docstring for the class + String *str = Getattr(n, "feature:docstring"); + if (counter == 0 && (str == 0 || Len(str) == 0)) { + if (CPlusPlus) { + Printf(doc, " Proxy of C++ %s class", full_name); + } else { + Printf(doc, " Proxy of C %s struct", full_name); + } + } + } + break; + case AUTODOC_CTOR: + if (counter == 0) + Printf(doc, " call-seq:\n"); + if (Strcmp(class_name, symname) == 0) { + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, " %s.new(%s)", class_name, paramList); + else + Printf(doc, " %s.new", class_name); + } else { + Printf(doc, " %s.new(%s)", class_name, make_autodocParmList(n, showTypes)); + } + break; + + case AUTODOC_DTOR: + break; + + case AUTODOC_STATICFUNC: + case AUTODOC_FUNC: + case AUTODOC_METHOD: + case AUTODOC_GETTER: + { + if (counter == 0) + Printf(doc, " call-seq:\n"); + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, " %s(%s)", symname, paramList); + else + Printf(doc, " %s", symname); + if (type_str) + Printf(doc, " -> %s", type_str); + break; + } + case AUTODOC_SETTER: + { + Printf(doc, " call-seq:\n"); + Printf(doc, " %s=(x)", symname); + if (type_str) + Printf(doc, " -> %s", type_str); + break; + } + case AUTODOC_NONE: + break; + } + } + + // if it's overloaded then get the next decl and loop around again + n = Getattr(n, "sym:nextSibling"); + if (n) + Append(doc, "\n"); + Delete(type_str); + } + + Printf(doc, "\n\n"); + if (!skipAuto) { + switch (ad_type) { + case AUTODOC_CLASS: + case AUTODOC_DTOR: + break; + case AUTODOC_CTOR: + Printf(doc, "Class constructor.\n"); + break; + case AUTODOC_STATICFUNC: + Printf(doc, "A class method.\n"); + break; + case AUTODOC_FUNC: + Printf(doc, "A module function.\n"); + break; + case AUTODOC_METHOD: + Printf(doc, "An instance method.\n"); + break; + case AUTODOC_GETTER: + Printf(doc, "Get value of attribute.\n"); + break; + case AUTODOC_SETTER: + Printf(doc, "Set new value for attribute.\n"); + break; + case AUTODOC_NONE: + break; + } + } + + + n = on; + while ( n ) { + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + + switch (dlevel) { + case NO_AUTODOC: + case NAMES_AUTODOC: + case TYPES_AUTODOC: + extended = 0; + break; + case STRING_AUTODOC: + extended = 2; + Replaceall( autodoc, "$class", class_name ); + Printv(doc, autodoc, ".", NIL); + break; + case EXTEND_AUTODOC: + case EXTEND_TYPES_AUTODOC: + extended = 1; + break; + } + + + if (extended) { + String *pdocs = Getattr(n, "feature:pdocs"); + if (pdocs) { + Printv(doc, "\n\n", pdocs, NULL); + break; + } + if ( extended == 2 ) break; + } + n = Getattr(n, "sym:nextSibling"); + } + + Delete(full_name); + Delete(class_name); + Delete(super_names); + Delete(methodName); + + return doc; + } + + /* ------------------------------------------------------------ + * convertValue() + * Check if string v can be a Ruby value literal, + * (eg. number or string), or translate it to a Ruby literal. + * ------------------------------------------------------------ */ + String *convertValue(String *v, SwigType *t) { + if (v && Len(v) > 0) { + char fc = (Char(v))[0]; + if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) { + /* number or string (or maybe NULL pointer) */ + if (SwigType_ispointer(t) && Strcmp(v, "0") == 0) + return NewString("None"); + else + return v; + } + if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0) + return SwigType_ispointer(t) ? NewString("nil") : NewString("0"); + if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0) + return NewString("True"); + if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0) + return NewString("False"); + } + return 0; + } + +public: + + /* --------------------------------------------------------------------- + * RUBY() + * + * Initialize member data + * --------------------------------------------------------------------- */ + RUBY() : + module(0), + modvar(0), + feature(0), + prefix(0), + current(0), + classes(0), + klass(0), + special_methods(0), + f_directors(0), + f_directors_h(0), + f_directors_helpers(0), + f_begin(0), + f_runtime(0), + f_runtime_h(0), + f_header(0), + f_wrappers(0), + f_init(0), + f_initbeforefunc(0), + useGlobalModule(false), + multipleInheritance(false), + last_mode(AUTODOC_NONE), + last_autodoc(NewString("")) { + current = NO_CPP; + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " rb_raise(rb_eRuntimeError,\"accessing abstract class or protected constructor\"); \n", " return Qnil;\n", "}\n", NIL); + director_multiple_inheritance = 0; + director_language = 1; + } + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + int autorename = 0; + + /* Set location of SWIG library */ + SWIG_library_directory("ruby"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-initname") == 0) { + if (argv[i + 1]) { + char *name = argv[i + 1]; + feature = NewString(name); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } + else if (strcmp(argv[i], "-feature") == 0) { + fprintf( stderr, "Warning: Ruby -feature option is deprecated, " + "please use -initname instead.\n"); + if (argv[i + 1]) { + char *name = argv[i + 1]; + feature = NewString(name); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-globalmodule") == 0) { + useGlobalModule = true; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-minherit") == 0) { + multipleInheritance = true; + director_multiple_inheritance = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-autorename") == 0) { + autorename = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noautorename") == 0) { + autorename = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + char *name = argv[i + 1]; + prefix = NewString(name); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } else if (strcmp(argv[i], "-cppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); + } + } + } + + if (autorename) { + /* Turn on the autorename mode */ + Preprocessor_define((DOH *) "SWIG_RUBY_AUTORENAME", 0); + } + + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGRUBY 1", 0); + + /* Add typemap definitions */ + SWIG_typemap_lang("ruby"); + SWIG_config_file("ruby.swg"); + allow_overloading(); + } + + /** + * Generate initialization code to define the Ruby module(s), + * accounting for nested modules as necessary. + */ + void defineRubyModule() { + List *modules = Split(module, ':', INT_MAX); + if (modules != 0 && Len(modules) > 0) { + String *mv = 0; + Iterator m; + m = First(modules); + while (m.item) { + if (Len(m.item) > 0) { + if (mv != 0) { + Printv(f_init, tab4, modvar, " = rb_define_module_under(", modvar, ", \"", m.item, "\");\n", NIL); + } else { + Printv(f_init, tab4, modvar, " = rb_define_module(\"", m.item, "\");\n", NIL); + mv = NewString(modvar); + } + } + m = Next(m); + } + Delete(mv); + Delete(modules); + } + } + + void registerMagicMethods() { + + special_methods = NewHash(); + + /* Python->Ruby style special method name. */ + /* Basic */ + Setattr(special_methods, "__repr__", "inspect"); + Setattr(special_methods, "__str__", "to_s"); + Setattr(special_methods, "__cmp__", "<=>"); + Setattr(special_methods, "__hash__", "hash"); + Setattr(special_methods, "__nonzero__", "nonzero?"); + + /* Callable */ + Setattr(special_methods, "__call__", "call"); + + /* Collection */ + Setattr(special_methods, "__len__", "length"); + Setattr(special_methods, "__getitem__", "[]"); + Setattr(special_methods, "__setitem__", "[]="); + + /* Operators */ + Setattr(special_methods, "__add__", "+"); + Setattr(special_methods, "__pos__", "+@"); + Setattr(special_methods, "__sub__", "-"); + Setattr(special_methods, "__neg__", "-@"); + Setattr(special_methods, "__mul__", "*"); + Setattr(special_methods, "__div__", "/"); + Setattr(special_methods, "__mod__", "%"); + Setattr(special_methods, "__lshift__", "<<"); + Setattr(special_methods, "__rshift__", ">>"); + Setattr(special_methods, "__and__", "&"); + Setattr(special_methods, "__or__", "|"); + Setattr(special_methods, "__xor__", "^"); + Setattr(special_methods, "__invert__", "~"); + Setattr(special_methods, "__lt__", "<"); + Setattr(special_methods, "__le__", "<="); + Setattr(special_methods, "__gt__", ">"); + Setattr(special_methods, "__ge__", ">="); + Setattr(special_methods, "__eq__", "=="); + + /* Other numeric */ + Setattr(special_methods, "__divmod__", "divmod"); + Setattr(special_methods, "__pow__", "**"); + Setattr(special_methods, "__abs__", "abs"); + Setattr(special_methods, "__int__", "to_i"); + Setattr(special_methods, "__float__", "to_f"); + Setattr(special_methods, "__coerce__", "coerce"); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + + String *mod_docstring = NULL; + + /** + * See if any Ruby module options have been specified as options + * to the %module directive. + */ + Node *swigModule = Getattr(n, "module"); + if (swigModule) { + Node *options = Getattr(swigModule, "options"); + if (options) { + if (Getattr(options, "directors")) { + allow_directors(); + } + if (Getattr(options, "dirprot")) { + allow_dirprot(); + } + if (Getattr(options, "ruby_globalmodule")) { + useGlobalModule = true; + } + if (Getattr(options, "ruby_minherit")) { + multipleInheritance = true; + director_multiple_inheritance = 1; + } + mod_docstring = Getattr(options, "docstring"); + } + } + + /* Set comparison with none for ConstructorToFunction */ + + + setSubclassInstanceCheck(NewStringf("strcmp(rb_obj_classname(self), classname) != 0")); + // setSubclassInstanceCheck(NewString("CLASS_OF(self) != cFoo.klass")); + + /* 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); + } + + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + f_directors_helpers = NewString(""); + f_initbeforefunc = NewString(""); + + 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); + } + } + + /* 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); + Swig_register_filebyname("director_helpers", f_directors_helpers); + Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + + modvar = 0; + current = NO_CPP; + klass = 0; + classes = NewHash(); + + registerMagicMethods(); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGRUBY\n#define SWIGRUBY\n#endif\n\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + Printf(f_runtime, "\n"); + + /* typedef void *VALUE */ + SwigType *value = NewSwigType(T_VOID); + SwigType_add_pointer(value); + SwigType_typedef(value, "VALUE"); + Delete(value); + + /* Set module name */ + set_module(Char(Getattr(n, "name"))); + + if (directorsEnabled()) { + /* Build a version of the module name for use in a C macro name. */ + String *module_macro = Copy(module); + Replaceall(module_macro, "::", "__"); + + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_macro); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_macro); + Printf(f_directors_h, "namespace Swig {\n"); + Printf(f_directors_h, " class Director;\n"); + Printf(f_directors_h, "}\n\n"); + + Printf(f_directors_helpers, "/* ---------------------------------------------------\n"); + Printf(f_directors_helpers, " * C++ director class helpers\n"); + Printf(f_directors_helpers, " * --------------------------------------------------- */\n\n"); + + 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); + } + + Delete(module_macro); + } + + Printf(f_header, "#define SWIG_init Init_%s\n", feature); + Printf(f_header, "#define SWIG_name \"%s\"\n\n", module); + + if (mod_docstring) { + if (Len(mod_docstring)) { + Printf(f_header, "/*\n Document-module: %s\n\n%s\n*/\n", module, mod_docstring); + } + Delete(mod_docstring); + mod_docstring = NULL; + } + + Printf(f_header, "static VALUE %s;\n", modvar); + + /* Start generating the initialization function */ + String* docs = docstring(n, AUTODOC_CLASS); + Printf(f_init, "/*\n%s\n*/", docs ); + Printv(f_init, "\n", "#ifdef __cplusplus\n", "extern \"C\"\n", "#endif\n", "SWIGEXPORT void Init_", feature, "(void) {\n", "size_t i;\n", "\n", NIL); + + Printv(f_init, tab4, "SWIG_InitRuntime();\n", NIL); + + if (!useGlobalModule) + defineRubyModule(); + + Printv(f_init, "\n", "SWIG_InitializeModule(0);\n", "for (i = 0; i < swig_module.size; i++) {\n", "SWIG_define_class(swig_module.types[i]);\n", "}\n", NIL); + Printf(f_init, "\n"); + + /* Initialize code to keep track of objects */ + Printf(f_init, "SWIG_RubyInitializeTrackings();\n"); + + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director_common.swg", f_runtime); + Swig_insert_file("director.swg", f_runtime); + } + + /* Finish off our init function */ + Printf(f_init, "}\n"); + SwigType_emit_type_table(f_runtime, f_wrappers); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors_helpers, f_begin); + 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); + } + + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_initbeforefunc); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * importDirective() + * ----------------------------------------------------------------------------- */ + + virtual int importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname) { + if (prefix) { + Insert(modname, 0, prefix); + } + + List *modules = Split(modname, ':', INT_MAX); + if (modules && Len(modules) > 0) { + modname = NewString(""); + String *last = NULL; + Iterator m = First(modules); + while (m.item) { + if (Len(m.item) > 0) { + if (last) { + Append(modname, "/"); + } + Append(modname, m.item); + last = m.item; + } + m = Next(m); + } + Printf(f_init, "rb_require(\"%s\");\n", modname); + Delete(modname); + } + Delete(modules); + } + return Language::importDirective(n); + } + + /* --------------------------------------------------------------------- + * set_module(const char *mod_name) + * + * Sets the module name. Does nothing if it's already set (so it can + * be overridden as a command line option). + *---------------------------------------------------------------------- */ + + void set_module(const char *s) { + String *mod_name = NewString(s); + if (module == 0) { + /* Start with the empty string */ + module = NewString(""); + + if (prefix) { + Insert(mod_name, 0, prefix); + } + + /* Account for nested modules */ + List *modules = Split(mod_name, ':', INT_MAX); + if (modules != 0 && Len(modules) > 0) { + String *last = 0; + Iterator m = First(modules); + while (m.item) { + if (Len(m.item) > 0) { + String *cap = NewString(m.item); + (Char(cap))[0] = (char)toupper((Char(cap))[0]); + if (last != 0) { + Append(module, "::"); + } + Append(module, cap); + last = m.item; + } + m = Next(m); + } + if (last) { + if (feature == 0) { + feature = Copy(last); + } + (Char(last))[0] = (char)toupper((Char(last))[0]); + modvar = NewStringf("m%s", last); + } + } + Delete(modules); + } + Delete(mod_name); + } + + /* -------------------------------------------------------------------------- + * nativeWrapper() + * -------------------------------------------------------------------------- */ + virtual int nativeWrapper(Node *n) { + String *funcname = Getattr(n, "wrap:name"); + Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, "Adding native function %s not supported (ignored).\n", funcname); + return SWIG_NOWRAP; + } + + /** + * Process the comma-separated list of aliases (if any). + */ + void defineAliases(Node *n, const_String_or_char_ptr iname) { + String *aliasv = Getattr(n, "feature:alias"); + if (aliasv) { + List *aliases = Split(aliasv, ',', INT_MAX); + if (aliases && Len(aliases) > 0) { + Iterator alias = First(aliases); + while (alias.item) { + if (Len(alias.item) > 0) { + if (current == NO_CPP) { + if (useGlobalModule) { + Printv(f_init, tab4, "rb_define_alias(rb_cObject, \"", alias.item, "\", \"", iname, "\");\n", NIL); + } else { + Printv(f_init, tab4, "rb_define_alias(rb_singleton_class(", modvar, "), \"", alias.item, "\", \"", iname, "\");\n", NIL); + } + } else if (multipleInheritance) { + Printv(klass->init, tab4, "rb_define_alias(", klass->mImpl, ", \"", alias.item, "\", \"", iname, "\");\n", NIL); + } else { + Printv(klass->init, tab4, "rb_define_alias(", klass->vname, ", \"", alias.item, "\", \"", iname, "\");\n", NIL); + } + } + alias = Next(alias); + } + } + Delete(aliases); + } + } + + /* --------------------------------------------------------------------- + * create_command(Node *n, char *iname) + * + * Creates a new command from a C function. + * iname = Name of function in scripting language + * + * A note about what "protected" and "private" mean in Ruby: + * + * A private method is accessible only within the class or its subclasses, + * and it is callable only in "function form", with 'self' (implicit or + * explicit) as a receiver. + * + * A protected method is callable only from within its class, but unlike + * a private method, it can be called with a receiver other than self, such + * as another instance of the same class. + * --------------------------------------------------------------------- */ + + void create_command(Node *n, const_String_or_char_ptr iname) { + + String *alloc_func = Swig_name_wrapper(iname); + String *wname = Swig_name_wrapper(iname); + if (CPlusPlus) { + Insert(wname, 0, "VALUEFUNC("); + Append(wname, ")"); + } + if (current != NO_CPP) + iname = klass->strip(iname); + if (Getattr(special_methods, iname)) { + iname = GetChar(special_methods, iname); + } + + String *s = NewString(""); + String *temp = NewString(""); + +#ifdef SWIG_PROTECTED_TARGET_METHODS + const char *rb_define_method = is_public(n) ? "rb_define_method" : "rb_define_protected_method"; +#else + const char *rb_define_method = "rb_define_method"; +#endif + switch (current) { + case MEMBER_FUNC: + { + if (multipleInheritance) { + Printv(klass->init, tab4, rb_define_method, "(", klass->mImpl, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + } else { + Printv(klass->init, tab4, rb_define_method, "(", klass->vname, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + } + } + break; + case CONSTRUCTOR_ALLOCATE: + Printv(s, tab4, "rb_define_alloc_func(", klass->vname, ", ", alloc_func, ");\n", NIL); + Replaceall(klass->init, "$allocator", s); + break; + case CONSTRUCTOR_INITIALIZE: + Printv(s, tab4, rb_define_method, "(", klass->vname, ", \"initialize\", ", wname, ", -1);\n", NIL); + Replaceall(klass->init, "$initializer", s); + break; + case MEMBER_VAR: + Append(temp, iname); + /* Check for _set or _get at the end of the name. */ + if (Len(temp) > 4) { + const char *p = Char(temp) + (Len(temp) - 4); + if (strcmp(p, "_set") == 0) { + Delslice(temp, Len(temp) - 4, DOH_END); + Append(temp, "="); + } else if (strcmp(p, "_get") == 0) { + Delslice(temp, Len(temp) - 4, DOH_END); + } + } + if (multipleInheritance) { + Printv(klass->init, tab4, "rb_define_method(", klass->mImpl, ", \"", temp, "\", ", wname, ", -1);\n", NIL); + } else { + Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"", temp, "\", ", wname, ", -1);\n", NIL); + } + break; + case STATIC_FUNC: + Printv(klass->init, tab4, "rb_define_singleton_method(", klass->vname, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + break; + case NO_CPP: + if (!useGlobalModule) { + Printv(s, tab4, "rb_define_module_function(", modvar, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + Printv(f_init, s, NIL); + } else { + Printv(s, tab4, "rb_define_global_function(\"", iname, "\", ", wname, ", -1);\n", NIL); + Printv(f_init, s, NIL); + } + break; + case DESTRUCTOR: + case CLASS_CONST: + case STATIC_VAR: + default: + assert(false); // Should not have gotten here for these types + } + + defineAliases(n, iname); + + Delete(temp); + Delete(s); + Delete(wname); + Delete(alloc_func); + } + + /* --------------------------------------------------------------------- + * applyInputTypemap() + * + * Look up the appropriate "in" typemap for this parameter (p), + * substitute the correct strings for the $target and $input typemap + * parameters, and dump the resulting code to the wrapper file. + * --------------------------------------------------------------------- */ + + Parm *applyInputTypemap(Parm *p, String *ln, String *source, Wrapper *f, String *symname) { + String *tm; + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$target", ln); + Replaceall(tm, "$source", source); + Replaceall(tm, "$input", source); + Replaceall(tm, "$symname", symname); + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + Setattr(p, "emit:input", Copy(source)); + 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); + } + return p; + } + + Parm *skipIgnoredArgs(Parm *p) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + return p; + } + + /* --------------------------------------------------------------------- + * marshalInputArgs() + * + * Process all of the arguments passed into the scripting language + * method and convert them into C/C++ function arguments using the + * supplied typemaps. + * --------------------------------------------------------------------- */ + + void marshalInputArgs(Node *n, ParmList *l, int numarg, int numreq, String *kwargs, bool allow_kwargs, Wrapper *f) { + int i; + Parm *p; + String *tm; + String *source; + String *target; + + source = NewString(""); + target = NewString(""); + + bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + + /** + * The 'start' value indicates which of the C/C++ function arguments + * produced here corresponds to the first value in Ruby's argv[] array. + * The value of start is either zero or one. If start is zero, then + * the first argument (with name arg1) is based on the value of argv[0]. + * If start is one, then arg1 is based on the value of argv[1]. + */ + int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; + + int varargs = emit_isvarargs(l); + + Printf(kwargs, "{ "); + for (i = 0, p = l; i < numarg; i++) { + + p = skipIgnoredArgs(p); + + String *pn = Getattr(p, "name"); + String *ln = Getattr(p, "lname"); + + /* Produce string representation of source argument */ + Clear(source); + + /* First argument is a special case */ + if (i == 0) { + Printv(source, (start == 0) ? "argv[0]" : "self", NIL); + } else { + Printf(source, "argv[%d]", i - start); + } + + /* Produce string representation of target argument */ + Clear(target); + Printf(target, "%s", Char(ln)); + + if (i >= (numreq)) { /* Check if parsing an optional argument */ + Printf(f->code, " if (argc > %d) {\n", i - start); + } + + /* Record argument name for keyword argument handling */ + if (Len(pn)) { + Printf(kwargs, "\"%s\",", pn); + } else { + Printf(kwargs, "\"arg%d\",", i + 1); + } + + /* Look for an input typemap */ + p = applyInputTypemap(p, ln, source, f, Getattr(n, "name")); + if (i >= numreq) { + Printf(f->code, "}\n"); + } + } + + /* Finish argument marshalling */ + Printf(kwargs, " NULL }"); + if (allow_kwargs) { +// kwarg support not implemented +// Printv(f->locals, tab4, "const char *kwnames[] = ", kwargs, ";\n", NIL); + } + + /* Trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Clear(source); + Printf(source, "argv[%d]", i - start); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", Copy(source)); + Printf(f->code, "if (argc > %d) {\n", i - start); + Printv(f->code, tm, "\n", NIL); + Printf(f->code, "}\n"); + } + } + + Delete(source); + Delete(target); + } + + /* --------------------------------------------------------------------- + * insertConstraintCheckingCode(ParmList *l, Wrapper *f) + * + * Checks each of the parameters in the parameter list for a "check" + * typemap and (if it finds one) inserts the typemapping code into + * the function wrapper. + * --------------------------------------------------------------------- */ + + void insertConstraintCheckingCode(ParmList *l, Wrapper *f) { + Parm *p; + String *tm; + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + } + + /* --------------------------------------------------------------------- + * insertCleanupCode(ParmList *l, String *cleanup) + * + * Checks each of the parameters in the parameter list for a "freearg" + * typemap and (if it finds one) inserts the typemapping code into + * the function wrapper. + * --------------------------------------------------------------------- */ + + void insertCleanupCode(ParmList *l, String *cleanup) { + String *tm; + for (Parm *p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + if (Len(tm) != 0) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + } + + /* --------------------------------------------------------------------- + * insertArgOutputCode(ParmList *l, String *outarg, int& need_result) + * + * Checks each of the parameters in the parameter list for a "argout" + * typemap and (if it finds one) inserts the typemapping code into + * the function wrapper. + * --------------------------------------------------------------------- */ + + void insertArgOutputCode(ParmList *l, String *outarg, int &need_result) { + String *tm; + for (Parm *p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "vresult"); + Replaceall(tm, "$result", "vresult"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + + Printv(outarg, tm, "\n", NIL); + need_result += 1; + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + } + + /* --------------------------------------------------------------------- + * validIdentifier() + * + * Is this a valid identifier in the scripting language? + * Ruby method names can include any combination of letters, numbers + * and underscores. A Ruby method name may optionally end with + * a question mark ("?"), exclamation point ("!") or equals sign ("="). + * + * Methods whose names end with question marks are, by convention, + * predicate methods that return true or false (e.g. Array#empty?). + * + * Methods whose names end with exclamation points are, by convention, + * called bang methods that modify the instance in place (e.g. Array#sort!). + * + * Methods whose names end with an equals sign are attribute setters + * (e.g. Thread#critical=). + * --------------------------------------------------------------------- */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + while (*c) { + if (!(isalnum(*c) || (*c == '_') || (*c == '?') || (*c == '!') || (*c == '='))) + return 0; + c++; + } + return 1; + } + + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + + String *nodeType; + bool destructor; + + String *symname = Copy(Getattr(n, "sym:name")); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + int director_method = 0; + String *tm; + + int need_result = 0; + + /* Ruby needs no destructor wrapper */ + if (current == DESTRUCTOR) + return SWIG_NOWRAP; + + nodeType = Getattr(n, "nodeType"); + destructor = (!Cmp(nodeType, "destructor")); + + /* If the C++ class constructor is overloaded, we only want to + * write out the "new" singleton method once since it is always + * the same. (It's the "initialize" method that will handle the + * overloading). */ + + if (current == CONSTRUCTOR_ALLOCATE && Swig_symbol_isoverloaded(n) && Getattr(n, "sym:nextSibling") != 0) + return SWIG_OK; + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(symname, n)) + return SWIG_ERROR; + } + + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *kwargs = NewString(""); + Wrapper *f = NewWrapper(); + + /* Rename predicate methods */ + if (GetFlag(n, "feature:predicate")) { + Append(symname, "?"); + } + + /* Rename bang methods */ + if (GetFlag(n, "feature:bang")) { + Append(symname, "!"); + } + + /* Determine the name of the SWIG wrapper function */ + String *wname = Swig_name_wrapper(symname); + if (overname && current != CONSTRUCTOR_ALLOCATE) { + Append(wname, overname); + } + + /* Emit arguments */ + if (current != CONSTRUCTOR_ALLOCATE) { + emit_parameter_variables(l, f); + } + + /* Attach standard typemaps */ + if (current != CONSTRUCTOR_ALLOCATE) { + emit_attach_parmmaps(l, f); + } + Setattr(n, "wrap:parms", l); + + /* Get number of arguments */ + int numarg = emit_num_arguments(l); + int numreq = emit_num_required(l); + int varargs = emit_isvarargs(l); + bool allow_kwargs = GetFlag(n, "feature:kwargs") ? true : false; + + bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; + + /* Now write the wrapper function itself */ + if (current == CONSTRUCTOR_ALLOCATE) { + Printv(f->def, "SWIGINTERN VALUE\n", NIL); + Printf(f->def, "#ifdef HAVE_RB_DEFINE_ALLOC_FUNC\n"); + Printv(f->def, wname, "(VALUE self)\n", NIL); + Printf(f->def, "#else\n"); + Printv(f->def, wname, "(int argc, VALUE *argv, VALUE self)\n", NIL); + Printf(f->def, "#endif\n"); + Printv(f->def, "{\n", NIL); + } else if (current == CONSTRUCTOR_INITIALIZE) { + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); + if (!varargs) { + Printf(f->code, "if ((argc < %d) || (argc > %d)) ", numreq - start, numarg - start); + } else { + Printf(f->code, "if (argc < %d) ", numreq - start); + } + Printf(f->code, "{rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc); SWIG_fail;}\n", numreq - start); + } else { + + if ( current == NO_CPP ) + { + String* docs = docstring(n, AUTODOC_FUNC); + Printf(f_wrappers, "%s", docs); + Delete(docs); + } + + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); + if (!varargs) { + Printf(f->code, "if ((argc < %d) || (argc > %d)) ", numreq - start, numarg - start); + } else { + Printf(f->code, "if (argc < %d) ", numreq - start); + } + Printf(f->code, "{rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc); SWIG_fail;}\n", numreq - start); + } + + /* Now walk the function parameter list and generate code */ + /* to get arguments */ + if (current != CONSTRUCTOR_ALLOCATE) { + marshalInputArgs(n, l, numarg, numreq, kwargs, allow_kwargs, f); + } + // FIXME? + if (ctor_director) { + numarg--; + numreq--; + } + + /* Insert constraint checking code */ + insertConstraintCheckingCode(l, f); + + /* Insert cleanup code */ + insertCleanupCode(l, cleanup); + + /* Insert argument output code */ + insertArgOutputCode(l, outarg, need_result); + + /* if the object is a director, and the method call originated from its + * underlying Ruby object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in Ruby. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Append(f->code, "upcall = (director && (director->swig_get_self() == self));\n"); + } + + /* Now write code to make the function call */ + if (current != CONSTRUCTOR_ALLOCATE) { + if (current == CONSTRUCTOR_INITIALIZE) { + Node *pn = Swig_methodclass(n); + String *symname = Getattr(pn, "sym:name"); + String *action = Getattr(n, "wrap:action"); + if (directorsEnabled()) { + String *classname = NewStringf("const char *classname SWIGUNUSED = \"%s::%s\"", module, symname); + Wrapper_add_local(f, "classname", classname); + } + if (action) { + SwigType *smart = Swig_cparse_smartptr(pn); + String *result_name = NewStringf("%s%s", smart ? "smart" : "", Swig_cresult_name()); + if (smart) { + String *result_var = NewStringf("%s *%s = 0", SwigType_namestr(smart), result_name); + Wrapper_add_local(f, result_name, result_var); + Printf(action, "\n%s = new %s(%s);", result_name, SwigType_namestr(smart), Swig_cresult_name()); + } + Printf(action, "\nDATA_PTR(self) = %s;", result_name); + if (GetFlag(pn, "feature:trackobjects")) { + Printf(action, "\nSWIG_RubyAddTracking(%s, self);", result_name); + } + Delete(result_name); + Delete(smart); + } + } + + /* Emit the function call */ + if (director_method) { + Printf(f->code, "try {\n"); + } + + Setattr(n, "wrap:name", wname); + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (director_method) { + Printf(actioncode, "} catch (Swig::DirectorException& e) {\n"); + Printf(actioncode, " rb_exc_raise(e.getError());\n"); + Printf(actioncode, " SWIG_fail;\n"); + Printf(actioncode, "}\n"); + } + + /* Return value if necessary */ + if (SwigType_type(t) != T_VOID && current != CONSTRUCTOR_INITIALIZE) { + need_result = 1; + if (GetFlag(n, "feature:predicate")) { + Printv(actioncode, tab4, "vresult = (", Swig_cresult_name(), " ? Qtrue : Qfalse);\n", NIL); + } else { + tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode); + actioncode = 0; + if (tm) { + Replaceall(tm, "$result", "vresult"); + Replaceall(tm, "$source", Swig_cresult_name()); + Replaceall(tm, "$target", "vresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + else + Replaceall(tm, "$owner", "0"); + +#if 1 + // FIXME: this will not try to unwrap directors returned as non-director + // base class pointers! + + /* New addition to unwrap director return values so that the original + * Ruby object is returned instead. + */ + bool unwrap = false; + String *decl = Getattr(n, "decl"); + int is_pointer = SwigType_ispointer_return(decl); + int is_reference = SwigType_isreference_return(decl); + if (is_pointer || is_reference) { + String *type = Getattr(n, "type"); + Node *parent = Swig_methodclass(n); + Node *modname = Getattr(parent, "module"); + Node *target = Swig_directormap(modname, type); + if (target) + unwrap = true; + } + if (unwrap) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director *>(%s);\n", Swig_cresult_name()); + Printf(f->code, "if (director) {\n"); + Printf(f->code, " vresult = director->swig_get_self();\n"); + Printf(f->code, "} else {\n"); + Printf(f->code, "%s\n", tm); + Printf(f->code, "}\n"); + director_method = 0; + } else { + Printf(f->code, "%s\n", tm); + } +#else + Printf(f->code, "%s\n", tm); +#endif + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s.\n", SwigType_str(t, 0)); + } + } + } + if (actioncode) { + Append(f->code, actioncode); + Delete(actioncode); + } + emit_return_variable(n, t, f); + } + + /* Extra code needed for new and initialize methods */ + if (current == CONSTRUCTOR_ALLOCATE) { + Node *pn = Swig_methodclass(n); + SwigType *smart = Swig_cparse_smartptr(pn); + if (smart) + SwigType_add_pointer(smart); + String *classtype = smart ? smart : t; + need_result = 1; + Printf(f->code, "VALUE vresult = SWIG_NewClassInstance(self, SWIGTYPE%s);\n", Char(SwigType_manglestr(classtype))); + Printf(f->code, "#ifndef HAVE_RB_DEFINE_ALLOC_FUNC\n"); + Printf(f->code, "rb_obj_call_init(vresult, argc, argv);\n"); + Printf(f->code, "#endif\n"); + Delete(smart); + } else if (current == CONSTRUCTOR_INITIALIZE) { + need_result = 1; + } + else + { + if ( need_result > 1 ) { + if ( SwigType_type(t) == T_VOID ) + Printf(f->code, "vresult = rb_ary_new();\n"); + else + { + Printf(f->code, "if (vresult == Qnil) vresult = rb_ary_new();\n"); + Printf(f->code, "else vresult = SWIG_Ruby_AppendOutput( " + "rb_ary_new(), vresult);\n"); + } + } + } + + /* Dump argument output code; */ + Printv(f->code, outarg, NIL); + + /* Dump the argument cleanup code */ + int need_cleanup = (current != CONSTRUCTOR_ALLOCATE) && (Len(cleanup) != 0); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + + + /* Look for any remaining cleanup. This processes the %new directive */ + if (current != CONSTRUCTOR_ALLOCATE && GetFlag(n, "feature:new")) { + tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0); + if (tm) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, "\n", NIL); + Delete(tm); + } + } + + /* Special processing on return value. */ + tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0); + if (tm) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printv(f->code, tm, NIL); + Delete(tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$input", Swig_cresult_name()); + Replaceall(tm, "$result", "vresult"); + Printf(f->code, "%s\n", tm); + } + } + + + /* Wrap things up (in a manner of speaking) */ + if (need_result) { + if (current == CONSTRUCTOR_ALLOCATE) { + Printv(f->code, tab4, "return vresult;\n", NIL); + } else if (current == CONSTRUCTOR_INITIALIZE) { + Printv(f->code, tab4, "return self;\n", NIL); + Printv(f->code, "fail:\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, tab4, "return Qnil;\n", NIL); + } else { + Wrapper_add_local(f, "vresult", "VALUE vresult = Qnil"); + Printv(f->code, tab4, "return vresult;\n", NIL); + Printv(f->code, "fail:\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, tab4, "return Qnil;\n", NIL); + } + } else { + Printv(f->code, tab4, "return Qnil;\n", NIL); + Printv(f->code, "fail:\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, tab4, "return Qnil;\n", NIL); + } + + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + /* Emit the function */ + Wrapper_print(f, f_wrappers); + + /* Now register the function with the interpreter */ + if (!Swig_symbol_isoverloaded(n)) { + create_command(n, symname); + } else { + if (current == CONSTRUCTOR_ALLOCATE) { + create_command(n, symname); + } else { + if (!Getattr(n, "sym:nextSibling")) + dispatchFunction(n); + } + } + + Delete(kwargs); + Delete(cleanup); + Delete(outarg); + DelWrapper(f); + Delete(symname); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "return %s(nargs, args, self);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + Printv(f->def, "SWIGINTERN VALUE ", wname, "(int nargs, VALUE *args, VALUE self) {", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { + Printf(tmp, "VALUE argv[%d]", maxargs + 1); + } else { + Printf(tmp, "VALUE argv[%d]", maxargs); + } + Wrapper_add_local(f, "argv", tmp); + Wrapper_add_local(f, "ii", "int ii"); + + if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { + maxargs += 1; + Printf(f->code, "argc = nargs + 1;\n"); + Printf(f->code, "argv[0] = self;\n"); + Printf(f->code, "if (argc > %d) SWIG_fail;\n", maxargs); + Printf(f->code, "for (ii = 1; (ii < argc); ++ii) {\n"); + Printf(f->code, "argv[ii] = args[ii-1];\n"); + Printf(f->code, "}\n"); + } else { + Printf(f->code, "argc = nargs;\n"); + Printf(f->code, "if (argc > %d) SWIG_fail;\n", maxargs); + Printf(f->code, "for (ii = 0; (ii < argc); ++ii) {\n"); + Printf(f->code, "argv[ii] = args[ii];\n"); + Printf(f->code, "}\n"); + } + + Replaceall(dispatch, "$args", "nargs, args, self"); + Printv(f->code, dispatch, "\n", NIL); + + + + // Generate prototype list, go to first node + Node *sibl = n; + + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + + // Constructors will be treated specially + const bool isCtor = (!Cmp(Getattr(sibl, "nodeType"), "constructor")); + const bool isMethod = ( Cmp(Getattr(sibl, "ismember"), "1") == 0 && + (!isCtor) ); + + // Construct real method name + String* methodName = NewString(""); + if ( isMethod ) { + // Sometimes a method node has no parent (SF#3034054). + // This value is used in an exception message, so just skip the class + // name in this case so at least we don't segfault. This is probably + // just working around a problem elsewhere though. + Node *parent_node = parentNode(sibl); + if (parent_node) + Printv( methodName, Getattr(parent_node,"sym:name"), ".", NIL ); + } + Append( methodName, Getattr(sibl,"sym:name" ) ); + if ( isCtor ) Append( methodName, ".new" ); + + // Generate prototype list + String *protoTypes = NewString(""); + do { + Append( protoTypes, "\n\" "); + if (!isCtor) { + SwigType *type = SwigType_str(Getattr(sibl, "type"), NULL); + Printv(protoTypes, type, " ", NIL); + Delete(type); + } + Printv(protoTypes, methodName, NIL ); + Parm* p = Getattr(sibl, "wrap:parms"); + if (p && (current == MEMBER_FUNC || current == MEMBER_VAR || + ctor_director) ) + p = nextSibling(p); // skip self + Append( protoTypes, "(" ); + while(p) + { + Append( protoTypes, SwigType_str(Getattr(p,"type"), Getattr(p,"name")) ); + if ( ( p = nextSibling(p)) ) Append(protoTypes, ", "); + } + Append( protoTypes, ")\\n\"" ); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + + Append(f->code, "fail:\n"); + Printf(f->code, "Ruby_Format_OverloadedError( argc, %d, \"%s\", %s);\n", + maxargs, methodName, protoTypes); + Append(f->code, "\nreturn Qnil;\n"); + + Delete(methodName); + Delete(protoTypes); + + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + create_command(n, Char(symname)); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* --------------------------------------------------------------------- + * variableWrapper() + * --------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + String* docs = docstring(n, AUTODOC_GETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + String *tm; + String *getfname, *setfname; + Wrapper *getf, *setf; + const int assignable = is_assignable(n); + + // Determine whether virtual global variables shall be used + // which have different getter and setter signatures, + // see https://docs.ruby-lang.org/en/2.6.0/extension_rdoc.html#label-Global+Variables+Shared+Between+C+and+Ruby + const bool use_virtual_var = (current == NO_CPP && useGlobalModule); + + getf = NewWrapper(); + setf = NewWrapper(); + + /* create getter */ + int addfail = 0; + String *getname = Swig_name_get(NSPACE_TODO, iname); + getfname = Swig_name_wrapper(getname); + Setattr(n, "wrap:name", getfname); + Printv(getf->def, "SWIGINTERN VALUE\n", getfname, "(", NIL); + Printf(getf->def, (use_virtual_var) ? "ID id, VALUE *data" : "VALUE self"); + Printf(getf->def, ") {"); + Wrapper_add_local(getf, "_val", "VALUE _val"); + + tm = Swig_typemap_lookup("varout", n, name, 0); + if (tm) { + Replaceall(tm, "$result", "_val"); + Replaceall(tm, "$target", "_val"); + Replaceall(tm, "$source", name); + /* Printv(getf->code,tm, NIL); */ + addfail = emit_action_code(n, getf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + Printv(getf->code, tab4, "return _val;\n", NIL); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return Qnil;\n"); + } + Append(getf->code, "}\n"); + + Wrapper_print(getf, f_wrappers); + + if (!assignable) { + setfname = NewString("(rb_gvar_setter_t *)NULL"); + } else { + /* create setter */ + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + String *setname = Swig_name_set(NSPACE_TODO, iname); + setfname = Swig_name_wrapper(setname); + Setattr(n, "wrap:name", setfname); + Printf(setf->def, "SWIGINTERN "); + if (use_virtual_var) { + Printv(setf->def, "void\n", setfname, "(VALUE _val, ID id, VALUE *data) {", NIL); + } else { + Printv(setf->def, "VALUE\n", setfname, "(VALUE self, VALUE _val) {", NIL); + } + tm = Swig_typemap_lookup("varin", n, name, 0); + if (tm) { + Replaceall(tm, "$input", "_val"); + Replaceall(tm, "$source", "_val"); + Replaceall(tm, "$target", name); + /* Printv(setf->code,tm,"\n",NIL); */ + emit_action_code(n, setf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s\n", SwigType_str(t, 0)); + } + if (use_virtual_var) { + Printf(setf->code, "fail:\n"); + Printv(setf->code, tab4, "return;\n", NIL); + } else { + Printv(setf->code, tab4, "return _val;\n", NIL); + Printf(setf->code, "fail:\n"); + Printv(setf->code, tab4, "return Qnil;\n", NIL); + } + Printf(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + Delete(setname); + } + + /* define accessor methods */ + Insert(getfname, 0, "VALUEFUNC("); + Append(getfname, ")"); + Insert(setfname, 0, (use_virtual_var) ? "SWIG_RUBY_VOID_ANYARGS_FUNC(" : "VALUEFUNC("); + Append(setfname, ")"); + + String *s = NewString(""); + switch (current) { + case STATIC_VAR: + /* C++ class variable */ + Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "\", ", getfname, ", 0);\n", NIL); + if (assignable) { + Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "=\", ", setfname, ", 1);\n", NIL); + } + Printv(klass->init, s, NIL); + break; + default: + /* C global variable */ + /* wrapped in Ruby module attribute */ + assert(current == NO_CPP); + if (!useGlobalModule) { + Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "\", ", getfname, ", 0);\n", NIL); + if (assignable) { + Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "=\", ", setfname, ", 1);\n", NIL); + } + } else { + Printv(s, tab4, "rb_define_virtual_variable(\"$", iname, "\", ", getfname, ", ", setfname, ");\n", NIL); + } + Printv(f_init, s, NIL); + Delete(s); + break; + } + Delete(getname); + Delete(getfname); + Delete(setfname); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_OK; + } + + + /* --------------------------------------------------------------------- + * validate_const_name(char *name) + * + * Validate constant name. + * --------------------------------------------------------------------- */ + + char *validate_const_name(char *name, const char *reason) { + if (!name || name[0] == '\0') + return name; + + if (isupper(name[0])) + return name; + + if (islower(name[0])) { + name[0] = (char)toupper(name[0]); + Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, "Wrong %s name (corrected to `%s')\n", reason, name); + return name; + } + + Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, "Wrong %s name %s\n", reason, name); + + return name; + } + + /* --------------------------------------------------------------------- + * constantWrapper() + * --------------------------------------------------------------------- */ + + virtual int constantWrapper(Node *n) { + Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL); + + char *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + + if (current == CLASS_CONST) { + iname = klass->strip(iname); + } + validate_const_name(iname, "constant"); + SetChar(n, "sym:name", iname); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + String *tm = Swig_typemap_lookup("constant", n, value, 0); + if (!tm) + tm = Swig_typemap_lookup("constcode", n, value, 0); + if (tm) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", iname); + Replaceall(tm, "$symname", iname); + Replaceall(tm, "$value", value); + if (current == CLASS_CONST) { + if (multipleInheritance) { + Replaceall(tm, "$module", klass->mImpl); + Printv(klass->init, tm, "\n", NIL); + } else { + Replaceall(tm, "$module", klass->vname); + Printv(klass->init, tm, "\n", NIL); + } + } else { + if (!useGlobalModule) { + Replaceall(tm, "$module", modvar); + } else { + Replaceall(tm, "$module", "rb_cObject"); + } + Printf(f_init, "%s\n", tm); + } + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value %s = %s\n", SwigType_str(type, 0), value); + } + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * classDeclaration() + * + * Records information about classes---even classes that might be defined in + * other modules referenced by %import. + * ----------------------------------------------------------------------------- */ + + virtual int classDeclaration(Node *n) { + if (!Getattr(n, "feature:onlychildren")) { + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + + String *namestr = SwigType_namestr(name); + klass = RCLASS(classes, Char(namestr)); + if (!klass) { + klass = new RClass(); + String *valid_name = NewString(symname ? symname : namestr); + validate_const_name(Char(valid_name), "class"); + klass->set_name(namestr, symname, valid_name); + SET_RCLASS(classes, Char(namestr), klass); + Delete(valid_name); + } + Delete(namestr); + } + return Language::classDeclaration(n); + } + + /** + * Process the comma-separated list of mixed-in module names (if any). + */ + void includeRubyModules(Node *n) { + String *mixin = Getattr(n, "feature:mixin"); + if (mixin) { + List *modules = Split(mixin, ',', INT_MAX); + if (modules && Len(modules) > 0) { + Iterator mod = First(modules); + while (mod.item) { + if (Len(mod.item) > 0) { + Printf(klass->init, "rb_include_module(%s, rb_eval_string(\"%s\"));\n", klass->vname, mod.item); + } + mod = Next(mod); + } + } + Delete(modules); + } + } + + void handleBaseClasses(Node *n) { + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + while (base.item) { + String *basename = Getattr(base.item, "name"); + String *basenamestr = SwigType_namestr(basename); + RClass *super = RCLASS(classes, Char(basenamestr)); + Delete(basenamestr); + if (super) { + SwigType *btype = NewString(basename); + SwigType_add_pointer(btype); + SwigType_remember(btype); + SwigType *smart = Swig_cparse_smartptr(base.item); + if (smart) { + SwigType_add_pointer(smart); + SwigType_remember(smart); + } + String *bmangle = SwigType_manglestr(smart ? smart : btype); + if (multipleInheritance) { + Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); + Append(bmangle, "->clientdata)->mImpl"); + Printv(klass->init, "rb_include_module(", klass->mImpl, ", ", bmangle, ");\n", NIL); + } else { + Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); + Append(bmangle, "->clientdata)->klass"); + Replaceall(klass->init, "$super", bmangle); + } + Delete(bmangle); + Delete(smart); + Delete(btype); + } + base = Next(base); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (!multipleInheritance) { + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, Getfile(n), Getline(n), + "Warning for %s, base %s ignored. Multiple inheritance is not supported in Ruby.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + } + + /** + * Check to see if a %markfunc was specified. + */ + void handleMarkFuncDirective(Node *n) { + String *markfunc = Getattr(n, "feature:markfunc"); + if (markfunc) { + Printf(klass->init, "SwigClass%s.mark = (void (*)(void *)) %s;\n", klass->name, markfunc); + } else { + Printf(klass->init, "SwigClass%s.mark = 0;\n", klass->name); + } + } + + /** + * Check to see if a %freefunc was specified. + */ + void handleFreeFuncDirective(Node *n) { + String *freefunc = Getattr(n, "feature:freefunc"); + if (freefunc) { + Printf(klass->init, "SwigClass%s.destroy = (void (*)(void *)) %s;\n", klass->name, freefunc); + } else { + if (klass->destructor_defined) { + Printf(klass->init, "SwigClass%s.destroy = (void (*)(void *)) free_%s;\n", klass->name, klass->mname); + } + } + } + + /** + * Check to see if tracking is enabled for this class. + */ + void handleTrackDirective(Node *n) { + int trackObjects = GetFlag(n, "feature:trackobjects"); + if (trackObjects) { + Printf(klass->init, "SwigClass%s.trackObjects = 1;\n", klass->name); + } else { + Printf(klass->init, "SwigClass%s.trackObjects = 0;\n", klass->name); + } + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + String* docs = docstring(n, AUTODOC_CLASS); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *namestr = SwigType_namestr(name); // does template expansion + + klass = RCLASS(classes, Char(namestr)); + assert(klass != 0); + Delete(namestr); + String *valid_name = NewString(symname); + validate_const_name(Char(valid_name), "class"); + + Clear(klass->type); + Printv(klass->type, Getattr(n, "classtype"), NIL); + Printv(f_wrappers, "static swig_class SwigClass", valid_name, ";\n\n", NIL); + Printv(klass->init, "\n", tab4, NIL); + + if (!useGlobalModule) { + Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar, ", \"", klass->name, "\", $super);\n", NIL); + } else { + Printv(klass->init, klass->vname, " = rb_define_class(\"", klass->name, + "\", $super);\n", NIL); + } + + if (multipleInheritance) { + Printv(klass->init, klass->mImpl, " = rb_define_module_under(", klass->vname, ", \"Impl\");\n", NIL); + } + + SwigType *tt = NewString(name); + SwigType_add_pointer(tt); + SwigType_remember(tt); + SwigType *smart = Swig_cparse_smartptr(n); + if (smart) { + SwigType_add_pointer(smart); + SwigType_remember(smart); + } + String *tm = SwigType_manglestr(smart ? smart : tt); + Printf(klass->init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) &SwigClass%s);\n", tm, valid_name); + Delete(tm); + Delete(smart); + Delete(tt); + Delete(valid_name); + + includeRubyModules(n); + + Printv(klass->init, "$allocator", NIL); + Printv(klass->init, "$initializer", NIL); + + Language::classHandler(n); + + handleBaseClasses(n); + handleMarkFuncDirective(n); + handleFreeFuncDirective(n); + handleTrackDirective(n); + + if (multipleInheritance) { + Printv(klass->init, "rb_include_module(", klass->vname, ", ", klass->mImpl, ");\n", NIL); + } + + String *s = NewString(""); + Printv(s, tab4, "rb_undef_alloc_func(", klass->vname, ");\n", NIL); + Replaceall(klass->init, "$allocator", s); + Replaceall(klass->init, "$initializer", ""); + + if (GetFlag(n, "feature:exceptionclass")) { + Replaceall(klass->init, "$super", "rb_eRuntimeError"); + } else { + Replaceall(klass->init, "$super", "rb_cObject"); + } + Delete(s); + + Printv(f_init, klass->init, NIL); + klass = 0; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * + * Method for adding C++ member function + * + * By default, we're going to create a function of the form : + * + * Foo_bar(this,args) + * + * Where Foo is the classname, bar is the member name and the this pointer + * is explicitly attached to the beginning. + * + * The renaming only applies to the member function part, not the full + * classname. + * + * --------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + current = MEMBER_FUNC; + + String* docs = docstring(n, AUTODOC_METHOD); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + Language::memberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * constructorHandler() + * + * Method for adding C++ member constructor + * -------------------------------------------------------------------- */ + + void set_director_ctor_code(Node *n) { + /* director ctor code is specific for each class */ + Delete(director_prot_ctor_code); + director_prot_ctor_code = NewString(""); + Node *pn = Swig_methodclass(n); + String *symname = Getattr(pn, "sym:name"); + String *name = Copy(symname); + char *cname = Char(name); + if (cname) + cname[0] = (char)toupper(cname[0]); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " rb_raise(rb_eNameError,\"accessing abstract class or protected constructor\"); \n", " return Qnil;\n", "}\n", NIL); + Delete(director_ctor_code); + director_ctor_code = NewString(""); + Printv(director_ctor_code, "if ( $comparison ) { /* subclassed */\n", " $director_new \n", "} else {\n", " $nondirector_new \n", "}\n", NIL); + Delete(name); + } + + virtual int constructorHandler(Node *n) { + int use_director = Swig_directorclass(n); + if (use_director) { + set_director_ctor_code(n); + } + + /* First wrap the allocate method */ + current = CONSTRUCTOR_ALLOCATE; + Swig_name_register("construct", "%n%c_allocate"); + + Language::constructorHandler(n); + + String* docs = docstring(n, AUTODOC_CTOR); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + /* + * If we're wrapping the constructor of a C++ director class, prepend a new parameter + * to receive the scripting language object (e.g. 'self') + * + */ + Swig_save("ruby:constructorHandler", n, "parms", NIL); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("VALUE"); + self = NewParm(type, name, n); + Delete(type); + Delete(name); + Setattr(self, "lname", "Qnil"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Delete(self); + } + + /* Now do the instance initialize method */ + current = CONSTRUCTOR_INITIALIZE; + Swig_name_register("construct", "new_%n%c"); + Language::constructorHandler(n); + + /* Restore original parameter list */ + Delattr(n, "wrap:self"); + Swig_restore(n); + + /* Done */ + Swig_name_unregister("construct"); + current = NO_CPP; + klass->constructor_defined = 1; + return SWIG_OK; + } + + virtual int copyconstructorHandler(Node *n) { + int use_director = Swig_directorclass(n); + if (use_director) { + set_director_ctor_code(n); + } + + /* First wrap the allocate method */ + current = CONSTRUCTOR_ALLOCATE; + Swig_name_register("construct", "%n%c_allocate"); + + return Language::copyconstructorHandler(n); + } + + + /* --------------------------------------------------------------------- + * destructorHandler() + * -------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + + /* Do no spit free function if user defined his own for this class */ + Node *pn = Swig_methodclass(n); + String *freefunc = Getattr(pn, "feature:freefunc"); + if (freefunc) return SWIG_OK; + + current = DESTRUCTOR; + Language::destructorHandler(n); + + freefunc = NewString(""); + String *freebody = NewString(""); + String *pname0 = Swig_cparm_name(0, 0); + + Printv(freefunc, "free_", klass->mname, NIL); + Printv(freebody, "SWIGINTERN void\n", freefunc, "(void *self) {\n", NIL); + Printv(freebody, tab4, klass->type, " *", pname0, " = (", klass->type, " *)self;\n", NIL); + Printv(freebody, tab4, NIL); + + /* Check to see if object tracking is activated for the class + that owns this destructor. */ + if (GetFlag(pn, "feature:trackobjects")) { + Printf(freebody, "SWIG_RubyRemoveTracking(%s);\n", pname0); + Printv(freebody, tab4, NIL); + } + + if (Extend) { + String *wrap = Getattr(n, "wrap:code"); + if (wrap) { + Printv(f_wrappers, wrap, NIL); + } + /* Printv(freebody, Swig_name_destroy(name), "(", pname0, ")", NIL); */ + Printv(freebody, Getattr(n, "wrap:action"), "\n", NIL); + } else { + String *action = Getattr(n, "wrap:action"); + if (action) { + Printv(freebody, action, "\n", NIL); + } else { + /* In the case swig emits no destroy function. */ + if (CPlusPlus) + Printf(freebody, "delete %s;\n", pname0); + else + Printf(freebody, "free((char*) %s);\n", pname0); + } + } + + Printv(freebody, "}\n\n", NIL); + + Printv(f_wrappers, freebody, NIL); + + klass->destructor_defined = 1; + current = NO_CPP; + Delete(freefunc); + Delete(freebody); + Delete(pname0); + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * membervariableHandler() + * + * This creates a pair of functions to set/get the variable of a member. + * -------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + String* docs = docstring(n, AUTODOC_GETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + if (is_assignable(n)) { + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + } + + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + String* docs = docstring(n, AUTODOC_STATICFUNC); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + current = STATIC_FUNC; + Language::staticmemberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * + * Create a C++ constant + * --------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + String* docs = docstring(n, AUTODOC_STATICFUNC); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + current = CLASS_CONST; + Language::memberconstantHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + String* docs = docstring(n, AUTODOC_GETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + if (is_assignable(n)) { + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + } + + current = STATIC_VAR; + Language::staticmembervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* C++ director class generation */ + virtual int classDirector(Node *n) { + return Language::classDirector(n); + } + + virtual int classDirectorInit(Node *n) { + String *declaration; + declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + virtual int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + virtual int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("VALUE"); + p = NewParm(type, NewString("self"), n); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + virtual int classDirectorDefaultConstructor(Node *n) { + String *classname; + Wrapper *w; + classname = Swig_class_name(n); + w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(VALUE self) : Swig::Director(self) { }", classname, classname); + Wrapper_print(w, f_directors); + DelWrapper(w); + Printf(f_directors_h, " SwigDirector_%s(VALUE self);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + /* --------------------------------------------------------------- + * exceptionSafeMethodCall() + * + * Emit a virtual director method to pass a method call on to the + * underlying Ruby instance. + * + * --------------------------------------------------------------- */ + + void exceptionSafeMethodCall(String *className, Node *n, Wrapper *w, int argc, String *args, bool initstack) { + Wrapper *body = NewWrapper(); + Wrapper *rescue = NewWrapper(); + + String *methodName = Getattr(n, "sym:name"); + + String *bodyName = NewStringf("%s_%s_body", className, methodName); + String *rescueName = NewStringf("%s_%s_rescue", className, methodName); + String *depthCountName = NewStringf("%s_%s_call_depth", className, methodName); + + // Check for an exception typemap of some kind + String *tm = Swig_typemap_lookup("director:except", n, Swig_cresult_name(), 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + } + + if ((tm != 0) && (Len(tm) > 0) && (Strcmp(tm, "1") != 0)) { + // Declare a global to hold the depth count + if (!Getattr(n, "sym:nextSibling")) { + Printf(body->def, "static int %s = 0;\n", depthCountName); + + // Function body + Printf(body->def, "VALUE %s(VALUE data) {\n", bodyName); + Wrapper_add_localv(body, "args", "Swig::body_args *", "args", "= reinterpret_cast<Swig::body_args *>(data)", NIL); + Wrapper_add_localv(body, Swig_cresult_name(), "VALUE", Swig_cresult_name(), "= Qnil", NIL); + Printf(body->code, "%s++;\n", depthCountName); + Printv(body->code, Swig_cresult_name(), " = rb_funcall2(args->recv, args->id, args->argc, args->argv);\n", NIL); + Printf(body->code, "%s--;\n", depthCountName); + Printv(body->code, "return ", Swig_cresult_name(), ";\n", NIL); + Printv(body->code, "}", NIL); + + // Exception handler + Printf(rescue->def, "VALUE %s(VALUE args, VALUE error) {\n", rescueName); + Replaceall(tm, "$error", "error"); + Printf(rescue->code, "%s--;\n", depthCountName); + Printf(rescue->code, "if (%s == 0) ", depthCountName); + Printv(rescue->code, Str(tm), "\n", NIL); + Printv(rescue->code, "rb_exc_raise(error);\n", NIL); + Printv(rescue->code, "return Qnil;\n", NIL); + Printv(rescue->code, "}", NIL); + } + + // Main code + Wrapper_add_localv(w, "args", "Swig::body_args", "args", NIL); + Wrapper_add_localv(w, "status", "int", "status", NIL); + Printv(w->code, "args.recv = swig_get_self();\n", NIL); + Printf(w->code, "args.id = rb_intern(\"%s\");\n", methodName); + Printf(w->code, "args.argc = %d;\n", argc); + if (argc > 0) { + Printf(w->code, "args.argv = new VALUE[%d];\n", argc); + for (int i = 0; i < argc; i++) { + Printf(w->code, "args.argv[%d] = obj%d;\n", i, i); + } + } else { + Printv(w->code, "args.argv = 0;\n", NIL); + } + Printf(w->code, "%s = rb_protect(PROTECTFUNC(%s), reinterpret_cast<VALUE>(&args), &status);\n", Swig_cresult_name(), bodyName); + if ( initstack ) Printf(w->code, "SWIG_RELEASE_STACK;\n"); + Printf(w->code, "if (status) {\n"); + Printf(w->code, "VALUE lastErr = rb_gv_get(\"$!\");\n"); + Printf(w->code, "%s(reinterpret_cast<VALUE>(&args), lastErr);\n", rescueName); + Printf(w->code, "}\n"); + if (argc > 0) { + Printv(w->code, "delete [] args.argv;\n", NIL); + } + // Dump wrapper code + Wrapper_print(body, f_directors_helpers); + Wrapper_print(rescue, f_directors_helpers); + } else { + if (argc > 0) { + Printf(w->code, "%s = rb_funcall(swig_get_self(), rb_intern(\"%s\"), %d%s);\n", Swig_cresult_name(), methodName, argc, args); + } else { + Printf(w->code, "%s = rb_funcall(swig_get_self(), rb_intern(\"%s\"), 0, Qnil);\n", Swig_cresult_name(), methodName); + } + if ( initstack ) Printf(w->code, "SWIG_RELEASE_STACK;\n"); + } + + // Clean up + Delete(bodyName); + Delete(rescueName); + Delete(depthCountName); + DelWrapper(body); + DelWrapper(rescue); + } + + virtual int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl = Getattr(n, "decl"); + String *name = Getattr(n, "name"); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *symname = Getattr(n, "sym:name"); + String *declaration = NewString(""); + ParmList *l = Getattr(n, "parms"); + Wrapper *w = NewWrapper(); + String *tm; + String *wrap_args = NewString(""); + String *returntype = Getattr(n, "type"); + Parm *p; + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + bool asvoid = checkAttribute( n, "feature:numoutputs", "0") ? true : false; + bool initstack = checkAttribute( n, "feature:initstack", "1") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + String *overnametmp = NewString(Getattr(n, "sym:name")); + if (Getattr(n, "sym:overloaded")) { + Printf(overnametmp, "::%s", Getattr(n, "sym:overname")); + } + + /* determine if the method returns a pointer */ + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(returntype, "void") && !is_pointer); + + /* virtual method definition */ + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + 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); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + if (Getattr(n, "noexcept")) { + Append(w->def, " noexcept"); + Append(declaration, " noexcept"); + } + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + 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"); + + if (initstack && !(ignored_method && !pure_virtual)) { + Append(w->def, "\nSWIG_INIT_STACK;\n"); + } + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($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 { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } + } else { + String *cres = SwigType_lstr(returntype, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> Ruby) */ + String *arglist = NewString(""); + + Swig_director_parms_fixup(l); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, w); + Swig_typemap_attach_parms("directorargout", l, w); + + char source[256]; + + int outputs = 0; + if (!is_void && !asvoid) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; p = l; + while ( p ) { + + if (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + continue; + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + if ( checkAttribute( p, "tmap:in:numinputs", "0") ) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + String *parameterName = Getattr(p, "name"); + String *parameterType = Getattr(p, "type"); + + Putc(',', arglist); + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + sprintf(source, "obj%d", idx++); + String *input = NewString(source); + Setattr(p, "emit:directorinput", input); + Replaceall(tm, "$input", input); + Replaceall(tm, "$owner", "0"); + Delete(input); + Printv(wrap_args, tm, "\n", NIL); + Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); + Printv(arglist, source, NIL); + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(parameterType, "void")) { + /** + * Special handling for pointers to other C++ director classes. + * Ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. In other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. We avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. Perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(parameterType) || SwigType_isreference(parameterType)) { + Node *modname = Getattr(parent, "module"); + Node *target = Swig_directormap(modname, parameterType); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(parameterType) + 2); + /* name as pointer */ + String *ppname = Copy(parameterName); + if (SwigType_isreference(parameterType)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Ruby doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", parameterName); + String *nonconst_i = NewStringf("= const_cast< %s >(%s)", SwigType_lstr(parameterType, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(parameterType, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(parameterType, parameterName), + SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(parameterType); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); + Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Printf(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "}\n"); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(parameterType, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + /* declare Ruby return value */ + String *value_result = NewStringf("VALUE SWIGUNUSED %s", Swig_cresult_name()); + Wrapper_add_local(w, Swig_cresult_name(), value_result); + Delete(value_result); + + /* wrap complex arguments to VALUEs */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Ruby object */ + exceptionSafeMethodCall(classname, n, w, idx, arglist, initstack); + + /* + * Ruby method may return a simple object, or an Array of objects. + * For in/out arguments, we have to extract the appropriate VALUEs from the Array, + * then marshal everything back to C/C++ (return value and output arguments). + */ + + /* Marshal return value and other outputs (if any) from VALUE to C/C++ type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + if (outputs > 1) { + Wrapper_add_local(w, "output", "VALUE output"); + Printf(w->code, "if (TYPE(%s) != T_ARRAY) {\n", Swig_cresult_name()); + Printf(w->code, "Ruby_DirectorTypeMismatchException(\"Ruby method failed to return an array.\");\n"); + Printf(w->code, "}\n"); + } + + idx = 0; + + /* Marshal return value */ + if (!is_void) { + tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); + if (tm != 0) { + if (outputs > 1 && !asvoid ) { + Printf(w->code, "output = rb_ary_entry(%s, %d);\n", Swig_cresult_name(), idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", Swig_cresult_name()); + } + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(returntype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* Marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + if (outputs > 1) { + Printf(w->code, "output = rb_ary_entry(%s, %d);\n", Swig_cresult_name(), idx++); + Replaceall(tm, "$result", "output"); + } else { + Replaceall(tm, "$result", Swig_cresult_name()); + } + Replaceall(tm, "$input", Getattr(p, "emit:directorinput")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(arglist); + Delete(cleanup); + Delete(outarg); + } + + /* any existing helper functions to handle this? */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(returntype, 0); + if (!SwigType_isreference(returntype)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Printf(w->code, "}\n"); + + // We expose 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) { + 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); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(pclassname); + DelWrapper(w); + return status; + } + + virtual int classDirectorConstructors(Node *n) { + return Language::classDirectorConstructors(n); + } + + virtual int classDirectorMethods(Node *n) { + return Language::classDirectorMethods(n); + } + + virtual int classDirectorDisown(Node *n) { + return Language::classDirectorDisown(n); + } + + String *runtimeCode() { + String *s = NewString(""); + String *shead = Swig_include_sys("rubyhead.swg"); + if (!shead) { + Printf(stderr, "*** Unable to open 'rubyhead.swg'\n"); + } else { + Append(s, shead); + Delete(shead); + } + String *serrors = Swig_include_sys("rubyerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'rubyerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *strack = Swig_include_sys("rubytracking.swg"); + if (!strack) { + Printf(stderr, "*** Unable to open 'rubytracking.swg'\n"); + } else { + Append(s, strack); + Delete(strack); + } + String *sapi = Swig_include_sys("rubyapi.swg"); + if (!sapi) { + Printf(stderr, "*** Unable to open 'rubyapi.swg'\n"); + } else { + Append(s, sapi); + Delete(sapi); + } + String *srun = Swig_include_sys("rubyrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'rubyrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigrubyrun.h"); + } + + /*---------------------------------------------------------------------- + * kwargsSupport() + *--------------------------------------------------------------------*/ + + bool kwargsSupport() const { + // kwargs support isn't actually implemented, but changing to return false may break something now as it turns on compactdefaultargs + return true; + } +}; /* class RUBY */ + +/* ----------------------------------------------------------------------------- + * swig_ruby() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_ruby() { + return new RUBY(); +} +extern "C" Language *swig_ruby(void) { + return new_swig_ruby(); +} + + +/* + * Local Variables: + * c-basic-offset: 2 + * End: + */ diff --git a/contrib/tools/swig/Source/Modules/scilab.cxx b/contrib/tools/swig/Source/Modules/scilab.cxx new file mode 100644 index 00000000000..23e45f78757 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/scilab.cxx @@ -0,0 +1,1156 @@ +/* ---------------------------------------------------------------------------- + * 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. + * + * scilab.cxx + * + * Scilab language module for SWIG. + * --------------------------------------------------------------------------*/ + +#include "swigmod.h" + +static const int SCILAB_IDENTIFIER_NAME_CHAR_MAX = 24; +static const int SCILAB_VARIABLE_NAME_CHAR_MAX = SCILAB_IDENTIFIER_NAME_CHAR_MAX - 4; + +static const char *usage = (char *) " \ +Scilab options (available with -scilab)\n \ + -builder - Generate a Scilab builder script\n \ + -buildercflags <cflags> - Add <cflags> to the builder compiler flags\n \ + -builderflagscript <file> - Set the Scilab script <file> to use by builder to configure the build flags\n \ + -builderldflags <ldflags> - Add <ldflags> to the builder linker flags\n \ + -buildersources <files> - Add the (comma separated) files <files> to the builder sources\n \ + -builderverbositylevel <level> - Set the builder verbosity level to <level> (default 0: off, 2: high)\n \ + -gatewayxml <gateway_id> - Generate gateway xml with the given <gateway_id>\n \ + -targetversion <scilab_major_version> - Generate for Scilab target (major) version (default: 5)\n \ +\n"; + + +class SCILAB:public Language { +protected: + /* General objects used for holding the strings */ + File *beginSection; + File *runtimeSection; + File *headerSection; + File *wrappersSection; + File *initSection; + + String *variablesCode; + + int targetVersion; + + bool generateBuilder; + File *builderFile; + String *builderCode; + int builderFunctionCount; + + List *sourceFileList; + List *cflags; + List *ldflags; + + String *verboseBuildLevel; + String *buildFlagsScript; + + String *gatewayHeader; + String *gatewayHeaderV5; + String *gatewayHeaderV6; + + bool createGatewayXML; + File *gatewayXMLFile; + String *gatewayXML; + String *gatewayID; + int primitiveID; + + bool createLoader; + File *loaderFile; + String *loaderScript; +public: + + /* ------------------------------------------------------------------------ + * main() + * ----------------------------------------------------------------------*/ + + virtual void main(int argc, char *argv[]) { + targetVersion = 5; + + generateBuilder = false; + sourceFileList = NewList(); + cflags = NewList(); + ldflags = NewList(); + verboseBuildLevel = NULL; + buildFlagsScript = NULL; + + gatewayHeader = NULL; + gatewayHeaderV5 = NULL; + gatewayHeaderV6 = NULL; + + createGatewayXML = false; + gatewayXML = NULL; + gatewayXMLFile = NULL; + gatewayID = NULL; + + createLoader = true; + loaderFile = NULL; + loaderScript = NULL; + + /* Manage command line arguments */ + for (int argIndex = 1; argIndex < argc; argIndex++) { + if (argv[argIndex] != NULL) { + if (strcmp(argv[argIndex], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } else if (strcmp(argv[argIndex], "-builder") == 0) { + Swig_mark_arg(argIndex); + generateBuilder = true; + createLoader = false; + } else if (strcmp(argv[argIndex], "-buildersources") == 0) { + if (argv[argIndex + 1] != NULL) { + Swig_mark_arg(argIndex); + char *sourceFile = strtok(argv[argIndex + 1], ","); + while (sourceFile != NULL) { + Insert(sourceFileList, Len(sourceFileList), sourceFile); + sourceFile = strtok(NULL, ","); + } + Swig_mark_arg(argIndex + 1); + } + } else if (strcmp(argv[argIndex], "-buildercflags") == 0) { + Swig_mark_arg(argIndex); + if (argv[argIndex + 1] != NULL) { + Insert(cflags, Len(cflags), argv[argIndex + 1]); + Swig_mark_arg(argIndex + 1); + } + } else if (strcmp(argv[argIndex], "-builderldflags") == 0) { + Swig_mark_arg(argIndex); + if (argv[argIndex + 1] != NULL) { + Insert(ldflags, Len(ldflags), argv[argIndex + 1]); + Swig_mark_arg(argIndex + 1); + } + } else if (strcmp(argv[argIndex], "-builderverbositylevel") == 0) { + Swig_mark_arg(argIndex); + verboseBuildLevel = NewString(argv[argIndex + 1]); + Swig_mark_arg(argIndex + 1); + } else if (strcmp(argv[argIndex], "-builderflagscript") == 0) { + Swig_mark_arg(argIndex); + buildFlagsScript = NewString(argv[argIndex + 1]); + Swig_mark_arg(argIndex + 1); + } else if (strcmp(argv[argIndex], "-gatewayxml") == 0) { + Swig_mark_arg(argIndex); + createGatewayXML = true; + gatewayID = NewString(argv[argIndex + 1]); + Swig_mark_arg(argIndex + 1); + } else if (strcmp(argv[argIndex], "-targetversion") == 0) { + if (argv[argIndex + 1] != NULL) { + Swig_mark_arg(argIndex); + targetVersion = atoi(argv[argIndex + 1]); + Swig_mark_arg(argIndex + 1); + } + } + } + } + + if (verboseBuildLevel == NULL) { + verboseBuildLevel = NewString("0"); + } + + /* Set language-specific subdirectory in SWIG library */ + SWIG_library_directory("scilab"); + + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGSCILAB 1", 0); + + /* Set scilab configuration file */ + SWIG_config_file("scilab.swg"); + + /* Set typemap for scilab */ + SWIG_typemap_lang("scilab"); + + allow_overloading(); + } + + /* ------------------------------------------------------------------------ + * top() + * ----------------------------------------------------------------------*/ + + virtual int top(Node *node) { + + /* Get the module name */ + String *gatewayName = Getattr(node, "name"); + + // Set library name + String *gatewayLibraryName = NewStringf("lib%s", gatewayName); + + /* Get the output file name */ + String *outputFilename = Getattr(node, "outfile"); + + /* Initialize I/O */ + beginSection = NewFile(outputFilename, "w", SWIG_output_files()); + if (!beginSection) { + FileErrorDisplay(outputFilename); + SWIG_exit(EXIT_FAILURE); + } + runtimeSection = NewString(""); + initSection = NewString(""); + headerSection = NewString(""); + wrappersSection = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("begin", beginSection); + Swig_register_filebyname("header", headerSection); + Swig_register_filebyname("wrapper", wrappersSection); + Swig_register_filebyname("runtime", runtimeSection); + Swig_register_filebyname("init", initSection); + + /* Output module initialization code */ + Swig_banner(beginSection); + + Printf(runtimeSection, "\n\n#ifndef SWIGSCILAB\n#define SWIGSCILAB\n#endif\n\n"); + + // Gateway header source merged with wrapper source in nobuilder mode + if (!generateBuilder) + startGatewayHeader(gatewayLibraryName); + + // Create builder file if required + if (generateBuilder) { + createBuilderFile(outputFilename); + } + + // Create gateway XML if required + if (createGatewayXML) { + createGatewayXMLFile(gatewayName); + } + + // Create loader script if required + if (createLoader) { + createLoaderFile(gatewayLibraryName); + } + + // Module initialization function + String *gatewayInitFunctionName = NewStringf("%s_Init", gatewayName); + + /* Add initialization function to builder table */ + addFunctionToScilab(gatewayInitFunctionName, gatewayInitFunctionName); + + // Add helper functions to builder table + addHelperFunctions(); + + // Open Scilab wrapper variables creation function + variablesCode = NewString(""); + Printf(variablesCode, "int SWIG_CreateScilabVariables(void *_pvApiCtx) {"); + + /* Emit code for children */ + if (CPlusPlus) { + Printf(wrappersSection, "extern \"C\" {\n"); + } + + Language::top(node); + + if (CPlusPlus) { + Printf(wrappersSection, "}\n"); + } + // Close Scilab wrapper variables creation function + Printf(variablesCode, " return SWIG_OK;\n}\n"); + + // Add Builder footer code and save + if (generateBuilder) { + saveBuilderFile(gatewayName); + } + + /* Close the init function and rename with module name */ + Printf(initSection, "return 0;\n}\n"); + Replaceall(initSection, "<module>", gatewayName); + + /* Write all to the wrapper file */ + SwigType_emit_type_table(runtimeSection, wrappersSection); // Declare pointer types, ... (Ex: SWIGTYPE_p_p_double) + + // Gateway header source merged with wrapper source in nobuilder mode + if (!generateBuilder) { + terminateGatewayHeader(gatewayLibraryName); + Printv(initSection, gatewayHeader, NIL); + } + + Dump(runtimeSection, beginSection); + Dump(headerSection, beginSection); + Dump(wrappersSection, beginSection); + Dump(variablesCode, beginSection); + Wrapper_pretty_print(initSection, beginSection); + + if (createGatewayXML) { + saveGatewayXMLFile(); + } + + if (createLoader) { + saveLoaderFile(gatewayLibraryName); + } + + /* Cleanup files */ + Delete(runtimeSection); + Delete(headerSection); + Delete(wrappersSection); + Delete(initSection); + Delete(beginSection); + + Delete(sourceFileList); + Delete(cflags); + Delete(ldflags); + + return SWIG_OK; + } + + /* ------------------------------------------------------------------------ + * emitBanner() + * ----------------------------------------------------------------------*/ + + void emitBanner(File *f) { + Printf(f, "// ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, "// "); + Printf(f, "// ----------------------------------------------------------------------------- */\n\n"); + } + + /* ------------------------------------------------------------------------ + * functionWrapper() + * ----------------------------------------------------------------------*/ + + virtual int functionWrapper(Node *node) { + + /* Get some useful attributes of this function */ + String *functionName = Getattr(node, "sym:name"); + SwigType *functionReturnType = Getattr(node, "type"); + ParmList *functionParamsList = Getattr(node, "parms"); + + int paramIndex = 0; // Used for loops over ParmsList + Parm *param = NULL; // Used for loops over ParamsList + + /* Create the wrapper object */ + Wrapper *wrapper = NewWrapper(); + + /* Create the function wrapper name */ + String *wrapperName = Swig_name_wrapper(functionName); + + /* Deal with overloading */ + String *overloadedName = Copy(wrapperName); + /* Determine whether the function is overloaded or not */ + bool isOverloaded = ! !Getattr(node, "sym:overloaded"); + /* Determine whether the function is the last overloaded */ + bool isLastOverloaded = isOverloaded && !Getattr(node, "sym:nextSibling"); + + if (!isOverloaded && !addSymbol(functionName, node)) { + DelWrapper(wrapper); + return SWIG_ERROR; + } + + if (isOverloaded) { + Append(overloadedName, Getattr(node, "sym:overname")); + } + + /* Write the wrapper function definition (standard Scilab gateway function prototype) */ + Printv(wrapper->def, "int ", overloadedName, "(SWIG_GatewayParameters) {", NIL); + + /* Emit all of the local variables for holding arguments */ + // E.g.: double arg1; + emit_parameter_variables(functionParamsList, wrapper); + + /* Attach typemaps to the parameter list */ + // Add local variables used in typemaps (iRows, iCols, ...) + emit_attach_parmmaps(functionParamsList, wrapper); + Setattr(node, "wrap:parms", functionParamsList); + + /* Check input/output arguments count */ + int maxInputArguments = emit_num_arguments(functionParamsList); + int minInputArguments = emit_num_required(functionParamsList); + int minOutputArguments = 0; + int maxOutputArguments = 0; + + if (!emit_isvarargs(functionParamsList)) { + Printf(wrapper->code, "SWIG_CheckInputArgument(pvApiCtx, $mininputarguments, $maxinputarguments);\n"); + } + else { + Printf(wrapper->code, "SWIG_CheckInputArgumentAtLeast(pvApiCtx, $mininputarguments-1);\n"); + } + Printf(wrapper->code, "SWIG_CheckOutputArgument(pvApiCtx, $minoutputarguments, $maxoutputarguments);\n"); + + /* Set context */ + Printf(wrapper->code, "SWIG_Scilab_SetFuncName(fname);\n"); + Printf(wrapper->code, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + + /* Write typemaps(in) */ + + for (paramIndex = 0, param = functionParamsList; paramIndex < maxInputArguments; ++paramIndex) { + // Ignore parameter if the typemap specifies numinputs=0 + while (checkAttribute(param, "tmap:in:numinputs", "0")) { + param = Getattr(param, "tmap:in:next"); + } + + SwigType *paramType = Getattr(param, "type"); + String *paramTypemap = Getattr(param, "tmap:in"); + + if (paramTypemap) { + // Replace $input by the position on Scilab stack + String *source = NewString(""); + Printf(source, "%d", paramIndex + 1); + Setattr(param, "emit:input", source); + Replaceall(paramTypemap, "$input", Getattr(param, "emit:input")); + + if (Getattr(param, "wrap:disown") || (Getattr(param, "tmap:in:disown"))) { + Replaceall(paramTypemap, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(paramTypemap, "$disown", "0"); + } + + if (paramIndex >= minInputArguments) { /* Optional input argument management */ + Printf(wrapper->code, "if (SWIG_NbInputArgument(pvApiCtx) > %d) {\n%s\n}\n", paramIndex, paramTypemap); + } else { + Printf(wrapper->code, "%s\n", paramTypemap); + } + param = Getattr(param, "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(paramType, 0)); + break; + } + } + + /* TODO write constraints */ + + Setattr(node, "wrap:name", overloadedName); + + /* Emit the function call */ + Swig_director_emit_dynamic_cast(node, wrapper); + String *functionActionCode = emit_action(node); + + /* Insert the return variable */ + emit_return_variable(node, functionReturnType, wrapper); + + /* Return the function value if necessary */ + String *functionReturnTypemap = Swig_typemap_lookup_out("out", node, Swig_cresult_name(), wrapper, functionActionCode); + if (functionReturnTypemap) { + // Result is actually the position of output value on stack + if (Len(functionReturnTypemap) > 0) { + Printf(wrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", 1); + } + Replaceall(functionReturnTypemap, "$result", "1"); + + if (GetFlag(node, "feature:new")) { + Replaceall(functionReturnTypemap, "$owner", "1"); + } else { + Replaceall(functionReturnTypemap, "$owner", "0"); + } + + Printf(wrapper->code, "%s\n", functionReturnTypemap); + + /* If the typemap is not empty, the function return one more argument than the typemaps gives */ + if (Len(functionReturnTypemap) > 0) { + minOutputArguments++; + maxOutputArguments++; + } + Delete(functionReturnTypemap); + + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(functionReturnType, 0), + functionName); + } + + /* Write typemaps(out) */ + for (param = functionParamsList; param;) { + String *paramTypemap = Getattr(param, "tmap:argout"); + if (paramTypemap) { + minOutputArguments++; + maxOutputArguments++; + Printf(wrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", minOutputArguments); + String *result = NewString(""); + Printf(result, "%d", minOutputArguments); + Replaceall(paramTypemap, "$result", result); + Printf(wrapper->code, "%s\n", paramTypemap); + Delete(paramTypemap); + param = Getattr(param, "tmap:argout:next"); + } else { + param = nextSibling(param); + } + } + /* Add cleanup code */ + for (param = functionParamsList; param;) { + String *tm; + if ((tm = Getattr(param, "tmap:freearg"))) { + if (tm && (Len(tm) != 0)) { + Replaceall(tm, "$source", Getattr(param, "lname")); + Printf(wrapper->code, "%s\n", tm); + } + param = Getattr(param, "tmap:freearg:next"); + } else { + param = nextSibling(param); + } + } + + /* See if there is any return cleanup code */ + String *tm; + if ((tm = Swig_typemap_lookup("ret", node, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(wrapper->code, "%s\n", tm); + Delete(tm); + } + + /* Close the function(ok) */ + Printv(wrapper->code, "return SWIG_OK;\n", NIL); + Printv(wrapper->code, "}\n", NIL); + + /* Add the failure cleanup code */ + /* TODO */ + + /* Final substitutions if applicable */ + Replaceall(wrapper->code, "$symname", functionName); + + /* Set CheckInputArgument and CheckOutputArgument input arguments */ + /* In Scilab there is always one output even if not defined */ + if (minOutputArguments == 0) { + maxOutputArguments = 1; + } + String *argnumber = NewString(""); + Printf(argnumber, "%d", minInputArguments); + Replaceall(wrapper->code, "$mininputarguments", argnumber); + + argnumber = NewString(""); + Printf(argnumber, "%d", maxInputArguments); + Replaceall(wrapper->code, "$maxinputarguments", argnumber); + + argnumber = NewString(""); + Printf(argnumber, "%d", minOutputArguments); + Replaceall(wrapper->code, "$minoutputarguments", argnumber); + + argnumber = NewString(""); + Printf(argnumber, "%d", maxOutputArguments); + Replaceall(wrapper->code, "$maxoutputarguments", argnumber); + + /* Dump the function out */ + Wrapper_print(wrapper, wrappersSection); + + String *scilabFunctionName = checkIdentifierName(functionName, SCILAB_IDENTIFIER_NAME_CHAR_MAX); + + /* Update builder.sce contents */ + if (isLastOverloaded) { + addFunctionToScilab(scilabFunctionName, wrapperName); + dispatchFunction(node); + } + + if (!isOverloaded) { + addFunctionToScilab(scilabFunctionName, wrapperName); + } + + /* tidy up */ + Delete(overloadedName); + Delete(wrapperName); + DelWrapper(wrapper); + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * dispatchFunction() + * ----------------------------------------------------------------------- */ + + void dispatchFunction(Node *node) { + Wrapper *wrapper = NewWrapper(); + + String *functionName = Getattr(node, "sym:name"); + String *wrapperName = Swig_name_wrapper(functionName); + int maxargs = 0; + + /* Generate the dispatch function */ + String *dispatch = Swig_overload_dispatch(node, "return %s(SWIG_GatewayArguments);", &maxargs); + String *tmp = NewString(""); + + Printv(wrapper->def, "int ", wrapperName, "(SWIG_GatewayParameters) {\n", NIL); + + /* Get the number of the parameters */ + Wrapper_add_local(wrapper, "argc", "int argc = SWIG_NbInputArgument(pvApiCtx)"); + Printf(tmp, "int argv[%d] = {", maxargs); + for (int j = 0; j < maxargs; ++j) { + Printf(tmp, "%s%d", j ? "," : " ", j + 1); + } + Printf(tmp, "}"); + Wrapper_add_local(wrapper, "argv", tmp); + + Printf(wrapper->code, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + + /* Dump the dispatch function */ + Printv(wrapper->code, dispatch, "\n", NIL); + Printf(wrapper->code, "Scierror(999, _(\"No matching function for overload\"));\n"); + Printf(wrapper->code, "return SWIG_ERROR;\n"); + Printv(wrapper->code, "}\n", NIL); + Wrapper_print(wrapper, wrappersSection); + + Delete(tmp); + DelWrapper(wrapper); + Delete(dispatch); + Delete(wrapperName); + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *node) { + + /* Get information about variable */ + String *origVariableName = Getattr(node, "name"); // Ex: Shape::nshapes + String *variableName = Getattr(node, "sym:name"); // Ex; Shape_nshapes (can be used for function names, ...) + + // Variable names can have SCILAB_VARIABLE_NAME_CHAR_MAX because of suffixes "_get" or "_set" added to function + String *scilabVariableName = checkIdentifierName(variableName, SCILAB_VARIABLE_NAME_CHAR_MAX); + + /* Manage GET function */ + Wrapper *getFunctionWrapper = NewWrapper(); + String *getFunctionName = Swig_name_get(NSPACE_TODO, variableName); + String *scilabGetFunctionName = Swig_name_get(NSPACE_TODO, scilabVariableName); + + Setattr(node, "wrap:name", getFunctionName); + Printv(getFunctionWrapper->def, "int ", getFunctionName, "(SWIG_GatewayParameters) {\n", NIL); + + /* Check the number of input and output */ + Printf(getFunctionWrapper->def, "SWIG_CheckInputArgument(pvApiCtx, 0, 0);\n"); + Printf(getFunctionWrapper->def, "SWIG_CheckOutputArgument(pvApiCtx, 1, 1);\n"); + Printf(getFunctionWrapper->def, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + + String *varoutTypemap = Swig_typemap_lookup("varout", node, origVariableName, 0); + if (varoutTypemap != NULL) { + Printf(getFunctionWrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", 1); + Replaceall(varoutTypemap, "$value", origVariableName); + Replaceall(varoutTypemap, "$result", "1"); + emit_action_code(node, getFunctionWrapper->code, varoutTypemap); + Delete(varoutTypemap); + } + Append(getFunctionWrapper->code, "return SWIG_OK;\n"); + Append(getFunctionWrapper->code, "}\n"); + Wrapper_print(getFunctionWrapper, wrappersSection); + + /* Add function to builder table */ + addFunctionToScilab(scilabGetFunctionName, getFunctionName); + + /* Manage SET function */ + if (is_assignable(node)) { + Wrapper *setFunctionWrapper = NewWrapper(); + String *setFunctionName = Swig_name_set(NSPACE_TODO, variableName); + String *scilabSetFunctionName = Swig_name_set(NSPACE_TODO, scilabVariableName); + + Setattr(node, "wrap:name", setFunctionName); + Printv(setFunctionWrapper->def, "int ", setFunctionName, "(SWIG_GatewayParameters) {\n", NIL); + + /* Check the number of input and output */ + Printf(setFunctionWrapper->def, "SWIG_CheckInputArgument(pvApiCtx, 1, 1);\n"); + Printf(setFunctionWrapper->def, "SWIG_CheckOutputArgument(pvApiCtx, 1, 1);\n"); + Printf(setFunctionWrapper->def, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + + String *varinTypemap = Swig_typemap_lookup("varin", node, origVariableName, 0); + if (varinTypemap != NULL) { + Replaceall(varinTypemap, "$input", "1"); + emit_action_code(node, setFunctionWrapper->code, varinTypemap); + Delete(varinTypemap); + } + Append(setFunctionWrapper->code, "return SWIG_OK;\n"); + Append(setFunctionWrapper->code, "}\n"); + Wrapper_print(setFunctionWrapper, wrappersSection); + + /* Add function to builder table */ + addFunctionToScilab(scilabSetFunctionName, setFunctionName); + + DelWrapper(setFunctionWrapper); + } + DelWrapper(getFunctionWrapper); + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * ----------------------------------------------------------------------- */ + + virtual int constantWrapper(Node *node) { + + /* Get the useful information from the node */ + String *nodeName = Getattr(node, "name"); + SwigType *type = Getattr(node, "type"); + String *constantName = Getattr(node, "sym:name"); + String *rawValue = Getattr(node, "rawval"); + String *constantValue = rawValue ? rawValue : Getattr(node, "value"); + String *constantTypemap = NULL; + + // If feature scilab:const enabled, constants & enums are wrapped to Scilab variables + if (GetFlag(node, "feature:scilab:const")) { + bool isConstant = ((SwigType_issimple(type)) || (SwigType_type(type) == T_STRING)); + bool isEnum = (Cmp(nodeType(node), "enumitem") == 0); + + if (isConstant || isEnum) { + if (isEnum) { + Setattr(node, "type", "double"); + constantValue = Getattr(node, "value"); + } + + constantTypemap = Swig_typemap_lookup("scilabconstcode", node, nodeName, 0); + if (constantTypemap != NULL) { + String *scilabConstantName = checkIdentifierName(constantName, SCILAB_IDENTIFIER_NAME_CHAR_MAX); + + Setattr(node, "wrap:name", constantName); + Replaceall(constantTypemap, "$result", scilabConstantName); + Replaceall(constantTypemap, "$value", constantValue); + + emit_action_code(node, variablesCode, constantTypemap); + Delete(constantTypemap); + return SWIG_OK; + } + } + } + + /* Create variables for member pointer constants, not supported by typemaps (like Python wrapper does) */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(constantName); + String *str = SwigType_str(type, wname); + Printf(headerSection, "static %s = %s;\n", str, constantValue); + Delete(str); + constantValue = wname; + } + // Constant names can have SCILAB_VARIABLE_NAME_CHAR_MAX because of suffixes "_get" added to function + String *scilabConstantName = checkIdentifierName(constantName, SCILAB_VARIABLE_NAME_CHAR_MAX); + + /* Create GET function to get the constant value */ + Wrapper *getFunctionWrapper = NewWrapper(); + String *getFunctionName = Swig_name_get(NSPACE_TODO, constantName); + String *scilabGetFunctionName = Swig_name_get(NSPACE_TODO, scilabConstantName); + Setattr(node, "wrap:name", getFunctionName); + Printv(getFunctionWrapper->def, "int ", getFunctionName, "(SWIG_GatewayParameters) {\n", NIL); + + /* Check the number of input and output */ + Printf(getFunctionWrapper->def, "SWIG_CheckInputArgument(pvApiCtx, 0, 0);\n"); + Printf(getFunctionWrapper->def, "SWIG_CheckOutputArgument(pvApiCtx, 1, 1);\n"); + Printf(getFunctionWrapper->def, "SWIG_Scilab_SetApiContext(pvApiCtx);\n"); + + constantTypemap = Swig_typemap_lookup("constcode", node, nodeName, 0); + if (constantTypemap != NULL) { + Printf(getFunctionWrapper->code, "SWIG_Scilab_SetOutputPosition(%d);\n", 1); + Replaceall(constantTypemap, "$value", constantValue); + Replaceall(constantTypemap, "$result", "1"); + emit_action_code(node, getFunctionWrapper->code, constantTypemap); + Delete(constantTypemap); + } + + /* Dump the wrapper function */ + Append(getFunctionWrapper->code, "return SWIG_OK;\n"); + Append(getFunctionWrapper->code, "}\n"); + Wrapper_print(getFunctionWrapper, wrappersSection); + + /* Add the function to Scilab */ + addFunctionToScilab(scilabGetFunctionName, getFunctionName); + + DelWrapper(getFunctionWrapper); + + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * enumvalueDeclaration() + * --------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *node) { + static int iPreviousEnumValue = 0; + + if (GetFlag(node, "feature:scilab:const")) { + // Compute the "absolute" value of enum if needed + // (most of time enum values are a linked list of relative values) + String *enumValue = Getattr(node, "enumvalue"); + String *enumValueEx = Getattr(node, "enumvalueex"); + + // First enum value ? + String *firstenumitem = Getattr(node, "firstenumitem"); + if (firstenumitem) { + if (enumValue) { + // Value is in 'enumvalue' + iPreviousEnumValue = atoi(Char(enumValue)); + } else if (enumValueEx) { + // Or value is in 'enumValueEx' + iPreviousEnumValue = atoi(Char(enumValueEx)); + + enumValue = NewString(""); + Printf(enumValue, "%d", iPreviousEnumValue); + Setattr(node, "enumvalue", enumValue); + } + } else if (!enumValue && enumValueEx) { + // Value is not specified, set it by incrementing last value + enumValue = NewString(""); + Printf(enumValue, "%d", ++iPreviousEnumValue); + Setattr(node, "enumvalue", enumValue); + } + // Enums in Scilab are mapped to double + Setattr(node, "type", "double"); + } + + return Language::enumvalueDeclaration(node); + } + + /* --------------------------------------------------------------------- + * membervariableHandler() + * --------------------------------------------------------------------- */ + virtual int membervariableHandler(Node *node) { + checkMemberIdentifierName(node, SCILAB_VARIABLE_NAME_CHAR_MAX); + return Language::membervariableHandler(node); + } + + /* ----------------------------------------------------------------------- + * checkIdentifierName() + * If Scilab target version is lower than 6: + * truncates (and displays a warning) too long member identifier names + * (applies on members of structs, classes...) + * (Scilab 5 identifier names are limited to 24 chars max) + * ----------------------------------------------------------------------- */ + + String *checkIdentifierName(String *name, int char_size_max) { + String *scilabIdentifierName; + if (targetVersion <= 5) { + if (Len(name) > char_size_max) { + scilabIdentifierName = DohNewStringWithSize(name, char_size_max); + Swig_warning(WARN_SCILAB_TRUNCATED_NAME, input_file, line_number, + "Identifier name '%s' exceeds 24 characters and has been truncated to '%s'.\n", name, scilabIdentifierName); + } else + scilabIdentifierName = name; + } else { + scilabIdentifierName = DohNewString(name); + } + return scilabIdentifierName; + } + + /* ----------------------------------------------------------------------- + * checkMemberIdentifierName() + * If Scilab target version is lower than 6: + * truncates (and displays a warning) too long member identifier names + * (applies on members of structs, classes...) + * (Scilab 5 identifier names are limited to 24 chars max) + * ----------------------------------------------------------------------- */ + + void checkMemberIdentifierName(Node *node, int char_size_max) { + if (targetVersion <= 5) { + String *memberName = Getattr(node, "sym:name"); + Node *containerNode = parentNode(node); + String *containerName = Getattr(containerNode, "sym:name"); + int lenContainerName = Len(containerName); + int lenMemberName = Len(memberName); + + if (lenContainerName + lenMemberName + 1 > char_size_max) { + int lenScilabMemberName = char_size_max - lenContainerName - 1; + + if (lenScilabMemberName > 0) { + String *scilabMemberName = DohNewStringWithSize(memberName, lenScilabMemberName); + Setattr(node, "sym:name", scilabMemberName); + Swig_warning(WARN_SCILAB_TRUNCATED_NAME, input_file, line_number, + "Wrapping functions names for member '%s.%s' will exceed 24 characters, " + "so member name has been truncated to '%s'.\n", containerName, memberName, scilabMemberName); + } else { + Swig_error(input_file, line_number, + "Wrapping functions names for member '%s.%s' will exceed 24 characters, " + "please rename the container of member '%s'.\n", containerName, memberName, containerName); + } + } + } + } + + /* ----------------------------------------------------------------------- + * addHelperFunctions() + * ----------------------------------------------------------------------- */ + + void addHelperFunctions() { + addFunctionToScilab("SWIG_this", "SWIG_this"); + addFunctionToScilab("SWIG_ptr", "SWIG_ptr"); + } + + /* ----------------------------------------------------------------------- + * addFunctionToScilab() + * Declare a wrapped function in Scilab (builder, gateway, XML, ...) + * ----------------------------------------------------------------------- */ + + void addFunctionToScilab(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr wrapperFunctionName) { + if (!generateBuilder) + addFunctionInGatewayHeader(scilabFunctionName, wrapperFunctionName); + + if (generateBuilder) { + addFunctionInScriptTable(scilabFunctionName, wrapperFunctionName, builderCode); + } + + if (createLoader) { + addFunctionInLoader(scilabFunctionName); + } + + if (gatewayXMLFile) { + Printf(gatewayXML, "<PRIMITIVE gatewayId=\"%s\" primitiveId=\"%d\" primitiveName=\"%s\"/>\n", gatewayID, primitiveID++, scilabFunctionName); + } + } + + + /* ----------------------------------------------------------------------- + * createBuilderCode() + * ----------------------------------------------------------------------- */ + + void createBuilderFile(String *outputFilename) { + String *builderFilename = NewStringf("builder.sce"); + builderFile = NewFile(builderFilename, "w", SWIG_output_files()); + if (!builderFile) { + FileErrorDisplay(builderFilename); + SWIG_exit(EXIT_FAILURE); + } + emitBanner(builderFile); + + builderFunctionCount = 0; + builderCode = NewString(""); + Printf(builderCode, "mode(-1);\n"); + Printf(builderCode, "lines(0);\n"); /* Useful for automatic tests */ + + // Scilab needs to be in the build directory + Printf(builderCode, "originaldir = pwd();\n"); + Printf(builderCode, "builddir = get_absolute_file_path('builder.sce');\n"); + Printf(builderCode, "cd(builddir);\n"); + + Printf(builderCode, "ilib_verbose(%s);\n", verboseBuildLevel); + + Printf(builderCode, "libs = [];\n"); + + // Flags from command line arguments + Printf(builderCode, "cflags = \"\";\n"); + for (int i = 0; i < Len(cflags); i++) { + String *cflag = Getitem(cflags, i); + Printf(builderCode, "cflags = cflags + \" %s\";\n", cflag); + } + + if (Len(ldflags) > 0) { + for (int i = 0; i < Len(ldflags); i++) { + String *ldflag = Getitem(ldflags, i); + if (i == 0) { + Printf(builderCode, "ldflags = \"%s\";\n", ldflag); + } else { + Printf(builderCode, "ldflags = ldflags + \" %s\";\n", ldflag); + } + } + } else { + Printf(builderCode, "ldflags = \"\";\n"); + } + + // External script to set flags + if (buildFlagsScript) { + Printf(builderCode, "exec(\"%s\");\n", buildFlagsScript); + Printf(builderCode, "cflags = cflags + getCompilationFlags();\n"); + Printf(builderCode, "ldflags = ldflags + getLinkFlags();\n"); + } + // Additional sources + Insert(sourceFileList, 0, outputFilename); + for (int i = 0; i < Len(sourceFileList); i++) { + String *sourceFile = Getitem(sourceFileList, i); + if (i == 0) { + Printf(builderCode, "files = \"%s\";\n", sourceFile); + } else { + Printf(builderCode, "files($ + 1) = \"%s\";\n", sourceFile); + } + } + + Printf(builderCode, "table = ["); + } + + /* ----------------------------------------------------------------------- + * addFunctionInBuilderCode() + * Add a function wrapper in the function table of generated builder script + * ----------------------------------------------------------------------- */ + + void addFunctionInScriptTable(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr wrapperFunctionName, String *scriptCode) { + if (++builderFunctionCount % 10 == 0) { + Printf(scriptCode, "];\ntable = [table;"); + } + Printf(scriptCode, "\"%s\",\"%s\";", scilabFunctionName, wrapperFunctionName); + } + + /* ----------------------------------------------------------------------- + * saveBuilderFile() + * ----------------------------------------------------------------------- */ + + void saveBuilderFile(String *gatewayName) { + Printf(builderCode, "];\n"); + Printf(builderCode, "ierr = 0;\n"); + Printf(builderCode, "if ~isempty(table) then\n"); + Printf(builderCode, " ierr = execstr(\"ilib_build(''%s'', table, files, libs, [], ldflags, cflags);\", 'errcatch');\n", gatewayName); + Printf(builderCode, " if ierr <> 0 then\n"); + Printf(builderCode, " err_msg = lasterror();\n"); + Printf(builderCode, " end\n"); + Printf(builderCode, "end\n"); + Printf(builderCode, "cd(originaldir);\n"); + Printf(builderCode, "if ierr <> 0 then\n"); + Printf(builderCode, " error(ierr, err_msg);\n"); + Printf(builderCode, "end\n"); + Printv(builderFile, builderCode, NIL); + Delete(builderFile); + } + + /* ----------------------------------------------------------------------- + * createGatewayXMLFile() + * This XML file is used by Scilab in the context of internal modules + * ----------------------------------------------------------------------- */ + + void createGatewayXMLFile(String *gatewayName) { + String *gatewayXMLFilename = NewStringf("%s_gateway.xml", gatewayName); + gatewayXMLFile = NewFile(gatewayXMLFilename, "w", SWIG_output_files()); + if (!gatewayXMLFile) { + FileErrorDisplay(gatewayXMLFilename); + SWIG_exit(EXIT_FAILURE); + } + // Add a slightly modified SWIG banner to the gateway XML ("--modify" is illegal in XML) + gatewayXML = NewString(""); + Printf(gatewayXML, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); + Printf(gatewayXML, "<!--\n"); + Printf(gatewayXML, "This file was automatically generated by SWIG (http://www.swig.org).\n"); + Printf(gatewayXML, "Version %s\n", Swig_package_version()); + Printf(gatewayXML, "\n"); + Printf(gatewayXML, "Do not make changes to this file unless you know what you are doing - modify\n"); + Printf(gatewayXML, "the SWIG interface file instead.\n"); + Printf(gatewayXML, "-->\n"); + Printf(gatewayXML, "<GATEWAY name=\"%s\">\n", gatewayName); + + primitiveID = 1; + } + + /* ----------------------------------------------------------------------- + * saveGatewayXMLFile() + * ----------------------------------------------------------------------- */ + + void saveGatewayXMLFile() { + Printf(gatewayXML, "</GATEWAY>\n"); + Printv(gatewayXMLFile, gatewayXML, NIL); + Delete(gatewayXMLFile); + } + + /* ----------------------------------------------------------------------- + * startGatewayHeader() + * Start the gateway header + * ----------------------------------------------------------------------- */ + void startGatewayHeader(String *gatewayLibraryName) { + gatewayHeader = NewString(""); + Printf(gatewayHeader, "\n"); + + gatewayHeaderV6 = NewString(""); + Printf(gatewayHeaderV6, "#ifdef __cplusplus\n"); + Printf(gatewayHeaderV6, "extern \"C\" {\n"); + Printf(gatewayHeaderV6, "#endif\n"); + Printf(gatewayHeaderV6, "#include \"c_gateway_prototype.h\"\n"); + Printf(gatewayHeaderV6, "#include \"addfunction.h\"\n"); + Printf(gatewayHeaderV6, "#ifdef __cplusplus\n"); + Printf(gatewayHeaderV6, "}\n"); + Printf(gatewayHeaderV6, "#endif\n"); + Printf(gatewayHeaderV6, "\n"); + Printf(gatewayHeaderV6, "#define MODULE_NAME L\"%s\"\n", gatewayLibraryName); + Printf(gatewayHeaderV6, "#ifdef __cplusplus\n"); + Printf(gatewayHeaderV6, "extern \"C\"\n"); + Printf(gatewayHeaderV6, "#endif\n"); + Printf(gatewayHeaderV6, "int %s(wchar_t *pwstFuncName) {\n", gatewayLibraryName); + Printf(gatewayHeaderV6, "\n"); + } + + /* ----------------------------------------------------------------------- + * addFunctionInGatewayHeader() + * Add a function in the gateway header + * ----------------------------------------------------------------------- */ + + void addFunctionInGatewayHeader(const_String_or_char_ptr scilabFunctionName, const_String_or_char_ptr wrapperFunctionName) { + if (gatewayHeaderV5 == NULL) { + gatewayHeaderV5 = NewString(""); + Printf(gatewayHeaderV5, "static GenericTable Tab[] = {\n"); + } else + Printf(gatewayHeaderV5, ",\n"); + Printf(gatewayHeaderV5, " {(Myinterfun)sci_gateway, (GT)%s, (char *)\"%s\"}", wrapperFunctionName, scilabFunctionName); + + Printf(gatewayHeaderV6, "if (wcscmp(pwstFuncName, L\"%s\") == 0) { addCStackFunction((wchar_t *)L\"%s\", &%s, (wchar_t *)MODULE_NAME); }\n", scilabFunctionName, scilabFunctionName, wrapperFunctionName); + } + + /* ----------------------------------------------------------------------- + * terminateGatewayHeader() + * Terminates the gateway header + * ----------------------------------------------------------------------- */ + + void terminateGatewayHeader(String *gatewayLibraryName) { + Printf(gatewayHeaderV5, "};\n"); + Printf(gatewayHeaderV5, "\n"); + Printf(gatewayHeaderV5, "#ifdef __cplusplus\n"); + Printf(gatewayHeaderV5, "extern \"C\" {\n"); + Printf(gatewayHeaderV5, "#endif\n"); + Printf(gatewayHeaderV5, "int C2F(%s)() {\n", gatewayLibraryName); + Printf(gatewayHeaderV5, " Rhs = Max(0, Rhs);\n"); + Printf(gatewayHeaderV5, " if (*(Tab[Fin-1].f) != NULL) {\n"); + Printf(gatewayHeaderV5, " if(pvApiCtx == NULL) {\n"); + Printf(gatewayHeaderV5, " pvApiCtx = (StrCtx *)MALLOC(sizeof(StrCtx));\n"); + Printf(gatewayHeaderV5, " }\n"); + Printf(gatewayHeaderV5, " pvApiCtx->pstName = (char *)Tab[Fin-1].name;\n"); + Printf(gatewayHeaderV5, " (*(Tab[Fin-1].f))(Tab[Fin-1].name,(GatefuncH)Tab[Fin-1].F);\n"); + Printf(gatewayHeaderV5, " }\n"); + Printf(gatewayHeaderV5, " return 0;\n"); + Printf(gatewayHeaderV5, "}\n"); + Printf(gatewayHeaderV5, "\n"); + Printf(gatewayHeaderV5, "#ifdef __cplusplus\n"); + Printf(gatewayHeaderV5, "}\n"); + Printf(gatewayHeaderV5, "#endif\n"); + + Printf(gatewayHeaderV6, "return 1;\n"); + Printf(gatewayHeaderV6, "};\n"); + + Printf(gatewayHeader, "#if SWIG_SCILAB_VERSION >= 600\n"); + Printv(gatewayHeader, gatewayHeaderV6, NIL); + Printf(gatewayHeader, "#else\n"); + Printv(gatewayHeader, gatewayHeaderV5, NIL); + Printf(gatewayHeader, "#endif\n"); + } + + + /* ----------------------------------------------------------------------- + * createLoaderScriptFile() + * Creates the loader script file (loader.sce) + * ----------------------------------------------------------------------- */ + + void createLoaderFile(String *gatewayLibraryName) { + String *loaderFilename = NewString("loader.sce"); + loaderFile = NewFile(loaderFilename, "w", SWIG_output_files()); + if (!loaderFile) { + FileErrorDisplay(loaderFilename); + SWIG_exit(EXIT_FAILURE); + } + + emitBanner(loaderFile); + + loaderScript = NewString(""); + Printf(loaderScript, "%s_path = get_absolute_file_path('loader.sce');\n", gatewayLibraryName); + Printf(loaderScript, "[bOK, ilib] = c_link('%s');\n", gatewayLibraryName); + Printf(loaderScript, "if bOK then\n"); + Printf(loaderScript, " ulink(ilib);\n"); + Printf(loaderScript, "end\n"); + Printf(loaderScript, "list_functions = [..\n"); + } + + /* ----------------------------------------------------------------------- + * addFunctionInLoaderScript() + * Add a function in the loader script table + * ----------------------------------------------------------------------- */ + + void addFunctionInLoader(const_String_or_char_ptr scilabFunctionName) { + Printf(loaderScript, " '%s'; ..\n", scilabFunctionName); + } + + /* ----------------------------------------------------------------------- + * saveLoaderScriptFile() + * Terminates and saves the loader script + * ----------------------------------------------------------------------- */ + + void saveLoaderFile(String *gatewayLibraryName) { + Printf(loaderScript, "];\n"); + Printf(loaderScript, "addinter(fullfile(%s_path, '%s' + getdynlibext()), '%s', list_functions);\n", + gatewayLibraryName, gatewayLibraryName, gatewayLibraryName); + Printf(loaderScript, "clear %s_path;\n", gatewayLibraryName); + Printf(loaderScript, "clear bOK;\n"); + Printf(loaderScript, "clear ilib;\n"); + Printf(loaderScript, "clear list_functions;\n"); + Printv(loaderFile, loaderScript, NIL); + + Delete(loaderFile); + } + +}; + +extern "C" Language *swig_scilab(void) { + return new SCILAB(); +} diff --git a/contrib/tools/swig/Source/Modules/swigmain.cxx b/contrib/tools/swig/Source/Modules/swigmain.cxx new file mode 100644 index 00000000000..84ac74294c3 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/swigmain.cxx @@ -0,0 +1,275 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * swigmain.cxx + * + * Simplified Wrapper and Interface Generator (SWIG) + * + * This file is the main entry point to SWIG. It collects the command + * line options, registers built-in language modules, and instantiates + * a module for code generation. If adding new language modules + * to SWIG, you would modify this file. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include <ctype.h> + +/* Module factories. These functions are used to instantiate + the built-in language modules. If adding a new language + module to SWIG, place a similar function here. Make sure + the function has "C" linkage. This is required so that modules + can be dynamically loaded in future versions. */ + +extern "C" { + Language *swig_csharp(void); + Language *swig_d(void); + Language *swig_go(void); + Language *swig_guile(void); + Language *swig_java(void); + Language *swig_javascript(void); + Language *swig_lua(void); + Language *swig_mzscheme(void); + Language *swig_ocaml(void); + Language *swig_octave(void); + Language *swig_perl5(void); + Language *swig_php(void); + Language *swig_python(void); + Language *swig_r(void); + Language *swig_ruby(void); + Language *swig_scilab(void); + Language *swig_tcl(void); + Language *swig_xml(void); +} + +/* Association of command line options to language modules. + Place an entry for new language modules here, keeping the + list sorted alphabetically. */ + +static TargetLanguageModule modules[] = { + {"-allegrocl", NULL, "ALLEGROCL", Disabled}, + {"-chicken", NULL, "CHICKEN", Disabled}, + {"-clisp", NULL, "CLISP", Disabled}, + {"-cffi", NULL, "CFFI", Disabled}, + {"-csharp", swig_csharp, "C#", Supported}, + {"-d", swig_d, "D", Supported}, + {"-go", swig_go, "Go", Supported}, + {"-guile", swig_guile, "Guile", Supported}, + {"-java", swig_java, "Java", Supported}, + {"-javascript", swig_javascript, "Javascript", Supported}, + {"-lua", swig_lua, "Lua", Supported}, + {"-modula3", NULL, "Modula 3", Disabled}, + {"-mzscheme", swig_mzscheme, "MzScheme/Racket", Experimental}, + {"-ocaml", swig_ocaml, "OCaml", Experimental}, + {"-octave", swig_octave, "Octave", Supported}, + {"-perl", swig_perl5, NULL, Supported}, + {"-perl5", swig_perl5, "Perl 5", Supported}, + {"-php", swig_php, NULL, Supported}, + {"-php5", NULL, "PHP 5", Disabled}, + {"-php7", swig_php, "PHP 7", Supported}, + {"-pike", NULL, "Pike", Disabled}, + {"-python", swig_python, "Python", Supported}, + {"-r", swig_r, "R (aka GNU S)", Supported}, + {"-ruby", swig_ruby, "Ruby", Supported}, + {"-scilab", swig_scilab, "Scilab", Supported}, + {"-sexp", NULL, "Lisp S-Expressions", Disabled}, + {"-tcl", swig_tcl, NULL, Supported}, + {"-tcl8", swig_tcl, "Tcl 8", Supported}, + {"-uffi", NULL, "Common Lisp / UFFI", Disabled}, + {"-xml", swig_xml, "XML", Supported}, + {NULL, NULL, NULL, Disabled} +}; + +#ifdef MACSWIG +#include <console.h> +#include <SIOUX.h> +#endif + +//----------------------------------------------------------------- +// main() +// +// Main program. Initializes the files and starts the parser. +//----------------------------------------------------------------- + +void SWIG_merge_envopt(const char *env, int oargc, char *oargv[], int *nargc, char ***nargv) { + if (!env) { + *nargc = oargc; + *nargv = (char **)malloc(sizeof(char *) * (oargc + 1)); + memcpy(*nargv, oargv, sizeof(char *) * (oargc + 1)); + return; + } + + int argc = 1; + int arge = oargc + 1024; + char **argv = (char **) malloc(sizeof(char *) * (arge + 1)); + char *buffer = (char *) malloc(2048); + char *b = buffer; + char *be = b + 1023; + const char *c = env; + while ((b != be) && *c && (argc < arge)) { + while (isspace(*c) && *c) + ++c; + if (*c) { + argv[argc] = b; + ++argc; + } + while ((b != be) && *c && !isspace(*c)) { + *(b++) = *(c++); + } + *b++ = 0; + } + + argv[0] = oargv[0]; + for (int i = 1; (i < oargc) && (argc < arge); ++i, ++argc) { + argv[argc] = oargv[i]; + } + argv[argc] = NULL; + + *nargc = argc; + *nargv = argv; +} + +static void insert_option(int *argc, char ***argv, int index, char const *start, char const *end) { + int new_argc = *argc; + char **new_argv = *argv; + size_t option_len = end - start; + + // Preserve the NULL pointer at argv[argc] + new_argv = (char **)realloc(new_argv, (new_argc + 2) * sizeof(char *)); + memmove(&new_argv[index + 1], &new_argv[index], sizeof(char *) * (new_argc + 1 - index)); + new_argc++; + + new_argv[index] = (char *)malloc(option_len + 1); + memcpy(new_argv[index], start, option_len); + new_argv[index][option_len] = '\0'; + + *argc = new_argc; + *argv = new_argv; +} + +static void merge_options_files(int *argc, char ***argv) { + static const int BUFFER_SIZE = 4096; + char buffer[BUFFER_SIZE]; + int i; + int insert; + char **new_argv = *argv; + int new_argc = *argc; + FILE *f; + + i = 1; + while (i < new_argc) { + if (new_argv[i] && new_argv[i][0] == '@' && (f = fopen(&new_argv[i][1], "r"))) { + int ci; + char *b; + char *be = &buffer[BUFFER_SIZE]; + int quote = 0; + bool escape = false; + + new_argc--; + memmove(&new_argv[i], &new_argv[i + 1], sizeof(char *) * (new_argc - i)); + insert = i; + b = buffer; + + while ((ci = fgetc(f)) != EOF) { + const char c = static_cast<char>(ci); + if (escape) { + if (b != be) { + *b = c; + ++b; + } + escape = false; + } else if (c == '\\') { + escape = true; + } else if (!quote && (c == '\'' || c == '"')) { + quote = c; + } else if (quote && c == quote) { + quote = 0; + } else if (isspace(c) && !quote) { + if (b != buffer) { + insert_option(&new_argc, &new_argv, insert, buffer, b); + insert++; + + b = buffer; + } + } else if (b != be) { + *b = c; + ++b; + } + } + if (b != buffer) + insert_option(&new_argc, &new_argv, insert, buffer, b); + fclose(f); + } else { + ++i; + } + } + + *argv = new_argv; + *argc = new_argc; +} + +int main(int margc, char **margv) { + int i; + const TargetLanguageModule *language_module = 0; + + int argc; + char **argv; + + SWIG_merge_envopt(getenv("SWIG_FEATURES"), margc, margv, &argc, &argv); + merge_options_files(&argc, &argv); + +#ifdef MACSWIG + SIOUXSettings.asktosaveonclose = false; + argc = ccommand(&argv); +#endif + + Swig_init_args(argc, argv); + + /* Get options */ + for (i = 1; i < argc; i++) { + if (argv[i]) { + bool is_target_language_module = false; + for (int j = 0; modules[j].name; j++) { + if (strcmp(modules[j].name, argv[i]) == 0) { + language_module = &modules[j]; + is_target_language_module = true; + break; + } + } + if (is_target_language_module) { + Swig_mark_arg(i); + if (language_module->status == Disabled) { + if (language_module->help) + Printf(stderr, "Target language option %s (%s) is no longer supported.\n", language_module->name, language_module->help); + else + Printf(stderr, "Target language option %s is no longer supported.\n", language_module->name); + SWIG_exit(EXIT_FAILURE); + } + } else if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0)) { + if (strcmp(argv[i], "--help") == 0) + strcpy(argv[i], "-help"); + Printf(stdout, "Supported Target Language Options\n"); + for (int j = 0; modules[j].name; j++) { + if (modules[j].help && modules[j].status == Supported) { + Printf(stdout, " %-15s - Generate %s wrappers\n", modules[j].name, modules[j].help); + } + } + Printf(stdout, "\nExperimental Target Language Options\n"); + for (int j = 0; modules[j].name; j++) { + if (modules[j].help && modules[j].status == Experimental) { + Printf(stdout, " %-15s - Generate %s wrappers\n", modules[j].name, modules[j].help); + } + } + // Swig_mark_arg not called as the general -help options also need to be displayed later on + } + } + } + + int res = SWIG_main(argc, argv, language_module); + + return res; +} diff --git a/contrib/tools/swig/Source/Modules/swigmod.h b/contrib/tools/swig/Source/Modules/swigmod.h new file mode 100644 index 00000000000..bfb93d1a705 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/swigmod.h @@ -0,0 +1,462 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * swigmod.h + * + * Main header file for SWIG modules. + * ----------------------------------------------------------------------------- */ + +#ifndef SWIG_SWIGMOD_H_ +#define SWIG_SWIGMOD_H_ + +#include "swig.h" +#include "preprocessor.h" +#include "swigwarn.h" + +#define NOT_VIRTUAL 0 +#define PLAIN_VIRTUAL 1 +#define PURE_VIRTUAL 2 + +extern String *input_file; +extern int line_number; +extern int start_line; +extern int CPlusPlus; // C++ mode +extern int Extend; // Extend mode +extern int Verbose; +extern int IsVirtual; +extern int ImportMode; +extern int NoExcept; // -no_except option +extern int Abstract; // abstract base class +extern int SmartPointer; // smart pointer methods being emitted +extern int SwigRuntime; + +/* Overload "argc" and "argv" */ +extern String *argv_template_string; +extern String *argc_template_string; + +/* Miscellaneous stuff */ + +#define tab2 " " +#define tab4 " " +#define tab8 " " + +class Dispatcher { +public: + + Dispatcher ():cplus_mode(PUBLIC) { + } + virtual ~ Dispatcher () { + } + + virtual int emit_one(Node *n); + virtual int emit_children(Node *n); + virtual int defaultHandler(Node *n); + + /* Top of the parse tree */ + virtual int top(Node *n) = 0; + + /* SWIG directives */ + + virtual int applyDirective(Node *n); + virtual int clearDirective(Node *n); + virtual int constantDirective(Node *n); + virtual int extendDirective(Node *n); + virtual int fragmentDirective(Node *n); + virtual int importDirective(Node *n); + virtual int includeDirective(Node *n); + virtual int insertDirective(Node *n); + virtual int moduleDirective(Node *n); + virtual int nativeDirective(Node *n); + virtual int pragmaDirective(Node *n); + virtual int typemapDirective(Node *n); + virtual int typemapitemDirective(Node *n); + virtual int typemapcopyDirective(Node *n); + virtual int typesDirective(Node *n); + + /* C/C++ parsing */ + + virtual int cDeclaration(Node *n); + virtual int externDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int enumvalueDeclaration(Node *n); + virtual int enumforwardDeclaration(Node *n); + virtual int classDeclaration(Node *n); + virtual int classforwardDeclaration(Node *n); + virtual int constructorDeclaration(Node *n); + virtual int destructorDeclaration(Node *n); + virtual int accessDeclaration(Node *n); + virtual int usingDeclaration(Node *n); + virtual int namespaceDeclaration(Node *n); + virtual int templateDeclaration(Node *n); + virtual int lambdaDeclaration(Node *n); + + enum AccessMode { PUBLIC, PRIVATE, PROTECTED }; + +protected: + AccessMode cplus_mode; +}; + +/* ---------------------------------------------------------------------------- + * class language: + * + * This class defines the functions that need to be supported by the + * scripting language being used. The translator calls these virtual + * functions to output different types of code for different languages. + * ------------------------------------------------------------------------- */ + +class Language:public Dispatcher { +public: + Language(); + virtual ~Language(); + virtual int emit_one(Node *n); + + String *directorClassName(Node *n); + + /* Parse command line options */ + + virtual void main(int argc, char *argv[]); + + /* Top of the parse tree */ + + virtual int top(Node *n); + + /* SWIG directives */ + + + virtual int applyDirective(Node *n); + virtual int clearDirective(Node *n); + virtual int constantDirective(Node *n); + virtual int extendDirective(Node *n); + virtual int fragmentDirective(Node *n); + virtual int importDirective(Node *n); + virtual int includeDirective(Node *n); + virtual int insertDirective(Node *n); + virtual int moduleDirective(Node *n); + virtual int nativeDirective(Node *n); + virtual int pragmaDirective(Node *n); + virtual int typemapDirective(Node *n); + virtual int typemapcopyDirective(Node *n); + virtual int typesDirective(Node *n); + + /* C/C++ parsing */ + + virtual int cDeclaration(Node *n); + virtual int externDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int enumvalueDeclaration(Node *n); + virtual int enumforwardDeclaration(Node *n); + virtual int classDeclaration(Node *n); + virtual int classforwardDeclaration(Node *n); + virtual int constructorDeclaration(Node *n); + virtual int destructorDeclaration(Node *n); + virtual int accessDeclaration(Node *n); + virtual int namespaceDeclaration(Node *n); + virtual int usingDeclaration(Node *n); + + /* Function handlers */ + + virtual int functionHandler(Node *n); + virtual int globalfunctionHandler(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int staticmemberfunctionHandler(Node *n); + virtual int callbackfunctionHandler(Node *n); + + /* Variable handlers */ + + virtual int variableHandler(Node *n); + virtual int globalvariableHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int staticmembervariableHandler(Node *n); + + /* C++ handlers */ + + virtual int memberconstantHandler(Node *n); + virtual int constructorHandler(Node *n); + virtual int copyconstructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int classHandler(Node *n); + + /* Miscellaneous */ + + virtual int typedefHandler(Node *n); + + /* Low-level code generation */ + + virtual int constantWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int functionWrapper(Node *n); + virtual int nativeWrapper(Node *n); + + /* C++ director class generation */ + virtual int classDirector(Node *n); + virtual int classDirectorInit(Node *n); + virtual int classDirectorEnd(Node *n); + virtual int unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_director, int &virtual_destructor, int protectedbase = 0); + virtual int classDirectorConstructor(Node *n); + virtual int classDirectorDefaultConstructor(Node *n); + virtual int classDirectorMethod(Node *n, Node *parent, String *super); + virtual int classDirectorConstructors(Node *n); + virtual int classDirectorDestructor(Node *n); + virtual int classDirectorMethods(Node *n); + virtual int classDirectorDisown(Node *n); + + /* Miscellaneous */ + virtual int validIdentifier(String *s); /* valid identifier? */ + virtual int addSymbol(const String *s, const Node *n, const_String_or_char_ptr scope = ""); /* Add symbol */ + virtual int addInterfaceSymbol(const String *interface_name, Node *n, const_String_or_char_ptr scope = ""); + virtual void dumpSymbols(); + virtual Node *symbolLookup(const String *s, const_String_or_char_ptr scope = ""); /* Symbol lookup */ + virtual Hash* symbolAddScope(const_String_or_char_ptr scope); + virtual Hash* symbolScopeLookup(const_String_or_char_ptr scope); + virtual Hash* symbolScopePseudoSymbolLookup(const_String_or_char_ptr scope); + static Node *classLookup(const SwigType *s); /* Class lookup */ + static Node *enumLookup(SwigType *s); /* Enum lookup */ + virtual int abstractClassTest(Node *n); /* Is class really abstract? */ + virtual int is_assignable(Node *n); /* Is variable assignable? */ + virtual String *runtimeCode(); /* returns the language specific runtime code */ + virtual String *defaultExternalRuntimeFilename(); /* the default filename for the external runtime */ + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm); /* Language specific special variable substitutions for $typemap() */ + + /* Runtime is C++ based, so extern "C" header section */ + void enable_cplus_runtime_mode(); + + /* Returns the cplus_runtime mode */ + int cplus_runtime_mode(); + + /* Allow director related code generation */ + void allow_directors(int val = 1); + + /* Return true if directors are enabled */ + int directorsEnabled() const; + + /* Allow director protected members related code generation */ + void allow_dirprot(int val = 1); + + /* Allow all protected members code generation (for directors) */ + void allow_allprotected(int val = 0); + + /* Returns the dirprot mode */ + int dirprot_mode() const; + + /* Check if the non public constructor is needed (for directors) */ + int need_nonpublic_ctor(Node *n); + + /* Check if the non public member is needed (for directors) */ + int need_nonpublic_member(Node *n); + + /* Set none comparison string */ + void setSubclassInstanceCheck(String *s); + + /* Set overload variable templates argc and argv */ + void setOverloadResolutionTemplates(String *argc, String *argv); + + /* Language instance is a singleton - get instance */ + static Language* instance(); + +protected: + /* Allow multiple-input typemaps */ + void allow_multiple_input(int val = 1); + + /* Allow overloaded functions */ + void allow_overloading(int val = 1); + + /* Wrapping class query */ + int is_wrapping_class() const; + + /* Return the node for the current class */ + Node *getCurrentClass() const; + + /* Return C++ mode */ + int getCPlusMode() const; + + /* Return the namespace for the class/enum - the nspace feature */ + String *getNSpace() const; + + /* Return the real name of the current class */ + String *getClassName() const; + + /* Return the classes hash */ + Hash *getClassHash() const; + + /* Return the current class prefix */ + String *getClassPrefix() const; + + /* Return the current enum class prefix */ + String *getEnumClassPrefix() const; + + /* Fully qualified type name to use */ + String *getClassType() const; + + /* Return true if the current method is part of a smart-pointer */ + int is_smart_pointer() const; + + /* Return the name to use for the given parameter. */ + virtual String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter = false) const; + + /* Some language modules require additional wrappers for virtual methods not declared in sub-classes */ + virtual bool extraDirectorProtectedCPPMethodsRequired() const; + +public: + enum NestedClassSupport { + NCS_None, // Target language does not have an equivalent to nested classes + NCS_Full, // Target language does have an equivalent to nested classes and is fully implemented + NCS_Unknown // Target language may or may not have an equivalent to nested classes. If it does, it has not been implemented yet. + }; + /* Does target language support nested classes? Default is NCS_Unknown. + If NCS_Unknown is returned, then the nested classes will be ignored unless + %feature "flatnested" is applied to them, in which case they will appear in global space. + If the target language does not support the notion of class + nesting, the language module should return NCS_None from this function, and + the nested classes will be moved to the global scope (like implicit global %feature "flatnested"). + */ + virtual NestedClassSupport nestedClassesSupport() const; + + /* Returns true if the target language supports key word arguments (kwargs) */ + virtual bool kwargsSupport() const; + +protected: + /* Identifies if a protected members that are generated when the allprotected option is used. + This does not include protected virtual methods as they are turned on with the dirprot option. */ + bool isNonVirtualProtectedAccess(Node *n) const; + + /* Identify if a wrapped global or member variable n should use the naturalvar feature */ + int use_naturalvar_mode(Node *n) const; + + /* Director subclass comparison test */ + String *none_comparison; + + /* Director constructor "template" code */ + String *director_ctor_code; + + /* Director 'protected' constructor "template" code */ + String *director_prot_ctor_code; + + /* Director allows multiple inheritance */ + int director_multiple_inheritance; + + /* Director language module */ + int director_language; + + /* Used to translate Doxygen comments to target documentation format */ + class DoxygenTranslator *doxygenTranslator; + +private: + Hash *symtabs; /* symbol tables */ + int overloading; + int multiinput; + int cplus_runtime; + int directors; + static Language *this_; +}; + +extern "C" { + void SWIG_typemap_lang(const char *); + typedef Language *(*ModuleFactory) (void); +} + +enum Status {Disabled, Experimental, Supported}; + +struct TargetLanguageModule { + const char *name; + ModuleFactory fac; + const char *help; + Status status; +}; + +int SWIG_main(int argc, char *argv[], const TargetLanguageModule *tlm); +void emit_parameter_variables(ParmList *l, Wrapper *f); +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f); +void SWIG_config_file(const_String_or_char_ptr ); +const String *SWIG_output_directory(); +void SWIG_config_cppext(const char *ext); +void Swig_print_xml(Node *obj, String *filename); + +/* get the list of generated files */ +List *SWIG_output_files(); + +void SWIG_library_directory(const char *); +int emit_num_arguments(ParmList *); +int emit_num_required(ParmList *); +int emit_isvarargs(ParmList *p); +bool emit_isvarargs_function(Node *n); +void emit_attach_parmmaps(ParmList *, Wrapper *f); +void emit_mark_varargs(ParmList *l); +String *emit_action(Node *n); +int emit_action_code(Node *n, String *wrappercode, String *action); +void Swig_overload_check(Node *n); +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *, const_String_or_char_ptr fmt_fastdispatch = 0); +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *); +List *Swig_overload_rank(Node *n, bool script_lang_wrapping); +SwigType *cplus_value_type(SwigType *t); + +/* directors.cxx start */ +String *Swig_csuperclass_call(String *base, String *method, ParmList *l); +String *Swig_class_declaration(Node *n, String *name); +String *Swig_class_name(Node *n); +String *Swig_method_call(const_String_or_char_ptr name, ParmList *parms); +String *Swig_method_decl(SwigType *return_base_type, SwigType *decl, const_String_or_char_ptr id, List *args, int default_args); +String *Swig_director_declaration(Node *n); +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f); +void Swig_director_parms_fixup(ParmList *parms); +/* directors.cxx end */ + +/* Utilities */ + +int is_public(Node *n); +int is_private(Node *n); +int is_protected(Node *n); +int is_member_director(Node *parentnode, Node *member); +int is_member_director(Node *member); +int is_non_virtual_protected_access(Node *n); /* Check if the non-virtual protected members are required (for directors) */ + +void Wrapper_virtual_elimination_mode_set(int); +void Wrapper_fast_dispatch_mode_set(int); +void Wrapper_cast_dispatch_mode_set(int); +void Wrapper_naturalvar_mode_set(int); + +void clean_overloaded(Node *n); + +extern "C" { + const char *Swig_to_string(DOH *object, int count = -1); + const char *Swig_to_string_with_location(DOH *object, int count = -1); + void Swig_print(DOH *object, int count = -1); + void Swig_print_with_location(DOH *object, int count = -1); +} + +/* Contracts */ +void Swig_contracts(Node *n); +void Swig_contract_mode_set(int flag); +int Swig_contract_mode_get(); + +/* Browser */ +void Swig_browser(Node *n, int); +void Swig_default_allocators(Node *n); +void Swig_process_types(Node *n); + +/* Nested classes */ +void Swig_nested_process_classes(Node *n); +void Swig_nested_name_unnamed_c_structs(Node *n); + +/* Interface feature */ +void Swig_interface_feature_enable(); +void Swig_interface_propagate_methods(Node *n); + +/* Miscellaneous */ +template <class T> class save_value { + T _value; + T& _value_ptr; + save_value(const save_value&); + save_value& operator=(const save_value&); + +public: + save_value(T& value) : _value(value), _value_ptr(value) {} + save_value(T& value, T new_val) : _value(value), _value_ptr(value) { value = new_val; } + ~save_value() { _value_ptr = _value; } +}; + +#endif diff --git a/contrib/tools/swig/Source/Modules/tcl8.cxx b/contrib/tools/swig/Source/Modules/tcl8.cxx new file mode 100644 index 00000000000..7a78ede9bc0 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/tcl8.cxx @@ -0,0 +1,1310 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * tcl8.cxx + * + * Tcl8 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +static const char *usage = "\ +Tcl 8 Options (available with -tcl8)\n\ + -itcl - Enable ITcl support\n\ + -nosafe - Leave out SafeInit module function.\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -namespace - Build module into a Tcl 8 namespace\n\ + -pkgversion - Set package version\n\n"; + +static String *cmd_tab = 0; /* Table of command names */ +static String *var_tab = 0; /* Table of global variables */ +static String *const_tab = 0; /* Constant table */ +static String *methods_tab = 0; /* Methods table */ +static String *attr_tab = 0; /* Attribute table */ +static String *prefix = 0; +static String *module = 0; +static int namespace_option = 0; +static String *init_name = 0; +static String *ns_name = 0; +static int have_constructor; +static String *constructor_name; +static int have_destructor; +static int have_base_classes; +static String *destructor_action = 0; +static String *version = (String *) "0.0"; +static String *class_name = 0; + +static int have_attributes; +static int have_methods; +static int nosafe = 0; + +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; +static File *f_begin = 0; +static File *f_runtime = 0; + + +// Itcl support +static int itcl = 0; +static File *f_shadow = 0; +static File *f_shadow_stubs = 0; + +static String *constructor = 0; +static String *destructor = 0; +static String *base_classes = 0; +static String *base_class_init = 0; +static String *methods = 0; +static String *imethods = 0; +static String *attributes = 0; +static String *attribute_traces = 0; +static String *iattribute_traces = 0; + + + +class TCL8:public Language { +public: + + /* ------------------------------------------------------------ + * TCL8::main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("tcl"); + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else + Swig_arg_error(); + } else if (strcmp(argv[i], "-pkgversion") == 0) { + if (argv[i + 1]) { + version = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } + } else if (strcmp(argv[i], "-namespace") == 0) { + namespace_option = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-itcl") == 0) { + itcl = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nosafe") == 0) { + nosafe = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } else if (strcmp(argv[i], "-cppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is now always on.\n", argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + Printf(stderr, "Deprecated command line option: %s. This option is no longer supported.\n", argv[i]); + Swig_mark_arg(i); + SWIG_exit(EXIT_FAILURE); + } + } + } + + Preprocessor_define("SWIGTCL 1", 0); + // SWIGTCL8 is deprecated, and no longer documented. + Preprocessor_define("SWIGTCL8 1", 0); + SWIG_typemap_lang("tcl8"); + SWIG_config_file("tcl8.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = 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); + + /* Initialize some variables for the object interface */ + + cmd_tab = NewString(""); + var_tab = NewString(""); + methods_tab = NewString(""); + const_tab = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n\n#ifndef SWIGTCL\n#define SWIGTCL\n#endif\n\n"); + + /* Set the module name, namespace, and prefix */ + + module = NewStringf("%(lower)s", Getattr(n, "name")); + init_name = NewStringf("%(title)s_Init", module); + + ns_name = prefix ? Copy(prefix) : Copy(module); + if (prefix) + Append(prefix, "_"); + + + /* If shadow classing is enabled, we're going to change the module name to "_module" */ + if (itcl) { + String *filen; + filen = NewStringf("%s%s.itcl", SWIG_output_directory(), module); + + Insert(module, 0, "_"); + + if ((f_shadow = NewFile(filen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + f_shadow_stubs = NewString(""); + + Swig_register_filebyname("shadow", f_shadow); + Swig_register_filebyname("itcl", f_shadow); + + Swig_banner_target_lang(f_shadow, "#"); + + Printv(f_shadow, "\npackage require Itcl\n\n", NIL); + Delete(filen); + } + + /* Generate some macros used throughout code generation */ + + Printf(f_header, "#define SWIG_init %s\n", init_name); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + if (namespace_option) { + Printf(f_header, "#define SWIG_prefix \"%s::\"\n", ns_name); + Printf(f_header, "#define SWIG_namespace \"%s\"\n\n", ns_name); + } else { + Printf(f_header, "#define SWIG_prefix \"%s\"\n", prefix); + } + Printf(f_header, "#define SWIG_version \"%s\"\n", version); + + Printf(cmd_tab, "\nstatic swig_command_info swig_commands[] = {\n"); + Printf(var_tab, "\nstatic swig_var_info swig_variables[] = {\n"); + Printf(const_tab, "\nstatic swig_const_info swig_constants[] = {\n"); + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* Start emitting code */ + Language::top(n); + + /* Done. Close up the module */ + Printv(cmd_tab, tab4, "{0, 0, 0}\n", "};\n", NIL); + Printv(var_tab, tab4, "{0,0,0,0}\n", "};\n", NIL); + Printv(const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); + + Printv(f_wrappers, cmd_tab, var_tab, const_tab, NIL); + + /* Dump the pointer equivalency table */ + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + /* Close the init function and quit */ + Printf(f_init, "return TCL_OK;\n}\n"); + + if (!nosafe) { + Printf(f_init, "SWIGEXPORT int %(title)s_SafeInit(Tcl_Interp *interp) {\n", module); + Printf(f_init, " return SWIG_init(interp);\n"); + Printf(f_init, "}\n"); + } + + if (itcl) { + Printv(f_shadow, f_shadow_stubs, "\n", NIL); + Delete(f_shadow); + } + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Printv(f_begin, f_header, f_wrappers, NIL); + 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; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + String *name = Getattr(n, "name"); /* Like to get rid of this */ + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + String *overname = 0; + + Parm *p; + int i; + String *tm; + Wrapper *f; + String *incode, *cleanup, *outarg, *argstr, *args; + int num_arguments = 0; + int num_required = 0; + int varargs = 0; + + char source[64]; + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + incode = NewString(""); + cleanup = NewString(""); + outarg = NewString(""); + argstr = NewString("\""); + args = NewString(""); + + f = NewWrapper(); + +#ifdef SWIG_USE_RESULTOBJ + Wrapper_add_local(f, "resultobj", "Tcl_Obj *resultobj = NULL"); +#endif + + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + Printv(f->def, "SWIGINTERN int\n ", wname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(parms, f); + + /* Attach standard typemaps */ + emit_attach_parmmaps(parms, f); + Setattr(n, "wrap:parms", parms); + + /* Get number of require and total arguments */ + num_arguments = emit_num_arguments(parms); + num_required = emit_num_required(parms); + varargs = emit_isvarargs(parms); + + /* Unmarshal parameters */ + + for (i = 0, p = parms; i < num_arguments; i++) { + /* Skip ignored arguments */ + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + /* Produce string representations of the source and target arguments */ + sprintf(source, "objv[%d]", i + 1); + + if (i == num_required) + Putc('|', argstr); + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + Replaceall(tm, "$target", ln); + Replaceall(tm, "$source", source); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + Putc('o', argstr); + Printf(args, ",(void *)0"); + if (i >= num_required) { + Printf(incode, "if (objc > %d) {\n", i + 1); + } + Printf(incode, "%s\n", tm); + if (i >= num_required) { + Printf(incode, "}\n"); + } + } else { + Printf(argstr, "%s", parse); + Printf(args, ",&%s", ln); + if (Strcmp(parse, "p") == 0) { + SwigType *lt = SwigType_ltype(pt); + SwigType_remember(pt); + if (Cmp(lt, "p.void") == 0) { + Printf(args, ",(void *)0"); + } else { + Printf(args, ",SWIGTYPE%s", SwigType_manglestr(pt)); + } + Delete(lt); + } + } + p = Getattr(p, "tmap:in:next"); + continue; + } 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); + } + + if (!varargs) { + Putc(':', argstr); + } else { + Putc(';', argstr); + /* If variable length arguments we need to emit the in typemap here */ + if (p && (tm = Getattr(p, "tmap:in"))) { + sprintf(source, "objv[%d]", i + 1); + Printf(incode, "if (objc > %d) {\n", i); + Replaceall(tm, "$input", source); + Printv(incode, tm, "\n", NIL); + Printf(incode, "}\n"); + } + } + + Printf(argstr, "%s\"", usage_string(Char(iname), type, parms)); + + Printv(f->code, "if (SWIG_GetArgs(interp, objc, objv,", argstr, args, ") == TCL_ERROR) SWIG_fail;\n", NIL); + + Printv(f->code, incode, NIL); + + /* Insert constraint checking code */ + for (p = parms; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (i = 0, p = parms; p; i++) { + if (!checkAttribute(p, "tmap:in:numinputs", "0") + && !Getattr(p, "tmap:in:parse") && (tm = Getattr(p, "tmap:freearg"))) { + if (Len(tm) != 0) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (i = 0, p = parms; p; i++) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); +#ifdef SWIG_USE_RESULTOBJ + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); +#else + Replaceall(tm, "$target", "(Tcl_GetObjResult(interp))"); + Replaceall(tm, "$result", "(Tcl_GetObjResult(interp))"); +#endif + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* Now write code to make the function call */ + String *actioncode = emit_action(n); + + /* Need to redo all of this code (eventually) */ + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) { + Replaceall(tm, "$source", Swig_cresult_name()); +#ifdef SWIG_USE_RESULTOBJ + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); +#else + Replaceall(tm, "$target", "(Tcl_GetObjResult(interp))"); + Replaceall(tm, "$result", "(Tcl_GetObjResult(interp))"); +#endif + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), name); + } + emit_return_variable(n, type, f); + + /* Dump output argument code */ + Printv(f->code, outarg, NIL); + + /* Dump the argument cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look for any remaining cleanup */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { + Replaceall(tm, "$source", Swig_cresult_name()); + Printf(f->code, "%s\n", tm); + } +#ifdef SWIG_USE_RESULTOBJ + Printv(f->code, "if (resultobj) Tcl_SetObjResult(interp, resultobj);\n", NIL); +#endif + Printv(f->code, "return TCL_OK;\n", NIL); + Printv(f->code, "fail:\n", cleanup, "return TCL_ERROR;\n", NIL); + Printv(f->code, "}\n", NIL); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + /* Dump out the function */ + Wrapper_print(f, f_wrappers); + + if (!Getattr(n, "sym:overloaded")) { + /* Register the function with Tcl */ + Printv(cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), ", NULL},\n", NIL); + } else { + if (!Getattr(n, "sym:nextSibling")) { + /* Emit overloading dispatch function */ + + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(clientData, interp, objc, argv - 1);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "SWIGINTERN int\n", dname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {", NIL); + Printf(df->code, "Tcl_Obj *CONST *argv = objv+1;\n"); + Printf(df->code, "int argc = objc-1;\n"); + Printv(df->code, dispatch, "\n", NIL); + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + String *fulldecl = Swig_name_decl(sibl); + Printf(protoTypes, "\n\" %s\\n\"", fulldecl); + Delete(fulldecl); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(df->code, "Tcl_SetResult(interp,(char *) " + "\"Wrong number or type of arguments for overloaded function '%s'.\\n\"" + "\n\" Possible C/C++ prototypes are:\\n\"%s, TCL_STATIC);\n", iname, protoTypes); + Delete(protoTypes); + Printf(df->code, "return TCL_ERROR;\n"); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printv(cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", dname, ", NULL},\n", NIL); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + } + + Delete(incode); + Delete(cleanup); + Delete(outarg); + Delete(argstr); + Delete(args); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + String *setname = 0; + String *setfname = 0; + Wrapper *setf = 0, *getf = 0; + int readonly = 0; + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* Create a function for getting a variable */ + int addfail = 0; + getf = NewWrapper(); + String *getname = Swig_name_get(NSPACE_TODO, iname); + String *getfname = Swig_name_wrapper(getname); + Setattr(n, "wrap:name", getfname); + Printv(getf->def, "SWIGINTERN const char *", getfname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, char *name1, char *name2, int flags) {", NIL); + Wrapper_add_local(getf, "value", "Tcl_Obj *value = 0"); + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "value"); + Replaceall(tm, "$result", "value"); + /* Printf(getf->code, "%s\n",tm); */ + addfail = emit_action_code(n, getf->code, tm); + Printf(getf->code, "if (value) {\n"); + Printf(getf->code, "Tcl_SetVar2(interp,name1,name2,Tcl_GetStringFromObj(value,NULL), flags);\n"); + Printf(getf->code, "Tcl_DecrRefCount(value);\n"); + Printf(getf->code, "}\n"); + Printf(getf->code, "return NULL;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Printf(getf->code, "return \"%s\";\n", iname); + } + Printf(getf->code, "}\n"); + Wrapper_print(getf, f_wrappers); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + DelWrapper(getf); + return SWIG_NOWRAP; + } + DelWrapper(getf); + + /* Try to create a function setting a variable */ + if (is_assignable(n)) { + setf = NewWrapper(); + setname = Swig_name_set(NSPACE_TODO, iname); + setfname = Swig_name_wrapper(setname); + Setattr(n, "wrap:name", setfname); + if (setf) { + Printv(setf->def, "SWIGINTERN const char *", setfname, + "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, char *name1, char *name2 SWIGUNUSED, int flags) {", NIL); + Wrapper_add_local(setf, "value", "Tcl_Obj *value = 0"); + Wrapper_add_local(setf, "name1o", "Tcl_Obj *name1o = 0"); + + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "value"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "value"); + Printf(setf->code, "name1o = Tcl_NewStringObj(name1,-1);\n"); + Printf(setf->code, "value = Tcl_ObjGetVar2(interp, name1o, 0, flags);\n"); + Printf(setf->code, "Tcl_DecrRefCount(name1o);\n"); + Printf(setf->code, "if (!value) SWIG_fail;\n"); + /* Printf(setf->code,"%s\n", tm); */ + emit_action_code(n, setf->code, tm); + Printf(setf->code, "return NULL;\n"); + Printf(setf->code, "fail:\n"); + Printf(setf->code, "return \"%s\";\n", iname); + Printf(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + readonly = 1; + } + } + DelWrapper(setf); + } else { + readonly = 1; + } + + + Printv(var_tab, tab4, "{ SWIG_prefix \"", iname, "\", 0, (swig_variable_func) ", getfname, ",", NIL); + if (readonly) { + static int readonlywrap = 0; + if (!readonlywrap) { + Wrapper *ro = NewWrapper(); + Printf(ro->def, + "SWIGINTERN const char *swig_readonly(ClientData clientData SWIGUNUSED, Tcl_Interp *interp SWIGUNUSED, char *name1 SWIGUNUSED, char *name2 SWIGUNUSED, int flags SWIGUNUSED) {"); + Printv(ro->code, "return \"Variable is read-only\";\n", "}\n", NIL); + Wrapper_print(ro, f_wrappers); + readonlywrap = 1; + DelWrapper(ro); + } + Printf(var_tab, "(swig_variable_func) swig_readonly},\n"); + } else { + Printv(var_tab, "(swig_variable_func) ", setfname, "},\n", NIL); + } + Delete(getfname); + Delete(setfname); + Delete(setname); + Delete(getname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *nsname = !namespace_option ? Copy(iname) : NewStringf("%s::%s", ns_name, iname); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + if (namespace_option) + Setattr(n, "sym:name", nsname); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(const_tab, "%s,\n", tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(f_init, "%s\n", tm); + } else { + Delete(nsname); + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + Delete(nsname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + String *funcname = Getattr(n, "wrap:name"); + if (!addSymbol(funcname, n)) + return SWIG_ERROR; + + Printf(f_init, "\t Tcl_CreateObjCommand(interp, SWIG_prefix \"%s\", (swig_wrapper_func) %s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n", name, + funcname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + static Hash *emitted = NewHash(); + String *mangled_classname = 0; + String *real_classname = 0; + + have_constructor = 0; + have_destructor = 0; + destructor_action = 0; + constructor_name = 0; + + if (itcl) { + constructor = NewString(""); + destructor = NewString(""); + base_classes = NewString(""); + base_class_init = NewString(""); + methods = NewString(""); + imethods = NewString(""); + attributes = NewString(""); + attribute_traces = NewString(""); + iattribute_traces = NewString(""); + + have_base_classes = 0; + have_methods = 0; + have_attributes = 0; + } + + class_name = Getattr(n, "sym:name"); + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + real_classname = Getattr(n, "name"); + mangled_classname = Swig_name_mangle(real_classname); + + if (Getattr(emitted, mangled_classname)) + return SWIG_NOWRAP; + Setattr(emitted, mangled_classname, "1"); + + attr_tab = NewString(""); + Printf(attr_tab, "static swig_attribute swig_"); + Printv(attr_tab, mangled_classname, "_attributes[] = {\n", NIL); + + methods_tab = NewStringf(""); + Printf(methods_tab, "static swig_method swig_"); + Printv(methods_tab, mangled_classname, "_methods[] = {\n", NIL); + + /* Generate normal wrappers */ + Language::classHandler(n); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType_add_pointer(t); + + // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' + // SwigType_remember(t); + String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); + SwigType_remember_clientdata(t, wrap_class); + + String *rt = Copy(getClassType()); + SwigType_add_pointer(rt); + + // Register the class structure with the type checker + /* Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_classname); */ + if (have_destructor) { + Printv(f_wrappers, "SWIGINTERN void swig_delete_", class_name, "(void *obj) {\n", NIL); + if (destructor_action) { + Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); + Printv(f_wrappers, destructor_action, "\n", NIL); + } else { + if (CPlusPlus) { + Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); + } else { + Printv(f_wrappers, " free((char *) obj);\n", NIL); + } + } + Printf(f_wrappers, "}\n"); + } + + Printf(methods_tab, " {0,0}\n};\n"); + Printv(f_wrappers, methods_tab, NIL); + + Printf(attr_tab, " {0,0,0}\n};\n"); + Printv(f_wrappers, attr_tab, NIL); + + /* Handle inheritance */ + + String *base_class = NewString(""); + String *base_class_names = NewString(""); + + if (itcl) { + base_classes = NewString(""); + } + + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + if (itcl) { + have_base_classes = 1; + Printv(base_classes, bname, " ", NIL); + Printv(base_class_init, " ", bname, "Ptr::constructor $ptr\n", NIL); + } + String *bmangle = Swig_name_mangle(bname); + // Printv(f_wrappers,"extern swig_class _wrap_class_", bmangle, ";\n", NIL); + // Printf(base_class,"&_wrap_class_%s",bmangle); + Printf(base_class, "0"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + /* Put code to register base classes in init function */ + + //Printf(f_init,"/* Register base : %s */\n", bmangle); + //Printf(f_init,"swig_%s_bases[%d] = (swig_class *) SWIG_TypeQuery(\"%s *\")->clientdata;\n", mangled_classname, index, SwigType_namestr(bname)); + b = Next(b); + index++; + Putc(',', base_class); + Delete(bmangle); + } + } + + if (itcl) { + String *ptrclass = NewString(""); + + // First, build the pointer base class + Printv(ptrclass, "itcl::class ", class_name, "Ptr {\n", NIL); + if (have_base_classes) + Printv(ptrclass, " inherit ", base_classes, "\n", NIL); + + // Define protected variables for SWIG object pointer + Printv(ptrclass, " protected variable swigobj\n", " protected variable thisown\n", NIL); + + // Define public variables + if (have_attributes) { + Printv(ptrclass, attributes, NIL); + + // base class swig_getset was being called for complex inheritance trees + if (namespace_option) { + + Printv(ptrclass, " protected method ", class_name, "_swig_getset {var name1 name2 op} {\n", NIL); + + Printv(ptrclass, + " switch -exact -- $op {\n", + " r {set $var [", ns_name, "::", class_name, "_[set var]_get $swigobj]}\n", + " w {", ns_name, "::", class_name, "_${var}_set $swigobj [set $var]}\n", " }\n", " }\n", NIL); + } else { + Printv(ptrclass, + " protected method ", class_name, "_swig_getset {var name1 name2 op} {\n", + " switch -exact -- $op {\n", + " r {set $var [", class_name, "_[set var]_get $swigobj]}\n", + " w {", class_name, "_${var}_set $swigobj [set $var]}\n", " }\n", " }\n", NIL); + } + } + // Add the constructor, which may include + // calls to base class class constructors + + Printv(ptrclass, " constructor { ptr } {\n", NIL); + if (have_base_classes) { + Printv(ptrclass, base_class_init, NIL); + Printv(ptrclass, " } {\n", NIL); + } + + Printv(ptrclass, " set swigobj $ptr\n", " set thisown 0\n", NIL); + + if (have_attributes) { + Printv(ptrclass, attribute_traces, NIL); + } + Printv(ptrclass, " }\n", NIL); + + + // Add destructor + Printv(ptrclass, " destructor {\n", + " set d_func delete_", class_name, "\n", + " if { $thisown && ([info command $d_func] != \"\") } {\n" " $d_func $swigobj\n", " }\n", " }\n", NIL); + + // Add methods + if (have_methods) { + Printv(ptrclass, imethods, NIL); + }; + + // Close out the pointer class + Printv(ptrclass, "}\n\n", NIL); + Printv(f_shadow, ptrclass, NIL); + // pointer class end + + + // Create the "real" class. + Printv(f_shadow, "itcl::class ", class_name, " {\n", NIL); + Printv(f_shadow, " inherit ", class_name, "Ptr\n", NIL); + + // If we have a constructor, then use it. + // If not, then we must have an abstract class without + // any constructor. So we create a class constructor + // which will fail for this class (but not for inherited + // classes). Note that the constructor must fail before + // calling the ptrclass constructor. + + if (have_constructor) { + Printv(f_shadow, constructor, NIL); + } else { + Printv(f_shadow, " constructor { } {\n", NIL); + Printv(f_shadow, " # This constructor will fail if called directly\n", NIL); + Printv(f_shadow, " if { [info class] == \"::", class_name, "\" } {\n", NIL); + Printv(f_shadow, " error \"No constructor for class ", class_name, (Getattr(n, "abstracts") ? " - class is abstract" : ""), "\"\n", NIL); + Printv(f_shadow, " }\n", NIL); + Printv(f_shadow, " }\n", NIL); + } + + Printv(f_shadow, "}\n\n", NIL); + } + + Printv(f_wrappers, "static swig_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); + Printv(f_wrappers, "static const char * swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); + Delete(base_class); + Delete(base_class_names); + + Printv(f_wrappers, "static swig_class _wrap_class_", mangled_classname, " = { \"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + + if (have_constructor) { + Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(NSPACE_TODO, constructor_name))); + Delete(constructor_name); + constructor_name = 0; + } else { + Printf(f_wrappers, "0"); + } + if (have_destructor) { + Printv(f_wrappers, ", swig_delete_", class_name, NIL); + } else { + Printf(f_wrappers, ",0"); + } + Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases,", + "swig_", mangled_classname, "_base_names, &swig_module, SWIG_TCL_HASHTABLE_INIT };\n", NIL); + + if (!itcl) { + Printv(cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, (ClientData)&_wrap_class_", mangled_classname, + "},\n", NIL); + }; + + Delete(t); + Delete(mangled_classname); + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + + String *realname, *rname; + + Language::memberfunctionHandler(n); + + realname = iname ? iname : name; + rname = Swig_name_wrapper(Swig_name_member(NSPACE_TODO, class_name, realname)); + if (!Getattr(n, "sym:nextSibling")) { + Printv(methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); + } + + if (itcl) { + ParmList *l = Getattr(n, "parms"); + Parm *p = 0; + String *pname = NewString(""); + + // Add this member to our class handler function + Printv(imethods, tab2, "method ", realname, " [list ", NIL); + + int pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + String *pn = Getattr(p, "name"); + String *dv = Getattr(p, "value"); + SwigType *pt = Getattr(p, "type"); + + Printv(pname, ",(", pt, ")", NIL); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + + if (Len(dv) > 0) { + String *defval = NewString(dv); + if (namespace_option) { + Insert(defval, 0, "::"); + Insert(defval, 0, ns_name); + } + if (Strncmp(dv, "(", 1) == 0) { + Insert(defval, 0, "$"); + Replaceall(defval, "(", ""); + Replaceall(defval, ")", ""); + } + Printv(imethods, "[list ", pname, " ", defval, "] ", NIL); + } else { + Printv(imethods, pname, " ", NIL); + } + } + ++pnum; + } + Printv(imethods, "] ", NIL); + + if (namespace_option) { + Printv(imethods, "{ ", ns_name, "::", class_name, "_", realname, " $swigobj", NIL); + } else { + Printv(imethods, "{ ", class_name, "_", realname, " $swigobj", NIL); + }; + + pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + String *pn = Getattr(p, "name"); + SwigType *pt = Getattr(p, "type"); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + Printv(imethods, " $", pname, NIL); + } + ++pnum; + } + Printv(imethods, " }\n", NIL); + have_methods = 1; + } + + Delete(rname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + String *rname; + + Language::membervariableHandler(n); + Printv(attr_tab, tab4, "{ \"-", symname, "\",", NIL); + rname = Swig_name_wrapper(Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname))); + Printv(attr_tab, rname, ", ", NIL); + Delete(rname); + if (!GetFlag(n, "feature:immutable")) { + rname = Swig_name_wrapper(Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, class_name, symname))); + Printv(attr_tab, rname, "},\n", NIL); + Delete(rname); + } else { + Printf(attr_tab, "0 },\n"); + } + + if (itcl) { + Printv(attributes, " public variable ", symname, "\n", NIL); + + Printv(attribute_traces, " trace variable ", symname, " rw [list ", class_name, "_swig_getset ", symname, "]\n", NIL); + Printv(attribute_traces, " set ", symname, "\n", NIL); + + have_attributes = 1; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + Language::constructorHandler(n); + + if (itcl) { + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + + String *realname; + + ParmList *l = Getattr(n, "parms"); + Parm *p = 0; + + String *pname = NewString(""); + + realname = iname ? iname : name; + + if (!have_constructor) { + // Add this member to our class handler function + Printf(constructor, " constructor { "); + + // Add parameter list + int pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + String *dv = Getattr(p, "value"); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + + if (Len(dv) > 0) { + Printv(constructor, "{", pname, " {", dv, "} } ", NIL); + } else { + Printv(constructor, pname, " ", NIL); + } + } + ++pnum; + } + Printf(constructor, "} { \n"); + + // [BRE] 08/17/00 Added test to see if we are instantiating this object + // type, or, if this constructor is being called as part of the itcl + // inheritance hierarchy. + // In the former case, we need to call the C++ constructor, in the + // latter we don't, or we end up with two C++ objects. + // Check to see if we are instantiating a 'realname' or something + // derived from it. + // + Printv(constructor, " if { [string equal -nocase \"", realname, "\" \"[namespace tail [info class]]\" ] } {\n", NIL); + + // Call to constructor wrapper and parent Ptr class + // [BRE] add -namespace/-prefix support + + if (namespace_option) { + Printv(constructor, " ", realname, "Ptr::constructor [", ns_name, "::new_", realname, NIL); + } else { + Printv(constructor, " ", realname, "Ptr::constructor [new_", realname, NIL); + } + + pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + Printv(constructor, " $", pname, NIL); + } + ++pnum; + } + + Printv(constructor, "]\n", " }\n", " } {\n", " set thisown 1\n", " }\n", NIL); + } + } + + if (!have_constructor) + constructor_name = NewString(Getattr(n, "sym:name")); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + have_destructor = 1; + destructor_action = Getattr(n, "wrap:action"); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + if (Strchr(s, ' ')) + return 0; + return 1; + } + + /* ------------------------------------------------------------ + * usage_string() + * ------------------------------------------------------------ */ + + char *usage_string(char *iname, SwigType *, ParmList *l) { + static String *temp = 0; + Parm *p; + int i, numopt, pcount; + + if (!temp) + temp = NewString(""); + Clear(temp); + if (namespace_option) { + Printf(temp, "%s::%s ", ns_name, iname); + } else { + Printf(temp, "%s ", iname); + } + /* Now go through and print parameters */ + i = 0; + pcount = emit_num_arguments(l); + numopt = pcount - emit_num_required(l); + for (p = l; p; p = nextSibling(p)) { + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + /* Only print an argument if not ignored */ + if (!checkAttribute(p, "tmap:in:numinputs", "0")) { + if (i >= (pcount - numopt)) + Putc('?', temp); + if (Len(pn) > 0) { + Printf(temp, "%s", pn); + } else { + Printf(temp, "%s", SwigType_str(pt, 0)); + } + if (i >= (pcount - numopt)) + Putc('?', temp); + Putc(' ', temp); + i++; + } + } + return Char(temp); + } + + String *runtimeCode() { + String *s = NewString(""); + String *serrors = Swig_include_sys("tclerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'tclerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *sapi = Swig_include_sys("tclapi.swg"); + if (!sapi) { + Printf(stderr, "*** Unable to open 'tclapi.swg'\n"); + } else { + Append(s, sapi); + Delete(sapi); + } + String *srun = Swig_include_sys("tclrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'tclrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigtclrun.h"); + } +}; + +/* ---------------------------------------------------------------------- + * swig_tcl() - Instantiate module + * ---------------------------------------------------------------------- */ + +static Language *new_swig_tcl() { + return new TCL8(); +} +extern "C" Language *swig_tcl(void) { + return new_swig_tcl(); +} diff --git a/contrib/tools/swig/Source/Modules/typepass.cxx b/contrib/tools/swig/Source/Modules/typepass.cxx new file mode 100644 index 00000000000..dc84cf94ae6 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/typepass.cxx @@ -0,0 +1,1303 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * typepass.cxx + * + * This module builds all of the internal type information by collecting + * typedef declarations as well as registering classes, structures, and unions. + * This information is needed to correctly handle shadow classes and other + * advanced features. This phase of compilation is also used to perform + * type-expansion. All types are fully qualified with namespace prefixes + * and other information needed for compilation. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +struct normal_node { + Symtab *symtab; + Hash *typescope; + List *normallist; + normal_node *next; +}; + +static normal_node *patch_list = 0; + +/* Singleton class - all non-static methods in this class are private */ +class TypePass:private Dispatcher { + Node *inclass; + Node *module; + int importmode; + String *nsname; + String *nssymname; + Hash *classhash; + List *normalize; + + TypePass() : + inclass(0), + module(0), + importmode(0), + nsname(0), + nssymname(0), + classhash(0), + normalize(0) { + } + + /* Normalize a type. Replaces type with fully qualified version */ + void normalize_type(SwigType *ty) { + SwigType *qty; + if (CPlusPlus) { + Replaceall(ty, "struct ", ""); + Replaceall(ty, "union ", ""); + Replaceall(ty, "class ", ""); + } + + qty = SwigType_typedef_qualified(ty); + /* Printf(stdout,"%s --> %s\n", ty, qty); */ + Clear(ty); + Append(ty, qty); + Delete(qty); + } + + /* Normalize a parameter list */ + + void normalize_parms(ParmList *p) { + while (p) { + SwigType *ty = Getattr(p, "type"); + normalize_type(ty); + /* This is a check for a function type */ + { + SwigType *qty = SwigType_typedef_resolve_all(ty); + if (SwigType_isfunction(qty)) { + SwigType_add_pointer(ty); + } + Delete(qty); + } + + String *value = Getattr(p, "value"); + if (value) { + Node *n = Swig_symbol_clookup(value, 0); + if (n) { + String *q = Swig_symbol_qualified(n); + if (q && Len(q)) { + String *vb = Swig_scopename_last(value); + Clear(value); + Printf(value, "%s::%s", SwigType_namestr(q), vb); + Delete(q); + } + } + } + if (value && SwigType_istemplate(value)) { + String *nv = SwigType_namestr(value); + Setattr(p, "value", nv); + } + p = nextSibling(p); + } + } + + void normalize_later(ParmList *p) { + while (p) { + SwigType *ty = Getattr(p, "type"); + Append(normalize, ty); + p = nextSibling(p); + } + } + + /* Walk through entries in normalize list and patch them up */ + void normalize_list() { + Hash *currentsym = Swig_symbol_current(); + + normal_node *nn = patch_list; + normal_node *np; + while (nn) { + Swig_symbol_setscope(nn->symtab); + SwigType_set_scope(nn->typescope); + Iterator t; + for (t = First(nn->normallist); t.item; t = Next(t)) { + normalize_type(t.item); + } + Delete(nn->normallist); + np = nn->next; + delete(nn); + nn = np; + } + Swig_symbol_setscope(currentsym); + } + + /* generate C++ inheritance type-relationships */ + void cplus_inherit_types_impl(Node *first, Node *cls, String *clsname, const char *bases, const char *baselist, int ispublic, String *cast = 0) { + + if (first == cls) + return; /* The Marcelo check */ + if (!cls) + cls = first; + List *alist = 0; + List *ilist = Getattr(cls, bases); + if (!ilist) { + List *nlist = Getattr(cls, baselist); + if (nlist) { + int len = Len(nlist); + int i; + for (i = 0; i < len; i++) { + Node *bcls = 0; + int clsforward = 0; + String *bname = Getitem(nlist, i); + String *sname = bname; + String *tname = 0; + + /* Try to locate the base class. We look in the symbol table and we chase + typedef declarations to get to the base class if necessary */ + Symtab *st = Getattr(cls, "sym:symtab"); + + if (SwigType_istemplate(bname)) { + tname = SwigType_typedef_resolve_all(bname); + sname = tname; + } + while (1) { + String *qsname = SwigType_typedef_qualified(sname); + bcls = Swig_symbol_clookup(qsname, st); + Delete(qsname); + if (bcls) { + if (Strcmp(nodeType(bcls), "class") != 0) { + /* Not a class. The symbol could be a typedef. */ + if (checkAttribute(bcls, "storage", "typedef")) { + SwigType *decl = Getattr(bcls, "decl"); + if (!decl || !(Len(decl))) { + sname = Getattr(bcls, "type"); + st = Getattr(bcls, "sym:symtab"); + if (SwigType_istemplate(sname)) { + if (tname) + Delete(tname); + tname = SwigType_typedef_resolve_all(sname); + sname = tname; + } + continue; + } + // A case when both outer and nested classes inherit from the same parent. Constructor may be found instead of the class itself. + } else if (GetFlag(cls, "nested") && checkAttribute(bcls, "nodeType", "constructor")) { + bcls = Getattr(bcls, "parentNode"); + if (Getattr(bcls, "typepass:visit")) { + if (!Getattr(bcls, "feature:onlychildren")) { + if (!ilist) + ilist = alist = NewList(); + Append(ilist, bcls); + } else { + if (!GetFlag(bcls, "feature:ignore")) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); + } + } + } + break; + } + if (Strcmp(nodeType(bcls), "classforward") != 0) { + Swig_error(Getfile(bname), Getline(bname), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); + Swig_error(Getfile(bcls), Getline(bcls), "See definition of '%s'.\n", SwigType_namestr(bname)); + } else { + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bname), Getline(bname), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname)); + clsforward = 1; + } + bcls = 0; + } else { + if (Getattr(bcls, "typepass:visit")) { + if (!Getattr(bcls, "feature:onlychildren")) { + if (!ilist) + ilist = alist = NewList(); + Append(ilist, bcls); + } else { + if (!GetFlag(bcls, "feature:ignore")) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); + } + } + } else { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' undefined.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "'%s' must be defined before it is used as a base class.\n", SwigType_namestr(bname)); + } + } + } + break; + } + + if (tname) + Delete(tname); + if (!bcls) { + if (!clsforward && !GetFlag(cls, "feature:ignore")) { + if (ispublic && !Getmeta(bname, "already_warned")) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); + if (Strchr(bname, '<')) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Maybe you forgot to instantiate '%s' using %%template.\n", SwigType_namestr(bname)); + } + Setmeta(bname, "already_warned", "1"); + } + } + SwigType_inherit(clsname, bname, cast, 0); + } + } + } + if (ilist) { + Setattr(cls, bases, ilist); + } + } + if (alist) + Delete(alist); + + if (!ilist) + return; + int len = Len(ilist); + int i; + for (i = 0; i < len; i++) { + Node *n = Getitem(ilist, i); + String *bname = Getattr(n, "name"); + Node *bclass = n; /* Getattr(n,"class"); */ + Hash *scopes = Getattr(bclass, "typescope"); + SwigType_inherit(clsname, bname, cast, 0); + if (ispublic && !GetFlag(bclass, "feature:ignore")) { + String *smartptr = Getattr(first, "feature:smartptr"); + if (smartptr) { + SwigType *smart = Swig_cparse_smartptr(first); + if (smart) { + /* Record a (fake) inheritance relationship between smart pointer + and smart pointer to base class, so that smart pointer upcasts + are automatically generated. */ + SwigType *bsmart = Copy(smart); + + // TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates + SwigType *rclsname = SwigType_typedef_resolve_all(clsname); + SwigType *rbname = SwigType_typedef_resolve_all(bname); + int replace_count = Replaceall(bsmart, rclsname, rbname); + if (replace_count == 0) { + // If no replacement made, it will be because rclsname is fully resolved, but the + // type in the smartptr feature used a typedef or not fully resolved name. + String *firstname = Getattr(first, "name"); + Replaceall(bsmart, firstname, rbname); + } + // The code above currently creates a smartptr of the base class by substitution, replacing Derived + // with Base resulting in something like: 'smartptr< Derived >' from 'smartptr< Base >'. Instead + // the feature:smartptr should be used as it also contains 'smartptr< Base >' as specified by the user. + // A similar fix should also be done in upcastsCode in java.cxx, csharp.cxx and writeClassUpcast in d.cxx. + // Printf(stdout, "smartcomparison %s <=> %s\n", SwigType_namestr(bsmart), Getattr(bclass, "feature:smartptr")); + + Delete(rclsname); + Delete(rbname); + String *smartnamestr = SwigType_namestr(smart); + String *bsmartnamestr = SwigType_namestr(bsmart); + /* construct casting code */ + String *convcode = NewStringf("\n *newmemory = SWIG_CAST_NEW_MEMORY;\n return (void *) new %s(*(%s *)$from);\n", bsmartnamestr, smartnamestr); + Delete(bsmartnamestr); + Delete(smartnamestr); + /* setup inheritance relationship between smart pointer templates */ + SwigType_inherit(smart, bsmart, 0, convcode); + if (!GetFlag(bclass, "feature:smartptr")) + Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Base class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(bclass, "name")), SwigType_namestr(Getattr(first, "name"))); + Delete(convcode); + Delete(bsmart); + } + Delete(smart); + } else { + if (GetFlag(bclass, "feature:smartptr")) + Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Derived class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(first, "name")), SwigType_namestr(Getattr(bclass, "name"))); + } + } + if (!importmode) { + String *btype = Copy(bname); + SwigType_add_pointer(btype); + SwigType_remember(btype); + Delete(btype); + } + if (scopes) { + SwigType_inherit_scope(scopes); + } + /* Set up inheritance in the symbol table */ + Symtab *st = Getattr(cls, "symtab"); + Symtab *bst = Getattr(bclass, "symtab"); + if (st == bst) { + Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", SwigType_namestr(Getattr(cls, "name"))); + continue; + } + Symtab *s = Swig_symbol_current(); + Swig_symbol_setscope(st); + Swig_symbol_inherit(bst); + Swig_symbol_setscope(s); + + /* Recursively hit base classes */ + String *namestr = SwigType_namestr(Getattr(bclass, "name")); + String *newcast = NewStringf("(%s *)%s", namestr, cast); + Delete(namestr); + cplus_inherit_types_impl(first, bclass, clsname, bases, baselist, ispublic, newcast); + Delete(newcast); + } + } + + void append_list(List *lb, List *la) { + if (la && lb) { + for (Iterator bi = First(la); bi.item; bi = Next(bi)) { + Append(lb, bi.item); + } + } + } + + void cplus_inherit_types(Node *first, Node *cls, String *clsname, String *cast = 0) { + cplus_inherit_types_impl(first, cls, clsname, "bases", "baselist", 1, cast); + cplus_inherit_types_impl(first, cls, clsname, "protectedbases", "protectedbaselist", 0, cast); + cplus_inherit_types_impl(first, cls, clsname, "privatebases", "privatebaselist", 0, cast); + + if (!cls) + cls = first; + + List *allbases = NewList(); + append_list(allbases, Getattr(cls, "bases")); + append_list(allbases, Getattr(cls, "protectedbases")); + append_list(allbases, Getattr(cls, "privatebases")); + if (Len(allbases)) { + Setattr(cls, "allbases", allbases); + } + Delete(allbases); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + importmode = 0; + module = Getattr(n, "module"); + inclass = 0; + normalize = 0; + nsname = 0; + nssymname = 0; + classhash = Getattr(n, "classes"); + emit_children(n); + normalize_list(); + SwigType_set_scope(0); + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * moduleDirective() + * ------------------------------------------------------------ */ + + virtual int moduleDirective(Node *n) { + if (!module) { + module = n; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + String *oldmodule = module; + int oldimport = importmode; + importmode = 1; + module = 0; + emit_children(n); + importmode = oldimport; + module = oldmodule; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * includeDirective() + * externDirective() + * extendDirective() + * ------------------------------------------------------------ */ + + virtual int includeDirective(Node *n) { + return emit_children(n); + } + virtual int externDeclaration(Node *n) { + return emit_children(n); + } + virtual int extendDirective(Node *n) { + return emit_children(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *unnamed = Getattr(n, "unnamed"); + String *storage = Getattr(n, "storage"); + String *kind = Getattr(n, "kind"); + save_value<Node*> oldinclass(inclass); + List *olist = normalize; + Symtab *symtab; + String *nname = 0; + String *fname = 0; + String *scopename = 0; + String *template_default_expanded = 0; + + normalize = NewList(); + + if (name) { + if (SwigType_istemplate(name)) { + // We need to fully resolve the name and expand default template parameters to make templates work correctly */ + Node *cn; + SwigType *resolved_name = SwigType_typedef_resolve_all(name); + SwigType *deftype_name = Swig_symbol_template_deftype(resolved_name, 0); + fname = Copy(resolved_name); + if (!Equal(resolved_name, deftype_name)) + template_default_expanded = Copy(deftype_name); + if (!Equal(fname, name) && (cn = Swig_symbol_clookup_local(fname, 0))) { + if ((n == cn) + || (Strcmp(nodeType(cn), "template") == 0) + || (Getattr(cn, "feature:onlychildren") != 0) + || (Getattr(n, "feature:onlychildren") != 0)) { + Swig_symbol_cadd(fname, n); + if (template_default_expanded) + Swig_symbol_cadd(template_default_expanded, n); + SwigType_typedef_class(fname); + scopename = Copy(fname); + } else { + Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "Template '%s' was already wrapped,\n", SwigType_namestr(name)); + Swig_warning(WARN_TYPE_REDEFINED, Getfile(cn), Getline(cn), "previous wrap of '%s'.\n", SwigType_namestr(Getattr(cn, "name"))); + scopename = 0; + } + } else { + Swig_symbol_cadd(fname, n); + SwigType_typedef_class(fname); + scopename = Copy(fname); + } + Delete(deftype_name); + Delete(resolved_name); + } else { + if ((CPlusPlus) || (unnamed)) { + SwigType_typedef_class(name); + } else { + SwigType_typedef_class(NewStringf("%s %s", kind, name)); + } + scopename = Copy(name); + } + } else { + scopename = 0; + } + + Setattr(n, "typepass:visit", "1"); + + /* Need to set up a typedef if unnamed */ + if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { + SwigType_typedef(unnamed, tdname); + } + // name of the outer class should already be patched to contain its outer classes names, but not to contain namespaces + // namespace name (if present) is added after processing child nodes + if (Getattr(n, "nested:outer") && name) { + String *outerName = Getattr(Getattr(n, "nested:outer"), "name"); + name = NewStringf("%s::%s", outerName, name); + Setattr(n, "name", name); + if (tdname) { + tdname = NewStringf("%s::%s", outerName, tdname); + Setattr(n, "tdname", tdname); + } + } + + if (nsname && name) { + nname = NewStringf("%s::%s", nsname, name); + String *tdname = Getattr(n, "tdname"); + if (tdname) { + tdname = NewStringf("%s::%s", nsname, tdname); + Setattr(n, "tdname", tdname); + } + } + if (nssymname) { + if (GetFlag(n, "feature:nspace")) + Setattr(n, "sym:nspace", nssymname); + } + SwigType_new_scope(scopename); + SwigType_attach_symtab(Getattr(n, "symtab")); + + /* Inherit type definitions into the class */ + if (name && !(GetFlag(n, "nested") && !checkAttribute(n, "access", "public") && + (GetFlag(n, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None))) { + cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name)); + } + + inclass = n; + symtab = Swig_symbol_setscope(Getattr(n, "symtab")); + emit_children(n); + Swig_symbol_setscope(symtab); + + Hash *ts = SwigType_pop_scope(); + Setattr(n, "typescope", ts); + Delete(ts); + Setattr(n, "module", module); + + // When a fully qualified templated type with default parameters is used in the parsed code, + // the following additional symbols and scopes are needed for successful lookups + if (template_default_expanded) { + Swig_symbol_alias(template_default_expanded, Getattr(n, "symtab")); + SwigType_scope_alias(template_default_expanded, Getattr(n, "typescope")); + } + + /* Normalize deferred types */ + { + normal_node *nn = new normal_node(); + nn->normallist = normalize; + nn->symtab = Getattr(n, "symtab"); + nn->next = patch_list; + nn->typescope = Getattr(n, "typescope"); + patch_list = nn; + } + + normalize = olist; + + /* If in a namespace, patch the class name */ + if (nname) { + Setattr(n, "name", nname); + Delete(nname); + } + Delete(fname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * templateDeclaration() + * ------------------------------------------------------------ */ + + virtual int templateDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *ttype = Getattr(n, "templatetype"); + if (Strcmp(ttype, "class") == 0) { + String *rname = SwigType_typedef_resolve_all(name); + SwigType_typedef_class(rname); + Delete(rname); + } else if (Strcmp(ttype, "classforward") == 0) { + String *rname = SwigType_typedef_resolve_all(name); + SwigType_typedef_class(rname); + Delete(rname); + /* SwigType_typedef_class(name); */ + } else if (Strcmp(ttype, "cdecl") == 0) { + String *rname = SwigType_typedef_resolve_all(name); + SwigType_typedef_class(rname); + Delete(rname); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * lambdaDeclaration() + * ------------------------------------------------------------ */ + + virtual int lambdaDeclaration(Node *) { + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classforwardDeclaration() + * ------------------------------------------------------------ */ + + virtual int classforwardDeclaration(Node *n) { + + /* Can't do inside a C struct because it breaks C nested structure wrapping */ + if ((!inclass) || (CPlusPlus)) { + String *name = Getattr(n, "name"); + SwigType_typedef_class(name); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * namespaceDeclaration() + * ------------------------------------------------------------ */ + + virtual int namespaceDeclaration(Node *n) { + Symtab *symtab; + String *name = Getattr(n, "name"); + String *alias = Getattr(n, "alias"); + List *olist = normalize; + normalize = NewList(); + if (alias) { + Typetab *ts = Getattr(n, "typescope"); + if (!ts) { + /* Create an empty scope for the alias */ + Node *ns = Getattr(n, "namespace"); + SwigType_scope_alias(name, Getattr(ns, "typescope")); + ts = Getattr(ns, "typescope"); + Setattr(n, "typescope", ts); + } + /* Namespace alias */ + return SWIG_OK; + } else { + if (name) { + Node *nn = Swig_symbol_clookup(name, n); + Hash *ts = 0; + if (nn) + ts = Getattr(nn, "typescope"); + if (!ts) { + SwigType_new_scope(name); + SwigType_attach_symtab(Getattr(n, "symtab")); + } else { + SwigType_set_scope(ts); + } + } + String *oldnsname = nsname; + String *oldnssymname = nssymname; + nsname = Swig_symbol_qualified(Getattr(n, "symtab")); + nssymname = Swig_symbol_qualified_language_scopename(Getattr(n, "symtab")); + symtab = Swig_symbol_setscope(Getattr(n, "symtab")); + emit_children(n); + Swig_symbol_setscope(symtab); + + if (name) { + Hash *ts = SwigType_pop_scope(); + Setattr(n, "typescope", ts); + Delete(ts); + } + + /* Normalize deferred types */ + { + normal_node *nn = new normal_node(); + nn->normallist = normalize; + nn->symtab = Getattr(n, "symtab"); + nn->next = patch_list; + nn->typescope = Getattr(n, "typescope"); + patch_list = nn; + } + normalize = olist; + + Delete(nssymname); + nssymname = oldnssymname; + Delete(nsname); + nsname = oldnsname; + return SWIG_OK; + } + } + + /* ------------------------------------------------------------ + * cDeclaration() + * ------------------------------------------------------------ */ + + virtual int cDeclaration(Node *n) { + if (NoExcept) { + Delattr(n, "throws"); + } + + /* Normalize types. */ + SwigType *ty = Getattr(n, "type"); + if (!ty) { + return SWIG_OK; + } + normalize_type(ty); + SwigType *decl = Getattr(n, "decl"); + if (decl) { + normalize_type(decl); + } + normalize_parms(Getattr(n, "parms")); + normalize_parms(Getattr(n, "throws")); + if (GetFlag(n, "conversion_operator")) { + /* The call to the operator in the generated wrapper must be fully qualified in order to compile */ + SwigType *name = Getattr(n, "name"); + SwigType *qualifiedname = Swig_symbol_string_qualify(name, 0); + Clear(name); + Append(name, qualifiedname); + Delete(qualifiedname); + } + + if (checkAttribute(n, "storage", "typedef")) { + String *name = Getattr(n, "name"); + ty = Getattr(n, "type"); + decl = Getattr(n, "decl"); + SwigType *t = Copy(ty); + { + /* If the typename is qualified, make sure the scopename is fully qualified when making a typedef */ + if (Swig_scopename_check(t) && strncmp(Char(t), "::", 2)) { + String *base, *prefix, *qprefix; + base = Swig_scopename_last(t); + prefix = Swig_scopename_prefix(t); + qprefix = SwigType_typedef_qualified(prefix); + Delete(t); + t = NewStringf("%s::%s", qprefix, base); + Delete(base); + Delete(prefix); + Delete(qprefix); + } + } + SwigType_push(t, decl); + if (CPlusPlus) { + Replaceall(t, "struct ", ""); + Replaceall(t, "union ", ""); + Replaceall(t, "class ", ""); + } + SwigType_typedef(t, name); + } + /* If namespaces are active. We need to patch the name with a namespace prefix */ + if (nsname && !inclass) { + String *name = Getattr(n, "name"); + if (name) { + String *nname = NewStringf("%s::%s", nsname, name); + Setattr(n, "name", nname); + Delete(nname); + } + } + clean_overloaded(n); + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * constructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int constructorDeclaration(Node *n) { + if (NoExcept) { + Delattr(n, "throws"); + } + + normalize_parms(Getattr(n, "parms")); + normalize_parms(Getattr(n, "throws")); + + clean_overloaded(n); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int destructorDeclaration(Node *) { + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantDirective() + * ------------------------------------------------------------ */ + + virtual int constantDirective(Node *n) { + SwigType *ty = Getattr(n, "type"); + if (ty) { + Setattr(n, "type", SwigType_typedef_qualified(ty)); + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + String *name = Getattr(n, "name"); + + if (name) { + String *scope = 0; + + // Add a typedef to the type table so that we can use 'enum Name' as well as just 'Name' + if (nsname || inclass) { + + // But first correct the name and tdname to contain the fully qualified scopename + if (nsname && inclass) { + scope = NewStringf("%s::%s", nsname, Getattr(inclass, "name")); + } else if (nsname) { + scope = NewStringf("%s", nsname); + } else if (inclass) { + scope = NewStringf("%s", Getattr(inclass, "name")); + } + + String *nname = NewStringf("%s::%s", scope, name); + Setattr(n, "name", nname); + + String *tdname = Getattr(n, "tdname"); + if (tdname) { + tdname = NewStringf("%s::%s", scope, tdname); + Setattr(n, "tdname", tdname); + } + + SwigType *t = NewStringf("enum %s", nname); + SwigType_typedef(t, name); + } else { + SwigType *t = NewStringf("enum %s", name); + SwigType_typedef(t, name); + } + Delete(scope); + } + + String *tdname = Getattr(n, "tdname"); + String *unnamed = Getattr(n, "unnamed"); + String *storage = Getattr(n, "storage"); + + // Construct enumtype - for declaring an enum of this type with SwigType_ltype() etc + String *enumtype = 0; + if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { + enumtype = Copy(Getattr(n, "tdname")); + } else if (name) { + enumtype = NewStringf("%s%s", CPlusPlus ? "" : "enum ", Getattr(n, "name")); + } else { + // anonymous enums + enumtype = Copy(Getattr(n, "type")); + } + Setattr(n, "enumtype", enumtype); + + if (nssymname) { + if (GetFlag(n, "feature:nspace")) + Setattr(n, "sym:nspace", nssymname); + } + + // This block of code is for dealing with %ignore on an enum item where the target language + // attempts to use the C enum value in the target language itself and expects the previous enum value + // to be one more than the previous value... the previous enum item might not exist if it is ignored! + // - It sets the first non-ignored enum item with the "firstenumitem" attribute. + // - It adds an enumvalue attribute if the previous enum item is ignored + { + Node *c; + int count = 0; + String *previous = 0; + bool previous_ignored = false; + bool firstenumitem = false; + for (c = firstChild(n); c; c = nextSibling(c)) { + assert(strcmp(Char(nodeType(c)), "enumitem") == 0); + + bool reset; + String *enumvalue = Getattr(c, "enumvalue"); + if (GetFlag(c, "feature:ignore") || !Getattr(c, "sym:name")) { + reset = enumvalue ? true : false; + previous_ignored = true; + } else { + if (!enumvalue && previous_ignored) { + if (previous) + Setattr(c, "enumvalue", NewStringf("(%s) + %d", previous, count+1)); + else + Setattr(c, "enumvalue", NewStringf("%d", count)); + SetFlag(c, "virtenumvalue"); // identify enumvalue as virtual, ie not from the parsed source + } + if (!firstenumitem) { + SetFlag(c, "firstenumitem"); + firstenumitem = true; + } + reset = true; + previous_ignored = false; + } + if (reset) { + previous = enumvalue ? enumvalue : Getattr(c, "name"); + count = 0; + } else { + count++; + } + } + } + + emit_children(n); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *value = Getattr(n, "value"); + String *scopedenum = Getattr(parentNode(n), "scopedenum"); + if (!value) + value = name; + if (Strcmp(value, name) == 0) { + String *new_value; + if ((nsname || inclass || scopedenum) && cparse_cplusplus) { + new_value = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); + } else { + new_value = NewString(value); + } + if ((nsname || inclass || scopedenum) && !cparse_cplusplus) { + String *cppvalue = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); + Setattr(n, "cppvalue", cppvalue); /* for target languages that always generate C++ code even when wrapping C code */ + } + Setattr(n, "value", new_value); + Delete(new_value); + } + Node *next = nextSibling(n); + + // Make up an enumvalue if one was not specified in the parsed code (not designed to be used on enum items and %ignore - enumvalue will be set instead) + if (!GetFlag(n, "feature:ignore")) { + if (Getattr(n, "_last") && !Getattr(n, "enumvalue")) { // Only the first enum item has _last set (Note: first non-ignored enum item has firstenumitem set) + Setattr(n, "enumvalueex", "0"); + } + if (next && !Getattr(next, "enumvalue")) { + Setattr(next, "enumvalueex", NewStringf("%s + 1", Getattr(n, "sym:name"))); + } + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumforwardDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumforwardDeclaration(Node *n) { + + // Use enumDeclaration() to do all the hard work. + // Note that no children can be emitted in a forward declaration as there aren't any. + int result = enumDeclaration(n); + if (result == SWIG_OK) { + // Detect when the real enum matching the forward enum declaration has not been parsed/declared + SwigType *ty = SwigType_typedef_resolve_all(Getattr(n, "type")); + Replaceall(ty, "enum ", ""); + Node *nn = Swig_symbol_clookup(ty, 0); + + String *nodetype = nn ? nodeType(nn) : 0; + if (nodetype) { + if (Equal(nodetype, "enumforward")) { + SetFlag(nn, "enumMissing"); + } // if a real enum was declared this would be an "enum" node type + } + Delete(ty); + } + return result; + } + +#ifdef DEBUG_OVERLOADED + static void show_overloaded(Node *n) { + Node *c = Getattr(n, "sym:overloaded"); + Node *checkoverloaded = c; + Printf(stdout, "-------------------- overloaded start %s sym:overloaded():%p -------------------------------\n", Getattr(n, "name"), c); + while (c) { + if (Getattr(c, "error")) { + c = Getattr(c, "sym:nextSibling"); + continue; + } + if (Getattr(c, "sym:overloaded") != checkoverloaded) { + Printf(stdout, "sym:overloaded error c:%p checkoverloaded:%p\n", c, checkoverloaded); + Swig_print_node(c); + SWIG_exit(EXIT_FAILURE); + } + + String *decl = Strcmp(nodeType(c), "using") == 0 ? NewString("------") : Getattr(c, "decl"); + Printf(stdout, " show_overloaded %s::%s(%s) [%s] nodeType:%s\n", parentNode(c) ? Getattr(parentNode(c), "name") : "NOPARENT", Getattr(c, "name"), decl, Getattr(c, "sym:overname"), nodeType(c)); + if (!Getattr(c, "sym:overloaded")) { + Printf(stdout, "sym:overloaded error.....%p\n", c); + Swig_print_node(c); + SWIG_exit(EXIT_FAILURE); + } + c = Getattr(c, "sym:nextSibling"); + } + Printf(stdout, "-------------------- overloaded end %s -------------------------------\n", Getattr(n, "name")); + } +#endif + + /* ------------------------------------------------------------ + * usingDeclaration() + * ------------------------------------------------------------ */ + + virtual int usingDeclaration(Node *n) { + if (Getattr(n, "namespace")) { + /* using namespace id */ + + /* For a namespace import. We set up inheritance in the type system */ + Node *ns = Getattr(n, "node"); + if (ns) { + Typetab *ts = Getattr(ns, "typescope"); + if (ts) { + SwigType_using_scope(ts); + } + } + return SWIG_OK; + } else { + Node *ns; + /* using id */ + Symtab *stab = Getattr(n, "sym:symtab"); + if (stab) { + String *uname = Getattr(n, "uname"); + ns = Swig_symbol_clookup(uname, stab); + if (!ns && SwigType_istemplate(uname)) { + String *tmp = Swig_symbol_template_deftype(uname, 0); + if (!Equal(tmp, uname)) { + ns = Swig_symbol_clookup(tmp, stab); + } + Delete(tmp); + } + } else { + ns = 0; + } + if (!ns) { + if (is_public(n)) { + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname"))); + } + } else { + /* Only a single symbol is being used. There are only a few symbols that + we actually care about. These are typedef, class declarations, and enum */ + String *ntype = nodeType(ns); + if (Strcmp(ntype, "cdecl") == 0) { + if (checkAttribute(ns, "storage", "typedef")) { + /* A typedef declaration */ + String *uname = Getattr(n, "uname"); + SwigType_typedef_using(uname); + } else { + /* A normal C declaration. */ + if ((inclass) && (!GetFlag(n, "feature:ignore")) && (Getattr(n, "sym:name"))) { + Node *c = ns; + Node *unodes = 0, *last_unodes = 0; + int ccount = 0; + String *symname = Getattr(n, "sym:name"); + while (c) { + if (Strcmp(nodeType(c), "cdecl") == 0) { + if (!(Swig_storage_isstatic(c) + || checkAttribute(c, "storage", "typedef") + || checkAttribute(c, "storage", "friend") + || (Getattr(c, "feature:extend") && !Getattr(c, "code")) + || GetFlag(c, "feature:ignore"))) { + + /* Don't generate a method if the method is overridden in this class, + * for example don't generate another m(bool) should there be a Base::m(bool) : + * struct Derived : Base { + * void m(bool); + * using Base::m; + * }; + */ + String *csymname = Getattr(c, "sym:name"); + if (!csymname || (Strcmp(csymname, symname) == 0)) { + { + String *decl = Getattr(c, "decl"); + Node *over = Getattr(n, "sym:overloaded"); + int match = 0; + while (over) { + String *odecl = Getattr(over, "decl"); + if (Cmp(decl, odecl) == 0) { + match = 1; + break; + } + over = Getattr(over, "sym:nextSibling"); + } + if (match) { + c = Getattr(c, "csym:nextSibling"); + continue; + } + } + Node *nn = copyNode(c); + Delattr(nn, "access"); // access might be different from the method in the base class + Setattr(nn, "access", Getattr(n, "access")); + if (!Getattr(nn, "sym:name")) + Setattr(nn, "sym:name", symname); + + if (!GetFlag(nn, "feature:ignore")) { + ParmList *parms = CopyParmList(Getattr(c, "parms")); + int is_pointer = SwigType_ispointer_return(Getattr(nn, "decl")); + int is_void = checkAttribute(nn, "type", "void") && !is_pointer; + Setattr(nn, "parms", parms); + Delete(parms); + if (Getattr(n, "feature:extend")) { + String *ucode = is_void ? NewStringf("{ self->%s(", Getattr(n, "uname")) : NewStringf("{ return self->%s(", Getattr(n, "uname")); + + for (ParmList *p = parms; p;) { + Append(ucode, Getattr(p, "name")); + p = nextSibling(p); + if (p) + Append(ucode, ","); + } + Append(ucode, "); }"); + Setattr(nn, "code", ucode); + Delete(ucode); + } + ParmList *throw_parm_list = Getattr(c, "throws"); + if (throw_parm_list) + Setattr(nn, "throws", CopyParmList(throw_parm_list)); + ccount++; + if (!last_unodes) { + last_unodes = nn; + unodes = nn; + } else { + Setattr(nn, "previousSibling", last_unodes); + Setattr(last_unodes, "nextSibling", nn); + Setattr(nn, "sym:previousSibling", last_unodes); + Setattr(last_unodes, "sym:nextSibling", nn); + Setattr(nn, "sym:overloaded", unodes); + Setattr(unodes, "sym:overloaded", unodes); + last_unodes = nn; + } + } else { + Delete(nn); + } + } + } + } + c = Getattr(c, "csym:nextSibling"); + } + if (unodes) { + set_firstChild(n, unodes); + if (ccount > 1) { + if (!Getattr(n, "sym:overloaded")) { + Setattr(n, "sym:overloaded", n); + Setattr(n, "sym:overname", "_SWIG_0"); + } + } + } + + /* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the + * list of overloaded methods we have just added in as child nodes to the "using" node. + * The node will still exist, it is just the symbol table linked list of overloaded methods + * which is hacked. */ + if (Getattr(n, "sym:overloaded")) { + int cnt = 0; +#ifdef DEBUG_OVERLOADED + Node *debugnode = n; + show_overloaded(n); +#endif + if (!firstChild(n)) { + // Remove from overloaded list ('using' node does not actually end up adding in any methods) + Node *ps = Getattr(n, "sym:previousSibling"); + Node *ns = Getattr(n, "sym:nextSibling"); + if (ps) { + Setattr(ps, "sym:nextSibling", ns); + } + if (ns) { + Setattr(ns, "sym:previousSibling", ps); + } + } else { + // The 'using' node results in methods being added in - slot in the these methods here + Node *ps = Getattr(n, "sym:previousSibling"); + Node *ns = Getattr(n, "sym:nextSibling"); + Node *fc = firstChild(n); + Node *pp = fc; + + Node *firstoverloaded = Getattr(n, "sym:overloaded"); + if (firstoverloaded == n) { + // This 'using' node we are cutting out was the first node in the overloaded list. + // Change the first node in the list to its first sibling + Delattr(firstoverloaded, "sym:overloaded"); + Node *nnn = Getattr(firstoverloaded, "sym:nextSibling"); + firstoverloaded = fc; + while (nnn) { + Setattr(nnn, "sym:overloaded", firstoverloaded); + nnn = Getattr(nnn, "sym:nextSibling"); + } + } + while (pp) { + Node *ppn = Getattr(pp, "sym:nextSibling"); + Setattr(pp, "sym:overloaded", firstoverloaded); + Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++)); + if (ppn) + pp = ppn; + else + break; + } + if (ps) { + Setattr(ps, "sym:nextSibling", fc); + Setattr(fc, "sym:previousSibling", ps); + } + if (ns) { + Setattr(ns, "sym:previousSibling", pp); + Setattr(pp, "sym:nextSibling", ns); + } +#ifdef DEBUG_OVERLOADED + debugnode = firstoverloaded; +#endif + } + Delattr(n, "sym:previousSibling"); + Delattr(n, "sym:nextSibling"); + Delattr(n, "sym:overloaded"); + Delattr(n, "sym:overname"); +#ifdef DEBUG_OVERLOADED + show_overloaded(debugnode); +#endif + clean_overloaded(n); // Needed? + } + } + } + } else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) { + /* We install the using class name as kind of a typedef back to the original class */ + String *uname = Getattr(n, "uname"); + /* Import into current type scope */ + SwigType_typedef_using(uname); + } else if (Strcmp(ntype, "enum") == 0) { + SwigType_typedef_using(Getattr(n, "uname")); + } else if (Strcmp(ntype, "template") == 0) { + SwigType_typedef_using(Getattr(n, "uname")); + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * typemapDirective() + * ------------------------------------------------------------ */ + + virtual int typemapDirective(Node *n) { + if (inclass || nsname) { + Node *items = firstChild(n); + while (items) { + Parm *pattern = Getattr(items, "pattern"); + Parm *parms = Getattr(items, "parms"); + normalize_later(pattern); + normalize_later(parms); + items = nextSibling(items); + } + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * typemapcopyDirective() + * ------------------------------------------------------------ */ + + virtual int typemapcopyDirective(Node *n) { + if (inclass || nsname) { + Node *items = firstChild(n); + ParmList *pattern = Getattr(n, "pattern"); + normalize_later(pattern); + while (items) { + ParmList *npattern = Getattr(items, "pattern"); + normalize_later(npattern); + items = nextSibling(items); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * applyDirective() + * ------------------------------------------------------------ */ + + virtual int applyDirective(Node *n) { + if (inclass || nsname) { + ParmList *pattern = Getattr(n, "pattern"); + normalize_later(pattern); + Node *items = firstChild(n); + while (items) { + Parm *apattern = Getattr(items, "pattern"); + normalize_later(apattern); + items = nextSibling(items); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * clearDirective() + * ------------------------------------------------------------ */ + + virtual int clearDirective(Node *n) { + if (inclass || nsname) { + Node *p; + for (p = firstChild(n); p; p = nextSibling(p)) { + ParmList *pattern = Getattr(p, "pattern"); + normalize_later(pattern); + } + } + return SWIG_OK; + } + +public: + static void pass(Node *n) { + TypePass t; + t.top(n); + } +}; + +void Swig_process_types(Node *n) { + if (!n) + return; + TypePass::pass(n); +} + diff --git a/contrib/tools/swig/Source/Modules/utils.cxx b/contrib/tools/swig/Source/Modules/utils.cxx new file mode 100644 index 00000000000..2964ed3a66a --- /dev/null +++ b/contrib/tools/swig/Source/Modules/utils.cxx @@ -0,0 +1,218 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * utils.cxx + * + * Various utility functions. + * ----------------------------------------------------------------------------- */ + +#include <swigmod.h> + +int is_public(Node *n) { + String *access = Getattr(n, "access"); + return !access || !Cmp(access, "public"); +} + +int is_private(Node *n) { + String *access = Getattr(n, "access"); + return access && !Cmp(access, "private"); +} + +int is_protected(Node *n) { + String *access = Getattr(n, "access"); + return access && !Cmp(access, "protected"); +} + +static int is_member_director_helper(Node *parentnode, Node *member) { + int parent_nodirector = GetFlag(parentnode, "feature:nodirector"); + if (parent_nodirector) + return 0; + int parent_director = Swig_director_mode() && GetFlag(parentnode, "feature:director"); + int cdecl_director = parent_director || GetFlag(member, "feature:director"); + int cdecl_nodirector = GetFlag(member, "feature:nodirector"); + return cdecl_director && !cdecl_nodirector && !GetFlag(member, "feature:extend"); +} + +int is_member_director(Node *parentnode, Node *member) { + if (parentnode && checkAttribute(member, "storage", "virtual")) { + return is_member_director_helper(parentnode, member); + } else { + return 0; + } +} + +int is_member_director(Node *member) { + return is_member_director(Getattr(member, "parentNode"), member); +} + +// Identifies the additional protected members that are generated when the allprotected option is used. +// This does not include protected virtual methods as they are turned on with the dirprot option. +int is_non_virtual_protected_access(Node *n) { + int result = 0; + if (Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode() && is_protected(n) && !checkAttribute(n, "storage", "virtual")) { + Node *parentNode = Getattr(n, "parentNode"); + // When vtable is empty, the director class does not get emitted, so a check for an empty vtable should be done. + // However, vtable is set in Language and so is not yet set when methods in Typepass call clean_overloaded() + // which calls is_non_virtual_protected_access. So commented out below. + // Moving the director vtable creation into Typepass should solve this problem. + if (is_member_director_helper(parentNode, n) /* && Getattr(parentNode, "vtable")*/) + result = 1; + } + return result; +} + +/* Clean overloaded list. Removes templates, ignored, and errors */ + +void clean_overloaded(Node *n) { + Node *nn = Getattr(n, "sym:overloaded"); + Node *first = 0; + while (nn) { + String *ntype = nodeType(nn); + if ((GetFlag(nn, "feature:ignore")) || + (Getattr(nn, "error")) || + (Strcmp(ntype, "template") == 0) || + ((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn) && !is_non_virtual_protected_access(n))) { + /* Remove from overloaded list */ + Node *ps = Getattr(nn, "sym:previousSibling"); + Node *ns = Getattr(nn, "sym:nextSibling"); + if (ps) { + Setattr(ps, "sym:nextSibling", ns); + } + if (ns) { + Setattr(ns, "sym:previousSibling", ps); + } + Delattr(nn, "sym:previousSibling"); + Delattr(nn, "sym:nextSibling"); + Delattr(nn, "sym:overloaded"); + nn = ns; + continue; + } else { + if (!first) + first = nn; + Setattr(nn, "sym:overloaded", first); + } + nn = Getattr(nn, "sym:nextSibling"); + } + if (!first || (first && !Getattr(first, "sym:nextSibling"))) { + if (Getattr(n, "sym:overloaded")) + Delattr(n, "sym:overloaded"); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_set_max_hash_expand() + * + * Controls how many Hash objects are displayed when displaying nested Hash objects. + * Makes DohSetMaxHashExpand an externally callable function (for debugger). + * ----------------------------------------------------------------------------- */ + +void Swig_set_max_hash_expand(int count) { + SetMaxHashExpand(count); +} + +extern "C" { + +/* ----------------------------------------------------------------------------- + * Swig_get_max_hash_expand() + * + * Returns how many Hash objects are displayed when displaying nested Hash objects. + * Makes DohGetMaxHashExpand an externally callable function (for debugger). + * ----------------------------------------------------------------------------- */ + +int Swig_get_max_hash_expand() { + return GetMaxHashExpand(); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_doh_string() + * + * DOH version of Swig_to_string() + * ----------------------------------------------------------------------------- */ + +static String *Swig_to_doh_string(DOH *object, int count) { + int old_count = Swig_get_max_hash_expand(); + if (count >= 0) + Swig_set_max_hash_expand(count); + + String *debug_string = object ? NewStringf("%s", object) : NewString("NULL"); + + Swig_set_max_hash_expand(old_count); + return debug_string; +} + +/* ----------------------------------------------------------------------------- + * Swig_to_doh_string_with_location() + * + * DOH version of Swig_to_string_with_location() + * ----------------------------------------------------------------------------- */ + +static String *Swig_to_doh_string_with_location(DOH *object, int count) { + int old_count = Swig_get_max_hash_expand(); + if (count >= 0) + Swig_set_max_hash_expand(count); + + String *debug_string = Swig_stringify_with_location(object); + + Swig_set_max_hash_expand(old_count); + return debug_string; +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string() + * + * Swig debug - return C string representation of any DOH type. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * Note: leaks memory. + * ----------------------------------------------------------------------------- */ + +const char *Swig_to_string(DOH *object, int count) { + return Char(Swig_to_doh_string(object, count)); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string_with_location() + * + * Swig debug - return C string representation of any DOH type, within [] brackets + * for Hash and List types, prefixed by line and file information. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * Note: leaks memory. + * ----------------------------------------------------------------------------- */ + +const char *Swig_to_string_with_location(DOH *object, int count) { + return Char(Swig_to_doh_string_with_location(object, count)); +} + +/* ----------------------------------------------------------------------------- + * Swig_print() + * + * Swig debug - display string representation of any DOH type. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * ----------------------------------------------------------------------------- */ + +void Swig_print(DOH *object, int count) { + String *output = Swig_to_doh_string(object, count); + Printf(stdout, "%s\n", output); + Delete(output); +} + +/* ----------------------------------------------------------------------------- + * Swig_to_string_with_location() + * + * Swig debug - display string representation of any DOH type, within [] brackets + * for Hash and List types, prefixed by line and file information. + * Nested Hash types expand count is value of Swig_get_max_hash_expand when count<0 + * ----------------------------------------------------------------------------- */ + +void Swig_print_with_location(DOH *object, int count) { + String *output = Swig_to_doh_string_with_location(object, count); + Printf(stdout, "%s\n", output); + Delete(output); +} + +} // extern "C" + diff --git a/contrib/tools/swig/Source/Modules/xml.cxx b/contrib/tools/swig/Source/Modules/xml.cxx new file mode 100644 index 00000000000..5f090561a89 --- /dev/null +++ b/contrib/tools/swig/Source/Modules/xml.cxx @@ -0,0 +1,326 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * xml.cxx + * + * An Xml parse tree generator. + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" + +static const char *usage = "\ +XML Options (available with -xml)\n\ + -xmllang <lang> - Typedef language\n\ + -xmllite - More lightweight version of XML\n\ + ------\n\ + deprecated (use -o): -xml <output.xml> - Use <output.xml> as output file (extension .xml mandatory)\n"; + +static File *out = 0; +static int xmllite = 0; + + +class XML:public Language { +public: + + int indent_level; + long id; + + XML() :indent_level(0) , id(0) { + } + + virtual ~ XML() { + } + + virtual void main(int argc, char *argv[]) { + SWIG_typemap_lang("xml"); + for (int iX = 0; iX < argc; iX++) { + if (strcmp(argv[iX], "-xml") == 0) { + char *extension = 0; + if (iX + 1 >= argc) + continue; + extension = argv[iX + 1] + strlen(argv[iX + 1]) - 4; + if (strcmp(extension, ".xml")) + continue; + iX++; + Swig_mark_arg(iX); + String *outfile = NewString(argv[iX]); + out = NewFile(outfile, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + continue; + } + if (strcmp(argv[iX], "-xmllang") == 0) { + Swig_mark_arg(iX); + iX++; + SWIG_typemap_lang(argv[iX]); + Swig_mark_arg(iX); + continue; + } + if (strcmp(argv[iX], "-help") == 0) { + fputs(usage, stdout); + } + if (strcmp(argv[iX], "-xmllite") == 0) { + Swig_mark_arg(iX); + xmllite = 1; + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGXML 1", 0); + } + + /* Top of the parse tree */ + + virtual int top(Node *n) { + if (out == 0) { + String *outfile = Getattr(n, "outfile"); + String *ext = Swig_file_extension(outfile); + // If there's an extension, ext will include the ".". + Delslice(outfile, Len(outfile) - Len(ext), DOH_END); + Delete(ext); + Append(outfile, ".xml"); + out = NewFile(outfile, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + } + Printf(out, "<?xml version=\"1.0\" ?> \n"); + Xml_print_tree(n); + return SWIG_OK; + } + + void print_indent(int l) { + int i; + for (i = 0; i < indent_level; i++) { + Printf(out, " "); + } + if (l) { + Printf(out, " "); + } + } + + void Xml_print_tree(DOH *obj) { + while (obj) { + Xml_print_node(obj); + obj = nextSibling(obj); + } + } + + void Xml_print_attributes(Node *obj) { + String *k; + indent_level += 4; + print_indent(0); + Printf(out, "<attributelist id=\"%ld\" addr=\"%p\" >\n", ++id, obj); + indent_level += 4; + Iterator ki; + ki = First(obj); + while (ki.key) { + k = ki.key; + if ((Cmp(k, "nodeType") == 0) + || (Cmp(k, "firstChild") == 0) + || (Cmp(k, "lastChild") == 0) + || (Cmp(k, "parentNode") == 0) + || (Cmp(k, "nextSibling") == 0) + || (Cmp(k, "previousSibling") == 0) + || (*(Char(k)) == '$')) { + /* Do nothing */ + } else if (Cmp(k, "module") == 0) { + Xml_print_module(Getattr(obj, k)); + } else if (Cmp(k, "baselist") == 0) { + Xml_print_baselist(Getattr(obj, k)); + } else if (!xmllite && Cmp(k, "typescope") == 0) { + Xml_print_typescope(Getattr(obj, k)); + } else if (!xmllite && Cmp(k, "typetab") == 0) { + Xml_print_typetab(Getattr(obj, k)); + } else if (Cmp(k, "kwargs") == 0) { + Xml_print_kwargs(Getattr(obj, k)); + } else if (Cmp(k, "parms") == 0 || Cmp(k, "pattern") == 0) { + Xml_print_parmlist(Getattr(obj, k)); + } else if (Cmp(k, "catchlist") == 0 || Cmp(k, "templateparms") == 0) { + Xml_print_parmlist(Getattr(obj, k), Char(k)); + } else { + DOH *o; + print_indent(0); + if (DohIsString(Getattr(obj, k))) { + String *ck = NewString(k); + o = Str(Getattr(obj, k)); + Replaceall(ck, ":", "_"); + Replaceall(ck, "<", "<"); + /* Do first to avoid aliasing errors. */ + Replaceall(o, "&", "&"); + Replaceall(o, "<", "<"); + Replaceall(o, "\"", """); + Replaceall(o, "\\", "\\\\"); + Replaceall(o, "\n", " "); + Printf(out, "<attribute name=\"%s\" value=\"%s\" id=\"%ld\" addr=\"%p\" />\n", ck, o, ++id, o); + Delete(o); + Delete(ck); + } else { + o = Getattr(obj, k); + String *ck = NewString(k); + Replaceall(ck, ":", "_"); + Printf(out, "<attribute name=\"%s\" value=\"%p\" id=\"%ld\" addr=\"%p\" />\n", ck, o, ++id, o); + Delete(ck); + } + } + ki = Next(ki); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</attributelist >\n"); + indent_level -= 4; + } + + void Xml_print_node(Node *obj) { + Node *cobj; + + print_indent(0); + Printf(out, "<%s id=\"%ld\" addr=\"%p\" >\n", nodeType(obj), ++id, obj); + Xml_print_attributes(obj); + cobj = firstChild(obj); + if (cobj) { + indent_level += 4; + Printf(out, "\n"); + Xml_print_tree(cobj); + indent_level -= 4; + } else { + print_indent(1); + Printf(out, "\n"); + } + print_indent(0); + Printf(out, "</%s >\n", nodeType(obj)); + } + + + void Xml_print_parmlist(ParmList *p, const char* markup = "parmlist") { + + print_indent(0); + Printf(out, "<%s id=\"%ld\" addr=\"%p\" >\n", markup, ++id, p); + indent_level += 4; + while (p) { + print_indent(0); + Printf(out, "<parm id=\"%ld\">\n", ++id); + Xml_print_attributes(p); + print_indent(0); + Printf(out, "</parm >\n"); + p = nextSibling(p); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</%s >\n", markup); + } + + void Xml_print_baselist(List *p) { + + print_indent(0); + Printf(out, "<baselist id=\"%ld\" addr=\"%p\" >\n", ++id, p); + indent_level += 4; + Iterator s; + for (s = First(p); s.item; s = Next(s)) { + print_indent(0); + String *item_name = Xml_escape_string(s.item); + Printf(out, "<base name=\"%s\" id=\"%ld\" addr=\"%p\" />\n", item_name, ++id, s.item); + Delete(item_name); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</baselist >\n"); + } + + String *Xml_escape_string(String *str) { + String *escaped_str = 0; + if (str) { + escaped_str = NewString(str); + Replaceall(escaped_str, "&", "&"); + Replaceall(escaped_str, "<", "<"); + Replaceall(escaped_str, "\"", """); + Replaceall(escaped_str, "\\", "\\\\"); + Replaceall(escaped_str, "\n", " "); + } + return escaped_str; + } + + void Xml_print_module(Node *p) { + + print_indent(0); + Printf(out, "<attribute name=\"module\" value=\"%s\" id=\"%ld\" addr=\"%p\" />\n", Getattr(p, "name"), ++id, p); + } + + void Xml_print_kwargs(Hash *p) { + Xml_print_hash(p, "kwargs"); + } + + void Xml_print_typescope(Hash *p) { + + Xml_print_hash(p, "typescope"); + } + + void Xml_print_typetab(Hash *p) { + + Xml_print_hash(p, "typetab"); + } + + + void Xml_print_hash(Hash *p, const char *markup) { + + print_indent(0); + Printf(out, "<%s id=\"%ld\" addr=\"%p\" >\n", markup, ++id, p); + Xml_print_attributes(p); + indent_level += 4; + Iterator n = First(p); + while (n.key) { + print_indent(0); + Printf(out, "<%ssitem id=\"%ld\" addr=\"%p\" >\n", markup, ++id, n.item); + Xml_print_attributes(n.item); + print_indent(0); + Printf(out, "</%ssitem >\n", markup); + n = Next(n); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</%s >\n", markup); + } + +}; + +/* ----------------------------------------------------------------------------- + * Swig_print_xml + * + * Dump an XML version of the parse tree. This is different from using the -xml + * language module normally as it allows the real language module to process the + * tree first, possibly stuffing in new attributes, so the XML that is output ends + * up being a post-processing version of the tree. + * ----------------------------------------------------------------------------- */ + +void Swig_print_xml(DOH *obj, String *filename) { + XML xml; + xmllite = 1; + + if (!filename) { + out = stdout; + } else { + out = NewFile(filename, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + } + + Printf(out, "<?xml version=\"1.0\" ?> \n"); + xml.Xml_print_tree(obj); +} + +static Language *new_swig_xml() { + return new XML(); +} +extern "C" Language *swig_xml(void) { + return new_swig_xml(); +} |