diff options
Diffstat (limited to 'Source/Modules')
36 files changed, 53571 insertions, 0 deletions
diff --git a/Source/Modules/README b/Source/Modules/README new file mode 100644 index 0000000..058779d --- /dev/null +++ b/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/Source/Modules/allegrocl.cxx b/Source/Modules/allegrocl.cxx new file mode 100644 index 0000000..d40538d --- /dev/null +++ b/Source/Modules/allegrocl.cxx @@ -0,0 +1,3222 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * allegrocl.cxx + * + * ALLEGROCL language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_allegrocl_cxx[] = "$Id: allegrocl.cxx 11471 2009-07-29 20:52:29Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +// #define ALLEGROCL_DEBUG +// #define ALLEGROCL_WRAP_DEBUG +// #define ALLEGROCL_TYPE_DEBUG +// #define ALLEGROCL_CLASS_DEBUG + +static File *f_cl = 0; +String *f_clhead = NewString(""); +String *f_clwrap = NewString("(swig-in-package ())\n\n"); +static File *f_begin; +static File *f_runtime; +static File *f_cxx_header = 0; +static File *f_cxx_wrapper = 0; + +static String *module_name = 0; +static String *swig_package = 0; + +const char *identifier_converter = "identifier-convert-null"; + +static bool CWrap = true; // generate wrapper file for C code by default. most correct. +static bool Generate_Wrapper = false; +static bool unique_swig_package = false; + +static SwigType *fwdref_ffi_type = NewString("__SWIGACL_FwdReference"); + +static String *current_namespace = NewString(""); +static String *current_package = NewString(""); +static Hash *defined_namespace_packages = NewHash(); +static Node *in_class = 0; + +static Node *first_linked_type = 0; +static Hash *defined_foreign_types = NewHash(); +static Hash *defined_foreign_ltypes = NewHash(); + +static String *anon_type_name = NewString("anontype"); +static int anon_type_count = 0; + +// stub +String *convert_literal(String *num_param, String *type, bool try_to_split = true); + +class ALLEGROCL:public Language { +public: + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int namespaceDeclaration(Node *n); + virtual int constructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int globalvariableHandler(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int classHandler(Node *n); + virtual int emit_one(Node *n); + virtual int enumDeclaration(Node *n); + virtual int enumvalueDeclaration(Node *n); + virtual int typedefHandler(Node *n); + virtual int classforwardDeclaration(Node *n); + virtual int templateDeclaration(Node *n); + virtual int validIdentifier(String *s); +private: + int emit_defun(Node *n, File *f_cl); + int emit_dispatch_defun(Node *n); + int emit_buffered_defuns(Node *n); + int cClassHandler(Node *n); + int cppClassHandler(Node *n); +}; +static ALLEGROCL *allegrocl = 0; + +static String *trim(String *str) { + char *c = Char(str); + while (*c != '\0' && isspace((int) *c)) + ++c; + String *result = NewString(c); + Chop(result); + return result; +} + +int is_integer(String *s) { + char *c = Char(s); + if (c[0] == '#' && (c[1] == 'x' || c[1] == 'o')) + c += 2; + + while (*c) { + if (!isdigit(*c)) + return 0; + c++; + } + return 1; +} + +String *class_from_class_or_class_ref(String *type) { + SwigType *stripped = SwigType_strip_qualifiers(type); + if (SwigType_isclass(stripped)) + return stripped; + + if (SwigType_ispointer(stripped) || SwigType_isreference(stripped)) { + // Printf(stderr,"It is a pointer/reference. Is it a class?\n"); + SwigType_pop(stripped); + if (SwigType_isclass(stripped)) { + return stripped; + } + } + return 0; +} + +String *lookup_defined_foreign_type(String *k) { + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Looking up defined type '%s'.\n Found: '%s'\n", k, Getattr(defined_foreign_types, k)); +#endif + + return Getattr(defined_foreign_types, k); +} + +String *listify_namespace(String *namespaze) { + if (Len(namespaze) == 0) + return NewString("()"); + String *result = NewStringf("(\"%s\")", namespaze); + Replaceall(result, "::", "\" \""); + return result; +} + +String *namespaced_name(Node *n, String *ns = current_namespace) { + + return NewStringf("%s%s%s", ns, (Len(ns) != 0) ? "::" : "", Getattr(n, "sym:name")); +} + +// "Namespace::Nested::Class2::Baz" -> "Baz" +static String *strip_namespaces(String *str) { + char *result = Char(str); + String *stripped_one; + while ((stripped_one = Strstr(result, "::"))) + result = Char(stripped_one) + 2; + return NewString(result); +} + +static String *namespace_of(String *str) { + char *p = Char(str); + char *start = Char(str); + char *result = 0; + String *stripped_one; + + while ((stripped_one = Strstr(p, "::"))) { + p = Char(stripped_one) + 2; + } + if (p > start) { + int len = p - start - 1; + result = (char *) malloc(len); + strncpy(result, start, len - 1); + result[len - 1] = 0; + } + return Char(result); +} + +void add_linked_type(Node *n) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Adding linked node of type: %s(%s) %s(%x)\n\n", nodeType(n), Getattr(n, "storage"), Getattr(n, "name"), n); + // Swig_print_node(n); +#endif + if (!first_linked_type) { + first_linked_type = n; + Setattr(n, "allegrocl:last_linked_type", n); + } else { + Node *t = Getattr(first_linked_type, "allegrocl:last_linked_type"); + Setattr(t, "allegrocl:next_linked_type", n); + Setattr(first_linked_type, "allegrocl:last_linked_type", n); + } +} + +void replace_linked_type(Node *old, Node *new_node) { + Node *prev = Getattr(old, "allegrocl:prev_linked_type"); + + Setattr(new_node, "allegrocl:next_linked_type", Getattr(old, "allegrocl:next_linked_type")); + if (prev) + Setattr(prev, "allegrocl:next_linked_type", new_node); + Delattr(old, "allegrocl:next_linked_type"); + Delattr(old, "allegrocl:prev_linked_type"); + + // check if we're replacing the first link. + if (first_linked_type == old) { + first_linked_type = new_node; + Setattr(first_linked_type, "allegrocl:last_linked_type", Getattr(old, "allegrocl:last_linked_type")); + } + // check if we're replacing the last link. + if (Getattr(first_linked_type, "allegrocl:last_linked_type") == old) + Setattr(first_linked_type, "allegrocl:last_linked_type", new_node); +} + +void insert_linked_type_at(Node *old, Node *new_node, int before = 1) { + Node *p = 0; + + if (!first_linked_type) { + add_linked_type(new_node); + return; + } + + if (!before) { + Setattr(new_node, "allegrocl:next_linked_type", Getattr(old, "allegrocl:next_linked_type")); + Setattr(old, "allegrocl:next_linked_type", new_node); + if (Getattr(first_linked_type, "allegrocl:last_linked_type") == old) + Setattr(first_linked_type, "allegrocl:last_linked_type", new_node); + } else { + Node *c = first_linked_type; + while (c) { + if (c == old) { + break; + } else { + p = c; + c = Getattr(c, "allegrocl:next_linked_type"); + } + } + if (c == old) { + Setattr(new_node, "allegrocl:next_linked_type", c); + if (first_linked_type == c) { + first_linked_type = new_node; + Setattr(first_linked_type, "allegrocl:last_linked_type", Getattr(c, "allegrocl:last_linked_type")); + Delattr(c, "allegrocl:last_linked_type"); + } + if (p) + Setattr(p, "allegrocl:next_linked_type", new_node); + } + } +} + +Node *find_linked_type_by_name(String *name) { + Node *p = 0; + Node *c = first_linked_type; + + // Printf(stderr,"in find_linked_type_by_name '%s'...", name); + while (c) { + String *key = Getattr(c, "name"); + if (!Strcmp(key, name)) { + break; + } else { + p = c; + c = Getattr(c, "allegrocl:next_linked_type"); + } + } + // Printf(stderr,"exit find_linked_type_by_name.\n"); + + if (p && c) + Setattr(c, "allegrocl:prev_linked_type", p); + // Printf(stderr,"find_linked_type_by_name: DONE\n"); + return c; +} + +Node *get_primary_synonym_of(Node *n) { + Node *p = Getattr(n, "allegrocl:synonym-of"); + Node *prim = n; + + // Printf(stderr, "getting primary synonym of %x\n", n); + while (p) { + // Printf(stderr, " found one! %x\n", p); + prim = p; + p = Getattr(p, "allegrocl:synonym-of"); + } + // Printf(stderr,"get_primary_syn: DONE. returning %s(%x)\n", Getattr(prim,"name"),prim); + return prim; +} + +void add_forward_referenced_type(Node *n, int overwrite = 0) { + String *k = Getattr(n, "name"); + String *name = Getattr(n, "sym:name"); + String *ns = listify_namespace(current_namespace); + + String *val = Getattr(defined_foreign_types, k); + + if (!val || overwrite) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Adding forward reference for %s (overwrite=%d)\n", k, overwrite); +#endif + Setattr(defined_foreign_types, Copy(k), NewString("forward-reference")); + + String *mangled_lname_gen = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", name, ns); + + Setattr(defined_foreign_ltypes, Copy(k), mangled_lname_gen); + // Printf(f_cl, ";; forward reference stub\n" + // "(swig-def-foreign-class \"%s\" (ff:foreign-pointer) (:class ))\n\n" + // , name); + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Linking forward reference type = %s(%x)\n", k, n); +#endif + add_linked_type(n); + } +} + +void add_defined_foreign_type(Node *n, int overwrite = 0, String *k = 0, + String *name = 0, String *ns = current_namespace) { + + String *val; + String *ns_list = listify_namespace(ns); + String *templated = n ? Getattr(n, "template") : 0; + String *cDeclName = n ? Getattr(n, "classDeclaration:name") : 0; + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "IN A-D-F-T. (n=%x, ow=%d, k=%s, name=%s, ns=%s\n", n, overwrite, k, name, ns); + Printf(stderr, " templated = '%x', classDecl = '%x'\n", templated, cDeclName); +#endif + if (n) { + if (!name) + name = Getattr(n, "sym:name"); + if (!name) + name = strip_namespaces(Getattr(n, "name")); + if (templated) { + k = namespaced_name(n); + } else { + String *kind_of_type = Getattr(n, "kind"); + + /* + For typedefs of the form: + + typedef struct __xxx { ... } xxx; + + behavior differs between C mode and C++ mode. + + C Mode: + add_defined_foreign_type will be called once via classHandler + to define the type for 'struct __xxx' and add the mapping from + 'struct __xxx' -> 'xxx' + + It will also be called once via typedefHandler to add the + mapping 'xxx' -> 'xxx' + + C++ Mode: + add_defined_foreign_type will be called once via classHandler + to define the type for 'xxx'. it also adds the mapping from + 'xxx' -> 'xxx' and also for 'struct xxx' -> 'xxx' + + In typedefHandler, we again try to add the mapping from + 'xxx' -> 'xxx', which already exists. This second mapping + is ignored. + + Both modes: + + All references to this typedef'd struct will appear in + generated lisp code as an objectd of type 'xxx'. For + non-typedef'd structs, the classHand mapping will be + + struct __xxx -> (swig-insert-id "__xxx") + */ + // Swig_print_node(n); + String *unnamed = Getattr(n, "unnamed"); + if (kind_of_type && (!Strcmp(kind_of_type, "struct") + || !Strcmp(kind_of_type, "union")) && cDeclName && !unnamed) { + k = NewStringf("%s %s", kind_of_type, cDeclName); + } else { + if (!Strcmp(nodeType(n), "enum") && unnamed) { + name = NewStringf("%s%d", anon_type_name, anon_type_count++); + k = NewStringf("enum %s", name); + Setattr(n, "allegrocl:name", name); + + } else { + k = k ? k : Getattr(n, "name"); + } + } + } + // Swig_print_node(n); + } + + if (SwigType_istemplate(name)) { + String *temp = strip_namespaces(SwigType_templateprefix(name)); + name = NewStringf("%s%s%s", temp, SwigType_templateargs(name), SwigType_templatesuffix(name)); + } + + val = lookup_defined_foreign_type(k); + + int is_fwd_ref = 0; + if (val) + is_fwd_ref = !Strcmp(val, "forward-reference"); + + if (!val || overwrite || is_fwd_ref) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Adding defined type '%s' = '%s' '%s' (overwrite=%d, in-class=%d)\n", k, ns, name, overwrite, in_class); +#endif + String *mangled_name_gen = NewStringf("#.(swig-insert-id \"%s\" %s :type :type)", name, ns_list); + String *mangled_lname_gen = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", name, ns_list); + + Setattr(defined_foreign_types, Copy(k), Copy(mangled_name_gen)); + Setattr(defined_foreign_ltypes, Copy(k), Copy(mangled_lname_gen)); + + if (CPlusPlus) { + bool cpp_struct = Strstr(k, "struct ") ? true : false; + bool cpp_union = Strstr(k, "union ") ? true : false; + + String *cpp_type = 0; + if (cpp_struct) { + cpp_type = Copy(k); + Replaceall(cpp_type, "struct ", ""); + } else if (cpp_union) { + cpp_type = Copy(k); + Replaceall(cpp_type, "union ", ""); + } + + if (cpp_struct || cpp_union) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " Also adding defined type '%s' = '%s' '%s' (overwrite=%d)\n", cpp_type, ns, name, overwrite); +#endif + Setattr(defined_foreign_types, Copy(cpp_type), Copy(mangled_name_gen)); + Setattr(defined_foreign_ltypes, Copy(cpp_type), Copy(mangled_lname_gen)); + } + } +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "looking to add %s/%s(%x) to linked_type_list...\n", k, name, n); +#endif + if (is_fwd_ref) { + // Printf(stderr,"*** 1\n"); + add_linked_type(n); + } else { + // Printf(stderr,"*** 1-a\n"); + if (SwigType_istemplate(k)) { + SwigType *resolved = SwigType_typedef_resolve_all(k); + // Printf(stderr,"*** 1-b\n"); + Node *match = find_linked_type_by_name(resolved); + Node *new_node = 0; + // Printf(stderr, "*** temp-1\n"); + if (n) { + new_node = n; + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Creating a new templateInst:\n"); + Printf(stderr, " name = %s\n", resolved); + Printf(stderr, " sym:name = %s\n", name); + Printf(stderr, " real-name = %s\n", k); + Printf(stderr, " type = %s\n", resolved); + Printf(stderr, " ns = %s\n\n", ns); +#endif + new_node = NewHash(); + Setattr(new_node, "nodeType", "templateInst"); + Setattr(new_node, "name", Copy(resolved)); + Setattr(new_node, "sym:name", Copy(name)); + Setattr(new_node, "real-name", Copy(k)); + Setattr(new_node, "type", Copy(resolved)); + Setattr(new_node, "allegrocl:namespace", ns); + Setattr(new_node, "allegrocl:package", ns); + } + + if (!match) { + if (!Strcmp(nodeType(new_node), "templateInst") && in_class) { + /* this is an implicit template instantiation found while + walking a class. need to insert this into the + linked_type list before the current class definition */ +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "trying to insert a templateInst before a class\n"); +#endif + insert_linked_type_at(in_class, new_node); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "DID IT!\n"); +#endif + } else { + // Printf(stderr,"*** 3\n"); + add_linked_type(new_node); + } + Setattr(new_node, "allegrocl:synonym:is-primary", "1"); + } else { + // a synonym type was found (held in variable 'match') + // Printf(stderr, "setting primary synonym of %x to %x\n", new_node, match); + if (new_node == match) + Printf(stderr, "Hey-4 * - '%s' is a synonym of iteself!\n", Getattr(new_node, "name")); + Setattr(new_node, "allegrocl:synonym-of", match); + // Printf(stderr,"*** 4\n"); + add_linked_type(new_node); + } + } else { + Node *match; + + if (!Strcmp(nodeType(n), "cdecl") && !Strcmp(Getattr(n, "storage"), "typedef")) { + SwigType *type = SwigType_strip_qualifiers(Getattr(n, "type")); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Examining typedef '%s' for class references. (%d)\n", type, SwigType_isclass(type)); +#endif + if (SwigType_isclass(type)) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Found typedef of a class '%s'\n", type); +#endif + /* + For the following parsed expression: + + typedef struct __xxx { ... } xxx; + + if n is of kind "class" (defining the class 'struct __xxx' + then we add n to the linked type list. + + if n is "cdecl" node of storage "typedef" (to note + that xxx is equivalent to 'struct __xxx' then we don't + want to add this node to the linked type list. + */ + String *defined_type = lookup_defined_foreign_type(type); + String *defined_key_type = lookup_defined_foreign_type(k); + + if ((Strstr(type, "struct ") || Strstr(type, "union ")) + && defined_type && !Strcmp(defined_type, defined_key_type)) { + // mark as a synonym but don't add to linked_type list + // Printf(stderr,"*** 4.8\n"); + Setattr(n, "allegrocl:synonym", "1"); + } else { + SwigType *lookup_type = SwigType_istemplate(type) ? SwigType_typedef_resolve_all(type) : Copy(type); + match = find_linked_type_by_name(lookup_type); + if (match) { + Setattr(n, "allegrocl:synonym", "1"); + Setattr(n, "allegrocl:synonym-of", match); + Setattr(n, "real-name", Copy(lookup_type)); + + // Printf(stderr, "*** pre-5: found match of '%s'(%x)\n", Getattr(match,"name"),match); + // if(n == match) Printf(stderr, "Hey-5 *** setting synonym of %x to %x\n", n, match); + // Printf(stderr,"*** 5\n"); + add_linked_type(n); + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Creating classfoward node for struct stub in typedef.\n"); +#endif + Node *new_node = NewHash(); + String *symname = Copy(type); + Replaceall(symname, "struct ", ""); + Setattr(new_node, "nodeType", "classforward"); + Setattr(new_node, "name", Copy(type)); + Setattr(new_node, "sym:name", symname); + Setattr(new_node, "allegrocl:namespace", ns); + Setattr(new_node, "allegrocl:package", ns); + + String *mangled_new_name = NewStringf("#.(swig-insert-id \"%s\" %s)", symname, ns_list); + String *mangled_new_lname = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", symname, ns_list); + Setattr(defined_foreign_types, Copy(symname), Copy(mangled_new_name)); + Setattr(defined_foreign_ltypes, Copy(symname), Copy(mangled_new_lname)); + + // Printf(stderr,"Weird! Can't find the type!\n"); + add_forward_referenced_type(new_node); + add_linked_type(new_node); + + Setattr(n, "allegrocl:synonym", "1"); + Setattr(n, "allegrocl:synonym-of", new_node); + + add_linked_type(n); + } + Delete(lookup_type); + } + } else { + // check if it's a pointer or reference to a class. + // Printf(stderr,"Checking if '%s' is a p. or r. to a class\n", type); + String *class_ref = class_from_class_or_class_ref(type); + if (class_ref) { + match = find_linked_type_by_name(class_ref); + Setattr(n, "allegrocl:synonym", "1"); + Setattr(n, "allegrocl:synonym-of", match); + add_linked_type(n); + } + } + Delete(type); + // synonym types have already been added. + // Printf(stderr,"*** 10\n"); + if (!Getattr(n, "allegrocl:synonym")) + add_linked_type(n); + } else if (Getattr(n, "template")) { + // Printf(stderr, "this is a class template node(%s)\n", nodeType(n)); + String *resolved = SwigType_typedef_resolve_all(Getattr(n, "name")); + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " looking up %s for linked type match with %s...\n", Getattr(n, "sym:name"), resolved); +#endif + match = find_linked_type_by_name(resolved); + if (!match) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "found no implicit instantiation of %%template node %s(%x)\n", Getattr(n, "name"), n); +#endif + add_linked_type(n); + } else { + Node *primary = get_primary_synonym_of(match); + + Setattr(n, "allegrocl:synonym:is-primary", "1"); + Delattr(primary, "allegrocl:synonym:is-primary"); + if (n == match) + Printf(stderr, "Hey-7 * setting synonym of %x to %x\n (match = %x)", primary, n, match); + Setattr(primary, "allegrocl:synonym-of", n); + // Printf(stderr,"*** 7\n"); + add_linked_type(n); + } + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "linking type '%s'(%x)\n", k, n); +#endif + // Printf(stderr,"*** 8\n"); + add_linked_type(n); + } + } + } + Delete(mangled_name_gen); + Delete(mangled_lname_gen); + } else { + if (!CPlusPlus || Strcmp(Getattr(n,"kind"),"typedef")) { + Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), + "Attempting to store a foreign type that exists: %s (%s)\n", + k, val); + } + } + + Delete(ns_list); + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "OUT A-D-F-T\n"); +#endif +} + +void note_implicit_template_instantiation(SwigType *t) { + // the namespace of the implicit instantiation is not necessarily + // current_namespace. Attempt to cull this from the type. +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "culling namespace of '%s' from '%s'\n", t, SwigType_templateprefix(t)); +#endif + String *implicit_ns = namespace_of(SwigType_templateprefix(t)); + add_defined_foreign_type(0, 0, t, t, implicit_ns ? implicit_ns : current_namespace); +} + +String *get_ffi_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + /* lookup defined foreign type. + if it exists, it will return a form suitable for placing + into lisp code to generate the def-foreign-type name */ + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "inside g_f_t: looking up '%s' '%s'\n", ty, name); +#endif + + String *found_type = lookup_defined_foreign_type(ty); + + if (found_type) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "found_type '%s'\n", found_type); +#endif + return (Strcmp(found_type, "forward-reference") ? Copy(found_type) : get_ffi_type(n, fwdref_ffi_type, "")); + } else { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("ffitype", node, name, 0); + Delete(node); + + if (tm) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "g-f-t: found ffitype typemap '%s'\n", tm); +#endif + return NewString(tm); + } + + if (SwigType_istemplate(ty)) { + note_implicit_template_instantiation(ty); + return Copy(lookup_defined_foreign_type(ty)); + } + } + return 0; +} + +String *lookup_defined_foreign_ltype(String *l) { + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Looking up defined ltype '%s'.\n Found: '%s'\n", l, Getattr(defined_foreign_ltypes, l)); +#endif + return Getattr(defined_foreign_ltypes, l); +} + +/* walk type and return string containing lisp version. + recursive. */ +String *internal_compose_foreign_type(Node *n, SwigType *ty) { + + SwigType *tok; + String *ffiType = NewString(""); + + // for a function type, need to walk the parm list. + while (Len(ty) != 0) { + tok = SwigType_pop(ty); + + if (SwigType_isfunction(tok)) { + // Generate Function wrapper + Printf(ffiType, "(:function "); + // walk parm list + List *pl = SwigType_parmlist(tok); + + Printf(ffiType, "("); // start parm list + for (Iterator i = First(pl); i.item; i = Next(i)) { + SwigType *f_arg = SwigType_strip_qualifiers(i.item); + Printf(ffiType, "%s ", internal_compose_foreign_type(n, f_arg)); + Delete(f_arg); + } + Printf(ffiType, ")"); // end parm list. + + // do function return type. + Printf(ffiType, " %s)", internal_compose_foreign_type(n, ty)); + break; + } else if (SwigType_ispointer(tok) || SwigType_isreference(tok)) { + Printf(ffiType, "(* %s)", internal_compose_foreign_type(n, ty)); + } else if (SwigType_isarray(tok)) { + Printf(ffiType, "(:array %s", internal_compose_foreign_type(n, ty)); + String *atype = NewString("int"); + String *dim = convert_literal(SwigType_array_getdim(tok, 0), atype); + Delete(atype); + if (is_integer(dim)) { + Printf(ffiType, " %s)", dim); + } else { + Printf(ffiType, " #| %s |#)", SwigType_array_getdim(tok, 0)); + } + } else if (SwigType_ismemberpointer(tok)) { + // temp + Printf(ffiType, "(* %s)", internal_compose_foreign_type(n, ty)); + } else { + String *res = get_ffi_type(n, tok, ""); + if (res) { + Printf(ffiType, "%s", res); + } else { + SwigType *resolved_type = SwigType_typedef_resolve(tok); + if (resolved_type) { + res = get_ffi_type(n, resolved_type, ""); + if (res) { + } else { + res = internal_compose_foreign_type(n, resolved_type); + } + if (res) + Printf(ffiType, "%s", res); + } + + if (!res) { + String *is_struct = 0; + String *tok_remove_text = 0; + String *tok_name = Copy(tok); + String *tok_key = SwigType_str(tok,0); + if ((is_struct = Strstr(tok_key, "struct ")) || Strstr(tok_key, "union ")) { + tok_remove_text = NewString(is_struct ? "struct " : "union "); + } + + /* be more permissive of opaque types. This is the swig way. + compiles will notice if these types are ultimately not + present. */ + + if(tok_remove_text) { + Replaceall(tok_name,tok_remove_text,""); + } + tok_name = strip_namespaces(tok_name); + Delete(tok_remove_text); + // Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(tok), Getline(tok), "Unable to find definition of '%s', assuming forward reference.\n", tok); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "i-c-f-t: adding forward reference for unknown type '%s'. mapping: %s -> %s\n", tok, tok_key, tok_name); +#endif + Node *nn = NewHash(); + Setattr(nn,"nodeType","classforward"); + Setattr(nn,"kind","class"); + Setattr(nn,"sym:name",tok_name); + Setattr(nn,"name",tok_key); + Setattr(nn,"allegrocl:package",current_namespace); + + add_forward_referenced_type(nn, 0); + // tok_name is dangling here, unused. ouch. why? + Printf(ffiType, "%s", get_ffi_type(n, tok, ""), tok_name); + } + } + } + } + return ffiType; +} + +String *compose_foreign_type(Node *n, SwigType *ty, String * /*id*/ = 0) { + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "compose_foreign_type: ENTER (%s)...\n ", ty); + // Printf(stderr, "compose_foreign_type: ENTER (%s)(%s)...\n ", ty, (id ? id : 0)); + /* String *id_ref = SwigType_str(ty, id); + Printf(stderr, "looking up typemap for %s, found '%s'(%x)\n", + id_ref, lookup_res ? Getattr(lookup_res, "code") : 0, lookup_res); + if (lookup_res) Swig_print_node(lookup_res); + */ +#endif + + /* should we allow named lookups in the typemap here? YES! */ + /* unnamed lookups should be found in get_ffi_type, called + by internal_compose_foreign_type(), below. */ + + /* I'm reverting to 'no' for the question above. I can no longer + remember why I needed it. If a user needed it, I'll find out + as soon as they upgrade. Sigh. -mutandiz 9/16/2008. */ + +/* + if(id && lookup_res) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "compose_foreign_type: EXIT-1 (%s)\n ", Getattr(lookup_res, "code")); +#endif + return NewString(Getattr(lookup_res, "code")); + } +*/ + + SwigType *temp = SwigType_strip_qualifiers(ty); + String *res = internal_compose_foreign_type(n, temp); + Delete(temp); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "compose_foreign_type: EXIT (%s)\n ", res); +#endif + + return res; +} + +void update_package_if_needed(Node *n, File *f = f_clwrap) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "update_package: ENTER... \n"); + Printf(stderr, " current_package = '%s'\n", current_package); + Printf(stderr, " node_package = '%s'\n", Getattr(n, "allegrocl:package")); + Printf(stderr, " node(%x) = '%s'\n", n, Getattr(n, "name")); +#endif + String *node_package = Getattr(n, "allegrocl:package"); + if (Strcmp(current_package, node_package)) { + String *lispy_package = listify_namespace(node_package); + + Delete(current_package); + current_package = Copy(node_package); + Printf(f, "\n(swig-in-package %s)\n", lispy_package); + Delete(lispy_package); + } +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "update_package: EXIT.\n"); +#endif +} + +static String *mangle_name(Node *n, char const *prefix = "ACL", String *ns = current_namespace) { + String *suffix = Getattr(n, "sym:overname"); + String *pre_mangled_name = NewStringf("%s_%s__%s%s", prefix, ns, Getattr(n, "sym:name"), suffix); + String *mangled_name = Swig_name_mangle(pre_mangled_name); + Delete(pre_mangled_name); + return mangled_name; +} + +/* utilities */ + +/* remove a pointer from ffitype. non-destructive. + (* :char) ==> :char + (* (:array :int 30)) ==> (:array :int 30) */ +String *dereference_ffitype(String *ffitype) { + char *start; + char *temp = Char(ffitype); + String *reduced_type = 0; + + if(temp && temp[0] == '(' && temp[1] == '*') { + temp += 2; + + // walk past start of pointer references + while(*temp == ' ') temp++; + start = temp; + // temp = Char(reduced_type); + reduced_type = NewString(start); + temp = Char(reduced_type); + // walk to end of string. remove closing paren + while(*temp != '\0') temp++; + *(--temp) = '\0'; + } + + return reduced_type ? reduced_type : Copy(ffitype); +} + +/* returns new string w/ parens stripped */ +String *strip_parens(String *string) { + string = Copy(string); + Replaceall(string, "(", ""); + Replaceall(string, ")", ""); + return string; +} + +int ALLEGROCL::validIdentifier(String *s) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "validIdentifier %s\n", s); +#endif + + char *c = Char(s); + + bool got_dot = false; + bool only_dots = true; + + /* Check that s is a valid common lisp symbol. There's a lot of leeway here. + A common lisp symbol is essentially any token that's not a number and + does not consist of only dots. + + We are expressly not allowing spaces in identifiers here, but spaces + could be added via the identifier converter. */ + while (*c) { + if (*c == '.') { + got_dot = true; + } else { + only_dots = false; + } + if (!isgraph(*c)) + return 0; + c++; + } + + return (got_dot && only_dots) ? 0 : 1; +} + +String *infix_to_prefix(String *val, char split_op, const String *op, String *type) { + List *ored = Split(val, split_op, -1); + + // some float hackery + if (((split_op == '+') || (split_op == '-')) && Len(ored) == 2 && + (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE)) { + // check that we're not splitting a float + String *possible_result = convert_literal(val, type, false); + if (possible_result) + return possible_result; + + } + // try parsing the split results. if any part fails, kick out. + bool part_failed = false; + if (Len(ored) > 1) { + String *result = NewStringf("(%s", op); + for (Iterator i = First(ored); i.item; i = Next(i)) { + String *converted = convert_literal(i.item, type); + if (converted) { + Printf(result, " %s", converted); + Delete(converted); + } else { + part_failed = true; + break; + } + } + Printf(result, ")"); + Delete(ored); + return part_failed ? 0 : result; + } + Delete(ored); + return 0; +} + +/* To be called by code generating the lisp interface + Will return a containing the literal based on type. + Will return null if there are problems. + + try_to_split defaults to true (see stub above). + */ +String *convert_literal(String *literal, String *type, bool try_to_split) { + String *num_param = Copy(literal); + String *trimmed = trim(num_param); + String *num = strip_parens(trimmed), *res = 0; + char *s = Char(num); + + String *ns = listify_namespace(current_namespace); + + // very basic parsing of infix expressions. + if (try_to_split && SwigType_type(type) != T_STRING) { + if ((res = infix_to_prefix(num, '|', "logior", type))) + return res; + if ((res = infix_to_prefix(num, '&', "logand", type))) + return res; + if ((res = infix_to_prefix(num, '^', "logxor", type))) + return res; + if ((res = infix_to_prefix(num, '*', "*", type))) + return res; + if ((res = infix_to_prefix(num, '/', "/", type))) + return res; + if ((res = infix_to_prefix(num, '+', "+", type))) + return res; + if ((res = infix_to_prefix(num, '-', "-", type))) + return res; + // if ((res = infix_to_prefix(num, '~', "lognot", type))) return res; + // if( (res = infix_to_prefix(num, '<<', "ash", type)) ) return res; + } + + // unary complement... + if (s[0] == '~' && Len(num) >= 2) { + String *id = NewString(++s); + String *id_conv = convert_literal(id, type, false); + Delete(id); + if (id_conv) + return NewStringf("(lognot %s)", id_conv); + s--; + } + + if (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE) { + // Use CL syntax for float literals + String *oldnum = Copy(num); + + // careful. may be a float identifier or float constant. + char *num_start = Char(num); + char *num_end = num_start + strlen(num_start) - 1; + + bool is_literal = isdigit(*num_start) || (*num_start == '.'); + + String *lisp_exp = 0; + if (is_literal) { + if (*num_end == 'f' || *num_end == 'F') { + lisp_exp = NewString("f"); + } else { + lisp_exp = NewString("d"); + } + + if (*num_end == 'l' || *num_end == 'L' || *num_end == 'f' || *num_end == 'F') { + *num_end = '\0'; + num_end--; + } + + int exponents = Replaceall(num, "e", lisp_exp) + Replaceall(num, "E", lisp_exp); + + if (!exponents) + Printf(num, "%s0", lisp_exp); + + if (exponents > 1 || (exponents + Replaceall(num, ".", ".") == 0)) { + // Printf(stderr, "Can't parse '%s' as type '%s'.\n", oldnum, type); + Delete(num); + num = 0; + } + Delete(lisp_exp); + } else { + String *id = NewStringf("#.(swig-insert-id \"%s\" %s :type :constant)", + num, ns); + Delete(num); + num = id; + } + + Delete(oldnum); + Delete(trimmed); + Delete(ns); + return num; + } else if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + Delete(num); + Delete(trimmed); + return NewStringf("#\\%s", num_param); + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + Delete(num); + Delete(trimmed); + return NewStringf("\"%s\"", num_param); + } else if (Len(num) >= 1 && (isdigit(s[0]) || s[0] == '+' || s[0] == '-')) { + /* use CL syntax for numbers */ + String *oldnum = Copy(num); + int usuffixes = Replaceall(num, "u", "") + Replaceall(num, "U", ""); + int lsuffixes = Replaceall(num, "l", "") + Replaceall(num, "L", ""); + if (usuffixes > 1 || lsuffixes > 1) { + Printf(stderr, "Weird!! number %s looks invalid.\n", oldnum); + SWIG_exit(EXIT_FAILURE); + } + s = Char(num); + if (s[0] == '0' && Len(num) >= 2) { + /*octal or hex */ + res = NewStringf("#%c%s", tolower(s[1]) == 'x' ? 'x' : 'o', s + 2); + Delete(num); + } else { + res = num; + } + Delete(oldnum); + Delete(trimmed); + return res; + } else if (allegrocl->validIdentifier(num)) { + /* convert C/C++ identifiers to CL symbols */ + res = NewStringf("#.(swig-insert-id \"%s\" %s :type :constant)", num, ns); + Delete(num); + Delete(trimmed); + Delete(ns); + return res; + } else { + Delete(trimmed); + return num; + } +} + + +void emit_stub_class(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_stub_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n); +#endif + + + String *name = Getattr(n, "sym:name"); + + if (Getattr(n, "allegrocl:synonym:already-been-stubbed")) + return; + + if (SwigType_istemplate(name)) { + String *temp = strip_namespaces(SwigType_templateprefix(name)); + name = NewStringf("%s%s%s", temp, SwigType_templateargs(name), SwigType_templatesuffix(name)); + + Delete(temp); + } else { + name = strip_namespaces(name); + } + + // Printf(f_clhead, ";; from emit-stub-class\n"); + update_package_if_needed(n, f_clhead); + Printf(f_clhead, ";; class template stub.\n"); + Printf(f_clhead, "(swig-def-foreign-stub \"%s\")\n", name); + + Setattr(n, "allegrocl:synonym:already-been-stubbed", "1"); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_stub_class: EXIT\n"); +#endif +} + +void emit_synonym(Node *synonym) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_synonym: ENTER... \n"); +#endif + + // Printf(stderr,"in emit_synonym for %s(%x)\n", Getattr(synonym,"name"),synonym); + int is_tempInst = !Strcmp(nodeType(synonym), "templateInst"); + String *synonym_type; + + Node *of = get_primary_synonym_of(synonym); + + if (is_tempInst) { + // Printf(stderr, "*** using real-name '%s'\n", Getattr(synonym,"real-name")); + synonym_type = Getattr(synonym, "real-name"); + } else { + // Printf(stderr, "*** using name '%s'\n", Getattr(synonym,"name")); + synonym_type = Getattr(synonym, "name"); + } + + String *synonym_ns = listify_namespace(Getattr(synonym, "allegrocl:namespace")); + String *syn_ltype, *syn_type, *of_ltype; + // String *of_cdeclname = Getattr(of,"allegrocl:classDeclarationName"); + String *of_ns = Getattr(of, "allegrocl:namespace"); + String *of_ns_list = listify_namespace(of_ns); + // String *of_name = of_cdeclname ? NewStringf("struct %s", Getattr(of,"name")) : NewStringf("%s::%s", of_ns, Getattr(of,"sym:name")); + // String *of_name = NewStringf("%s::%s", of_ns, Getattr(of,"sym:name")); + String *of_name = namespaced_name(of, of_ns); + + if (CPlusPlus && !Strcmp(nodeType(synonym), "cdecl")) { + syn_ltype = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", + strip_namespaces(Getattr(synonym, "real-name")), synonym_ns); + syn_type = NewStringf("#.(swig-insert-id \"%s\" %s :type :type)", + strip_namespaces(Getattr(synonym, "real-name")), synonym_ns); + } else { + syn_ltype = lookup_defined_foreign_ltype(synonym_type); + syn_type = lookup_defined_foreign_type(synonym_type); + } + + of_ltype = lookup_defined_foreign_ltype(of_name); + + // Printf(stderr,";; from emit-synonym syn='%s' of_ltype='%s'\n", syn_ltype, of_ltype); + if( of_ltype ) + Printf(f_clhead, "(swig-def-synonym-type %s\n %s\n %s)\n", syn_ltype, of_ltype, syn_type); + + Delete(synonym_ns); + Delete(of_ns_list); + Delete(of_name); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_synonym: EXIT\n"); +#endif +} + +void emit_full_class(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_full_class: ENTER... \n"); +#endif + + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + // Printf(stderr,"in emit_full_class: '%s'(%x).", Getattr(n,"name"),n); + if (Getattr(n, "allegrocl:synonym-of")) { + // Printf(stderr,"but it's a synonym of something.\n"); + update_package_if_needed(n, f_clhead); + emit_synonym(n); + return; + } + // collect superclasses + String *bases = Getattr(n, "bases"); + String *supers = NewString("("); + if (bases) { + int first = 1; + for (Iterator i = First(bases); i.item; i = Next(i)) { + if (!first) + Printf(supers, " "); + String *s = lookup_defined_foreign_ltype(Getattr(i.item, "name")); + // String *name = Getattr(i.item,"name"); + if (s) { + Printf(supers, "%s", s); + } else { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "emit_templ_inst: did not find ltype for base class %s (%s)", Getattr(i.item, "name"), Getattr(n, "allegrocl:namespace")); +#endif + } + } + } else { + Printf(supers, "ff:foreign-pointer"); + } + + Printf(supers, ")"); + + // Walk children to generate type definition. + String *slotdefs = NewString(" "); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, " walking children...\n"); +#endif + + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + String *storage_type = Getattr(c, "storage"); + if ((!Strcmp(nodeType(c), "cdecl") && (!storage_type || Strcmp(storage_type, "typedef")))) { + String *access = Getattr(c, "access"); + + // hack. why would decl have a value of "variableHandler" and now "0"? + String *childDecl = Getattr(c, "decl"); + // Printf(stderr,"childDecl = '%s' (%s)\n", childDecl, Getattr(c,"view")); + if (!Strcmp(childDecl, "0")) + childDecl = NewString(""); + + SwigType *childType; + String *cname; + + // don't include types for private slots (yet). spr33959. + if(access && Strcmp(access,"public")) { + childType = NewStringf("int"); + cname = NewString("nil"); + } else { + childType = NewStringf("%s%s", childDecl, Getattr(c, "type")); + cname = Copy(Getattr(c, "name")); + } + + if (!SwigType_isfunction(childType)) { + // Printf(slotdefs, ";;; member functions don't appear as slots.\n "); + // Printf(slotdefs, ";; "); + String *ns = listify_namespace(Getattr(n, "allegrocl:package")); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "slot name = '%s' ns = '%s' class-of '%s' and type = '%s'\n", cname, ns, name, childType); +#endif + Printf(slotdefs, "(#.(swig-insert-id \"%s\" %s :type :slot :class \"%s\") %s)", cname, ns, name, compose_foreign_type(n, childType)); + Delete(ns); + if (access && Strcmp(access, "public")) + Printf(slotdefs, " ;; %s member", access); + + Printf(slotdefs, "\n "); + } + Delete(childType); + Delete(cname); + } + } + + String *ns_list = listify_namespace(Getattr(n, "allegrocl:namespace")); + update_package_if_needed(n, f_clhead); + Printf(f_clhead, "(swig-def-foreign-class \"%s\"\n %s\n (:%s\n%s))\n\n", name, supers, kind, slotdefs); + + Delete(supers); + Delete(ns_list); + + Setattr(n, "allegrocl:synonym:already-been-stubbed", "1"); +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_full_class: EXIT\n"); +#endif + +} + +void emit_class(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n); +#endif + + int is_tempInst = !Strcmp(nodeType(n), "templateInst"); + + String *ns_list = listify_namespace(Getattr(n, "allegrocl:namespace")); + String *name = Getattr(n, is_tempInst ? "real-name" : "name"); + + if (SwigType_istemplate(name)) { + String *temp = strip_namespaces(SwigType_templateprefix(name)); + name = NewStringf("%s%s%s", temp, SwigType_templateargs(name), SwigType_templatesuffix(name)); + + Delete(temp); + } else { + name = strip_namespaces(name); + } + + if (Getattr(n, "allegrocl:synonym:is-primary")) { + // Printf(stderr," is primary... "); + if (is_tempInst) { + emit_stub_class(n); + } else { + emit_full_class(n); + } + } else { + // Node *primary = Getattr(n,"allegrocl:synonym-of"); + Node *primary = get_primary_synonym_of(n); + if (primary && (primary != n)) { + // Printf(stderr," emitting synonym... "); + emit_stub_class(primary); + update_package_if_needed(n, f_clhead); + emit_synonym(n); + } else { + emit_full_class(n); + } + } + // Printf(stderr,"DONE\n"); + Delete(name); + Delete(ns_list); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_class: EXIT\n"); +#endif +} + +void emit_typedef(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_typedef: ENTER... \n"); +#endif + + String *name; + String *sym_name = Getattr(n, "sym:name"); + String *type = NewStringf("%s%s", Getattr(n, "decl"), Getattr(n, "type")); + String *lisp_type = compose_foreign_type(n, type); + Delete(type); + Node *in_class = Getattr(n, "allegrocl:typedef:in-class"); + + // Printf(stderr,"in emit_typedef: '%s'(%x).",Getattr(n,"name"),n); + if (Getattr(n, "allegrocl:synonym-of")) { + // Printf(stderr," but it's a synonym of something.\n"); + emit_synonym(n); + return; + } + + if (in_class) { + String *class_name = Getattr(in_class, "name"); + if (SwigType_istemplate(class_name)) { + String *temp = strip_namespaces(SwigType_templateprefix(class_name)); + class_name = NewStringf("%s%s%s", temp, SwigType_templateargs(class_name), SwigType_templatesuffix(class_name)); + Delete(temp); + } + + name = NewStringf("%s__%s", class_name, sym_name); + Setattr(n, "allegrocl:in-class", in_class); + } else { + name = sym_name ? Copy(sym_name) : Copy(Getattr(n, "name")); + } + + // leave these in for now. might want to change these to def-foreign-class at some point. +// Printf(f_clhead, ";; %s\n", SwigType_typedef_resolve_all(lisp_type)); + Printf(f_clhead, "(swig-def-foreign-type \"%s\"\n %s)\n", name, lisp_type); + + Delete(name); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_typedef: EXIT\n"); +#endif +} + +void emit_enum_type_no_wrap(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type_no_wrap: ENTER... \n"); +#endif + + String *unnamed = Getattr(n, "unnamed"); + String *name; + // SwigType *enumtype; + + name = unnamed ? Getattr(n, "allegrocl:name") : Getattr(n, "sym:name"); + SwigType *tmp = NewStringf("enum %s", unnamed ? unnamed : name); + + Node *node = NewHash(); + Setattr(node, "type", tmp); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *enumtype = Swig_typemap_lookup("ffitype", node, "", 0); + Delete(node); + + Delete(tmp); + + if (name) { + String *ns = listify_namespace(current_namespace); + + Printf(f_clhead, "(swig-def-foreign-type \"%s\" %s)\n", name, enumtype); + Delete(ns); + + // walk children. + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + if (!Getattr(c, "error")) { + String *val = Getattr(c, "enumvalue"); + if (!val) + val = Getattr(c, "enumvalueex"); + String *converted_val = convert_literal(val, Getattr(c, "type")); + String *valname = Getattr(c, "sym:name"); + + if (converted_val) { + Printf(f_clhead, "(swig-defconstant \"%s\" %s)\n", valname, converted_val); + Delete(converted_val); + } else { + Swig_warning(WARN_LANG_DISCARD_CONST, Getfile(n), Getline(n), "Unable to parse enum value '%s'. Setting to NIL\n", val); + Printf(f_clhead, "(swig-defconstant \"%s\" nil #| %s |#)\n", valname, val); + } + } + } + } + Printf(f_clhead, "\n"); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type_no_wrap: EXIT\n"); +#endif + +} + +void emit_enum_type(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type: ENTER... \n"); +#endif + + if (!Generate_Wrapper) { + emit_enum_type_no_wrap(n); + return; + } + + String *unnamed = Getattr(n, "unnamed"); + String *name; + // SwigType *enumtype; + + name = unnamed ? Getattr(n, "allegrocl:name") : Getattr(n, "sym:name"); + SwigType *tmp = NewStringf("enum %s", unnamed ? unnamed : name); + + Node *node = NewHash(); + Setattr(node, "type", tmp); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *enumtype = Swig_typemap_lookup("ffitype", node, "", 0); + Delete(node); + + Delete(tmp); + + if (name) { + String *ns = listify_namespace(current_namespace); + + Printf(f_clhead, "(swig-def-foreign-type \"%s\" %s)\n", name, enumtype); + Delete(ns); + + // walk children. + Node *c; + for(c = firstChild(n); c; c=nextSibling(c)) { + String *mangled_name = mangle_name(c, "ACL_ENUM", Getattr(c,"allegrocl:package")); + Printf(f_clhead, "(swig-defvar \"%s\" \"%s\" :type :constant :ftype :signed-long)\n", Getattr(c, "sym:name"), mangled_name); + Delete(mangled_name); + } + } +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type: EXIT\n"); +#endif + +} + +void emit_default_linked_type(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_default_linked_type: ENTER... \n"); +#endif + + // catchall for non class types. + if (!Strcmp(nodeType(n), "classforward")) { + Printf(f_clhead, ";; forward referenced stub.\n"); + Printf(f_clhead, "(swig-def-foreign-class \"%s\" (ff:foreign-pointer) (:class ))\n\n", Getattr(n, "sym:name")); + } else if (!Strcmp(nodeType(n), "enum")) { + emit_enum_type(n); + } else { + Printf(stderr, "Don't know how to emit node type '%s' named '%s'\n", nodeType(n), Getattr(n, "name")); + } + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_default_linked_type: EXIT\n"); +#endif + +} + +void dump_linked_types(File *f) { + Node *n = first_linked_type; + int i = 0; + while (n) { + Printf(f, "%d: (%x) node '%s' name '%s'\n", i++, n, nodeType(n), Getattr(n, "sym:name")); + + Node *t = Getattr(n, "allegrocl:synonym-of"); + if (t) + Printf(f, " synonym-of %s(%x)\n", Getattr(t, "name"), t); + n = Getattr(n, "allegrocl:next_linked_type"); + } +} + +void emit_linked_types() { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_linked_types: ENTER... "); +#endif + + Node *n = first_linked_type; + + while (n) { + String *node_type = nodeType(n); + + // Printf(stderr,"emitting node %s(%x) of type %s.", Getattr(n,"name"),n, nodeType(n)); + if (!Strcmp(node_type, "class") || !Strcmp(node_type, "templateInst")) { + // may need to emit a stub, so it will update the package itself. + // Printf(stderr," Passing to emit_class."); + emit_class(n); + } else if (!Strcmp(nodeType(n), "cdecl")) { + // Printf(stderr," Passing to emit_typedef."); + update_package_if_needed(n, f_clhead); + emit_typedef(n); + } else { + // Printf(stderr," Passing to default_emitter."); + update_package_if_needed(n, f_clhead); + emit_default_linked_type(n); + } + + n = Getattr(n, "allegrocl:next_linked_type"); + // Printf(stderr,"returned.\n"); + } + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_linked_types: EXIT\n"); +#endif +} + +extern "C" Language *swig_allegrocl(void) { + return (allegrocl = new ALLEGROCL()); +} + +void ALLEGROCL::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGALLEGROCL 1", 0); + SWIG_library_directory("allegrocl"); + SWIG_config_file("allegrocl.swg"); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-identifier-converter")) { + char *conv = argv[i + 1]; + + if (!conv) + Swig_arg_error(); + + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + + /* check for built-ins */ + if (!strcmp(conv, "lispify")) { + identifier_converter = "identifier-convert-lispify"; + } else if (!strcmp(conv, "null")) { + identifier_converter = "identifier-convert-null"; + } else { + /* Must be user defined */ + char *idconv = new char[strlen(conv) + 1]; + strcpy(idconv, conv); + identifier_converter = idconv; + } + } else if (!strcmp(argv[i], "-cwrap")) { + CWrap = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocwrap")) { + CWrap = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-isolate")) { + unique_swig_package = true; + Swig_mark_arg(i); + } + + if (!strcmp(argv[i], "-help")) { + fprintf(stdout, "Allegro CL Options (available with -allegrocl)\n"); + fprintf(stdout, + " -identifier-converter <type or funcname>\n" + "\tSpecifies the type of conversion to do on C identifiers to convert\n" + "\tthem to symbols. There are two built-in converters: 'null' and\n" + "\t 'lispify'. The default is 'null'. If you supply a name other\n" + "\tthan one of the built-ins, then a function by that name will be\n" + "\tcalled to convert identifiers to symbols.\n" + "\n" + " -[no]cwrap\n" + "\tTurn on or turn off generation of an intermediate C file when\n" "\tcreating a C interface. By default this is only done for C++ code.\n" + " -isolate\n" + "Define all SWIG helper functions in a package unique to this module. Avoids redefinition warnings when loading multiple SWIGged modules\n" + "into the same running Allegro CL image.\n"); + + } + + } + + allow_overloading(); +} + +int ALLEGROCL::top(Node *n) { + module_name = Getattr(n, "name"); + String *cxx_filename = Getattr(n, "outfile"); + String *cl_filename = NewString(""); + + swig_package = unique_swig_package ? NewStringf("swig.%s", module_name) : NewString("swig"); + + Printf(cl_filename, "%s%s.cl", SWIG_output_directory(), module_name); + + f_cl = NewFile(cl_filename, "w", SWIG_output_files()); + if (!f_cl) { + Printf(stderr, "Unable to open %s for writing\n", cl_filename); + SWIG_exit(EXIT_FAILURE); + } + + Generate_Wrapper = CPlusPlus || CWrap; + + if (Generate_Wrapper) { + f_begin = NewFile(cxx_filename, "w", SWIG_output_files()); + if (!f_begin) { + Close(f_cl); + Delete(f_cl); + Printf(stderr, "Unable to open %s for writing\n", cxx_filename); + SWIG_exit(EXIT_FAILURE); + } + } else + f_begin = NewString(""); + + f_runtime = NewString(""); + f_cxx_header = f_runtime; + f_cxx_wrapper = NewString(""); + + Swig_register_filebyname("header", f_cxx_header); + Swig_register_filebyname("wrapper", f_cxx_wrapper); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("lisp", f_clwrap); + Swig_register_filebyname("lisphead", f_cl); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGALLEGROCL\n"); + Printf(f_runtime, "\n"); + + Swig_banner_target_lang(f_cl, ";;"); + + Printf(f_cl, "\n" + "(defpackage :%s\n" + " (:use :common-lisp :ff :excl)\n" + " (:export #:*swig-identifier-converter* #:*swig-module-name*\n" + " #:*void* #:*swig-export-list*))\n" + "(in-package :%s)\n\n" + "(eval-when (:compile-toplevel :load-toplevel :execute)\n" + " (defparameter *swig-identifier-converter* '%s)\n" + " (defparameter *swig-module-name* :%s))\n\n", swig_package, swig_package, identifier_converter, module_name); + Printf(f_cl, "(defpackage :%s\n" " (:use :common-lisp :%s :ff :excl))\n\n", module_name, swig_package); + + Printf(f_clhead, "(in-package :%s)\n", module_name); + + // Swig_print_tree(n); + + Language::top(n); + + // SwigType_emit_type_table(f_runtime,f_cxx_wrapper); + + // Swig_print_tree(n); +#ifdef ALLEGROCL_TYPE_DEBUG + dump_linked_types(stderr); +#endif + emit_linked_types(); + + Printf(f_clwrap, "\n(cl::in-package :%s)\n", swig_package); + Printf(f_clwrap, "\n(macrolet ((swig-do-export ()\n"); + Printf(f_clwrap, " `(dolist (s ',*swig-export-list*)\n"); + Printf(f_clwrap, " (apply #'export s))))\n"); + Printf(f_clwrap, " (swig-do-export))\n"); + Printf(f_clwrap, "\n(setq *swig-export-list* nil)\n"); + + Printf(f_cl, "%s\n", f_clhead); + Printf(f_cl, "%s\n", f_clwrap); + + Close(f_cl); + Delete(f_cl); // Delete the handle, not the file + Delete(f_clhead); + Delete(f_clwrap); + + Dump(f_runtime, f_begin); + Printf(f_begin, "%s\n", f_cxx_wrapper); + + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + Delete(f_cxx_wrapper); + + // Swig_print_tree(n); + + return SWIG_OK; +} + +/* very shamelessly 'borrowed' from overload.cxx, which + keeps the below Swig_overload_rank() code to itself. + We don't need a dispatch function in the C++ wrapper + code; we want it over on the lisp side. */ + +#define MAX_OVERLOAD 256 + +/* 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 */ +}; + +/* ----------------------------------------------------------------------------- + * 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. + * ----------------------------------------------------------------------------- */ + +static 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")) { + 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)) { + // 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 (no type checking rule 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 (no type checking rule 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 %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), Getfile(nodes[i].n), Getline(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(%s) ignored. Method %s(%s) const at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n, "name"), ParmList_errorstr(nodes[i].parms), Getfile(nodes[i].n), Getline(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 %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), Getfile(nodes[i].n), Getline(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(%s) const ignored. Method %s(%s) at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n, "name"), ParmList_errorstr(nodes[i].parms), Getfile(nodes[i].n), Getline(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 is shadowed by %s at %s:%d.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(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. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(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; +} + +/* end shameless borrowing */ + +int any_varargs(ParmList *pl) { + Parm *p; + + for (p = pl; p; p = nextSibling(p)) { + if (SwigType_isvarargs(Getattr(p, "type"))) + return 1; + } + + return 0; +} + +String *get_lisp_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setattr(node, "name", name); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("lisptype", node, "", 0); + Delete(node); + + return tm ? NewString(tm) : NewString(""); +} + +Node *parent_node_skipping_extends(Node *n) { + Node *result = n; + do { + result = parentNode(result); + } + while (Cmp("extend", nodeType(result)) == 0); + return result; +} + +/* ----------------------------------------------------------------------------- + * emit_num_lin_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_lin_arguments(ParmList *parms) { + Parm *p = parms; + int nargs = 0; + + while (p) { + // Printf(stderr,"enla: '%s' lin='%x'\n", Getattr(p,"name"), Getattr(p,"tmap:lin")); + if (Getattr(p, "tmap:lin")) { + nargs += GetInt(p, "tmap:lin:numinputs"); + p = Getattr(p, "tmap:lin: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; +} + +String *id_converter_type(SwigType const *type) { + SwigType *t = Copy(type); + String *result = 0; + + if (SwigType_ispointer(t)) { + SwigType_pop(t); + String *pointee = id_converter_type(t); + result = NewStringf("(:* %s)", pointee); + Delete(pointee); + } else if (SwigType_ismemberpointer(t)) { + String *klass = SwigType_parm(t); + SwigType_pop(t); + String *member = id_converter_type(t); + result = NewStringf("(:member \"%s\" %s)", klass, member); + Delete(klass); + Delete(member); + } else if (SwigType_isreference(t)) { + SwigType_pop(t); + String *referencee = id_converter_type(t); + result = NewStringf("(:& %s)", referencee); + Delete(referencee); + } else if (SwigType_isarray(t)) { + String *size = SwigType_parm(t); + SwigType_pop(t); + String *element_type = id_converter_type(t); + result = NewStringf("(:array %s \"%s\")", element_type, size); + Delete(size); + Delete(element_type); + } else if (SwigType_isfunction(t)) { + result = NewString("(:function ("); + String *parmlist_str = SwigType_parm(t); + List *parms = SwigType_parmlist(parmlist_str); + + for (Iterator i = First(parms); i.item;) { + String *parm = id_converter_type((SwigType *) i.item); + Printf(result, "%s", parm); + i = Next(i); + if (i.item) + Printf(result, " "); + Delete(parm); + } + SwigType_pop(t); + String *ret = id_converter_type(t); + Printf(result, ") %s)", ret); + + Delete(parmlist_str); + Delete(parms); + Delete(ret); + } else if (SwigType_isqualifier(t)) { + result = NewString("(:qualified ("); + String *qualifiers_str = Copy(SwigType_parm(t)); // ?! + // Replaceall below SEGVs if we don't put the Copy here... + SwigType_pop(t); + String *qualifiee = id_converter_type(t); + + Replaceall(qualifiers_str, " ", " :"); + if (Len(qualifiers_str) > 0) + Printf(result, ":"); + Printf(result, "%s) %s)", qualifiers_str, qualifiee); + + Delete(qualifiers_str); + Delete(qualifiee); + } else if (SwigType_istemplate(t)) { + result = NewStringf("(:template \"%s\")", t); + } else { /* if (SwigType_issimple(t)) */ + + if (Strstr(Char(t), "::")) { + result = listify_namespace(t); + } else { + result = NewStringf("\"%s\"", t); + } + } + + Delete(t); + return result; +} + +static ParmList *parmlist_with_names(ParmList *pl) { + ParmList *pl2 = CopyParmList(pl); + for (Parm *p = pl, *p2 = pl2; p2; p = nextSibling(p), p2 = nextSibling(p2)) { + if (!Getattr(p2, "name")) + Setattr(p2, "name", Getattr(p2, "lname")); + Setattr(p2, "name", strip_namespaces(Getattr(p2, "name"))); + Setattr(p2, "tmap:ctype", Getattr(p, "tmap:ctype")); + + String *temp = Getattr(p, "tmap:lin"); + if (temp) { + Setattr(p2, "tmap:lin", temp); + Setattr(p2, "tmap:lin:next", Getattr(p, "tmap:lin:next")); + } + } + return pl2; +} + +static String *parmlist_str_id_converter(ParmList *pl) { + String *result = NewString(""); + for (Parm *p = pl; p;) { + String *lispy_type = id_converter_type(Getattr(p, "type")); + Printf(result, "(\"%s\" %s)", Getattr(p, "name"), lispy_type); + Delete(lispy_type); + if ((p = nextSibling(p))) + Printf(result, " "); + } + return result; +} + +String *collect_others_args(Node *overload) { + String *overloaded_from = Getattr(overload, "sym:overloaded"); + String *others_args = NewString(""); + int first_overload = 1; + + for (Node *overload2 = overloaded_from; overload2; overload2 = Getattr(overload2, "sym:nextSibling")) { + if (overload2 == overload || GetInt(overload2, "overload:ignore")) + continue; + + ParmList *opl = parmlist_with_names(Getattr(overload2, "wrap:parms")); + String *args = parmlist_str_id_converter(opl); + if (!first_overload) + Printf(others_args, "\n "); + Printf(others_args, "(%s)", args); + Delete(args); + Delete(opl); + first_overload = 0; + } + return others_args; +} + +struct IDargs { + String *name; + String *type; + String *klass; + String *arity; + + IDargs():name(0), type(0), klass(0), arity(0) { + } + + String *full_quoted_str() { + String *result = no_others_quoted_str(); + if (arity) + Printf(result, " :arity %s", arity); + return result; + } + + String *no_others_quoted_str() { + String *result = NewString(""); + Printf(result, "\"%s\" :type :%s", name, type); + if (klass) + Printf(result, " :class \"%s\"", klass); + return result; + } + + String *noname_str() { + String *result = NewString(""); + Printf(result, " :type :%s", type); + if (klass) + Printf(result, " :class \"%s\"", klass); + if (arity) + Printf(result, " :arity %s", arity); + return result; + } +}; +IDargs *id_converter_arguments(Node *n) { + IDargs *result = (IDargs *) GetVoid(n, "allegrocl:id-converter-args"); + if (!result) + result = new IDargs; + + // Base name + if (!result->name) { + result->name = Getattr(n, "allegrocl:old-sym:name"); + if (!result->name) + result->name = Getattr(n, "sym:name"); + result->name = Copy(result->name); + } + // :type + if (result->type) + Delete(result->type); + if (!Getattr(n, "allegrocl:kind")) + Setattr(n, "allegrocl:kind", "function"); + if (Strstr(Getattr(n, "name"), "operator ")) + Replaceall(Getattr(n, "allegrocl:kind"), "function", "operator"); + if (Strstr(Getattr(n, "allegrocl:kind"), "variable")) { + int name_end = Len(Getattr(n, "sym:name")) - 4; + char *str = Char(Getattr(n, "sym:name")); + String *get_set = NewString(str + name_end + 1); + result->type = Copy(Getattr(n, "allegrocl:kind")); + Replaceall(result->type, "variable", ""); + Printf(result->type, "%ster", get_set); + Delete(get_set); + } else { + result->type = Copy(Getattr(n, "allegrocl:kind")); + } + + // :class + if (Strstr(result->type, "member ")) { + Replaceall(result->type, "member ", ""); + if (!result->klass) + result->klass = Copy(Getattr(parent_node_skipping_extends(n), "sym:name")); + } + // :arity + if (Getattr(n, "sym:overloaded")) { + if (result->arity) + Delete(result->arity); + result->arity = NewStringf("%d", + // emit_num_arguments(Getattr(n, "wrap:parms"))); + emit_num_lin_arguments(Getattr(n, "wrap:parms"))); + // Printf(stderr, "got arity of '%s' node '%s' '%x'\n", result->arity, Getattr(n,"name"), Getattr(n,"wrap:parms")); + } + + SetVoid(n, "allegrocl:id-converter-args", result); + return result; +} + +int ALLEGROCL::emit_buffered_defuns(Node *n) { + + Node *overloaded_from = Getattr(n, "sym:overloaded"); + + String *wrap; + + if (!overloaded_from) { + wrap = Getattr(n, "allegrocl:lisp-wrap"); + + Printf(f_clwrap, "%s\n", wrap); + Delattr(n, "allegrocl:lisp-wrap"); + Delete(wrap); + } else { + for (Node *overload = overloaded_from; overload; overload = Getattr(overload, "sym:nextSibling")) { + String *others_args = collect_others_args(overload); + wrap = Getattr(overload, "allegrocl:lisp-wrap"); + + Replaceall(wrap, "@@OTHERS-ARGS-GO-HERE@@", others_args); +// IDargs* id_args = id_converter_arguments(overload); +// Replaceall(id_args->others_args, "@@OTHERS-ARGS-GO-HERE@@", others_args); + + if (!GetInt(overload, "overload:ignore")) + Printf(f_clwrap, "%s", wrap); + + Delattr(overload, "allegrocl:lisp-wrap"); + Delete(wrap); + } + } + return SWIG_OK; +} + +String *dispatching_type(Node *n, Parm *p) { + String *result = 0; + + String *parsed = Getattr(p, "type"); //Swig_cparse_type(Getattr(p,"tmap:ctype")); + String *cl_t = SwigType_typedef_resolve_all(parsed); + + Node *node = NewHash(); + Setattr(node, "type", parsed); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("lispclass", node, Getattr(p, "name"), 0); + Delete(node); + + if (tm) { + result = Copy(tm); + } else { + String *lookup_type = class_from_class_or_class_ref(parsed); + if (lookup_type) + result = lookup_defined_foreign_ltype(lookup_type); + } + + // if (!result && SwigType_ispointer(cl_t)) { + // SwigType_pop(cl_t); + // result = lookup_defined_foreign_ltype(cl_t); + // } + + if (!result) + result = NewStringf("ff:foreign-pointer"); + + // Delete(parsed); + Delete(cl_t); + return result; +} + +int ALLEGROCL::emit_dispatch_defun(Node *n) { +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_dispatch_defun: ENTER... "); +#endif + List *overloads = Swig_overload_rank(n, true); + + String *id_args = id_converter_arguments(n)->no_others_quoted_str(); + Printf(f_clwrap, "(swig-dispatcher (%s :arities (", id_args); + + int last_arity = -1; + for (Iterator i = First(overloads); i.item; i = Next(i)) { + int arity = emit_num_lin_arguments(Getattr(i.item, "wrap:parms")); + if (arity == last_arity) + continue; + + Printf(f_clwrap, "%s%d", last_arity == -1 ? "" : " ", arity); + + last_arity = arity; + } + Printf(f_clwrap, ")))\n"); + + Delete(id_args); + Delete(overloads); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_dispatch_defun: EXIT\n"); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::emit_defun(Node *n, File *fcl) { +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_defun: ENTER... "); +#endif + +#ifdef ALLEGROCL_DEBUG + int auto_generated = Cmp(Getattr(n, "view"), "globalfunctionHandler"); + Printf(stderr, "%s%sfunction %s%s%s\n", auto_generated ? "> " : "", Getattr(n, "sym:overloaded") + ? "overloaded " : "", current_namespace, (current_namespace) > 0 ? "::" : "", Getattr(n, "sym:name")); + Printf(stderr, " (view: %s)\n", Getattr(n, "view")); +#endif + + String *funcname = Getattr(n, "allegrocl:old-sym:name"); + if (!funcname) + funcname = Getattr(n, "sym:name"); + String *mangled_name = Getattr(n, "wrap:name"); + ParmList *pl = parmlist_with_names(Getattr(n, "wrap:parms")); + + // attach typemap info. + Wrapper *wrap = NewWrapper(); + Swig_typemap_attach_parms("lin", pl, wrap); + // Swig_typemap_attach_parms("ffitype", pl, wrap); + Swig_typemap_lookup("lout", n, "result", 0); + + SwigType *result_type = Swig_cparse_type(Getattr(n, "tmap:ctype")); + // prime the pump, with support for OUTPUT, INOUT typemaps. + Printf(wrap->code, + "(cl::let ((ACL_ffresult %s:*void*)\n ACL_result)\n $body\n (cl::if (cl::eq ACL_ffresult %s:*void*)\n (cl::values-list ACL_result)\n (cl::values-list (cl::cons ACL_ffresult ACL_result))))", + swig_package, swig_package); + + Parm *p; + int largnum = 0, argnum = 0, first = 1; + // int varargs=0; + if (Generate_Wrapper) { + String *extra_parms = id_converter_arguments(n)->noname_str(); + if (Getattr(n, "sym:overloaded")) + Printf(fcl, "(swig-defmethod (\"%s\" \"%s\"%s)\n", funcname, mangled_name, extra_parms); + else + Printf(fcl, "(swig-defun (\"%s\" \"%s\"%s)\n", funcname, mangled_name, extra_parms); + Delete(extra_parms); + } + // Just C + else { + Printf(fcl, "(swig-defun (\"%s\" \"%s\")\n", funcname, Generate_Wrapper ? mangled_name : funcname); + } + + ////////////////////////////////////// + // Lisp foreign call parameter list // + ////////////////////////////////////// + Printf(fcl, " ("); + + /* Special cases */ + + if (ParmList_len(pl) == 0) { + Printf(fcl, ":void"); +/* } else if (any_varargs(pl)) { + Printf(fcl, "#| varargs |#"); + varargs=1; */ + } else { + String *largs = NewString(""); + + for (p = pl; p; p = nextSibling(p), argnum++, largnum++) { + // SwigType *argtype=Getattr(p, "type"); + SwigType *argtype = Swig_cparse_type(Getattr(p, "tmap:ctype")); + SwigType *parmtype = Getattr(p,"type"); + + if (!first) { + Printf(fcl, "\n "); + } + + /* by default, skip varargs */ + if (!SwigType_isvarargs(parmtype)) { + String *argname = NewStringf("PARM%d_%s", largnum, Getattr(p, "name")); + + // Printf(stderr,"%s\n", Getattr(p,"tmap:lin")); + String *ffitype = compose_foreign_type(n, argtype, Getattr(p,"name")); + String *deref_ffitype = dereference_ffitype(ffitype); + String *lisptype = get_lisp_type(n, parmtype, Getattr(p, "name")); + +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "lisptype of '%s' '%s' = '%s'\n", parmtype, + Getattr(p, "name"), lisptype); +#endif + + // while we're walking the parameters, generating LIN + // wrapper code... + Setattr(p, "lname", NewStringf("SWIG_arg%d", largnum)); + + String *parm_code = Getattr(p, "tmap:lin"); + if (parm_code) { + String *lname = Getattr(p, "lname"); + + Printf(largs, " %s", lname); + Replaceall(parm_code, "$in_fftype", ffitype); // must come before $in + Replaceall(parm_code, "$in", argname); + Replaceall(parm_code, "$out", lname); + Replaceall(parm_code, "$*in_fftype", deref_ffitype); + Replaceall(wrap->code, "$body", parm_code); + } + + String *dispatchtype = Getattr(n, "sym:overloaded") ? dispatching_type(n, p) : NewString(""); + + // if this parameter has been removed from the C/++ wrapper + // it shouldn't be in the lisp wrapper either. + if (!checkAttribute(p, "tmap:in:numinputs", "0")) { + Printf(fcl, "(%s %s %s %s %s)", + // parms in the ff wrapper, but not in the lisp wrapper. + (checkAttribute(p, "tmap:lin:numinputs", "0") ? ":p-" : ":p+"), argname, dispatchtype, ffitype, lisptype); + + first = 0; + } + + Delete(argname); + Delete(ffitype); + Delete(deref_ffitype); + Delete(lisptype); + } + } + + Printf(wrap->locals, "%s", largs); + } + + String *lout = Getattr(n, "tmap:lout"); + Replaceall(lout, "$owner", GetFlag(n, "feature:new") ? "t" : "nil"); + + Replaceall(wrap->code, "$body", lout); + // $lclass handling. + String *lclass = (String *) 0; + SwigType *parsed = Swig_cparse_type(Getattr(n, "tmap:ctype")); + // SwigType *cl_t = SwigType_typedef_resolve_all(parsed); + SwigType *cl_t = class_from_class_or_class_ref(parsed); + String *out_ffitype = compose_foreign_type(n, parsed); + String *deref_out_ffitype; + String *out_temp = Copy(parsed); + + if (SwigType_ispointer(out_temp)) { + SwigType_pop(out_temp); + deref_out_ffitype = compose_foreign_type(n, out_temp); + } else { + deref_out_ffitype = Copy(out_ffitype); + } + + Delete(out_temp); + + Delete(parsed); + + int isPtrReturn = 0; + + if (cl_t) { + lclass = lookup_defined_foreign_ltype(cl_t); + isPtrReturn = 1; + } + + int ff_foreign_ptr = 0; + if (!lclass) { + ff_foreign_ptr = 1; + lclass = NewStringf("ff:foreign-pointer"); + } +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "for output wrapping %s: type=%s, ctype=%s\n", Getattr(n, "name"), + Getattr(n, "type"), Swig_cparse_type(Getattr(n, "tmap:ctype"))); +#endif + + if (lclass) + Replaceall(wrap->code, "$lclass", lclass); + if (out_ffitype) + Replaceall(wrap->code, "$out_fftype", out_ffitype); + if (deref_out_ffitype) + Replaceall(wrap->code, "$*out_fftype", deref_out_ffitype); + // if(Replaceall(wrap->code,"$lclass", lclass) && !isPtrReturn) { + // Swig_warning(WARN_LANG_RETURN_TYPE,Getfile(n), Getline(n), + // "While Wrapping %s, replaced a $lclass reference when return type is non-pointer %s!\n", + // Getattr(n,"name"), cl_t); + // } + + Replaceall(wrap->code, "$body", NewStringf("(swig-ff-call%s)", wrap->locals)); +// Replaceall(wrap->code,"$body", +// (!Strcmp(result_type,"void") ? +// NewStringf("(swig-ff-call%s)", wrap->locals) : +// NewStringf("(push (swig-ff-call%s) ACL_result)", wrap->locals))); + String *ldestructor = Copy(lclass); + if (ff_foreign_ptr) + Replaceall(ldestructor, ldestructor, "identity"); + else + Replaceall(ldestructor, ":type :class", ":type :destructor"); + Replaceall(wrap->code, "$ldestructor", ldestructor); + Delete(ldestructor); + + Printf(fcl, ")\n"); /* finish arg list */ + + ///////////////////////////////////////////////////// + // Lisp foreign call return type and optimizations // + ///////////////////////////////////////////////////// + Printf(fcl, " (:returning (%s %s)", compose_foreign_type(n, result_type), get_lisp_type(n, Getattr(n, "type"), "result")); + + for (Iterator option = First(n); option.item; option = Next(option)) { + if (Strncmp("feature:ffargs:", option.key, 15)) + continue; + String *option_val = option.item; + String *option_name = NewString(Char(option.key) + 14); + Replaceall(option_name, "_", "-"); + + // TODO: varargs vs call-direct ? + Printf(fcl, "\n %s %s", option_name, option_val); + + Delete(option_name); + } + + Printf(fcl, ")\n %s)\n\n", wrap->code); + // Wrapper_print(wrap, stderr); + + Delete(result_type); + Delete(mangled_name); + Delete(pl); + DelWrapper(wrap); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_defun: EXIT\n"); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::functionWrapper(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "functionWrapper %s\n", Getattr(n,"name")); + Swig_print_node(n); +#endif + + + ParmList *parms = CopyParmList(Getattr(n, "parms")); + Wrapper *f = NewWrapper(); + SwigType *t = Getattr(n, "type"); + String *name = Getattr(n, "name"); + + String *raw_return_type = Swig_typemap_lookup("ctype", n, "", 0); + SwigType *return_type = Swig_cparse_type(raw_return_type); + SwigType *resolved = SwigType_typedef_resolve_all(return_type); + int is_void_return = (Cmp(resolved, "void") == 0); + + Delete(resolved); + + if (!is_void_return) { + String *lresult_init = + NewStringf("= (%s)0", + SwigType_str(SwigType_strip_qualifiers(return_type),0)); + Wrapper_add_localv(f, "lresult", + SwigType_lstr(SwigType_ltype(return_type), "lresult"), + lresult_init, NIL); + Delete(lresult_init); + } + // Emit all of the local variables for holding arguments. + emit_parameter_variables(parms, f); + + // Attach the standard typemaps + Swig_typemap_attach_parms("ctype", parms, f); + Swig_typemap_attach_parms("lin", parms, f); + emit_attach_parmmaps(parms, f); + + String *mangled = mangle_name(n); + Node *overloaded = Getattr(n, "sym:overloaded"); + + // Parameter overloading + Setattr(n, "wrap:parms", parms); + Setattr(n, "wrap:name", mangled); + + if (overloaded) { + // emit warnings when overloading is impossible on the lisp side. + // basically Swig_overload_check(n), but with script_lang_wrapping + // set to true. + Delete(Swig_overload_rank(n, true)); + if (Getattr(n, "overload:ignore")) { + // if we're the last overload, make sure to force the emit + // of the rest of the overloads before we leave. + Printf(stderr, "ignored overload %s(%x)\n", name, Getattr(n, "sym:nextSibling")); + if (!Getattr(n, "sym:nextSibling")) { + update_package_if_needed(n); + emit_buffered_defuns(n); + emit_dispatch_defun(n); + } + DelWrapper(f); + return SWIG_OK; + } + } + // Get number of required and total arguments + int num_arguments = emit_num_arguments(parms); + int gencomma = 0; + +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "Walking parameters for %s '%s'\n", Getattr(n, "allegrocl:kind"), name); +#endif + // Now walk the function parameter list and generate code to get arguments + String *name_and_parms = NewStringf("%s (", mangled); + int i; + Parm *p; + for (i = 0, p = parms; i < num_arguments; i++) { + + while (p && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + if (!p) + break; + + SwigType *c_parm_type = Swig_cparse_type(Getattr(p, "tmap:ctype")); + String *arg = NewStringf("l%s", Getattr(p, "lname")); + + // Emit parameter declaration + if (gencomma) + Printf(name_and_parms, ", "); + String *parm_decl = SwigType_str(c_parm_type, arg); + Printf(name_and_parms, "%s", parm_decl); +#ifdef ALLEGROCL_DEBUG + Printf(stderr, " param: %s\n", parm_decl); +#endif + Delete(parm_decl); + gencomma = 1; + + // Emit parameter conversion code + String *parm_code = Getattr(p, "tmap:in"); + //if (!parm_code) { + // Swig_warning(...); + // p = nextSibling(p); + /*} else */ { + // canThrow(n, "in", p); + Replaceall(parm_code, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", parm_code); + p = Getattr(p, "tmap:in:next"); + } + + Delete(arg); + } + Printf(name_and_parms, ")"); + + // Emit the function definition + String *signature = SwigType_str(return_type, name_and_parms); + Printf(f->def, "EXPORT %s {", signature); + if (CPlusPlus) + Printf(f->code, " try {\n"); + + String *actioncode = emit_action(n); + + String *tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode); + if (!is_void_return && tm) { + if (tm) { + Replaceall(tm, "$result", "lresult"); + Printf(f->code, "%s\n", tm); + Printf(f->code, " return lresult;\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(t, 0), name); + } + } + + emit_return_variable(n, t, f); + + if (CPlusPlus) { + Printf(f->code, " } catch (...) {\n"); + if (!is_void_return) + Printf(f->code, " return (%s)0;\n", + SwigType_str(SwigType_strip_qualifiers(return_type),0)); + Printf(f->code, " }\n"); + } + Printf(f->code, "}\n"); + + /* print this when in C mode? make this a command-line arg? */ + if (Generate_Wrapper) + Wrapper_print(f, f_cxx_wrapper); + + String *f_buffer = NewString(""); + + emit_defun(n, f_buffer); + Setattr(n, "allegrocl:lisp-wrap", f_buffer); + + if (!overloaded || !Getattr(n, "sym:nextSibling")) { + update_package_if_needed(n); + emit_buffered_defuns(n); + // this is the last overload. + if (overloaded) { + emit_dispatch_defun(n); + } + } + + DelWrapper(f); + + return SWIG_OK; +} + +int ALLEGROCL::namespaceDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "namespaceDecl: '%s'(0x%x) (fc=0x%x)\n", Getattr(n, "sym:name"), n, firstChild(n)); +#endif + + /* don't wrap a namespace with no contents. package bloat. + also, test-suite/namespace_class.i claims an unnamed namespace + is 'private' and should not be wrapped. Complying... + */ + if (Getattr(n,"unnamed") || !firstChild(n)) + return SWIG_OK; + + String *name = Getattr(n, "sym:name"); + + String *old_namespace = current_namespace; + if (Cmp(current_namespace, "") == 0) + current_namespace = NewStringf("%s", name); + else + current_namespace = NewStringf("%s::%s", current_namespace, name); + + if (!GetInt(defined_namespace_packages, current_namespace)) { + SetInt(defined_namespace_packages, current_namespace, 1); + String *lispy_namespace = listify_namespace(current_namespace); + Printf(f_clhead, "(swig-defpackage %s)\n", lispy_namespace); + Delete(lispy_namespace); + } + + emit_children(n); + + Delete(current_namespace); + current_namespace = old_namespace; + return SWIG_OK; +} + +int ALLEGROCL::constructorHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "constructorHandler %s\n", Getattr(n, "name")); +#endif + // Swig_print_node(n); + Setattr(n, "allegrocl:kind", "constructor"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a global forwarding function. + return Language::constructorHandler(n); +} + +int ALLEGROCL::destructorHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "destructorHandler %s\n", Getattr(n, "name")); +#endif + + Setattr(n, "allegrocl:kind", "destructor"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a global forwarding function. + return Language::destructorHandler(n); +} + +int ALLEGROCL::constantWrapper(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "constantWrapper %s\n", Getattr(n, "name")); +#endif + + if (Generate_Wrapper) { + // Setattr(n,"wrap:name",mangle_name(n, "ACLPP")); + String *const_type = Getattr(n, "type"); + + String *const_val = 0; + String *raw_const = Getattr(n, "value"); + + if (SwigType_type(const_type) == T_STRING) { + const_val = NewStringf("\"%s\"", raw_const); + } else if (SwigType_type(const_type) == T_CHAR) { + const_val = NewStringf("'%s'", raw_const); + } else { + const_val = Copy(raw_const); + } + + SwigType_add_qualifier(const_type, "const"); + + String *ppcname = NewStringf("ACLppc_%s", Getattr(n, "sym:name")); + // Printf(f_runtime, "static const %s = %s;\n", SwigType_lstr(const_type, ppcname), const_val); + Printf(f_runtime, "static %s = %s;\n", SwigType_lstr(const_type, ppcname), const_val); + + Setattr(n, "name", ppcname); + SetFlag(n, "feature:immutable"); + + Delete(const_val); + return variableWrapper(n); + } + + String *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *converted_value = convert_literal(value, type); + String *name = Getattr(n, "sym:name"); + + Setattr(n, "allegrocl:kind", "constant"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + +#if 0 + Printf(stdout, "constant %s is of type %s. value: %s\n", name, type, converted_value); +#endif + + if (converted_value) { + Printf(f_clwrap, "(swig-defconstant \"%s\" %s)\n", name, converted_value); + } else { + Swig_warning(WARN_LANG_DISCARD_CONST, Getfile(n), Getline(n), "Unable to parse constant value '%s'. Setting to NIL\n", value); + Printf(f_clwrap, "(swig-defconstant \"%s\" nil #| %s |#)\n", name, value); + } + + Delete(converted_value); + + return SWIG_OK; +} + +int ALLEGROCL::globalvariableHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "globalvariableHandler %s\n", Getattr(n, "name")); +#endif + + if (Generate_Wrapper) + return Language::globalvariableHandler(n); + + // String *name = Getattr(n, "name"); + SwigType *type = Getattr(n, "type"); + SwigType *ctype; + SwigType *rtype = SwigType_typedef_resolve_all(type); + + int pointer_added = 0; + + if (SwigType_isclass(rtype)) { + SwigType_add_pointer(type); + SwigType_add_pointer(rtype); + pointer_added = 1; + } + + ctype = SwigType_str(type, 0); + // EXPORT <SwigType_str> <mangled_name>; + // <SwigType_str> <mangled_name> = <name>; + // Printf(f_runtime, "EXPORT %s %s;\n%s %s = %s%s;\n", ctype, mangled_name, + // ctype, mangled_name, (pointer_added ? "&" : ""), name); + + Printf(f_clwrap, "(swig-defvar \"%s\" \"%s\" :type %s)\n", + Getattr(n, "sym:name"), Getattr(n, "sym:name"), ((SwigType_isconst(type)) ? ":constant" : ":variable")); + + return SWIG_OK; +} + +int ALLEGROCL::variableWrapper(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "variableWrapper %s\n", Getattr(n, "name")); +#endif + Setattr(n, "allegrocl:kind", "variable"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a get/set function pair. + if (Generate_Wrapper) + return Language::variableWrapper(n); + + String *name = Getattr(n, "name"); + SwigType *type = Getattr(n, "type"); + SwigType *ctype; + SwigType *rtype = SwigType_typedef_resolve_all(type); + + String *mangled_name = mangle_name(n); + + int pointer_added = 0; + + if (SwigType_isclass(rtype)) { + SwigType_add_pointer(type); + SwigType_add_pointer(rtype); + pointer_added = 1; + } + + ctype = SwigType_str(type, 0); + + // EXPORT <SwigType_str> <mangled_name>; + // <SwigType_str> <mangled_name> = <name>; + Printf(f_runtime, "EXPORT %s %s;\n%s %s = %s%s;\n", ctype, mangled_name, ctype, mangled_name, (pointer_added ? "&" : ""), name); + + Printf(f_cl, "(swig-defvar \"%s\" :type %s)\n", mangled_name, ((SwigType_isconst(type)) ? ":constant" : ":variable")); + + Printf(stderr,"***\n"); + Delete(mangled_name); + +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "DONE variable %s\n", Getattr(n, "name")); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::memberfunctionHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "memberfunctionHandler %s::%s\n", Getattr(parent_node_skipping_extends(n), "name"), Getattr(n, "name")); +#endif + Setattr(n, "allegrocl:kind", "member function"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a global forwarding function. + return Language::memberfunctionHandler(n); +} + +int ALLEGROCL::membervariableHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "membervariableHandler %s::%s\n", Getattr(parent_node_skipping_extends(n), "name"), Getattr(n, "name")); +#endif + Setattr(n, "allegrocl:kind", "member variable"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a get/set function pair. + return Language::membervariableHandler(n); +} + +int ALLEGROCL::typedefHandler(Node *n) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "In typedefHandler\n"); +#endif + + SwigType *typedef_type = Getattr(n,"type"); + // has the side-effect of noting any implicit + // template instantiations in type. + String *ff_type = compose_foreign_type(n, typedef_type); + + String *sym_name = Getattr(n, "sym:name"); + + String *name; + String *type_ref; + + if (in_class) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, " typedef in class '%s'(%x)\n", Getattr(in_class, "sym:name"), in_class); +#endif + Setattr(n, "allegrocl:typedef:in-class", in_class); + + String *class_name = Getattr(in_class, "name"); + name = NewStringf("%s__%s", class_name, sym_name); + type_ref = NewStringf("%s::%s", class_name, sym_name); + Setattr(n, "allegrocl:in-class", in_class); + } else { + name = Copy(sym_name); + type_ref = Copy(Getattr(n, "name")); + } + + Setattr(n, "allegrocl:namespace", current_namespace); + + String *lookup = lookup_defined_foreign_type(typedef_type); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "** lookup='%s'(%x), typedef_type='%s', strcmp = '%d' strstr = '%d'\n", lookup, lookup, typedef_type, Strcmp(typedef_type,"void"), Strstr(ff_type,"__SWIGACL_FwdReference")); +#endif + + if(lookup || (!lookup && Strcmp(typedef_type,"void")) || + (!lookup && Strstr(ff_type,"__SWIGACL_FwdReference"))) { + add_defined_foreign_type(n, 0, type_ref, name); + } else { + add_forward_referenced_type(n); + } + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Out typedefHandler\n"); +#endif + + Delete(ff_type); + + return SWIG_OK; +} + +// forward referenced classes are added specially to defined_foreign_types +int ALLEGROCL::classforwardDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "classforwardDeclaration %s\n", Getattr(n, "name")); +#endif + + add_forward_referenced_type(n); + return SWIG_OK; +} + +int ALLEGROCL::classHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "classHandler %s::%s\n", current_namespace, Getattr(n, "sym:name")); +#endif + + int result; + + if (Generate_Wrapper) + result = cppClassHandler(n); + else + result = cClassHandler(n); + + return result; +} + +int ALLEGROCL::cClassHandler(Node *n) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "In cClassHandler\n"); +#endif + // String *cDeclName = Getattr(n,"classDeclaration:name"); + // String *name= Getattr(n, "sym:name"); + // String *kind = Getattr(n,"kind"); + // Node *c; + + /* Add this structure to the known lisp types */ + // Printf(stderr, "Adding %s foreign type\n", name); + String *ns = listify_namespace(current_namespace); + + add_defined_foreign_type(n); + + Delete(ns); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Out cClassHandler\n"); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::cppClassHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "cppClassHandler %s\n", Getattr(n, "name")); +#endif + + // String *name=Getattr(n, "sym:name"); + // String *kind = Getattr(n,"kind"); + + /* Template instantiation. + Careful. + SWIG does not create instantiations of templated classes whenever + it sees a templated class reference (say, as a return type, or + in a parameter list). + + The %template directive results in a templated class instantiation + that will actually be seen by <LANG> :: classHandler(). + + In this case, we don't want to error if the type already exists; + the point is to force the creation of wrappers for the templated + class. + */ + String *templated = Getattr(n, "template"); + String *t_name; + // String *ns = listify_namespace(current_namespace); + + if (templated) { + t_name = namespaced_name(n); + } else { + t_name = Getattr(n, "name"); + } + + Setattr(n, "allegrocl:namespace", current_namespace); + + /* Add this structure to the known lisp types. + Class may contain references to the type currently being + defined */ + if (!templated || !lookup_defined_foreign_type(t_name)) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Adding %s foreign type\n", Getattr(n, "sym:name")); +#endif + add_defined_foreign_type(n); + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "cppClassHand: type %s already exists. Assuming %%template instantiation for wrapping purposes.\n", Getattr(n, "sym:name")); +#endif + add_defined_foreign_type(n, 1); + } + + // Generate slot accessors, constructor, and destructor. + Node *prev_class = in_class; + in_class = n; + + Node *c; + // walk all member variables. +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " MANUALLY walking class members... \n"); +#endif + for (c = firstChild(n); c; c = nextSibling(c)) { + // ping the types of all children--even protected and private + // so their types can be added to the linked_type_list. + SwigType *childType = NewStringf("%s%s", Getattr(c, "decl"), + Getattr(c, "type")); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "looking at child '%x' of type '%s'\n", c, childType); +#endif + if (!SwigType_isfunction(childType)) + Delete(compose_foreign_type(n, childType)); + + Delete(childType); + } +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " MANUAL walk DONE.\n"); +#endif + + // this will walk all necessary methods. +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " LANGUAGE walk of children...\n"); +#endif + Language::classHandler(n); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " LANGUAGE walk DONE\n"); +#endif + in_class = prev_class; + + return SWIG_OK; +} + +int ALLEGROCL::emit_one(Node *n) { + // When the current package does not correspond with the current + // namespace we need to generate an IN-PACKAGE form, unless the + // current node is another namespace node. + if (Cmp(nodeType(n), "namespace") != 0 && Cmp(current_package, current_namespace) != 0) { + String *lispy_namespace = listify_namespace(current_namespace); + Printf(f_clwrap, "(swig-in-package %s)\n", lispy_namespace); + Delete(lispy_namespace); + Delete(current_package); + current_package = NewStringf("%s", current_namespace); + } + + Setattr(n, "allegrocl:package", current_package); + + return Language::emit_one(n); +} + +int ALLEGROCL::enumDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "enumDeclaration %s\n", Getattr(n, "name")); +#endif + + if (Getattr(n, "sym:name")) { + add_defined_foreign_type(n); + } + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + ALLEGROCL::enumvalueDeclaration(c); + // since we walk our own children, we need to add + // the current package ourselves. + Setattr(c, "allegrocl:package", current_package); + } + return SWIG_OK; +} + + +int ALLEGROCL::enumvalueDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "enumvalueDeclaration %s\n", Getattr(n, "name")); +#endif + /* print this when in C mode? make this a command-line arg? */ + if (Generate_Wrapper) { + SwigType *enum_type = Copy(Getattr(n,"type")); + String *mangled_name = + mangle_name(n, "ACL_ENUM", + in_class ? Getattr(in_class,"name") : + current_namespace); + + SwigType_add_qualifier(enum_type,"const"); + + String *enum_decl = SwigType_str(enum_type, mangled_name); + Printf(f_cxx_wrapper, "EXPORT %s;\n", enum_decl); + Printf(f_cxx_wrapper, "%s = %s;\n", enum_decl, Getattr(n, "value")); + + Delete(mangled_name); + Delete(enum_type); + Delete(enum_decl); + } + return SWIG_OK; +} + +int ALLEGROCL::templateDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "templateDeclaration %s\n", Getattr(n, "name")); +#endif + + String *type = Getattr(n, "templatetype"); + + // Printf(stderr, "tempDecl: %s %s\n", Getattr(n,"name"), + // type); + // Swig_print_node(n); + + if (!Strcmp(type, "cdecl")) { + SwigType *ty = NewStringf("%s%s", Getattr(n, "decl"), + Getattr(n, "type")); + Delete(ty); + } + + Delete(type); + + return SWIG_OK; +} diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx new file mode 100644 index 0000000..b52578b --- /dev/null +++ b/Source/Modules/allocate.cxx @@ -0,0 +1,955 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * 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. + * ----------------------------------------------------------------------------- */ + +char cvsroot_allocate_cxx[] = "$Id: allocate.cxx 11583 2009-08-15 23:22:20Z wsfulton $"; + +#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 (!Getattr(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 (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) + 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 *abstract = Getattr(base, "abstract"); + if (abstract) { + int dabstract = 0; + int len = Len(abstract); + for (int i = 0; i < len; i++) { + Node *nn = Getitem(abstract, i); + String *name = Getattr(nn, "name"); + if (!name) + continue; + String *base_decl = Getattr(nn, "decl"); + if (base_decl) + base_decl = SwigType_typedef_resolve_all(base_decl); + if (Strchr(name, '~')) + continue; /* Don't care about destructors */ + + 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 *nabstract = Getattr(n, "abstract"); + if (!nabstract) { + nabstract = NewList(); + Setattr(n, "abstract", nabstract); + Delete(nabstract); + } + Append(nabstract, nn); + if (!Getattr(n, "abstract:firstnode")) { + Setattr(n, "abstract: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); + String *kind = Getattr(cls, "kind"); + int mode = PUBLIC; + if (kind && (Strcmp(kind, "class") == 0)) + mode = PRIVATE; + + 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 ((!symname || (!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, "classname", 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"); + } + } + } + } + } + } + + if (Strcmp(nodeType(c), "access") == 0) { + kind = Getattr(c, "kind"); + if (Strcmp(kind, "public") == 0) + mode = PUBLIC; + else + mode = PRIVATE; + } + 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 constructued 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); + 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")); + + 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, "abstract") && 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, "abstract: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, "abstract")) { + List *abstract = NewList(); + Append(abstract, na); + Setattr(n, "abstract", abstract); + Delete(abstract); + } + } + } + } + } + + 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, "abstract")) { + 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, "abstract")) { + 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. We need to check a few things here too */ + 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 destructor was defined. We need to check a few things here too */ + 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 default destructor, 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 destructor was defined. We need to check a few things here too */ + 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 default destructor, 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((char *) "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")); + } + } + } + } + + /* Only care about default behavior. Remove temporary values */ + Setattr(n, "allocate:visit", "1"); + inclass = 0; + 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 (checkAttribute(n, "storage", "static")) { + 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 */ + Setattr(inclass, "allocate:has_assign", "1"); + Setattr(inclass, "allocate:noassign", "1"); + } else if (Strcmp(name, "operator new") == 0) { + /* Look for a private new operator */ + Setattr(inclass, "allocate:has_new", "1"); + Setattr(inclass, "allocate:nonew", "1"); + } + } else { + if (Strcmp(name, "operator =") == 0) { + Setattr(inclass, "allocate:has_assign", "1"); + } else if (Strcmp(name, "operator new") == 0) { + Setattr(inclass, "allocate:has_new", "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 = 1; + Setattr(inclass, "allocate:smartpointerconst", "1"); + } + List *methods = smart_pointer_methods(sc, 0, isconst); + Setattr(inclass, "allocate:smartpointer", methods); + Setattr(inclass, "allocate:smartpointerbase", base); + } 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((char *) "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"); + } + } + return SWIG_OK; + } +}; + +void Swig_default_allocators(Node *n) { + if (!n) + return; + Allocate *a = new Allocate; + a->top(n); + delete a; +} diff --git a/Source/Modules/browser.cxx b/Source/Modules/browser.cxx new file mode 100644 index 0000000..dd1679a --- /dev/null +++ b/Source/Modules/browser.cxx @@ -0,0 +1,413 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * browser.cxx + * + * A web-base parse tree browser using SWILL. This is an optional + * feature that's normally disabled. + * ----------------------------------------------------------------------------- */ + +char cvsroot_browser_cxx[] = "$Id: browser.cxx 10003 2007-10-17 21:42:11Z wsfulton $"; + +#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%x\"></a>[<a href=\"hide.html?node=0x%x&hn=0x%x#n%x\">-</a>] ", n, t, n, n); + } else { + Printf(out, "<a name=\"n%x\"></a>[<a href=\"show.html?node=0x%x&hn=0x%x#n%x\">+</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=0x%x\">?</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=0x%x\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj, k), k, o, trunc); + Delete(o); + } else { + Printf(os, "<a href=\"data.html?n=0x%x\">?</a> %-12s - 0x%x\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=0x%x\">%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 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=0x%x\">Top</a> ]", tree_top); + if (n != tree_top) { + Printf(f, " [ <a href=\"index.html?node=0x%x\">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=0x%x\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj, k), k, o, trunc); + Delete(o); + } else { + Printf(os, " <a href=\"data.html?n=0x%x\">?</a> %-12s - 0x%x\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=0x%x\">?</a> [%d] - \"%(escape)-0.70s%s\"\n", o, i, s, trunc); + Delete(s); + } else { + Printf(os, " <a href=\"data.html?n=0x%x\">?</a> [%d] - 0x%x\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=0x%x\">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=0x%x\">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=\"0x%x\">\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=0x%x\">%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/Source/Modules/cffi.cxx b/Source/Modules/cffi.cxx new file mode 100644 index 0000000..053bab7 --- /dev/null +++ b/Source/Modules/cffi.cxx @@ -0,0 +1,1081 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * cffi.cxx + * + * cffi language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_cffi_cxx[] = "$Id: cffi.cxx 11380 2009-07-08 12:17:45Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +//#define CFFI_DEBUG +//#define CFFI_WRAP_DEBUG + +class CFFI:public Language { +public: + String *f_cl; + String *f_clhead; + String *f_clwrap; + bool CWrap; // generate wrapper file for C code? + File *f_begin; + File *f_runtime; + File *f_cxx_header; + File *f_cxx_wrapper; + File *f_clos; + + String *module; + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + // virtual int classDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int typedefHandler(Node *n); + + //c++ specific code + virtual int constructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int classHandler(Node *n); + +private: + void emit_defun(Node *n, String *name); + void emit_defmethod(Node *n); + void emit_initialize_instance(Node *n); + void emit_getter(Node *n); + void emit_setter(Node *n); + void emit_class(Node *n); + void emit_struct_union(Node *n, bool un); + void emit_export(Node *n, String *name); + void emit_inline(Node *n, String *name); + String *lispy_name(char *name); + String *lispify_name(Node *n, String *ty, const char *flag, bool kw = false); + String *convert_literal(String *num_param, String *type, bool try_to_split = true); + String *infix_to_prefix(String *val, char split_op, const String *op, String *type); + String *strip_parens(String *string); + String *trim(String *string); + int generate_typedef_flag; + bool no_swig_lisp; +}; + +void CFFI::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGCFFI 1", 0); + SWIG_library_directory("cffi"); + SWIG_config_file("cffi.swg"); + generate_typedef_flag = 0; + no_swig_lisp = false; + CWrap = false; + for (i = 1; i < argc; i++) { + if (!Strcmp(argv[i], "-help")) { + Printf(stdout, "cffi Options (available with -cffi)\n"); + Printf(stdout, + " -generate-typedef\n" + "\tIf this option is given then defctype will be used to generate\n" + "\tshortcuts according to the typedefs in the input.\n" + " -[no]cwrap\n" + "\tTurn on or turn off generation of an intermediate C file when\n" + "\tcreating a C interface. By default this is only done for C++ code.\n" + " -[no]swig-lisp\n" + "\tTurns on or off generation of code for helper lisp macro, functions,\n" + "\tetc. which SWIG uses while generating wrappers. These macros, functions\n" "\tmay still be used by generated wrapper code.\n"); + } else if (!strcmp(argv[i], "-cwrap")) { + CWrap = true; + Swig_mark_arg(i); + } else if ((Strcmp(argv[i], "-generate-typedef") == 0)) { + generate_typedef_flag = 1; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocwrap")) { + CWrap = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-swig-lisp")) { + no_swig_lisp = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-noswig-lisp")) { + no_swig_lisp = true; + Swig_mark_arg(i); + } + + } + f_clhead = NewString(""); + f_clwrap = NewString(""); + f_cl = NewString(""); + + allow_overloading(); +} + +int CFFI::top(Node *n) { + File *f_null = NewString(""); + module = Getattr(n, "name"); + + String *cxx_filename = Getattr(n, "outfile"); + String *lisp_filename = NewString(""); + + Printf(lisp_filename, "%s%s.lisp", SWIG_output_directory(), module); + + File *f_lisp = NewFile(lisp_filename, "w", SWIG_output_files()); + if (!f_lisp) { + FileErrorDisplay(lisp_filename); + SWIG_exit(EXIT_FAILURE); + } + + if (CPlusPlus || CWrap) { + f_begin = NewFile(cxx_filename, "w", SWIG_output_files()); + if (!f_begin) { + Close(f_lisp); + Delete(f_lisp); + Printf(stderr, "Unable to open %s for writing\n", cxx_filename); + SWIG_exit(EXIT_FAILURE); + } + + String *clos_filename = NewString(""); + Printf(clos_filename, "%s%s-clos.lisp", SWIG_output_directory(), module); + f_clos = NewFile(clos_filename, "w", SWIG_output_files()); + if (!f_clos) { + Close(f_lisp); + Delete(f_lisp); + Printf(stderr, "Unable to open %s for writing\n", cxx_filename); + SWIG_exit(EXIT_FAILURE); + } + } else { + f_begin = NewString(""); + f_clos = NewString(""); + } + + f_runtime = NewString(""); + f_cxx_header = f_runtime; + f_cxx_wrapper = NewString(""); + + Swig_register_filebyname("header", f_cxx_header); + Swig_register_filebyname("wrapper", f_cxx_wrapper); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("lisphead", f_clhead); + if (!no_swig_lisp) + Swig_register_filebyname("swiglisp", f_cl); + else + Swig_register_filebyname("swiglisp", f_null); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCFFI\n"); + Printf(f_runtime, "\n"); + + Swig_banner_target_lang(f_lisp, ";;;"); + + Language::top(n); + Printf(f_lisp, "%s\n", f_clhead); + Printf(f_lisp, "%s\n", f_cl); + Printf(f_lisp, "%s\n", f_clwrap); + + Close(f_lisp); + Delete(f_lisp); // Deletes the handle, not the file + Delete(f_cl); + Delete(f_clhead); + Delete(f_clwrap); + Dump(f_runtime, f_begin); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + Delete(f_cxx_wrapper); + Delete(f_null); + + return SWIG_OK; +} + +int CFFI::classHandler(Node *n) { +#ifdef CFFI_DEBUG + Printf(stderr, "class %s::%s\n", "some namespace", //current_namespace, + Getattr(n, "sym:name")); +#endif + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + // maybe just remove this check and get rid of the else clause below. + if (Strcmp(kind, "struct") == 0) { + emit_struct_union(n, false); + return SWIG_OK; + } else if (Strcmp(kind, "union") == 0) { + emit_struct_union(n, true); + return SWIG_OK; + } else if (Strcmp(kind, "class") == 0) { + emit_class(n); + Language::classHandler(n); + } else { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + return SWIG_OK; + } + + return SWIG_OK; +} + +int CFFI::constructorHandler(Node *n) { +#ifdef CFFI_DEBUG + Printf(stderr, "constructor %s\n", Getattr(n, "name")); + Printf(stderr, "constructor %s\n and %s and %s", Getattr(n, "kind"), Getattr(n, "sym:name"), Getattr(n, "allegrocl:old-sym:name")); +#endif + Setattr(n, "cffi:constructorfunction", "1"); + // Let SWIG generate a global forwarding function. + return Language::constructorHandler(n); +} + +int CFFI::destructorHandler(Node *n) { +#ifdef CFFI_DEBUG + Printf(stderr, "destructor %s\n", Getattr(n, "name")); +#endif + + // Let SWIG generate a global forwarding function. + return Language::destructorHandler(n); +} + +void CFFI::emit_defmethod(Node *n) { + String *args_placeholder = NewStringf(""); + String *args_call = NewStringf(""); + + ParmList *pl = Getattr(n, "parms"); + int argnum = 0; + Node *parent = getCurrentClass(); + bool first = 0; + + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + String *ffitype = Swig_typemap_lookup("lispclass", p, "", 0); + + int tempargname = 0; + + if(!first) + first = true; + else + Printf(args_placeholder, " "); + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) { + argname = NewStringf("t-arg%d", argnum); + tempargname = 1; + } + if (Len(ffitype) > 0) + Printf(args_placeholder, "(%s %s)", argname, ffitype); + else + Printf(args_placeholder, "%s", argname); + + if (ffitype && Strcmp(ffitype, lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'classname")) == 0) + Printf(args_call, " (ff-pointer %s)", argname); + else + Printf(args_call, " %s", argname); + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + + String *method_name = Getattr(n, "name"); + int x = Replace(method_name, "operator ", "", DOH_REPLACE_FIRST); // + + if (x == 1) + Printf(f_clos, "(cl:shadow \"%s\")\n", method_name); + + Printf(f_clos, "(cl:defmethod %s (%s)\n (%s%s))\n\n", + lispify_name(n, lispy_name(Char(method_name)), "'method"), args_placeholder, + lispify_name(n, Getattr(n, "sym:name"), "'function"), args_call); + +} + +void CFFI::emit_initialize_instance(Node *n) { + String *args_placeholder = NewStringf(""); + String *args_call = NewStringf(""); + + ParmList *pl = Getattr(n, "parms"); + int argnum = 0; + Node *parent = getCurrentClass(); + + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + String *ffitype = Swig_typemap_lookup("lispclass", p, "", 0); + + int tempargname = 0; + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) { + argname = NewStringf("t-arg%d", argnum); + tempargname = 1; + } + if (Len(ffitype) > 0) + Printf(args_placeholder, " (%s %s)", argname, ffitype); + else + Printf(args_placeholder, " %s", argname); + + if (Strcmp(ffitype, lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'classname")) == 0) + Printf(args_call, " (ff-pointer %s)", argname); + else + Printf(args_call, " %s", argname); + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + + Printf(f_clos, "(cl:defmethod initialize-instance :after ((obj %s) &key%s)\n (setf (slot-value obj 'ff-pointer) (%s%s)))\n\n", + lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), args_placeholder, + lispify_name(n, Getattr(n, "sym:name"), "'function"), args_call); + +} + +void CFFI::emit_setter(Node *n) { + Node *parent = getCurrentClass(); + Printf(f_clos, "(cl:defmethod (cl:setf %s) (arg0 (obj %s))\n (%s (ff-pointer obj) arg0))\n\n", + lispify_name(n, Getattr(n, "name"), "'method"), + lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), lispify_name(n, Getattr(n, "sym:name"), "'function")); +} + + +void CFFI::emit_getter(Node *n) { + Node *parent = getCurrentClass(); + Printf(f_clos, "(cl:defmethod %s ((obj %s))\n (%s (ff-pointer obj)))\n\n", + lispify_name(n, Getattr(n, "name"), "'method"), + lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), lispify_name(n, Getattr(n, "sym:name"), "'function")); +} + +int CFFI::memberfunctionHandler(Node *n) { + // Let SWIG generate a global forwarding function. + Setattr(n, "cffi:memberfunction", "1"); + return Language::memberfunctionHandler(n); +} + +int CFFI::membervariableHandler(Node *n) { + // Let SWIG generate a get/set function pair. + Setattr(n, "cffi:membervariable", "1"); + return Language::membervariableHandler(n); +} + +int CFFI::functionWrapper(Node *n) { + + ParmList *parms = Getattr(n, "parms"); + String *iname = Getattr(n, "sym:name"); + Wrapper *f = NewWrapper(); + + String *raw_return_type = Swig_typemap_lookup("ctype", n, "", 0); + SwigType *return_type = Swig_cparse_type(raw_return_type); + SwigType *resolved = SwigType_typedef_resolve_all(return_type); + int is_void_return = (Cmp(resolved, "void") == 0); + Delete(resolved); + + if (!is_void_return) { + String *lresult_init = NewStringf("lresult = (%s)0", raw_return_type); + Wrapper_add_localv(f, "lresult", raw_return_type, lresult_init, NIL); + Delete(lresult_init); + } + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(parms, f); + + // Attach the standard typemaps + Swig_typemap_attach_parms("ctype", parms, f); + emit_attach_parmmaps(parms, f); + + int num_arguments = emit_num_arguments(parms); + String *name_and_parms = NewStringf("%s (", wname); + int i; + Parm *p; + int gencomma = 0; + +#ifdef CFFI_DEBUG + Printf(stderr, "function - %s - %d\n", Getattr(n, "name"), num_arguments); +#endif + + for (i = 0, p = parms; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *c_parm_type = Swig_cparse_type(Getattr(p, "tmap:ctype")); + String *arg = NewStringf("l%s", Getattr(p, "lname")); + + // Emit parameter declaration + if (gencomma) + Printf(name_and_parms, ", "); + String *parm_decl = SwigType_str(c_parm_type, arg); + Printf(name_and_parms, "%s", parm_decl); +#ifdef CFFI_DEBUG + Printf(stderr, " param: %s\n", parm_decl); +#endif + Delete(parm_decl); + gencomma = 1; + + // Emit parameter conversion code + String *parm_code = Getattr(p, "tmap:in"); + { + Replaceall(parm_code, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", parm_code); + p = Getattr(p, "tmap:in:next"); + } + + Delete(arg); + } + Printf(name_and_parms, ")"); + + // Emit the function definition + String *signature = SwigType_str(return_type, name_and_parms); + Printf(f->def, "EXPORT %s {", signature); + Printf(f->code, " try {\n"); + + String *actioncode = emit_action(n); + + String *result_convert = Swig_typemap_lookup_out("out", n, "result", f, actioncode); + Replaceall(result_convert, "$result", "lresult"); + Printf(f->code, "%s\n", result_convert); + if(!is_void_return) Printf(f->code, " return lresult;\n"); + Delete(result_convert); + emit_return_variable(n, Getattr(n, "type"), f); + + Printf(f->code, " } catch (...) {\n"); + if (!is_void_return) + Printf(f->code, " return (%s)0;\n", raw_return_type); + Printf(f->code, " }\n"); + Printf(f->code, "}\n"); + + if (CPlusPlus) + Wrapper_print(f, f_runtime); + + if (CPlusPlus) { + emit_defun(n, wname); + if (Getattr(n, "cffi:memberfunction")) + emit_defmethod(n); + else if (Getattr(n, "cffi:membervariable")) { + if (Getattr(n, "memberget")) + emit_getter(n); + else if (Getattr(n, "memberset")) + emit_setter(n); + } + else if (Getattr(n, "cffi:constructorfunction")) { + emit_initialize_instance(n); + } + } else + emit_defun(n, iname); + + // if (!overloaded || !Getattr(n, "sym:nextSibling")) { + // update_package_if_needed(n); + // emit_buffered_defuns(n); + // // this is the last overload. + // if (overloaded) { + // emit_dispatch_defun(n); + // } + // } + + Delete(wname); + DelWrapper(f); + + return SWIG_OK; +} + + +void CFFI::emit_defun(Node *n, String *name) { + + // String *storage=Getattr(n,"storage"); + // if(!storage || (Strcmp(storage,"extern") && Strcmp(storage,"externc"))) + // return SWIG_OK; + + String *func_name = Getattr(n, "sym:name"); + + ParmList *pl = Getattr(n, "parms"); + + int argnum = 0; + + func_name = lispify_name(n, func_name, "'function"); + + emit_inline(n, func_name); + + Printf(f_cl, "\n(cffi:defcfun (\"%s\" %s)", name, func_name); + String *ffitype = Swig_typemap_lookup("cout", n, ":pointer", 0); + + Printf(f_cl, " %s", ffitype); + Delete(ffitype); + + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + + if (SwigType_isvarargs(Getattr(p, "type"))) { + Printf(f_cl, "\n %s", NewString("&rest")); + continue; + } + + String *argname = Getattr(p, "name"); + + ffitype = Swig_typemap_lookup("cin", p, "", 0); + + int tempargname = 0; + if (!argname) { + + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) { + argname = NewStringf("t_arg%d", argnum); + tempargname = 1; + } + + Printf(f_cl, "\n (%s %s)", argname, ffitype); + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + Printf(f_cl, ")\n"); /* finish arg list */ + + emit_export(n, func_name); +} + + +int CFFI::constantWrapper(Node *n) { + String *type = Getattr(n, "type"); + String *converted_value = convert_literal(Getattr(n, "value"), type); + String *name = lispify_name(n, Getattr(n, "sym:name"), "'constant"); + + if (Strcmp(name, "t") == 0 || Strcmp(name, "T") == 0) + name = NewStringf("t_var"); + + Printf(f_cl, "\n(cl:defconstant %s %s)\n", name, converted_value); + Delete(converted_value); + + emit_export(n, name); + return SWIG_OK; +} + +int CFFI::variableWrapper(Node *n) { + // String *storage=Getattr(n,"storage"); + // Printf(stdout,"\"%s\" %s)\n",storage,Getattr(n, "sym:name")); + + // if(!storage || (Strcmp(storage,"extern") && Strcmp(storage,"externc"))) + // return SWIG_OK; + + String *var_name = Getattr(n, "sym:name"); + String *lisp_type = Swig_typemap_lookup("cin", n, "", 0); + String *lisp_name = lispify_name(n, var_name, "'variable"); + + if (Strcmp(lisp_name, "t") == 0 || Strcmp(lisp_name, "T") == 0) + lisp_name = NewStringf("t_var"); + + Printf(f_cl, "\n(cffi:defcvar (\"%s\" %s)\n %s)\n", var_name, lisp_name, lisp_type); + + Delete(lisp_type); + + emit_export(n, lisp_name); + return SWIG_OK; +} + +int CFFI::typedefHandler(Node *n) { + if (generate_typedef_flag && strncmp(Char(Getattr(n, "type")), "enum", 4)) { + String *lisp_name = lispify_name(n, Getattr(n, "name"), "'typename"); + Printf(f_cl, "\n(cffi:defctype %s %s)\n", lisp_name, Swig_typemap_lookup("cin", n, "", 0)); + emit_export(n, lisp_name); + } + return Language::typedefHandler(n); +} + +int CFFI::enumDeclaration(Node *n) { + String *name = Getattr(n, "sym:name"); + bool slot_name_keywords; + String *lisp_name = 0; + if (name && Len(name) != 0) { + lisp_name = lispify_name(n, name, "'enumname"); + if (GetFlag(n, "feature:bitfield")) { + Printf(f_cl, "\n(cffi:defbitfield %s", lisp_name); + } else { + Printf(f_cl, "\n(cffi:defcenum %s", lisp_name); + } + slot_name_keywords = true; + + //Registering the enum name to the cin and cout typemaps + Parm *pattern = NewParm(name, NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + //Registering with the kind, i.e., enum + pattern = NewParm(NewStringf("enum %s", name), NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + + } else { + Printf(f_cl, "\n(defanonenum %s", name); + slot_name_keywords = false; + } + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + + String *slot_name = lispify_name(c, Getattr(c, "name"), "'enumvalue", slot_name_keywords); + String *value = Getattr(c, "enumvalue"); + + if (!value || GetFlag(n, "feature:bitfield:ignore_values")) + Printf(f_cl, "\n\t%s", slot_name); + else { + String *type = Getattr(c, "type"); + String *converted_value = convert_literal(value, type); + Printf(f_cl, "\n\t(%s #.%s)", slot_name, converted_value); + Delete(converted_value); + } + Delete(value); + } + + Printf(f_cl, ")\n"); + + // No need to export keywords + if (lisp_name && Len(lisp_name) != 0) { + emit_export(n, lisp_name); + } else { + for (Node *c = firstChild(n); c; c = nextSibling(c)) + emit_export(c, lispify_name(c, Getattr(c, "name"), "'enumvalue")); + } + + return SWIG_OK; +} +void CFFI::emit_class(Node *n) { + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, "emit_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n); +#endif + + String *name = Getattr(n, "sym:name"); + String *lisp_name = lispify_name(n, lispy_name(Char(name)), "'classname"); + + String *bases = Getattr(n, "bases"); + String *supers = NewString("("); + if (bases) { + int first = 1; + for (Iterator i = First(bases); i.item; i = Next(i)) { + if (!first) + Printf(supers, " "); + String *s = Getattr(i.item, "name"); + Printf(supers, "%s", lispify_name(i.item, s, "'classname")); + } + } else { + // Printf(supers,"ff:foreign-pointer"); + } + + Printf(supers, ")"); + Printf(f_clos, "\n(cl:defclass %s%s", lisp_name, supers); + Printf(f_clos, "\n ((ff-pointer :reader ff-pointer)))\n\n"); + + Parm *pattern = NewParm(Getattr(n, "name"), NULL); + + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + SwigType_add_pointer(Getattr(pattern, "type")); + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + SwigType_add_qualifier(Getattr(pattern, "type"), "const"); + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + SwigType_del_pointer(Getattr(pattern, "type")); + SwigType_add_reference(Getattr(pattern, "type")); + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, " pattern %s name %s .. ... %s .\n", pattern, lisp_name); +#endif + + Delete(pattern); + + // Walk children to generate type definition. + String *slotdefs = NewString(" "); + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, " walking children...\n"); +#endif + + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + String *storage_type = Getattr(c, "storage"); + if ((!Strcmp(nodeType(c), "cdecl") && (!storage_type || Strcmp(storage_type, "typedef")))) { + String *access = Getattr(c, "access"); + + // hack. why would decl have a value of "variableHandler" and now "0"? + String *childDecl = Getattr(c, "decl"); + // Printf(stderr,"childDecl = '%s' (%s)\n", childDecl, Getattr(c,"view")); + if (!Strcmp(childDecl, "0")) + childDecl = NewString(""); + + SwigType *childType = NewStringf("%s%s", childDecl, + Getattr(c, "type")); + String *cname = (access && Strcmp(access, "public")) ? NewString("nil") : Copy(Getattr(c, "name")); + + if (!SwigType_isfunction(childType)) { + // Printf(slotdefs, ";;; member functions don't appear as slots.\n "); + // Printf(slotdefs, ";; "); + // String *ns = listify_namespace(Getattr(n, "cffi:package")); + String *ns = NewString(""); +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, "slot name = '%s' ns = '%s' class-of '%s' and type = '%s'\n", cname, ns, name, childType); +#endif + Printf(slotdefs, "(#.(swig-insert-id \"%s\" %s :type :slot :class \"%s\") %s)", cname, ns, name, childType); //compose_foreign_type(childType) + Delete(ns); + if (access && Strcmp(access, "public")) + Printf(slotdefs, " ;; %s member", access); + + Printf(slotdefs, "\n "); + } + Delete(childType); + Delete(cname); + } + } + + + // String *ns_list = listify_namespace(Getattr(n,"cffi:namespace")); + // update_package_if_needed(n,f_clhead); + // Printf(f_clos, + // "(swig-def-foreign-class \"%s\"\n %s\n (:%s\n%s))\n\n", + // name, supers, kind, slotdefs); + + Delete(supers); + // Delete(ns_list); + + // Parm *pattern = NewParm(name,NULL); + // Swig_typemap_register("cin",pattern,lisp_name,NULL,NULL); + //Swig_typemap_register("cout",pattern,lisp_name,NULL,NULL); + //Delete(pattern); + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, "emit_class: EXIT\n"); +#endif +} + +// Includes structs +void CFFI::emit_struct_union(Node *n, bool un = false) { +#ifdef CFFI_DEBUG + Printf(stderr, "struct/union %s\n", Getattr(n, "name")); + Printf(stderr, "struct/union %s\n and %s", Getattr(n, "kind"), Getattr(n, "sym:name")); +#endif + + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + if (Strcmp(kind, "struct") != 0 && Strcmp(kind, "union") != 0) { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + } + String *lisp_name = lispify_name(n, name, "'classname"); + + //Register the struct/union name to the cin and cout typemaps + + Parm *pattern = NewParm(name, NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + //Registering with the kind, i.e., struct or union + pattern = NewParm(NewStringf("%s %s", kind, name), NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + + if (un) { + Printf(f_cl, "\n(cffi:defcunion %s", lisp_name); + } else + Printf(f_cl, "\n(cffi:defcstruct %s", lisp_name); + + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { +#ifdef CFFI_DEBUG + Printf(stderr, "struct/union %s\n", Getattr(c, "name")); + Printf(stderr, "struct/union %s and %s \n", Getattr(c, "kind"), Getattr(c, "sym:name")); +#endif + + if (Strcmp(nodeType(c), "cdecl")) { + //C declaration ignore + // Printf(stderr, "Structure %s has a slot that we can't deal with.\n", + // name); + // Printf(stderr, "nodeType: %s, name: %s, type: %s\n", + // nodeType(c), + // Getattr(c, "name"), + // Getattr(c, "type")); + // SWIG_exit(EXIT_FAILURE); + } else { + SwigType *childType = NewStringf("%s%s", Getattr(c, "decl"), Getattr(c, "type")); + + Node *node = NewHash(); + Setattr(node, "type", childType); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("cin", node, "", 0); + + String *typespec = tm ? NewString(tm) : NewString(""); + + String *slot_name = lispify_name(c, Getattr(c, "sym:name"), "'slotname"); + if (Strcmp(slot_name, "t") == 0 || Strcmp(slot_name, "T") == 0) + slot_name = NewStringf("t_var"); + + Printf(f_cl, "\n\t(%s %s)", slot_name, typespec); + + Delete(node); + Delete(childType); + Delete(typespec); + } + } + + Printf(f_cl, ")\n"); + + emit_export(n, lisp_name); + for (Node *child = firstChild(n); child; child = nextSibling(child)) { + if (!Strcmp(nodeType(child), "cdecl")) { + emit_export(child, lispify_name(child, Getattr(child, "sym:name"), "'slotname")); + } + } + + /* Add this structure to the known lisp types */ + //Printf(stdout, "Adding %s foreign type\n", name); + // add_defined_foreign_type(name); + +} + +void CFFI::emit_export(Node *n, String *name) { + if (GetInt(n, "feature:export")) + Printf(f_cl, "\n(cl:export '%s)\n", name); +} + +void CFFI::emit_inline(Node *n, String *name) { + if (GetInt(n, "feature:inline")) + Printf(f_cl, "\n(cl:declaim (cl:inline %s))\n", name); +} + +String *CFFI::lispify_name(Node *n, String *ty, const char *flag, bool kw) { + String *intern_func = Getattr(n, "feature:intern_function"); + if (intern_func) { + if (Strcmp(intern_func, "1") == 0) + intern_func = NewStringf("swig-lispify"); + return NewStringf("#.(%s \"%s\" %s%s)", intern_func, ty, flag, kw ? " :keyword" : ""); + } else if (kw) + return NewStringf(":%s", ty); + else + return ty; +} + +/* utilities */ +/* returns new string w/ parens stripped */ +String *CFFI::strip_parens(String *string) { + char *s = Char(string), *p; + int len = Len(string); + String *res; + + if (len == 0 || s[0] != '(' || s[len - 1] != ')') { + return NewString(string); + } + + p = (char *) malloc(len - 2 + 1); + if (!p) { + Printf(stderr, "Malloc failed\n"); + SWIG_exit(EXIT_FAILURE); + } + + strncpy(p, s + 1, len - 1); + p[len - 2] = 0; /* null terminate */ + + res = NewString(p); + free(p); + + return res; +} + +String *CFFI::trim(String *str) { + char *c = Char(str); + while (*c != '\0' && isspace((int) *c)) + ++c; + String *result = NewString(c); + Chop(result); + return result; +} + +String *CFFI::infix_to_prefix(String *val, char split_op, const String *op, String *type) { + List *ored = Split(val, split_op, -1); + + // some float hackery + //i don't understand it, if you do then please explain + // if ( ((split_op == '+') || (split_op == '-')) && Len(ored) == 2 && + // (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || + // SwigType_type(type) == T_LONGDOUBLE) ) { + // // check that we're not splitting a float + // String *possible_result = convert_literal(val, type, false); + // if (possible_result) return possible_result; + + // } + + // try parsing the split results. if any part fails, kick out. + bool part_failed = false; + if (Len(ored) > 1) { + String *result = NewStringf("(%s", op); + for (Iterator i = First(ored); i.item; i = Next(i)) { + String *converted = convert_literal(i.item, type); + if (converted) { + Printf(result, " %s", converted); + Delete(converted); + } else { + part_failed = true; + break; + } + } + Printf(result, ")"); + Delete(ored); + return part_failed ? 0 : result; + } else { + Delete(ored); + } + return 0; +} + +/* To be called by code generating the lisp interface + Will return a String containing the literal based on type. + Will return null if there are problems. + + try_to_split defaults to true (see stub above). +*/ +String *CFFI::convert_literal(String *literal, String *type, bool try_to_split) { + String *num_param = Copy(literal); + String *trimmed = trim(num_param); + String *num = strip_parens(trimmed), *res = 0; + Delete(trimmed); + char *s = Char(num); + + // very basic parsing of infix expressions. + if (try_to_split) { + if ((res = infix_to_prefix(num, '|', "cl:logior", type))) + return res; + if ((res = infix_to_prefix(num, '&', "cl:logand", type))) + return res; + if ((res = infix_to_prefix(num, '^', "cl:logxor", type))) + return res; + if ((res = infix_to_prefix(num, '*', "cl:*", type))) + return res; + if ((res = infix_to_prefix(num, '/', "cl:/", type))) + return res; + if ((res = infix_to_prefix(num, '+', "cl:+", type))) + return res; + if ((res = infix_to_prefix(num, '-', "cl:-", type))) + return res; + } + + if (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE) { + // Use CL syntax for float literals + + // careful. may be a float identifier or float constant. + char *num_start = Char(num); + char *num_end = num_start + strlen(num_start) - 1; + + bool is_literal = isdigit(*num_start) || (*num_start == '.') || (*num_start == '+') || (*num_start == '-'); + + String *lisp_exp = 0; + if (is_literal) { + if (*num_end == 'f' || *num_end == 'F') { + lisp_exp = NewString("f"); + } else { + lisp_exp = NewString("d"); + } + + if (*num_end == 'l' || *num_end == 'L' || *num_end == 'f' || *num_end == 'F') { + *num_end = '\0'; + num_end--; + } + + int exponents = Replaceall(num, "e", lisp_exp) + Replaceall(num, "E", lisp_exp); + + if (!exponents) + Printf(num, "%s0", lisp_exp); + + if (exponents > 1 || (exponents + Replaceall(num, ".", ".") == 0)) { + Delete(num); + num = 0; + } + } + return num; + } else if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + String* result = NewStringf("#\\%c", s[2]); + Delete(num); + // Printf(stderr, "%s %c %d", s, s[2], s); + return result; + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + String* result = NewStringf("\"%s\"", num_param); + Delete(num); + return result; + } else if (SwigType_type(type) == T_INT || SwigType_type(type) == T_UINT) { + // Printf(stderr, "Is a T_INT or T_UINT %s, before replaceall\n", s); + Replaceall(num, "u", ""); + Replaceall(num, "U", ""); + Replaceall(num, "l", ""); + Replaceall(num, "L", ""); + + int i, j; + if (sscanf(s, "%d >> %d", &i, &j) == 2) { + String* result = NewStringf("(cl:ash %d -%d)", i, j); + Delete(num); + return result; + } else if (sscanf(s, "%d << %d", &i, &j) == 2) { + String* result = NewStringf("(cl:ash %d %d)", i, j); + Delete(num); + return result; + } + } + + if (Len(num) >= 2 && s[0] == '0') { /* octal or hex */ + if (s[1] == 'x'){ + DohReplace(num,"0","#",DOH_REPLACE_FIRST); + } + else{ + DohReplace(num,"0","#o",DOH_REPLACE_FIRST); + } + } + return num; +} + +//less flexible as it does the conversion in C, the lispify name does the conversion in lisp +String *CFFI::lispy_name(char *name) { + bool helper = false; + String *new_name = NewString(""); + for (unsigned int i = 0; i < strlen(name); i++) { + if (name[i] == '_' || name[i] == '-') { + Printf(new_name, "%c", '-'); + helper = false; + } else if (name[i] >= 'A' && name[i] <= 'Z') { + if (helper) + Printf(new_name, "%c", '-'); + Printf(new_name, "%c", ('a' + (name[i] - 'A'))); + helper = false; + } else { + helper = true; + Printf(new_name, "%c", name[i]); + } + } + return new_name; +} + +extern "C" Language *swig_cffi(void) { + return new CFFI(); +} diff --git a/Source/Modules/chicken.cxx b/Source/Modules/chicken.cxx new file mode 100644 index 0000000..3bf6602 --- /dev/null +++ b/Source/Modules/chicken.cxx @@ -0,0 +1,1552 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * chicken.cxx + * + * CHICKEN language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_chicken_cxx[] = "$Id: chicken.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +static const char *chicken_usage = (char *) "\ +\ +CHICKEN Options (available with -chicken)\n\ + -proxy - Export TinyCLOS class definitions\n\ + -closprefix <prefix> - Prepend <prefix> to all clos identifiers\n\ + -useclassprefix - Prepend the class name to all clos identifiers\n\ + -unhideprimitive - Unhide the primitive: symbols\n\ + -nounit - Do not (declare (unit ...)) in scheme file\n\ + -noclosuses - Do not (declare (uses ...)) in scheme file\n\ + -nocollection - Do not register pointers with chicken garbage\n\ + collector and export destructors\n\ +\n"; + +static char *module = 0; +static char *chicken_path = (char *) "chicken"; +static int num_methods = 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; +static String *chickentext = 0; +static String *closprefix = 0; +static String *swigtype_ptr = 0; + + +static String *f_sym_size = 0; + +/* some options */ +static int declare_unit = 1; +static int no_collection = 0; +static int clos_uses = 1; + +/* C++ Support + Clos Classes */ +static int clos = 0; +static String *c_class_name = 0; +static String *class_name = 0; +static String *short_class_name = 0; + +static int in_class = 0; +static int have_constructor = 0; +static bool exporting_destructor = false; +static bool exporting_constructor = false; +static String *constructor_name = 0; +static String *member_name = 0; + +/* sections of the .scm code */ +static String *scm_const_defs = 0; +static String *clos_class_defines = 0; +static String *clos_methods = 0; + +/* Some clos options */ +static int useclassprefix = 0; +static String *clossymnameprefix = 0; +static int hide_primitive = 1; +static Hash *primitive_names = 0; + +/* Used for overloading constructors */ +static int has_constructor_args = 0; +static List *constructor_arg_types = 0; +static String *constructor_dispatch = 0; + +static Hash *overload_parameter_lists = 0; + +class CHICKEN:public Language { +public: + + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int classHandler(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int constructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int validIdentifier(String *s); + virtual int staticmembervariableHandler(Node *n); + virtual int staticmemberfunctionHandler(Node *n); + virtual int importDirective(Node *n); + +protected: + void addMethod(String *scheme_name, String *function); + /* Return true iff T is a pointer type */ + int isPointer(SwigType *t); + void dispatchFunction(Node *n); + + String *chickenNameMapping(String *, const_String_or_char_ptr ); + String *chickenPrimitiveName(String *); + + String *runtimeCode(); + String *defaultExternalRuntimeFilename(); + String *buildClosFunctionCall(List *types, const_String_or_char_ptr closname, const_String_or_char_ptr funcname); +}; + +/* ----------------------------------------------------------------------- + * swig_chicken() - Instantiate module + * ----------------------------------------------------------------------- */ + +static Language *new_swig_chicken() { + return new CHICKEN(); +} + +extern "C" { + Language *swig_chicken(void) { + return new_swig_chicken(); + } +} + +void CHICKEN::main(int argc, char *argv[]) { + int i; + + SWIG_library_directory(chicken_path); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(chicken_usage, stdout); + SWIG_exit(0); + } else if (strcmp(argv[i], "-proxy") == 0) { + clos = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-closprefix") == 0) { + if (argv[i + 1]) { + clossymnameprefix = 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], "-unhideprimitive") == 0) { + hide_primitive = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nounit") == 0) { + declare_unit = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noclosuses") == 0) { + clos_uses = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocollection") == 0) { + no_collection = 1; + Swig_mark_arg(i); + } + } + } + + if (!clos) + hide_primitive = 0; + + // Add a symbol for this module + Preprocessor_define("SWIGCHICKEN 1", 0); + + // Set name of typemaps + + SWIG_typemap_lang("chicken"); + + // Read in default typemaps */ + SWIG_config_file("chicken.swg"); + allow_overloading(); +} + +int CHICKEN::top(Node *n) { + String *chicken_filename = NewString(""); + File *f_scm; + String *scmmodule; + + /* 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(""); + chickentext = NewString(""); + closprefix = NewString(""); + f_sym_size = NewString(""); + primitive_names = NewHash(); + overload_parameter_lists = NewHash(); + + /* 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("chicken", chickentext); + Swig_register_filebyname("closprefix", closprefix); + + clos_class_defines = NewString(""); + clos_methods = NewString(""); + scm_const_defs = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCHICKEN\n"); + + if (no_collection) + Printf(f_runtime, "#define SWIG_CHICKEN_NO_COLLECTION 1\n"); + + Printf(f_runtime, "\n"); + + /* Set module name */ + module = Swig_copy_string(Char(Getattr(n, "name"))); + scmmodule = NewString(module); + Replaceall(scmmodule, "_", "-"); + + Printf(f_header, "#define SWIG_init swig_%s_init\n", module); + Printf(f_header, "#define SWIG_name \"%s\"\n", scmmodule); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + Language::top(n); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + Printf(f_init, "C_kontinue (continuation, ret);\n"); + Printf(f_init, "}\n\n"); + + Printf(f_init, "#ifdef __cplusplus\n"); + Printf(f_init, "}\n"); + Printf(f_init, "#endif\n"); + + Printf(chicken_filename, "%s%s.scm", SWIG_output_directory(), module); + if ((f_scm = NewFile(chicken_filename, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(chicken_filename); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner_target_lang(f_scm, ";;"); + Printf(f_scm, "\n"); + + if (declare_unit) + Printv(f_scm, "(declare (unit ", scmmodule, "))\n\n", NIL); + Printv(f_scm, "(declare \n", + tab4, "(hide swig-init swig-init-return)\n", + tab4, "(foreign-declare \"C_extern void swig_", module, "_init(C_word,C_word,C_word) C_noret;\"))\n", NIL); + Printv(f_scm, "(define swig-init (##core#primitive \"swig_", module, "_init\"))\n", NIL); + Printv(f_scm, "(define swig-init-return (swig-init))\n\n", NIL); + + if (clos) { + //Printf (f_scm, "(declare (uses tinyclos))\n"); + //New chicken versions have tinyclos as an egg + Printf(f_scm, "(require-extension tinyclos)\n"); + Replaceall(closprefix, "$module", scmmodule); + Printf(f_scm, "%s\n", closprefix); + Printf(f_scm, "%s\n", clos_class_defines); + Printf(f_scm, "%s\n", clos_methods); + } else { + Printf(f_scm, "%s\n", scm_const_defs); + } + + Printf(f_scm, "%s\n", chickentext); + + + Close(f_scm); + Delete(f_scm); + + char buftmp[20]; + sprintf(buftmp, "%d", num_methods); + Replaceall(f_init, "$nummethods", buftmp); + Replaceall(f_init, "$symsize", f_sym_size); + + if (hide_primitive) + Replaceall(f_init, "$veclength", buftmp); + else + Replaceall(f_init, "$veclength", "0"); + + Delete(chicken_filename); + Delete(chickentext); + Delete(closprefix); + Delete(overload_parameter_lists); + + Delete(clos_class_defines); + Delete(clos_methods); + Delete(scm_const_defs); + + /* Close all of the files */ + Delete(primitive_names); + Delete(scmmodule); + 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_sym_size); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; +} + +int CHICKEN::functionWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + Parm *p; + int i; + String *wname; + Wrapper *f; + String *mangle = NewString(""); + String *get_pointers; + String *cleanup; + String *argout; + String *tm; + String *overname = 0; + String *declfunc = 0; + String *scmname; + bool any_specialized_arg = false; + List *function_arg_types = NewList(); + + int num_required; + int num_arguments; + int have_argout; + + Printf(mangle, "\"%s\"", SwigType_manglestr(d)); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + wname = NewString(""); + get_pointers = NewString(""); + cleanup = NewString(""); + argout = NewString(""); + declfunc = NewString(""); + scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + /* Local vars */ + Wrapper_add_local(f, "resultobj", "C_word resultobj"); + + /* 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 */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + Append(wname, Swig_name_wrapper(iname)); + if (overname) { + Append(wname, overname); + } + // Check for interrupts + Printv(f->code, "C_trace(\"", scmname, "\");\n", NIL); + + Printv(f->def, "static ", "void ", wname, " (C_word argc, C_word closure, C_word continuation", NIL); + Printv(declfunc, "void ", wname, "(C_word,C_word,C_word", NIL); + + /* Generate code for argument marshalling */ + 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"); + + Printf(f->def, ", C_word scm%d", i + 1); + Printf(declfunc, ",C_word"); + + /* Look for an input typemap */ + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + String *source = NewStringf("scm%d", i + 1); + 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 (i >= num_required) + Printf(get_pointers, "if (argc-2>%i && (%s)) {\n", i, source); + Printv(get_pointers, tm, "\n", NIL); + if (i >= num_required) + Printv(get_pointers, "}\n", NIL); + + if (clos) { + if (i < num_required) { + if (strcmp("void", Char(pt)) != 0) { + Node *class_node = 0; + String *clos_code = Getattr(p, "tmap:in:closcode"); + class_node = classLookup(pt); + if (clos_code && class_node) { + String *class_name = NewStringf("<%s>", Getattr(class_node, "sym:name")); + Replaceall(class_name, "_", "-"); + Append(function_arg_types, class_name); + Append(function_arg_types, Copy(clos_code)); + any_specialized_arg = true; + Delete(class_name); + } else { + Append(function_arg_types, "<top>"); + Append(function_arg_types, "$input"); + } + } + } + } + Delete(source); + } + + 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 */ + + Printf(f->def, ") {"); + Printf(declfunc, ")"); + + if (num_required != num_arguments) { + Append(function_arg_types, "^^##optional$$"); + } + + /* First check the number of arguments is correct */ + if (num_arguments != num_required) + Printf(f->code, "if (argc-2<%i || argc-2>%i) C_bad_argc(argc,%i);\n", num_required, num_arguments, num_required + 2); + else + Printf(f->code, "if (argc!=%i) C_bad_argc(argc,%i);\n", num_arguments + 2, num_arguments + 2); + + /* Now piece together the first part of the wrapper function */ + Printv(f->code, get_pointers, 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 ((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 */ + have_argout = 0; + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + + if (!have_argout) { + have_argout = 1; + // Print initial argument output code + Printf(argout, "SWIG_Chicken_SetupArgout\n"); + } + + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printf(argout, "%s", tm); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + Setattr(n, "wrap:name", wname); + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* Return the function value */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + + Printf(f->code, "%s", tm); + + if (have_argout) + Printf(f->code, "\nSWIG_APPEND_VALUE(resultobj);\n"); + + } 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); + + /* Insert the argumetn output code */ + Printv(f->code, argout, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + + if (have_argout) { + Printf(f->code, "C_kontinue(continuation,C_SCHEME_END_OF_LIST);\n"); + } else { + if (exporting_constructor && clos && hide_primitive) { + /* Don't return a proxy, the wrapped CLOS class is the proxy */ + Printf(f->code, "C_kontinue(continuation,resultobj);\n"); + } else { + // make the continuation the proxy creation function, if one exists + Printv(f->code, "{\n", + "C_word func;\n", + "SWIG_Chicken_FindCreateProxy(func, resultobj)\n", + "if (C_swig_is_closurep(func))\n", + " ((C_proc4)(void *)C_block_item(func, 0))(4,func,continuation,resultobj,C_SCHEME_FALSE);\n", + "else\n", " C_kontinue(continuation, resultobj);\n", "}\n", NIL); + } + } + + /* Error handling code */ +#ifdef USE_FAIL + Printf(f->code, "fail:\n"); + Printv(f->code, cleanup, NIL); + Printf(f->code, "swig_panic (\"failure in " "'$symname' SWIG function wrapper\");\n"); +#endif + 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", "resultobj"); + + /* Dump the function out */ + Printv(f_wrappers, "static ", declfunc, " C_noret;\n", NIL); + Wrapper_print(f, f_wrappers); + + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + if (exporting_destructor && !no_collection) { + Printf(f_init, "((swig_chicken_clientdata *)(SWIGTYPE%s->clientdata))->destroy = (swig_chicken_destructor) %s;\n", swigtype_ptr, wname); + } else { + addMethod(scmname, wname); + } + + /* Only export if we are not in a class, or if in a class memberfunction */ + if (!in_class || member_name) { + String *method_def; + String *clos_name; + if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + + if (!any_specialized_arg) { + method_def = NewString(""); + Printv(method_def, "(define ", clos_name, " ", chickenPrimitiveName(scmname), ")", NIL); + } else { + method_def = buildClosFunctionCall(function_arg_types, clos_name, chickenPrimitiveName(scmname)); + } + Printv(clos_methods, method_def, "\n", NIL); + Delete(clos_name); + Delete(method_def); + } + + if (have_constructor && !has_constructor_args && any_specialized_arg) { + has_constructor_args = 1; + constructor_arg_types = Copy(function_arg_types); + } + } else { + /* add function_arg_types to overload hash */ + List *flist = Getattr(overload_parameter_lists, scmname); + if (!flist) { + flist = NewList(); + Setattr(overload_parameter_lists, scmname, flist); + } + + Append(flist, Copy(function_arg_types)); + + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + + Delete(wname); + Delete(get_pointers); + Delete(cleanup); + Delete(declfunc); + Delete(mangle); + Delete(function_arg_types); + DelWrapper(f); + return SWIG_OK; +} + +int CHICKEN::variableWrapper(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + String *wname = NewString(""); + String *mangle = NewString(""); + String *tm; + String *tm2 = NewString("");; + String *argnum = NewString("0"); + String *arg = NewString("argv[0]"); + Wrapper *f; + String *overname = 0; + String *scmname; + + int num_required; + int num_arguments; + + scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + Printf(mangle, "\"%s\"", SwigType_manglestr(t)); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + // evaluation function names + Append(wname, Swig_name_wrapper(iname)); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Check for interrupts + Printv(f->code, "C_trace(\"", scmname, "\");\n", NIL); + + if (1 || (SwigType_type(t) != T_USER) || (isPointer(t))) { + + Printv(f->def, "static ", "void ", wname, "(C_word, C_word, C_word, C_word) C_noret;\n", NIL); + Printv(f->def, "static " "void ", wname, "(C_word argc, C_word closure, " "C_word continuation, C_word value) {\n", NIL); + + Wrapper_add_local(f, "resultobj", "C_word resultobj"); + + Printf(f->code, "if (argc!=2 && argc!=3) C_bad_argc(argc,2);\n"); + + /* Check for a setting of the variable value */ + if (!GetFlag(n, "feature:immutable")) { + Printf(f->code, "if (argc > 2) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "value"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "value"); + /* Printv(f->code, tm, "\n",NIL); */ + emit_action_code(n, f->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)); + } + Printf(f->code, "}\n"); + } + + String *varname; + if (SwigType_istemplate((char *) name)) { + varname = SwigType_namestr((char *) name); + } else { + varname = name; + } + + // Now return the value of the variable - regardless + // of evaluating or setting. + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", varname); + Replaceall(tm, "$varname", varname); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + /* Printf(f->code, "%s\n", tm); */ + emit_action_code(n, f->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(f->code, "{\n", + "C_word func;\n", + "SWIG_Chicken_FindCreateProxy(func, resultobj)\n", + "if (C_swig_is_closurep(func))\n", + " ((C_proc4)(void *)C_block_item(func, 0))(4,func,continuation,resultobj,C_SCHEME_FALSE);\n", + "else\n", " C_kontinue(continuation, resultobj);\n", "}\n", NIL); + + /* Error handling code */ +#ifdef USE_FAIL + Printf(f->code, "fail:\n"); + Printf(f->code, "swig_panic (\"failure in " "'%s' SWIG wrapper\");\n", proc_name); +#endif + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + /* Now register the variable with the interpreter. */ + addMethod(scmname, wname); + + if (!in_class || member_name) { + String *clos_name; + if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + + Node *class_node = classLookup(t); + String *clos_code = Getattr(n, "tmap:varin:closcode"); + if (class_node && clos_code && !GetFlag(n, "feature:immutable")) { + Replaceall(clos_code, "$input", "(car lst)"); + Printv(clos_methods, "(define (", clos_name, " . lst) (if (null? lst) (", chickenPrimitiveName(scmname), ") (", + chickenPrimitiveName(scmname), " ", clos_code, ")))\n", NIL); + } else { + /* Simply re-export the procedure */ + if (GetFlag(n, "feature:immutable") && GetFlag(n, "feature:constasvar")) { + Printv(clos_methods, "(define ", clos_name, " (", chickenPrimitiveName(scmname), "))\n", NIL); + Printv(scm_const_defs, "(set! ", scmname, " (", scmname, "))\n", NIL); + } else { + Printv(clos_methods, "(define ", clos_name, " ", chickenPrimitiveName(scmname), ")\n", NIL); + } + } + Delete(clos_name); + } + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + + Delete(wname); + Delete(argnum); + Delete(arg); + Delete(tm2); + Delete(mangle); + DelWrapper(f); + return SWIG_OK; +} + +/* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + +int CHICKEN::constantWrapper(Node *n) { + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *value = Getattr(n, "value"); + + String *proc_name = NewString(""); + String *wname = NewString(""); + String *mangle = NewString(""); + String *tm; + String *tm2 = NewString(""); + String *source = NewString(""); + String *argnum = NewString("0"); + String *arg = NewString("argv[0]"); + Wrapper *f; + String *overname = 0; + String *scmname; + String *rvalue; + SwigType *nctype; + + int num_required; + int num_arguments; + + scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + Printf(source, "swig_const_%s", iname); + Replaceall(source, "::", "__"); + + Printf(mangle, "\"%s\"", SwigType_manglestr(t)); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + Append(wname, Swig_name_wrapper(iname)); + if (overname) { + Append(wname, overname); + } + + nctype = NewString(t); + if (SwigType_isconst(nctype)) { + Delete(SwigType_pop(nctype)); + } + + if (SwigType_type(nctype) == T_STRING) { + rvalue = NewStringf("\"%s\"", value); + } else if (SwigType_type(nctype) == T_CHAR) { + rvalue = NewStringf("\'%s\'", value); + } else { + rvalue = NewString(value); + } + + /* Special hook for member pointer */ + if (SwigType_type(t) == T_MPOINTER) { + Printf(f_header, "static %s = %s;\n", SwigType_str(t, source), rvalue); + } else { + if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", rvalue); + Replaceall(tm, "$target", source); + Replaceall(tm, "$result", source); + Replaceall(tm, "$value", rvalue); + Printf(f_header, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + } + + f = NewWrapper(); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + // evaluation function names + + // Check for interrupts + Printv(f->code, "C_trace(\"", scmname, "\");\n", NIL); + + if (1 || (SwigType_type(t) != T_USER) || (isPointer(t))) { + + Setattr(n, "wrap:name", wname); + Printv(f->def, "static ", "void ", wname, "(C_word, C_word, C_word) C_noret;\n", NIL); + + Printv(f->def, "static ", "void ", wname, "(C_word argc, C_word closure, " "C_word continuation) {\n", NIL); + + Wrapper_add_local(f, "resultobj", "C_word resultobj"); + + Printf(f->code, "if (argc!=2) C_bad_argc(argc,2);\n"); + + // Return the value of the variable + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + + Replaceall(tm, "$source", source); + Replaceall(tm, "$varname", source); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + /* Printf(f->code, "%s\n", tm); */ + emit_action_code(n, f->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(f->code, "{\n", + "C_word func;\n", + "SWIG_Chicken_FindCreateProxy(func, resultobj)\n", + "if (C_swig_is_closurep(func))\n", + " ((C_proc4)(void *)C_block_item(func, 0))(4,func,continuation,resultobj,C_SCHEME_FALSE);\n", + "else\n", " C_kontinue(continuation, resultobj);\n", "}\n", NIL); + + /* Error handling code */ +#ifdef USE_FAIL + Printf(f->code, "fail:\n"); + Printf(f->code, "swig_panic (\"failure in " "'%s' SWIG wrapper\");\n", proc_name); +#endif + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + /* Now register the variable with the interpreter. */ + addMethod(scmname, wname); + + if (!in_class || member_name) { + String *clos_name; + if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + if (GetFlag(n, "feature:constasvar")) { + Printv(clos_methods, "(define ", clos_name, " (", chickenPrimitiveName(scmname), "))\n", NIL); + Printv(scm_const_defs, "(set! ", scmname, " (", scmname, "))\n", NIL); + } else { + Printv(clos_methods, "(define ", clos_name, " ", chickenPrimitiveName(scmname), ")\n", NIL); + } + Delete(clos_name); + } + + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + + Delete(wname); + Delete(nctype); + Delete(proc_name); + Delete(argnum); + Delete(arg); + Delete(tm2); + Delete(mangle); + Delete(source); + Delete(rvalue); + DelWrapper(f); + return SWIG_OK; +} + +int CHICKEN::classHandler(Node *n) { + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + constructor_dispatch = 0; + constructor_name = 0; + + c_class_name = NewString(Getattr(n, "sym:name")); + class_name = NewString(""); + short_class_name = NewString(""); + Printv(class_name, "<", c_class_name, ">", NIL); + Printv(short_class_name, c_class_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 base = First(baselist); + while (base.item) { + if (!Getattr(base.item, "feature:ignore")) + Printv(base_class, "<", Getattr(base.item, "sym:name"), "> ", NIL); + base = Next(base); + } + } + + Replaceall(base_class, "_", "-"); + + String *scmmod = NewString(module); + Replaceall(scmmod, "_", "-"); + + Printv(clos_class_defines, "(define ", class_name, "\n", " (make <swig-metaclass-", scmmod, "> 'name \"", short_class_name, "\"\n", NIL); + Delete(scmmod); + + if (Len(base_class)) { + Printv(clos_class_defines, " 'direct-supers (list ", base_class, ")\n", NIL); + } else { + Printv(clos_class_defines, " 'direct-supers (list <object>)\n", NIL); + } + + Printf(clos_class_defines, " 'direct-slots (list 'swig-this\n"); + + String *mangled_classname = Swig_name_mangle(Getattr(n, "sym:name")); + + SwigType *ct = NewStringf("p.%s", Getattr(n, "name")); + swigtype_ptr = SwigType_manglestr(ct); + + Printf(f_runtime, "static swig_chicken_clientdata _swig_chicken_clientdata%s = { 0 };\n", mangled_classname); + Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", swigtype_ptr, ", (void *) &_swig_chicken_clientdata", mangled_classname, ");\n", NIL); + SwigType_remember(ct); + + /* Emit all of the members */ + + in_class = 1; + Language::classHandler(n); + in_class = 0; + + Printf(clos_class_defines, ")))\n\n"); + + if (have_constructor) { + Printv(clos_methods, "(define-method (initialize (obj ", class_name, ") initargs)\n", " (swig-initialize obj initargs ", NIL); + if (constructor_arg_types) { + String *initfunc_name = NewStringf("%s@@SWIG@initmethod", class_name); + String *func_call = buildClosFunctionCall(constructor_arg_types, initfunc_name, chickenPrimitiveName(constructor_name)); + Printf(clos_methods, "%s)\n)\n", initfunc_name); + Printf(clos_methods, "(declare (hide %s))\n", initfunc_name); + Printf(clos_methods, "%s\n", func_call); + Delete(func_call); + Delete(initfunc_name); + Delete(constructor_arg_types); + constructor_arg_types = 0; + } else if (constructor_dispatch) { + Printf(clos_methods, "%s)\n)\n", constructor_dispatch); + Delete(constructor_dispatch); + constructor_dispatch = 0; + } else { + Printf(clos_methods, "%s)\n)\n", chickenPrimitiveName(constructor_name)); + } + Delete(constructor_name); + constructor_name = 0; + } else { + Printv(clos_methods, "(define-method (initialize (obj ", class_name, ") initargs)\n", " (swig-initialize obj initargs (lambda x #f)))\n", NIL); + } + + /* export class initialization function */ + if (clos) { + String *funcname = NewString(mangled_classname); + Printf(funcname, "_swig_chicken_setclosclass"); + String *closfuncname = NewString(funcname); + Replaceall(closfuncname, "_", "-"); + + Printv(f_wrappers, "static void ", funcname, "(C_word,C_word,C_word,C_word) C_noret;\n", + "static void ", funcname, "(C_word argc, C_word closure, C_word continuation, C_word cl) {\n", + " C_trace(\"", funcname, "\");\n", + " if (argc!=3) C_bad_argc(argc,3);\n", + " swig_chicken_clientdata *cdata = (swig_chicken_clientdata *) SWIGTYPE", swigtype_ptr, "->clientdata;\n", + " cdata->gc_proxy_create = CHICKEN_new_gc_root();\n", + " CHICKEN_gc_root_set(cdata->gc_proxy_create, cl);\n", " C_kontinue(continuation, C_SCHEME_UNDEFINED);\n", "}\n", NIL); + addMethod(closfuncname, funcname); + + Printv(clos_methods, "(", chickenPrimitiveName(closfuncname), " (lambda (x lst) (if lst ", + "(cons (make ", class_name, " 'swig-this x) lst) ", "(make ", class_name, " 'swig-this x))))\n\n", NIL); + Delete(closfuncname); + Delete(funcname); + } + + Delete(mangled_classname); + Delete(swigtype_ptr); + swigtype_ptr = 0; + + Delete(class_name); + Delete(short_class_name); + Delete(c_class_name); + class_name = 0; + short_class_name = 0; + c_class_name = 0; + + return SWIG_OK; +} + +int CHICKEN::memberfunctionHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + member_name = chickenNameMapping(proc, short_class_name); + Language::memberfunctionHandler(n); + Delete(member_name); + member_name = NULL; + Delete(proc); + + return SWIG_OK; +} + +int CHICKEN::staticmemberfunctionHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + member_name = NewStringf("%s-%s", short_class_name, proc); + Language::staticmemberfunctionHandler(n); + Delete(member_name); + member_name = NULL; + Delete(proc); + + return SWIG_OK; +} + +int CHICKEN::membervariableHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + //String *pb = SwigType_typedef_resolve_all(SwigType_base(Getattr(n, "type"))); + + Language::membervariableHandler(n); + + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + //Node *class_node = Swig_symbol_clookup(pb, Getattr(n, "sym:symtab")); + Node *class_node = classLookup(Getattr(n, "type")); + + //String *getfunc = NewStringf("%s-%s-get", short_class_name, proc); + //String *setfunc = NewStringf("%s-%s-set", short_class_name, proc); + String *getfunc = Swig_name_get(Swig_name_member(c_class_name, iname)); + Replaceall(getfunc, "_", "-"); + String *setfunc = Swig_name_set(Swig_name_member(c_class_name, iname)); + Replaceall(setfunc, "_", "-"); + + Printv(clos_class_defines, " (list '", proc, " ':swig-virtual ':swig-get ", chickenPrimitiveName(getfunc), NIL); + + if (!GetFlag(n, "feature:immutable")) { + if (class_node) { + Printv(clos_class_defines, " ':swig-set (lambda (x y) (", chickenPrimitiveName(setfunc), " x (slot-ref y 'swig-this))))\n", NIL); + } else { + Printv(clos_class_defines, " ':swig-set ", chickenPrimitiveName(setfunc), ")\n", NIL); + } + } else { + Printf(clos_class_defines, ")\n"); + } + + Delete(proc); + Delete(setfunc); + Delete(getfunc); + return SWIG_OK; +} + +int CHICKEN::staticmembervariableHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + member_name = NewStringf("%s-%s", short_class_name, proc); + Language::staticmembervariableHandler(n); + Delete(member_name); + member_name = NULL; + Delete(proc); + + return SWIG_OK; +} + +int CHICKEN::constructorHandler(Node *n) { + have_constructor = 1; + has_constructor_args = 0; + + + exporting_constructor = true; + Language::constructorHandler(n); + exporting_constructor = false; + + has_constructor_args = 1; + + String *iname = Getattr(n, "sym:name"); + constructor_name = Swig_name_construct(iname); + Replaceall(constructor_name, "_", "-"); + return SWIG_OK; +} + +int CHICKEN::destructorHandler(Node *n) { + + if (no_collection) + member_name = NewStringf("delete-%s", short_class_name); + + exporting_destructor = true; + Language::destructorHandler(n); + exporting_destructor = false; + + if (no_collection) { + Delete(member_name); + member_name = NULL; + } + + return SWIG_OK; +} + +int CHICKEN::importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname && clos_uses) { + + // 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); + + if (mod) { + String *name = Getattr(mod, "name"); + if (name) { + Printf(closprefix, "(declare (uses %s))\n", name); + } + } + } + + return Language::importDirective(n); +} + +String *CHICKEN::buildClosFunctionCall(List *types, const_String_or_char_ptr closname, const_String_or_char_ptr funcname) { + String *method_signature = NewString(""); + String *func_args = NewString(""); + String *func_call = NewString(""); + + Iterator arg_type; + int arg_count = 0; + int optional_arguments = 0; + + for (arg_type = First(types); arg_type.item; arg_type = Next(arg_type)) { + if (Strcmp(arg_type.item, "^^##optional$$") == 0) { + optional_arguments = 1; + } else { + Printf(method_signature, " (arg%i %s)", arg_count, arg_type.item); + arg_type = Next(arg_type); + if (!arg_type.item) + break; + + String *arg = NewStringf("arg%i", arg_count); + String *access_arg = Copy(arg_type.item); + + Replaceall(access_arg, "$input", arg); + Printf(func_args, " %s", access_arg); + + Delete(arg); + Delete(access_arg); + } + arg_count++; + } + + if (optional_arguments) { + Printf(func_call, "(define-method (%s %s . args) (apply %s %s args))", closname, method_signature, funcname, func_args); + } else { + Printf(func_call, "(define-method (%s %s) (%s %s))", closname, method_signature, funcname, func_args); + } + + Delete(method_signature); + Delete(func_args); + + return func_call; +} + +extern "C" { + + /* compares based on non-primitive names */ + static int compareTypeListsHelper(const DOH *a, const DOH *b, int opt_equal) { + List *la = (List *) a; + List *lb = (List *) b; + + Iterator ia = First(la); + Iterator ib = First(lb); + + while (ia.item && ib.item) { + int ret = Strcmp(ia.item, ib.item); + if (ret) + return ret; + ia = Next(Next(ia)); + ib = Next(Next(ib)); + } if (opt_equal && ia.item && Strcmp(ia.item, "^^##optional$$") == 0) + return 0; + if (ia.item) + return -1; + if (opt_equal && ib.item && Strcmp(ib.item, "^^##optional$$") == 0) + return 0; + if (ib.item) + return 1; + + return 0; + } + + static int compareTypeLists(const DOH *a, const DOH *b) { + return compareTypeListsHelper(a, b, 0); + } +} + +void CHICKEN::dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "%s (2+$numargs,closure," "continuation$commaargs);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *iname = Getattr(n, "sym:name"); + String *wname = NewString(""); + String *scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + Append(wname, Swig_name_wrapper(iname)); + + Printv(f->def, "static void real_", wname, "(C_word, C_word, C_word, C_word) C_noret;\n", NIL); + + Printv(f->def, "static void real_", wname, "(C_word oldargc, C_word closure, C_word continuation, C_word args) {", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "C_word argv[%d]", maxargs + 1); + Wrapper_add_local(f, "argv", tmp); + Wrapper_add_local(f, "ii", "int ii"); + Wrapper_add_local(f, "t", "C_word t = args"); + Printf(f->code, "if (!C_swig_is_list (args)) {\n"); + Printf(f->code, " swig_barf (SWIG_BARF1_BAD_ARGUMENT_TYPE, " "\"Argument #1 must be a list of overloaded arguments\");\n"); + Printf(f->code, "}\n"); + Printf(f->code, "argc = C_unfix (C_i_length (args));\n"); + Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++, t = C_block_item (t, 1)) {\n", maxargs); + Printf(f->code, "argv[ii] = C_block_item (t, 0);\n"); + Printf(f->code, "}\n"); + + Printv(f->code, dispatch, "\n", NIL); + Printf(f->code, "swig_barf (SWIG_BARF1_BAD_ARGUMENT_TYPE," "\"No matching function for overloaded '%s'\");\n", iname); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + addMethod(scmname, wname); + + DelWrapper(f); + f = NewWrapper(); + + /* varargs */ + Printv(f->def, "void ", wname, "(C_word, C_word, C_word, ...) C_noret;\n", NIL); + Printv(f->def, "void ", wname, "(C_word c, C_word t0, C_word t1, ...) {", NIL); + Printv(f->code, + "C_word t2;\n", + "va_list v;\n", + "C_word *a, c2 = c;\n", + "C_save_rest (t1, c2, 2);\n", "a = C_alloc((c-2)*3);\n", "t2 = C_restore_rest (a, C_rest_count (0));\n", "real_", wname, " (3, t0, t1, t2);\n", NIL); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + + /* Now deal with overloaded function when exporting clos */ + if (clos) { + List *flist = Getattr(overload_parameter_lists, scmname); + if (flist) { + Delattr(overload_parameter_lists, scmname); + + SortList(flist, compareTypeLists); + + String *clos_name; + int construct = 0; + if (have_constructor && !has_constructor_args) { + has_constructor_args = 1; + constructor_dispatch = NewStringf("%s@SWIG@new@dispatch", short_class_name); + clos_name = Copy(constructor_dispatch); + construct = 1; + Printf(clos_methods, "(declare (hide %s))\n", clos_name); + } else if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + + Iterator f; + List *prev = 0; + int all_primitive = 1; + + /* first check for duplicates and an empty call */ + String *newlist = NewList(); + for (f = First(flist); f.item; f = Next(f)) { + /* check if cur is a duplicate of prev */ + if (prev && compareTypeListsHelper(f.item, prev, 1) == 0) { + Delete(f.item); + } else { + Append(newlist, f.item); + prev = f.item; + Iterator j; + for (j = First(f.item); j.item; j = Next(j)) { + if (Strcmp(j.item, "^^##optional$$") != 0 && Strcmp(j.item, "<top>") != 0) + all_primitive = 0; + } + } + } + Delete(flist); + flist = newlist; + + if (all_primitive) { + Printf(clos_methods, "(define %s %s)\n", clos_name, chickenPrimitiveName(scmname)); + } else { + for (f = First(flist); f.item; f = Next(f)) { + /* now export clos code for argument */ + String *func_call = buildClosFunctionCall(f.item, clos_name, chickenPrimitiveName(scmname)); + Printf(clos_methods, "%s\n", func_call); + Delete(f.item); + Delete(func_call); + } + } + + Delete(clos_name); + Delete(flist); + } + } + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); +} + +int CHICKEN::isPointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); +} + +void CHICKEN::addMethod(String *scheme_name, String *function) { + String *sym = NewString(""); + if (clos) { + Append(sym, "primitive:"); + } + Append(sym, scheme_name); + + /* add symbol to Chicken internal symbol table */ + if (hide_primitive) { + Printv(f_init, "{\n", + " C_word *p0 = a;\n", " *(a++)=C_CLOSURE_TYPE|1;\n", " *(a++)=(C_word)", function, ";\n", " C_mutate(return_vec++, (C_word)p0);\n", "}\n", NIL); + } else { + Printf(f_sym_size, "+C_SIZEOF_INTERNED_SYMBOL(%d)", Len(sym)); + Printf(f_init, "sym = C_intern (&a, %d, \"%s\");\n", Len(sym), sym); + Printv(f_init, "C_mutate ((C_word*)sym+1, (*a=C_CLOSURE_TYPE|1, a[1]=(C_word)", function, ", tmp=(C_word)a, a+=2, tmp));\n", NIL); + } + + if (hide_primitive) { + Setattr(primitive_names, scheme_name, NewStringf("(vector-ref swig-init-return %i)", num_methods)); + } else { + Setattr(primitive_names, scheme_name, Copy(sym)); + } + + num_methods++; + + Delete(sym); +} + +String *CHICKEN::chickenPrimitiveName(String *name) { + String *value = Getattr(primitive_names, name); + if (value) + return value; + else { + Swig_error(input_file, line_number, "Internal Error: attempting to reference non-existant primitive name %s\n", name); + return NewString("#f"); + } +} + +int CHICKEN::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; +} + + /* ------------------------------------------------------------ + * closNameMapping() + * Maps the identifier from C++ to the CLOS 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 *CHICKEN::chickenNameMapping(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 (clossymnameprefix) { + Printf(n, "%s%s", clossymnameprefix, name); + } else { + Printf(n, "%s", name); + } + } else { + if (useclassprefix) { + Printf(n, "%s-%s", class_name, name); + } else { + if (clossymnameprefix) { + Printf(n, "%s%s", clossymnameprefix, name); + } else { + Printf(n, "%s", name); + } + } + } + return n; +} + +String *CHICKEN::runtimeCode() { + String *s = Swig_include_sys("chickenrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'chickenrun.swg'\n"); + s = NewString(""); + } + return s; +} + +String *CHICKEN::defaultExternalRuntimeFilename() { + return NewString("swigchickenrun.h"); +} diff --git a/Source/Modules/clisp.cxx b/Source/Modules/clisp.cxx new file mode 100644 index 0000000..665a8c2 --- /dev/null +++ b/Source/Modules/clisp.cxx @@ -0,0 +1,509 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * clisp.cxx + * + * clisp language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_clisp_cxx[] = "$Id: clisp.cxx 11380 2009-07-08 12:17:45Z wsfulton $"; + +#include "swigmod.h" + +class CLISP:public Language { +public: + File *f_cl; + String *module; + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int classDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int typedefHandler(Node *n); + List *entries; +private: + String *get_ffi_type(Node *n, SwigType *ty); + String *convert_literal(String *num_param, String *type); + String *strip_parens(String *string); + int extern_all_flag; + int generate_typedef_flag; + int is_function; +}; + +void CLISP::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGCLISP 1", 0); + SWIG_library_directory("clisp"); + SWIG_config_file("clisp.swg"); + generate_typedef_flag = 0; + extern_all_flag = 0; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-help")) { + Printf(stdout, "clisp Options (available with -clisp)\n"); + Printf(stdout, + " -extern-all\n" + "\t If this option is given then clisp definitions for all the functions\n" + "and global variables will be created otherwise only definitions for \n" + "externed functions and variables are created.\n" + " -generate-typedef\n" + "\t If this option is given then def-c-type will be used to generate shortcuts\n" + "according to the typedefs in the input.\n"); + } else if ((Strcmp(argv[i], "-extern-all") == 0)) { + extern_all_flag = 1; + Swig_mark_arg(i); + } else if ((Strcmp(argv[i], "-generate-typedef") == 0)) { + generate_typedef_flag = 1; + Swig_mark_arg(i); + } + } +} + +int CLISP::top(Node *n) { + + File *f_null = NewString(""); + module = Getattr(n, "name"); + String *output_filename; + entries = NewList(); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + if (!outfile) + output_filename = outfile; + else { + output_filename = NewString(""); + Printf(output_filename, "%s%s.lisp", SWIG_output_directory(), module); + } + + f_cl = NewFile(output_filename, "w+", SWIG_output_files()); + if (!f_cl) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + + Swig_register_filebyname("header", f_null); + Swig_register_filebyname("begin", f_null); + Swig_register_filebyname("runtime", f_null); + Swig_register_filebyname("wrapper", f_null); + + String *header = NewString(""); + + Swig_banner_target_lang(header, ";;"); + + Printf(header, "\n(defpackage :%s\n (:use :common-lisp :ffi)", module); + + Language::top(n); + + Iterator i; + + long len = Len(entries); + if (len > 0) { + Printf(header, "\n (:export"); + } + //else nothing to export + + for (i = First(entries); i.item; i = Next(i)) { + Printf(header, "\n\t:%s", i.item); + } + + if (len > 0) { + Printf(header, ")"); + } + + Printf(header, ")\n"); + Printf(header, "\n(in-package :%s)\n", module); + Printf(header, "\n(default-foreign-language :stdc)\n"); + + len = Tell(f_cl); + + Printf(f_cl, "%s", header); + + long end = Tell(f_cl); + + for (len--; len >= 0; len--) { + end--; + Seek(f_cl, len, SEEK_SET); + int ch = Getc(f_cl); + Seek(f_cl, end, SEEK_SET); + Putc(ch, f_cl); + } + + Seek(f_cl, 0, SEEK_SET); + Write(f_cl, Char(header), Len(header)); + + Close(f_cl); + Delete(f_cl); // Deletes the handle, not the file + + return SWIG_OK; +} + + +int CLISP::functionWrapper(Node *n) { + is_function = 1; + String *storage = Getattr(n, "storage"); + if (!extern_all_flag && (!storage || (Strcmp(storage, "extern") && Strcmp(storage, "externc")))) + return SWIG_OK; + + String *func_name = Getattr(n, "sym:name"); + + ParmList *pl = Getattr(n, "parms"); + + int argnum = 0, first = 1; + + Printf(f_cl, "\n(ffi:def-call-out %s\n\t(:name \"%s\")\n", func_name, func_name); + + Append(entries, func_name); + + if (ParmList_len(pl) != 0) { + Printf(f_cl, "\t(:arguments "); + } + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + + String *argname = Getattr(p, "name"); + // SwigType *argtype; + + String *ffitype = get_ffi_type(n, Getattr(p, "type")); + + int tempargname = 0; + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } + + if (!first) { + Printf(f_cl, "\n\t\t"); + } + Printf(f_cl, "(%s %s)", argname, ffitype); + first = 0; + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + if (ParmList_len(pl) != 0) { + Printf(f_cl, ")\n"); /* finish arg list */ + } + String *ffitype = get_ffi_type(n, Getattr(n, "type")); + if (Strcmp(ffitype, "NIL")) { //when return type is not nil + Printf(f_cl, "\t(:return-type %s)\n", ffitype); + } + Printf(f_cl, "\t(:library +library-name+))\n"); + + return SWIG_OK; +} + + +int CLISP::constantWrapper(Node *n) { + is_function = 0; + String *type = Getattr(n, "type"); + String *converted_value = convert_literal(Getattr(n, "value"), type); + String *name = Getattr(n, "sym:name"); + + Printf(f_cl, "\n(defconstant %s %s)\n", name, converted_value); + Append(entries, name); + Delete(converted_value); + + return SWIG_OK; +} + +int CLISP::variableWrapper(Node *n) { + is_function = 0; + // SwigType *type=; + String *storage = Getattr(n, "storage"); + + if (!extern_all_flag && (!storage || (Strcmp(storage, "extern") && Strcmp(storage, "externc")))) + return SWIG_OK; + + String *var_name = Getattr(n, "sym:name"); + String *lisp_type = get_ffi_type(n, Getattr(n, "type")); + Printf(f_cl, "\n(ffi:def-c-var %s\n (:name \"%s\")\n (:type %s)\n", var_name, var_name, lisp_type); + Printf(f_cl, "\t(:library +library-name+))\n"); + Append(entries, var_name); + + Delete(lisp_type); + return SWIG_OK; +} + +int CLISP::typedefHandler(Node *n) { + if (generate_typedef_flag) { + is_function = 0; + Printf(f_cl, "\n(ffi:def-c-type %s %s)\n", Getattr(n, "name"), get_ffi_type(n, Getattr(n, "type"))); + } + + return Language::typedefHandler(n); +} + +int CLISP::enumDeclaration(Node *n) { + is_function = 0; + String *name = Getattr(n, "sym:name"); + + Printf(f_cl, "\n(ffi:def-c-enum %s ", name); + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + + String *slot_name = Getattr(c, "name"); + String *value = Getattr(c, "enumvalue"); + + Printf(f_cl, "(%s %s)", slot_name, value); + + Append(entries, slot_name); + + Delete(value); + } + + Printf(f_cl, ")\n"); + return SWIG_OK; +} + + +// Includes structs +int CLISP::classDeclaration(Node *n) { + is_function = 0; + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + if (Strcmp(kind, "struct")) { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + } + + + Printf(f_cl, "\n(ffi:def-c-struct %s", name); + + Append(entries, NewStringf("make-%s", name)); + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + + if (Strcmp(nodeType(c), "cdecl")) { + Printf(stderr, "Structure %s has a slot that we can't deal with.\n", name); + Printf(stderr, "nodeType: %s, name: %s, type: %s\n", nodeType(c), Getattr(c, "name"), Getattr(c, "type")); + SWIG_exit(EXIT_FAILURE); + } + + String *temp = Copy(Getattr(c, "decl")); + Append(temp, Getattr(c, "type")); //appending type to the end, otherwise wrong type + String *lisp_type = get_ffi_type(n, temp); + Delete(temp); + + String *slot_name = Getattr(c, "sym:name"); + Printf(f_cl, "\n\t(%s %s)", slot_name, lisp_type); + + Append(entries, NewStringf("%s-%s", name, slot_name)); + + Delete(lisp_type); + } + + Printf(f_cl, ")\n"); + + /* Add this structure to the known lisp types */ + //Printf(stdout, "Adding %s foreign type\n", name); + // add_defined_foreign_type(name); + + return SWIG_OK; +} + +/* utilities */ +/* returns new string w/ parens stripped */ +String *CLISP::strip_parens(String *string) { + char *s = Char(string), *p; + int len = Len(string); + String *res; + + if (len == 0 || s[0] != '(' || s[len - 1] != ')') { + return NewString(string); + } + + p = (char *) malloc(len - 2 + 1); + if (!p) { + Printf(stderr, "Malloc failed\n"); + SWIG_exit(EXIT_FAILURE); + } + + strncpy(p, s + 1, len - 1); + p[len - 2] = 0; /* null terminate */ + + res = NewString(p); + free(p); + + return res; +} + +String *CLISP::convert_literal(String *num_param, String *type) { + String *num = strip_parens(num_param), *res; + char *s = Char(num); + + /* Make sure doubles use 'd' instead of 'e' */ + if (!Strcmp(type, "double")) { + String *updated = Copy(num); + if (Replace(updated, "e", "d", DOH_REPLACE_ANY) > 1) { + Printf(stderr, "Weird!! number %s looks invalid.\n", num); + SWIG_exit(EXIT_FAILURE); + } + Delete(num); + return updated; + } + + if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + return NewStringf("#\\%s", num_param); + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + return NewStringf("\"%s\"", num_param); + } + + if (Len(num) < 2 || s[0] != '0') { + return num; + } + + /* octal or hex */ + + res = NewStringf("#%c%s", s[1] == 'x' ? 'x' : 'o', s + 2); + Delete(num); + + return res; +} + +String *CLISP::get_ffi_type(Node *n, SwigType *ty) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("in", node, "", 0); + Delete(node); + + if (tm) { + return NewString(tm); + } else if (SwigType_ispointer(ty)) { + SwigType *cp = Copy(ty); + SwigType_del_pointer(cp); + String *inner_type = get_ffi_type(n, cp); + + if (SwigType_isfunction(cp)) { + return inner_type; + } + + SwigType *base = SwigType_base(ty); + String *base_name = SwigType_str(base, 0); + + String *str; + if (!Strcmp(base_name, "int") || !Strcmp(base_name, "float") || !Strcmp(base_name, "short") + || !Strcmp(base_name, "double") || !Strcmp(base_name, "long") || !Strcmp(base_name, "char")) { + + str = NewStringf("(ffi:c-ptr %s)", inner_type); + } else { + str = NewStringf("(ffi:c-pointer %s)", inner_type); + } + Delete(base_name); + Delete(base); + Delete(cp); + Delete(inner_type); + return str; + } else if (SwigType_isarray(ty)) { + SwigType *cp = Copy(ty); + String *array_dim = SwigType_array_getdim(ty, 0); + + if (!Strcmp(array_dim, "")) { //dimension less array convert to pointer + Delete(array_dim); + SwigType_del_array(cp); + SwigType_add_pointer(cp); + String *str = get_ffi_type(n, cp); + Delete(cp); + return str; + } else { + SwigType_pop_arrays(cp); + String *inner_type = get_ffi_type(n, cp); + Delete(cp); + + int ndim = SwigType_array_ndim(ty); + String *dimension; + if (ndim == 1) { + dimension = array_dim; + } else { + dimension = array_dim; + for (int i = 1; i < ndim; i++) { + array_dim = SwigType_array_getdim(ty, i); + Append(dimension, " "); + Append(dimension, array_dim); + Delete(array_dim); + } + String *temp = dimension; + dimension = NewStringf("(%s)", dimension); + Delete(temp); + } + String *str; + if (is_function) + str = NewStringf("(ffi:c-ptr (ffi:c-array %s %s))", inner_type, dimension); + else + str = NewStringf("(ffi:c-array %s %s)", inner_type, dimension); + + Delete(inner_type); + Delete(dimension); + return str; + } + } else if (SwigType_isfunction(ty)) { + SwigType *cp = Copy(ty); + SwigType *fn = SwigType_pop_function(cp); + String *args = NewString(""); + ParmList *pl = SwigType_function_parms(fn); + if (ParmList_len(pl) != 0) { + Printf(args, "(:arguments "); + } + int argnum = 0, first = 1; + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + SwigType *argtype = Getattr(p, "type"); + String *ffitype = get_ffi_type(n, argtype); + + int tempargname = 0; + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } + if (!first) { + Printf(args, "\n\t\t"); + } + Printf(args, "(%s %s)", argname, ffitype); + first = 0; + Delete(ffitype); + if (tempargname) + Delete(argname); + } + if (ParmList_len(pl) != 0) { + Printf(args, ")\n"); /* finish arg list */ + } + String *ffitype = get_ffi_type(n, cp); + String *str = NewStringf("(ffi:c-function %s \t\t\t\t(:return-type %s))", args, ffitype); + Delete(fn); + Delete(args); + Delete(cp); + Delete(ffitype); + return str; + } + String *str = SwigType_str(ty, 0); + if (str) { + char *st = Strstr(str, "struct"); + if (st) { + st += 7; + return NewString(st); + } + char *cl = Strstr(str, "class"); + if (cl) { + cl += 6; + return NewString(cl); + } + } + return str; +} + +extern "C" Language *swig_clisp(void) { + return new CLISP(); +} diff --git a/Source/Modules/contract.cxx b/Source/Modules/contract.cxx new file mode 100644 index 0000000..89e3150 --- /dev/null +++ b/Source/Modules/contract.cxx @@ -0,0 +1,354 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * contract.cxx + * + * Support for Wrap by Contract in SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_contract_cxx[] = "$Id: contract.cxx 11049 2009-01-10 01:15:03Z wsfulton $"; + +#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"), "result"); + 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 && !checkAttribute(n, "storage", "static"))); + 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; + InClass = 1; + CurrentClass = n; + emit_children(n); + InClass = 0; + CurrentClass = 0; + return ret; +} + +int Contracts::top(Node *n) { + emit_children(n); + return SWIG_OK; +} diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx new file mode 100644 index 0000000..5713257 --- /dev/null +++ b/Source/Modules/csharp.cxx @@ -0,0 +1,3960 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * csharp.cxx + * + * C# language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_csharp_cxx[] = "$Id: csharp.cxx 11583 2009-08-15 23:22:20Z wsfulton $"; + +#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; + 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 *module_class_code; + String *proxy_class_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 overriden by %pragma + String *module_class_modifiers; //class modifiers for module class overriden 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 + + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + int first_class_dmethod; + int curr_class_dmethod; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + + static Parm *NewParmFromNode(SwigType *type, const_String_or_char_ptr name, Node *n) { + Parm *p = NewParm(type, name); + Setfile(p, Getfile(n)); + Setline(p, Getline(n)); + return p; + } + +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), + 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), + module_class_code(NULL), + proxy_class_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), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(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 + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *directorClassName(Node *n) { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = Getattr(n, "sym:name"); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + + return dirclassname; + } + + /* ------------------------------------------------------------ + * 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]); + 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], "-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(); + } + + /* --------------------------------------------------------------------- + * 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")); + } + + 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 (!namespce) + namespce = NewString(""); + if (!dllimport) + dllimport = Copy(module_class_name); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCSHARP\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) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + Printf(f_runtime, "\n"); + + Swig_name_register((char *) "wrapper", (char *) "CSharp_%f"); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%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.swg", f_runtime); + } + // Generate the intermediary class + { + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), 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); + + addOpenNamespace(namespce, 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(namespce, f_im); + + Close(f_im); + } + + // Generate the C# module class + { + String *filen = NewStringf("%s%s.cs", 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); + + addOpenNamespace(namespce, 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(namespce, f_module); + + Close(f_module); + } + + 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"); + + Close(f_runtime_h); + Delete(f_runtime_h); + f_runtime_h = NULL; + Delete(f_directors); + f_directors = NULL; + Delete(f_directors_h); + f_directors_h = NULL; + } + + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * 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 *decl, String *overloaded_name) { + UpcallData *udata; + String *imclass_methodidx; + String *class_methodidx; + Hash *new_udata; + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, key))) { + Delete(key); + return Getattr(udata, "methodoff"); + } + + imclass_methodidx = NewStringf("%d", n_dmethods); + class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); + n_dmethods++; + + new_udata = NewHash(); + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, key, new_udata); + + Setattr(new_udata, "method", Copy(class_method)); + // TODO: remove fdesc +// Setattr(new_udata, "fdesc", Copy(class_desc)); +// Setattr(new_udata, "imclass_method", Copy(imclass_method)); +// Setattr(new_udata, "imclass_methodidx", imclass_methodidx); + 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)) + 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 { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, 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; + int num_required = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(Getattr(n, "sym:name"), n)) + return SWIG_ERROR; + } + + /* + 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")) + return SWIG_OK; + } + + Printv(imclass_class_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", overloaded_name, "\")]\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); + num_required = emit_num_required(l); + int gencomma = 0; + + // Now walk the function parameter list and generate code to get arguments + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + String *im_param_type = NewString(""); + String *c_param_type = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* Get the ctype types of the parameter */ + if ((tm = 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 ((tm = Getattr(p, "tmap:throws"))) { + canThrow(n, "throws", p); + } + } + } + + String *null_attribute = 0; + // Now write code to make the function call + if (!native_function_flag) { + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) + Swig_restore(n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + canThrow(n, "out", n); + Replaceall(tm, "$source", "result"); /* 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, "result", 0))) { + canThrow(n, "newfree", n); + Replaceall(tm, "$source", "result"); /* 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, "result", 0))) { + canThrow(n, "ret", n); + Replaceall(tm, "$source", "result"); /* 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(Swig_name_member(proxy_class_name, 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; + } + + /* ---------------------------------------------------------------------- + * 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; + + 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 + + // 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); + } 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 *filen = NewStringf("%s%s.cs", SWIG_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); + + addOpenNamespace(namespce, f_enum); + + Printv(f_enum, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + addCloseNamespace(namespce, f_enum); + + Close(f_enum); + } + } 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; + } + 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"); + 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); + + { + EnumFeature enum_feature = decodeEnumFeature(parentNode(n)); + + if ((enum_feature == ProperEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymous) C/C++ enum with a proper C# enum + // Emit the enum item. + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + 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 + const String *parent_name = Getattr(parentNode(n), "name"); + String *typemap_lookup_type = parent_name ? Copy(parent_name) : NewString("int"); + const String *tm = typemapLookup(n, "cstype", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF); + String *return_type = Copy(tm); + Delete(typemap_lookup_type); + typemap_lookup_type = NULL; + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if ((enum_feature == TypesafeEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymouse) 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 + 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); + } + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parentNode(n), "enumvalues"); + if (!enumvalues) + Setattr(parentNode(n), "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + } + + 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"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + // 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)); + } + + // Add the stripped quotes back in + String *new_value = NewString(""); + Swig_save("constantWrapper", n, "value", NIL); + 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 *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(constants_code, " %s\n", outattributes); + const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + + 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, imclass_name, Swig_name_get(symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(symname)); + } + } else + Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(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 + 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) { + String *code = Getattr(n, "code"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + Replaceall(code, "$dllimport", dllimport); + return Language::insertDirective(n); + } + + /* ----------------------------------------------------------------------------- + * 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 { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + + // 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 && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (base.item) { + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + base = Next(base); + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (derived && purebase_notderived) + pure_baseclass = empty_string; + const String *wanted_base = baseclass ? baseclass : pure_baseclass; + + if (purebase_replace) { + wanted_base = pure_baseclass; + derived = false; + Delete(baseclass); + baseclass = NULL; + if (purebase_notderived) + Swig_error(input_file, line_number, "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure C# interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE); + // Start writing the proxy class + 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(pure_interfaces)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {", 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 Dispose method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + attributes = NewHash(); + String *destruct_methodname = NULL; + String *destruct_methodmodifiers = NULL; + if (derived) { + tm = typemapLookup(n, "csdestruct_derived", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdestruct_derived:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdestruct_derived:methodmodifiers"); + } else { + tm = typemapLookup(n, "csdestruct", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdestruct:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdestruct:methodmodifiers"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(input_file, line_number, "No methodname attribute defined in csdestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(input_file, line_number, + "No methodmodifiers attribute defined in csdestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + } + } + // Emit the Finalize and Dispose methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "csfinalize", typemap_lookup_type, WARN_NONE), NIL); + } + // Dispose method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$imcall", destructor_call); + else + Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) + Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", + 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(SwigDirector%s);\n", methid, proxy_class_name, methid, overname); + } + Printf(proxy_class_code, " %s.%s_director_connect(swigCPtr", imclass_name, proxy_class_name); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + Printf(proxy_class_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, Type[] methodTypes) {\n"); + Printf(proxy_class_code, + " System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | 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(attributes); + Delete(destruct); + + // Emit extra user code + Printv(proxy_class_def, typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "\n", NIL); + + // Substitute various strings into the above template + Replaceall(proxy_class_code, "$csclassname", proxy_class_name); + Replaceall(proxy_class_def, "$csclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(imclass_cppcasts_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", proxy_class_name, "Upcast", "\")]\n", NIL); + Printf(imclass_cppcasts_code, " public static extern IntPtr $csclassnameUpcast(IntPtr objectRef);\n"); + + Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name); + + Printv(upcasts_code, + "SWIGEXPORT $cbaseclass * SWIGSTDCALL CSharp_$imclazznameUpcast", + "($cclass *objectRef) {\n", " return ($cbaseclass *)objectRef;\n" "}\n", "\n", NIL); + + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", proxy_class_name); + Replaceall(upcasts_code, "$cclass", c_classname); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + 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); + } + + String *filen = NewStringf("%s%s.cs", SWIG_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); + filen = NULL; + + // Start writing out the proxy class file + emitBanner(f_proxy); + + addOpenNamespace(namespce, f_proxy); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + destructor_call = NewString(""); + proxy_class_constants_code = NewString(""); + } + + Language::classHandler(n); + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + 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(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", imclass_name); + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + Replaceall(proxy_class_constants_code, "$dllimport", dllimport); + + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) + Printv(f_proxy, proxy_class_constants_code, NIL); + + Printf(f_proxy, "}\n"); + addCloseNamespace(namespce, f_proxy); + Close(f_proxy); + f_proxy = NULL; + + /* Output the downcast method, if necessary. Note: There's no other really + good place to put this code, since Abstract Base Classes (ABCs) can and should have + downcasts, making the constructorHandler() a bad place (because ABCs don't get to + have constructors emitted.) */ + if (GetFlag(n, "feature:javadowncast")) { + String *norm_name = SwigType_namestr(Getattr(n, "name")); + + Printf(imclass_class_code, " public final static native %s downcast%s(long cPtrBase, boolean cMemoryOwn);\n", proxy_class_name, proxy_class_name); + + Wrapper *dcast_wrap = NewWrapper(); + + Printf(dcast_wrap->def, "SWIGEXPORT jobject SWIGSTDCALL CSharp_downcast%s(JNIEnv *jenv, jclass jcls, jlong jCPtrBase, jboolean cMemoryOwn) {", + proxy_class_name); + Printf(dcast_wrap->code, " Swig::Director *director = (Swig::Director *) 0;\n"); + Printf(dcast_wrap->code, " jobject jresult = (jobject) 0;\n"); + Printf(dcast_wrap->code, " %s *obj = *((%s **)&jCPtrBase);\n", norm_name, norm_name); + Printf(dcast_wrap->code, " if (obj) director = dynamic_cast<Swig::Director *>(obj);\n"); + Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self(jenv);\n"); + Printf(dcast_wrap->code, " return jresult;\n"); + Printf(dcast_wrap->code, "}\n"); + + Wrapper_print(dcast_wrap, f_wrappers); + DelWrapper(dcast_wrap); + } + + emitDirectorExtraMethods(n); + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + Delete(proxy_class_constants_code); + proxy_class_constants_code = NULL; + } + + 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(proxy_class_name, 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(proxy_class_name, 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(""); + + 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(Swig_name_member(proxy_class_name, 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); + + Printv(imcall, 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, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // 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(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 (this.GetType() == typeof(%s)) %s; else %s", proxy_class_name, imcall, ex_imcall); + else + Printf(excode, "((this.GetType() == typeof(%s)) ? %s : %s)", proxy_class_name, imcall, ex_imcall); + + 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_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) { + 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(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 + 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, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", p); + 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(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(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(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, 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 *construct_tm = Copy(typemapLookup(n, "csconstruct", Getattr(n, "name"), + 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, imclass_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + } + 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; + int num_required = 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(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); + num_required = emit_num_required(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 { + // 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()", imclass_name, Swig_name_get(symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(Swig_name_member(proxy_class_name, symname))); + } + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t) { + Node *enum_name = NULL; + Node *n = enumLookup(t); + if (n) { + 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) + enum_name = NewStringf("%s.%s", proxyname, symname); + else + enum_name = NewStringf("%s", symname); + Delete(scopename_prefix); + } + } + + return enum_name; + } + + /* ----------------------------------------------------------------------------- + * 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)); + 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); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) { + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype); + if (enumname) + Replaceall(tm, classnamespecialvariable, enumname); + else + Replaceall(tm, classnamespecialvariable, NewStringf("int")); + } else { + String *classname = getProxyName(classnametype); + if (classname) { + Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replaceall(tm, classnamespecialvariable, descriptor); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, classnametype); + Delete(descriptor); + } + } + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) { + + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0; + arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn); + + if (setter && Cmp(arg, "self") != 0) { + // Note that in C# properties, the input variable name is always called 'value' + Delete(arg); + arg = NewString("value"); + } + + return arg; + } + + /* ----------------------------------------------------------------------------- + * 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.cs", 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); + + addOpenNamespace(namespce, 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); + + Printv(f_swigtype, swigtype, NIL); + + addCloseNamespace(namespce, f_swigtype); + + Close(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; + } + + /* ----------------------------------------------------------------------------- + * 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(String *namspace, File *file) { + if (namspace) + if (Len(namspace) > 0) + Printf(file, "namespace %s {\n", namspace); + } + + /* ----------------------------------------------------------------------------- + * addCloseNamespace() + * ----------------------------------------------------------------------------- */ + + void addCloseNamespace(String *namspace, File *file) { + if (namspace) + if (Len(namspace) > 0) + Printf(file, "\n}\n"); + } + + /*---------------------------------------------------------------------- + * 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 *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name); + String *sym_name = Getattr(n, "sym:name"); + Wrapper *code_wrap; + + Printv(imclass_class_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", swig_director_connect, "\")]\n", NIL); + Printf(imclass_class_code, " public static extern void %s(HandleRef jarg1", swig_director_connect); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, "SWIGEXPORT void SWIGSTDCALL CSharp_%s(void *objarg", swig_director_connect); + + Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + // TODO: if statement not needed?? - Java too + Printf(code_wrap->code, " if (director) {\n"); + 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, "SwigDirector_%s::SWIG_Callback%s_t callback%s", sym_name, methid, methid); + Printf(code_wrap->code, "callback%s", methid); + Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", sym_name, sym_name, methid, methid); + } + + Printf(code_wrap->def, ") {\n"); + Printf(code_wrap->code, ");\n"); + Printf(imclass_class_code, ");\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect); + } + + /* --------------------------------------------------------------- + * 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 *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *returntype = Getattr(n, "returntype"); + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *tm; + Parm *p; + int i; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(returntype, "void")); + String *qualified_return = NewString(""); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + int status = SWIG_OK; + bool output_director = true; + String *dirclassname = 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(""); + int gencomma = 0; + 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(classname, overloaded_name)); + + if (returntype) { + + qualified_return = SwigType_rcaststr(returntype, "c_result"); + + if (!is_void && !ignored_method) { + if (!SwigType_isclass(returntype)) { + if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + String *base_typename = SwigType_base(returntype); + String *resolved_typename = SwigType_typedef_resolve_all(base_typename); + Symtab *symtab = Getattr(n, "sym:symtab"); + Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + + if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default - if a C# exception occurs, then the pointer returns + something other than a NULL-initialized reference. */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= &result_default", NIL); + + Delete(non_ref_type); + } + + Delete(base_typename); + Delete(resolved_typename); + } + } else { + SwigType *vt; + + vt = cplus_value_type(returntype); + if (!vt) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); + Delete(vt); + } + } + } + + /* Create the intermediate class wrapper */ + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + tm = Swig_typemap_lookup("imtype", tp, "", 0); + if (tm) { + String *imtypeout = Getattr(tp, "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(tp, "tmap:imtype:directoroutattributes"); + if (im_directoroutattributes) { + Printf(callback_def, " %s\n", im_directoroutattributes); + Printf(director_delegate_definitions, " %s\n", im_directoroutattributes); + } + + Printf(callback_def, " private %s SwigDirector%s(", tm, overloaded_name); + if (!ignored_method) + Printf(director_delegate_definitions, " public delegate %s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(returntype, 0)); + } + + Parm *retpm = NewParmFromNode(returntype, empty_str, n); + + if ((c_ret_type = Swig_typemap_lookup("ctype", retpm, "", 0))) { + + if (!is_void && !ignored_method) { + String *jretval_decl = NewStringf("%s jresult", c_ret_type); + Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); + Delete(jretval_decl); + } + } else { + Swig_warning(WARN_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; + } + + Delete(retpm); + } + + /* Go through argument list, attach lnames for arguments */ + for (i = 0, p = l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + /* Attach the standard typemaps */ + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("ctype", l, 0); + Swig_typemap_attach_parms("imtype", l, 0); + Swig_typemap_attach_parms("cstype", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("csdirectorin", l, 0); + + /* Preamble code */ + if (!ignored_method) + Printf(w->code, "if (!swig_callback%s) {\n", overloaded_name); + + if (!pure_virtual) { + String *super_call = Swig_method_call(super, l); + if (is_void) { + Printf(w->code, "%s;\n", super_call); + if (!ignored_method) + Printf(w->code, "return;\n"); + } else { + Printf(w->code, "return %s;\n", super_call); + } + Delete(super_call); + } else { + Printf(w->code, " throw Swig::DirectorPureVirtualException(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + } + + if (!ignored_method) + Printf(w->code, "} else {\n"); + + /* Go through argument list, convert from native to Java */ + for (p = l; p; /* empty */ ) { + /* Is this superfluous? */ + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Copy(Getattr(p, "name")); + String *c_param_type = NULL; + String *c_decl = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* And add to the upcall args */ + if (gencomma > 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; + + Parm *tp = NewParmFromNode(c_param_type, empty_str, n); + String *desc_tm = NULL; + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + if (!ignored_method) + Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + + /* Add input marshalling code */ + if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (tm = Getattr(p, "tmap:directorin"))) { + + Replaceall(tm, "$input", arg); + Replaceall(tm, "$owner", "0"); + + if (Len(tm)) + if (!ignored_method) + Printf(w->code, "%s\n", tm); + + Delete(tm); + + /* Add C type to callback typedef */ + if (gencomma > 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); + + if (gencomma > 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); + 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"); + + Delete(desc_tm); + } else { + if (!desc_tm) { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } else if (!tm) { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } + + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + gencomma++; + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + } + + /* header declaration, start wrapper definition */ + String *target; + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Add any exception specifications to the methods in the director class + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* Finish 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 (!is_void) { + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + if ((tm = Swig_typemap_lookup("csdirectorout", tp, "", 0))) { + substituteClassname(returntype, tm); + Replaceall(tm, "$cscall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + Delete(tm); + Delete(tp); + } else + Printf(callback_code, " %s;\n", upcall); + + Printf(callback_code, " }\n"); + Delete(upcall); + + if (!ignored_method) { + if (!is_void) + Printf(w->code, "jresult = (%s) ", c_ret_type); + + Printf(w->code, "swig_callback%s(%s);\n", overloaded_name, jupcall_args); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("c_result"); + Parm *tp = NewParmFromNode(returntype, result_str, n); + + /* Copy jresult into c_result... */ + if ((tm = Swig_typemap_lookup("directorout", tp, result_str, w))) { + Replaceall(tm, "$input", jresult_str); + Replaceall(tm, "$result", result_str); + Printf(w->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s used in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } + + /* Terminate wrapper code */ + Printf(w->code, "}\n"); + if (!is_void) + Printf(w->code, "return %s;", qualified_return); + } + + Printf(w->code, "}"); + + // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit code */ + if (status == SWIG_OK && output_director) { + if (!is_void) { + Replaceall(w->code, "$null", qualified_return); + } else { + Replaceall(w->code, "$null", ""); + } + if (!ignored_method) + Printv(director_delegate_callback, "\n", callback_def, callback_code, NIL); + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + if (!ignored_method) { + /* Emit the actual upcall through */ + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name); + String *methid = Getattr(udata, "class_methodidx"); + + 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 Type[] swigMethodTypes%s = new Type[] { %s };\n", methid, proxy_method_types); + Printf(director_connect_parms, "SwigDirector%s%s delegate%s", classname, methid, methid); + } + + Delete(qualified_return); + Delete(c_ret_type); + Delete(declaration); + Delete(callback_typedef_parms); + Delete(delegate_parms); + Delete(proxy_method_types); + Delete(callback_def); + Delete(callback_code); + 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 *classname = 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, classname, parms, 0, 0); + String *call = Swig_csuperclass_call(0, basetype, superparms); + String *classtype = SwigType_namestr(Getattr(n, "name")); + + Printf(f_directors, "%s::%s : %s, %s {\n", classname, target, call, Getattr(parent, "director:ctor")); + Printf(f_directors, " swig_init_callbacks();\n"); + Printf(f_directors, "}\n\n"); + + Delete(classtype); + Delete(target); + Delete(call); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + Wrapper *w = NewWrapper(); + + Printf(w->def, "SwigDirector_%s::SwigDirector_%s() : %s {", classname, classname, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " SwigDirector_%s();\n", classname); + DelWrapper(w); + Delete(classtype); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + Java_director_declaration(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); + } + + /* ---------------------------------------------------------------------- + * classDirectorDestructor() + * ---------------------------------------------------------------------- */ + + int classDirectorDestructor(Node *n) { + Node *current_class = getCurrentClass(); + String *full_classname = Getattr(current_class, "name"); + String *classname = Swig_class_name(current_class); + Wrapper *w = NewWrapper(); + + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() throw () {\n", classname, classname); + } else { + Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); + } + + /* Ensure that correct directordisconnect typemap's method name is called + * here: */ + + const String *disconn_tm = NULL; + Node *disconn_attr = NewHash(); + String *disconn_methodname = NULL; + + disconn_tm = typemapLookup(n, "directordisconnect", full_classname, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); + + Printv(w->code, "}\n", NIL); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(disconn_attr); + Delete(classname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + 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("); + + Printf(w->def, "void %s::swig_connect_director(", director_classname); + + 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_callback_typedefs) > 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", 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); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + *--------------------------------------------------------------------*/ + + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * Java_director_declaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void Java_director_declaration(Node *n) { + + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director()"); + + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + 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); + } + +}; /* 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 = (char *) "\ +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\ +\n"; diff --git a/Source/Modules/directors.cxx b/Source/Modules/directors.cxx new file mode 100644 index 0000000..158b535 --- /dev/null +++ b/Source/Modules/directors.cxx @@ -0,0 +1,288 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * directors.cxx + * + * Director support functions. + * Not all of these may be necessary, and some may duplicate existing functionality + * in SWIG. --MR + * ----------------------------------------------------------------------------- */ + +char cvsroot_directors_cxx[] = "$Id"; + +#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; +} + +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 = 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; +} + + +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 + * + * Misnamed and misappropriated! Taken from SWIG's type string manipulation utilities + * and modified to generate full (or partial) type qualifiers for method declarations, + * local variable declarations, and return value casting. More importantly, it merges + * parameter type information with actual parameter names to produce a complete method + * declaration that fully mirrors the original method declaration. + * + * There is almost certainly a saner way to do this. + * + * This function needs to be cleaned up and possibly split into several smaller + * functions. For instance, attaching default names to parameters should be done in a + * separate function. + * + */ + +String *Swig_method_decl(SwigType *returntype, SwigType *decl, const_String_or_char_ptr id, List *args, int strip, int values) { + String *result; + List *elements; + String *element = 0, *nextelement; + int is_const = 0; + int nelements, i; + int is_func = 0; + int arg_idx = 0; + + if (id) { + result = NewString(Char(id)); + } else { + result = NewString(""); + } + + elements = SwigType_split(decl); + nelements = Len(elements); + if (nelements > 0) { + element = Getitem(elements, 0); + } + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i + 1); + } else { + nextelement = 0; + } + if (SwigType_isqualifier(element)) { + int skip = 0; + DOH *q = 0; + if (!strip) { + q = SwigType_parm(element); + if (!Cmp(q, "const")) { + is_const = 1; + is_func = SwigType_isfunction(nextelement); + if (is_func) + skip = 1; + skip = 1; + } + if (!skip) { + Insert(result, 0, " "); + Insert(result, 0, q); + } + Delete(q); + } + } else if (SwigType_isfunction(element)) { + Parm *parm; + String *p; + Append(result, "("); + parm = args; + while (parm != 0) { + 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); + } + if (!name) { + name = NewString(""); + } + p = SwigType_str(type, name); + Append(result, p); + String *value = Getattr(parm, "value"); + if (values && (value != 0)) { + Printf(result, " = %s", value); + } + parm = nextSibling(parm); + if (parm != 0) + Append(result, ", "); + } + Append(result, ")"); + } else if (returntype) { // This check is intended for conversion operators to a pointer/reference which needs the pointer/reference ignoring in the declaration + if (SwigType_ispointer(element)) { + Insert(result, 0, "*"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_ismemberpointer(element)) { + String *q; + q = SwigType_parm(element); + Insert(result, 0, "::*"); + Insert(result, 0, q); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + Delete(q); + } else if (SwigType_isreference(element)) { + Insert(result, 0, "&"); + } else if (SwigType_isarray(element)) { + DOH *size; + Append(result, "["); + size = SwigType_parm(element); + Append(result, size); + Append(result, "]"); + Delete(size); + } else { + if (Strcmp(element, "v(...)") == 0) { + Insert(result, 0, "..."); + } else { + String *bs = SwigType_namestr(element); + Insert(result, 0, " "); + Insert(result, 0, bs); + Delete(bs); + } + } + } + element = nextelement; + } + + Delete(elements); + + if (is_const) { + if (is_func) { + Append(result, " "); + Append(result, "const"); + } else { + Insert(result, 0, "const "); + } + } + + Chop(result); + + if (returntype) { + Insert(result, 0, " "); + String *rtype = SwigType_str(returntype, 0); + Insert(result, 0, rtype); + Delete(rtype); + } + + 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) && !(checkAttribute(n, "staticmemberfunctionHandler:storage", "static") || + checkAttribute(n, "storage", "static")) + && !Equal(nodeType(n), "constructor"))) { + Node *parent = Getattr(n, "parentNode"); + String *symname = Getattr(parent, "sym:name"); + String *dirname = NewStringf("SwigDirector_%s", symname); + String *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); + } +} + diff --git a/Source/Modules/emit.cxx b/Source/Modules/emit.cxx new file mode 100644 index 0000000..99631c1 --- /dev/null +++ b/Source/Modules/emit.cxx @@ -0,0 +1,512 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * emit.cxx + * + * Useful functions for emitting various pieces of code. + * ----------------------------------------------------------------------------- */ + +char cvsroot_emit_cxx[] = "$Id: emit.cxx 11471 2009-07-29 20:52:29Z wsfulton $"; + +#include "swigmod.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, "result"); + if (SwigType_ispointer(lt)) { + Wrapper_add_localv(f, "result", lstr, "= 0", NULL); + } else { + Wrapper_add_local(f, "result", 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; + String *tm; + while (p) { + 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"))) { + Setattr(l, "emit:varargs", lp); + break; + } + 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 function is a varargs function + * ----------------------------------------------------------------------------- */ + +int emit_isvarargs(ParmList *p) { + if (!p) + return 0; + if (Getattr(p, "emit:varargs")) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * 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, "$")) { + Replaceall(tm, "$name", Getattr(n, "name")); + Replaceall(tm, "$symname", Getattr(n, "sym:name")); + Replaceall(tm, "$function", eaction); // deprecated + Replaceall(tm, "$action", eaction); + Replaceall(tm, "$wrapname", Getattr(n, "wrap:name")); + String *overloaded = Getattr(n, "sym:overloaded"); + Replaceall(tm, "$overname", overloaded ? Char(Getattr(n, "sym:overname")) : ""); + + if (Strstr(tm, "$decl")) { + String *decl = Swig_name_decl(n); + Replaceall(tm, "$decl", decl); + Delete(decl); + } + if (Strstr(tm, "$fulldecl")) { + String *fulldecl = Swig_name_fulldecl(n); + Replaceall(tm, "$fulldecl", fulldecl); + Delete(fulldecl); + } + } + 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; + SwigType *rt; + 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); + + /* Get the return type */ + rt = Getattr(n, "type"); + + /* 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"); + } + + Printv(eaction, action, NIL); + + if (catchlist) { + int unknown_catch = 0; + Printf(eaction, "}\n"); + 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(...) {"); + } else { + Printf(eaction, "catch(%s) {", SwigType_str(et, "&_e")); + } + Printv(eaction, em, "\n", NIL); + Printf(eaction, "}\n"); + } 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) { + Printf(eaction, "catch(...) { throw; }\n"); + } + } + + /* Look for except typemap (Deprecated) */ + tm = Swig_typemap_lookup("except", n, "result", 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/Source/Modules/guile.cxx b/Source/Modules/guile.cxx new file mode 100644 index 0000000..2520a07 --- /dev/null +++ b/Source/Modules/guile.cxx @@ -0,0 +1,1759 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * guile.cxx + * + * Guile language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_guile_cxx[] = "$Id: guile.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +// Note string broken in half for compilers that can't handle long strings +static const char *guile_usage = (char *) "\ +Guile Options (available with -guile)\n\ + -prefix <name> - Use <name> as prefix [default \"gswig_\"]\n\ + -package <name> - Set the path of the module to <name>\n\ + (default NULL)\n\ + -emitsetters - Emit procedures-with-setters for variables\n\ + and structure slots.\n\ + -onlysetters - Don't emit traditional getter and setter\n\ + procedures for structure slots,\n\ + only emit procedures-with-setters.\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\ + -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\ + -scmstub - Output Scheme file with module declaration and\n\ + exports; only with `passive' and `simple' linkage\n\ + -gh - Use the gh_ Guile API. (Guile <= 1.8) \n\ + -scm - Use the scm Guile API. (Guile >= 1.6, default) \n\ + -proxy - Export GOOPS class definitions\n\ + -emitslotaccessors - Emit accessor methods for all GOOPS slots\n" "\ + -primsuffix <suffix> - Name appended to primitive module when exporting\n\ + GOOPS classes. (default = \"primitive\")\n\ + -goopsprefix <prefix> - Prepend <prefix> to all goops identifiers\n\ + -useclassprefix - Prepend the class name to all goops identifiers\n\ + -exportprimitive - Add the (export ...) code from scmstub into the\n\ + GOOPS file.\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 char *prefix = (char *) "gswig_"; +static char *module = 0; +static char *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 use_scm_interface = 1; +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") != NULL; + } +} + +class GUILE:public Language { +public: + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i, orig_len; + + 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(guile_usage, stdout); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = new char[strlen(argv[i + 1]) + 2]; + strcpy(prefix, 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 = new char[strlen(argv[i + 1]) + 2]; + strcpy(package, 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) { + use_scm_interface = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-scm") == 0) { + use_scm_interface = 1; + 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 == NULL) + 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"); + exit(1); + } + } + + 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 + + orig_len = strlen(prefix); + if (prefix[orig_len - 1] != '_') { + prefix[1 + orig_len] = 0; + prefix[orig_len] = '_'; + } + + /* Add a symbol for this module */ + Preprocessor_define("SWIGGUILE 1", 0); + /* Read in default typemaps */ + if (use_scm_interface) + SWIG_config_file("guile_scm.swg"); + else + SWIG_config_file("guile_gh.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"); + Printf(f_runtime, "#define SWIGGUILE\n"); + + if (!use_scm_interface) { + if (SwigRuntime == 1) + Printf(f_runtime, "#define SWIG_GLOBAL\n"); + if (SwigRuntime == 2) + Printf(f_runtime, "#define SWIG_NOINCLUDE\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); + Close(f_begin); + 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 == NULL) ? (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) ? 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 (use_scm_interface && 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 + if (!use_scm_interface) + Printv(f->code, tab4, "gh_defer_ints();\n", NIL); + + String *actioncode = emit_action(n); + + if (!use_scm_interface) + Printv(actioncode, tab4, "gh_allow_ints();\n", NIL); + + // Now have return value, figure out what to do with it. + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$result", "gswig_result"); + Replaceall(tm, "$target", "gswig_result"); + Replaceall(tm, "$source", "result"); + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + 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 */ + if (use_scm_interface) { + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s_rest);\n", proc_name, wname); + } else { + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s_rest, 0, 0, 1);\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 = "); + if (use_scm_interface) { + /* 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); + } else { + if (only_setters && !goops) + Printf(f_init, "scm_make_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + else + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s, %d, %d, 0);\n", proc_name, wname, numreq, numargs - numreq); + } + 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 */ + if (use_scm_interface) { + Printf(f_init, "scm_c_define"); + } else { + Printf(f_init, "gh_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 */ + if (use_scm_interface) { + Printf(f_init, "scm_c_define"); + } else { + Printf(f_init, "gh_define"); + } + Printf(f_init, "(\"%s\", getter);\n", pws_name); + } + Printf(exported_symbols, "\"%s\", ", pws_name); + free(pws_name); + } + } else { + /* Register the function */ + if (use_scm_interface) { + 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 { + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s, %d, %d, 0);\n", proc_name, wname, numreq, numargs - numreq); + } + } + } 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); + if (use_scm_interface) { + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s);\n", proc_name, dname); + } else { + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s, 0, 0, 1);\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, (char *) ""); + 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 (use_scm_interface) { + + 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 { + Printf(f_init, "\t gh_new_procedure(\"%s\", (swig_guile_proc) %s, 0, %d, 0);\n", proc_name, var_name, !GetFlag(n, "feature:immutable")); + } + } else { + /* Read/write variables become a procedure with setter. */ + if (use_scm_interface) { + 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"); + } else { + Printf(f_init, "\t{ SCM p = gh_new_procedure(\"%s\", (swig_guile_proc) %s, 0, 1, 0);\n", proc_name, var_name); + Printf(f_init, "gh_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, (char *) ""); + 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 *value = Getattr(n, "value"); + int constasvar = GetFlag(n, "feature:constasvar"); + + + String *proc_name; + String *var_name; + String *rvalue; + 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 (SwigType_type(nctype) == T_STRING) { + rvalue = NewStringf("\"%s\"", value); + } else if (SwigType_type(nctype) == T_CHAR) { + rvalue = NewStringf("\'%s\'", value); + } else { + rvalue = NewString(value); + } + + if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { + Replaceall(tm, "$source", rvalue); + Replaceall(tm, "$value", rvalue); + Replaceall(tm, "$target", name); + Printv(f_header, tm, "\n", NIL); + } else { + // Create variable and assign it a value + Printf(f_header, "static %s = %s;\n", SwigType_lstr(nctype, var_name), rvalue); + } + { + /* Hack alert: will cleanup later -- Dave */ + Node *n = NewHash(); + Setattr(n, "name", var_name); + Setattr(n, "sym:name", iname); + Setattr(n, "type", nctype); + SetFlag(n, "feature:immutable"); + if (constasvar) { + SetFlag(n, "feature:constasvar"); + } + variableWrapper(n); + Delete(n); + } + Delete(var_name); + Delete(nctype); + Delete(proc_name); + Delete(rvalue); + 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 */ + if (use_scm_interface) { + 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; + if (use_scm_interface) { + s = Swig_include_sys("guile_scm_run.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'guile_scm_run.swg"); + s = NewString(""); + } + } else { + s = Swig_include_sys("guile_gh_run.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'guile_gh_run.swg"); + s = NewString(""); + } + } + return s; + } + + String *defaultExternalRuntimeFilename() { + if (use_scm_interface) { + return NewString("swigguilerun.h"); + } else { + return NewString("swigguileghrun.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/Source/Modules/java.cxx b/Source/Modules/java.cxx new file mode 100644 index 0000000..469f899 --- /dev/null +++ b/Source/Modules/java.cxx @@ -0,0 +1,4166 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * java.cxx + * + * Java language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_java_cxx[] = "$Id: java.cxx 11584 2009-08-16 00:04:29Z wsfulton $"; + +#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 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 + + 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 *module_class_code; + String *proxy_class_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 *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 overriden by %pragma + String *module_class_modifiers; //class modifiers for module class overriden 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; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + + static Parm *NewParmFromNode(SwigType *type, const_String_or_char_ptr name, Node *n) { + Parm *p = NewParm(type, name); + Setfile(p, Getfile(n)); + Setline(p, Getline(n)); + return p; + } + +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), + imclass_name(NULL), + module_class_name(NULL), + imclass_class_code(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + module_class_code(NULL), + proxy_class_name(NULL), + variable_name(NULL), + proxy_class_constants_code(NULL), + module_class_constants_code(NULL), + package(NULL), + jnipackage(NULL), + package_path(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), + imclass_directors(NULL), + destructor_call(NULL), + destructor_throws_clause(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(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 + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /* ----------------------------------------------------------------------------- + * makeValidJniName() + * ----------------------------------------------------------------------------- */ + + String *makeValidJniName(const String *name) { + String *valid_jni_name = NewString(name); + Replaceall(valid_jni_name, "_", "_1"); + return valid_jni_name; + } + + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *directorClassName(Node *n) { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = Getattr(n, "sym:name"); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + + return dirclassname; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("java"); + + // 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]); + 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], "-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); + } + } + } + + // 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(); + } + + /* --------------------------------------------------------------------- + * 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")); + } + + 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(""); + imclass_directors = NewString(""); + upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + if (!package) + package = NewString(""); + jnipackage = NewString(""); + package_path = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n#define SWIGJAVA\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) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + Printf(f_runtime, "\n"); + + String *wrapper_name = NewString(""); + + if (Len(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", Char(jnipackage), jniname); + Delete(jniname); + + Swig_name_register((char *) "wrapper", Char(wrapper_name)); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%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.swg", f_runtime); + } + // Generate the intermediary class + { + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), 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 (Len(package) > 0) + 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"); + Close(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 (Len(package) > 0) + Printf(f_module, "package %s;\n", package); + + 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, "extends %s ", module_baseclass); + if (Len(module_interfaces) > 0) { + if (Len(module_class_constants_code) != 0) + Printv(f_module, "implements ", Getattr(n, "name"), "Constants, ", module_interfaces, " ", NIL); + else + Printv(f_module, "implements ", module_interfaces, " ", NIL); + } else { + if (Len(module_class_constants_code) != 0) + Printv(f_module, "implements ", Getattr(n, "name"), "Constants ", 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"); + Close(f_module); + } + + // Generate the Java constants interface + if (Len(module_class_constants_code) != 0) { + String *filen = NewStringf("%s%sConstants.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 Java constants interface file + emitBanner(f_module); + + if (Len(package) > 0) + Printf(f_module, "package %s;\n", package); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + Printf(f_module, "public interface %sConstants {\n", module_class_name); + + // Write out all the global constants + Printv(f_module, module_class_constants_code, NIL); + + // Finish off the Java interface + Printf(f_module, "}\n"); + Close(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_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(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"); + + Close(f_runtime_h); + Delete(f_runtime_h); + f_runtime_h = NULL; + Delete(f_directors); + f_directors = NULL; + Delete(f_directors_h); + f_directors_h = NULL; + } + + Dump(f_wrappers, f_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); + Close(f_begin); + 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) { + UpcallData *udata; + String *imclass_methodidx; + String *class_methodidx; + Hash *new_udata; + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, key))) { + Delete(key); + return Getattr(udata, "methodoff"); + } + + imclass_methodidx = NewStringf("%d", n_dmethods); + class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); + n_dmethods++; + + new_udata = NewHash(); + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, key, new_udata); + + Setattr(new_udata, "method", Copy(class_method)); + Setattr(new_udata, "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)) + 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 { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, 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 num_required = 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(Getattr(n, "sym:name"), n)) + 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")) + return SWIG_OK; + } + + Printf(imclass_class_code, " public final static native %s %s(", im_return_type, overloaded_name); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(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 ((tm = Getattr(p, "tmap:throws"))) { + addThrows(n, "tmap:throws", p); + } + } + } + + if (!native_function_flag) { + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + // Now write code to make the function call + 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); + + if (Cmp(nodeType(n), "constant") == 0) + Swig_restore(n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + addThrows(n, "tmap:out", n); + Replaceall(tm, "$source", "result"); /* 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, "result", 0))) { + addThrows(n, "tmap:newfree", n); + Replaceall(tm, "$source", "result"); /* 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, "result", 0))) { + addThrows(n, "tmap:ret", n); + Replaceall(tm, "$source", "result"); /* 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(Swig_name_member(proxy_class_name, 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; + } + + /* ---------------------------------------------------------------------- + * 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; + + 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 + + // 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 ", ""); + } 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 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"); + + Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL); + } else { + // Global enums are defined in their own file + String *filen = NewStringf("%s%s.java", SWIG_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 (Len(package) > 0) + Printf(f_enum, "package %s;\n", package); + + Printv(f_enum, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + Printf(f_enum, "\n"); + Close(f_enum); + } + } 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; + } + 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"); + 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); + + { + EnumFeature enum_feature = decodeEnumFeature(parentNode(n)); + + if ((enum_feature == ProperEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymous) C/C++ enum with a proper Java enum + // Emit the enum item. + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + 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 + const String *parent_name = Getattr(parentNode(n), "name"); + String *typemap_lookup_type = parent_name ? Copy(parent_name) : NewString("int"); + const String *tm = typemapLookup(n, "jstype", typemap_lookup_type, WARN_JAVA_TYPEMAP_JSTYPE_UNDEF); + String *return_type = Copy(tm); + Delete(typemap_lookup_type); + typemap_lookup_type = NULL; + + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if ((enum_feature == TypesafeEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymouse) 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); + } + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parentNode(n), "enumvalues"); + if (!enumvalues) + Setattr(parentNode(n), "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + } + + 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"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + // 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(""); + Swig_save("constantWrapper", n, "value", NIL); + 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 *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + 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, imclass_name, Swig_name_get(symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(symname)); + } + } else + Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(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 + 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) { + String *code = Getattr(n, "code"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + return Language::insertDirective(n); + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * jniclassbase - base (extends) for 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, "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) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use the moduleimports pragma.\n", input_file, line_number); + } else if (Strcmp(code, "moduleinterface") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use the moduleinterfaces pragma.\n", input_file, line_number); + } else if (Strcmp(code, "modulemethodmodifiers") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%javamethodmodifiers.\n", input_file, line_number); + } else if (Strcmp(code, "allshadowimport") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaimports).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowcode") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javacode).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowbase") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javabase).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowinterface") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javainterfaces).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowclassmodifiers") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n", input_file, line_number); + } else if (proxy_flag) { + if (Strcmp(code, "shadowcode") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javacode).\n", input_file, line_number); + } else if (Strcmp(code, "shadowimport") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaimports).\n", input_file, line_number); + } else if (Strcmp(code, "shadowbase") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javabase).\n", input_file, line_number); + } else if (Strcmp(code, "shadowinterface") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javainterfaces).\n", input_file, line_number); + } else if (Strcmp(code, "shadowclassmodifiers") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n", input_file, line_number); + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + + // 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 && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (base.item) { + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + base = Next(base); + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (derived && purebase_notderived) + pure_baseclass = empty_string; + const String *wanted_base = baseclass ? baseclass : pure_baseclass; + + if (purebase_replace) { + wanted_base = pure_baseclass; + derived = false; + Delete(baseclass); + baseclass = NULL; + if (purebase_notderived) + Swig_error(input_file, line_number, "The javabase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure Java interfaces + const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", 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(pure_interfaces) ? // Pure Java interfaces + " implements " : "", pure_interfaces, " {", 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(); + String *destruct_methodname = NULL; + String *destruct_methodmodifiers = 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"); + } 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"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(input_file, line_number, + "No methodname attribute defined in javadestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(input_file, line_number, + "No methodmodifiers attribute defined in javadestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + } + } + // 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 ", destruct_methodmodifiers, " void ", destruct_methodname, "()", destructor_throws_clause, " ", destruct, "\n", 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; + + destruct_jnicall = NewStringf("%s()", destruct_methodname); + release_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, false)", imclass_name, proxy_class_name); + take_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, true)", imclass_name, proxy_class_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(release_jnicall); + Delete(take_jnicall); + } + + 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); + + // Substitute various strings into the above template + Replaceall(proxy_class_code, "$javaclassname", proxy_class_name); + Replaceall(proxy_class_def, "$javaclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(imclass_cppcasts_code, " public final static native long SWIG$javaclassnameUpcast(long jarg1);\n", NIL); + + Replaceall(imclass_cppcasts_code, "$javaclassname", proxy_class_name); + + Printv(upcasts_code, + "SWIGEXPORT jlong JNICALL Java_$jnipackage$imimclass_SWIG$imclazznameUpcast", + "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n", + " jlong baseptr = 0;\n" + " (void)jenv;\n" " (void)jcls;\n" " *($cbaseclass **)&baseptr = *($cclass **)&jarg1;\n" " return baseptr;\n" "}\n", "\n", NIL); + + String *imimclass = makeValidJniName(imclass_name); + String *imclazzname = makeValidJniName(proxy_class_name); + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", imclazzname); + Replaceall(upcasts_code, "$cclass", c_classname); + Replaceall(upcasts_code, "$jnipackage", jnipackage); + Replaceall(upcasts_code, "$imimclass", imimclass); + + Delete(imclazzname); + Delete(imimclass); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + 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); + } + + String *filen = NewStringf("%s%s.java", SWIG_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); + filen = NULL; + + // Start writing out the proxy class file + emitBanner(f_proxy); + + if (Len(package) > 0) + Printf(f_proxy, "package %s;\n", package); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + destructor_call = NewString(""); + destructor_throws_clause = NewString(""); + proxy_class_constants_code = NewString(""); + } + + Language::classHandler(n); + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + 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(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", imclass_name); + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) + Printv(f_proxy, proxy_class_constants_code, NIL); + + Printf(f_proxy, "}\n"); + Close(f_proxy); + f_proxy = NULL; + + /* Output the downcast method, if necessary. Note: There's no other really + good place to put this code, since Abstract Base Classes (ABCs) can and should have + downcasts, making the constructorHandler() a bad place (because ABCs don't get to + have constructors emitted.) */ + if (GetFlag(n, "feature:javadowncast")) { + String *jni_imclass_name = makeValidJniName(imclass_name); + String *jni_class_name = makeValidJniName(proxy_class_name); + String *norm_name = SwigType_namestr(Getattr(n, "name")); + + Printf(imclass_class_code, " public final static native %s downcast%s(long cPtrBase, boolean cMemoryOwn);\n", proxy_class_name, proxy_class_name); + + Wrapper *dcast_wrap = NewWrapper(); + + Printf(dcast_wrap->def, "SWIGEXPORT jobject JNICALL Java_%s%s_downcast%s(JNIEnv *jenv, jclass jcls, jlong jCPtrBase, jboolean cMemoryOwn) {", + jnipackage, jni_imclass_name, jni_class_name); + Printf(dcast_wrap->code, " Swig::Director *director = (Swig::Director *) 0;\n"); + Printf(dcast_wrap->code, " jobject jresult = (jobject) 0;\n"); + Printf(dcast_wrap->code, " %s *obj = *((%s **)&jCPtrBase);\n", norm_name, norm_name); + Printf(dcast_wrap->code, " if (obj) director = dynamic_cast<Swig::Director *>(obj);\n"); + Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self(jenv);\n"); + Printf(dcast_wrap->code, " return jresult;\n"); + Printf(dcast_wrap->code, "}\n"); + + Wrapper_print(dcast_wrap, f_wrappers); + DelWrapper(dcast_wrap); + } + + emitDirectorExtraMethods(n); + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + Delete(destructor_throws_clause); + destructor_throws_clause = NULL; + Delete(proxy_class_constants_code); + proxy_class_constants_code = NULL; + } + + 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(proxy_class_name, 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(proxy_class_name, 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(""); + + 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(Swig_name_member(proxy_class_name, variable_name))) == 0); + } + + /* 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); + + Printv(imcall, imclass_name, ".$imfuncname(", NIL); + if (!static_flag) { + Printf(imcall, "swigCPtr"); + + String *this_type = Copy(getClassType()); + String *name = NewString("self"); + String *qualifier = Getattr(n, "qualifier"); + if (qualifier) + SwigType_push(this_type, qualifier); + SwigType_add_pointer(this_type); + Parm *this_parm = NewParm(this_type, name); + 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, ", "); + 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); + } + } + + 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(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 (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)); + } + + generateThrowsClause(n, function_code); + 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(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(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); + + 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, 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 *construct_tm = Copy(typemapLookup(n, "javaconstruct", Getattr(n, "name"), + 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, imclass_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + generateThrowsClause(n, destructor_throws_clause); + } + 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; + int num_required = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_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("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(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); + num_required = emit_num_required(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 ? (const String *) 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 { + // 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()", imclass_name, Swig_name_get(symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(Swig_name_member(proxy_class_name, symname))); + } + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * + * If jnidescriptor is set, inner class names are separated with '$' otherwise a '.' + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t, bool jnidescriptor) { + Node *enum_name = NULL; + Node *n = enumLookup(t); + if (n) { + 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) { + const char *class_separator = jnidescriptor ? "$" : "."; + enum_name = NewStringf("%s%s%s", proxyname, class_separator, symname); + } else { + enum_name = NewStringf("%s", symname); + } + Delete(scopename_prefix); + } + } + + return enum_name; + } + + /* ----------------------------------------------------------------------------- + * 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. + * 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 '.' + * 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)); + 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); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable, bool jnidescriptor) { + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype, jnidescriptor); + if (enumname) + Replaceall(tm, classnamespecialvariable, enumname); + else + Replaceall(tm, classnamespecialvariable, NewStringf("int")); + } else { + String *classname = getProxyName(classnametype); + if (classname) { + Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replaceall(tm, classnamespecialvariable, descriptor); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, classnametype); + Delete(descriptor); + } + } + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) { + + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0; + arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn); + + if (setter && Cmp(arg, "self") != 0) { + // Note that for setters the parameter name is always set but sometimes includes C++ + // scope resolution, so we need to strip off the scope resolution to make a valid name. + Delete(arg); + arg = NewString("value"); //Swig_scopename_last(pn); + } + + return arg; + } + + /* ----------------------------------------------------------------------------- + * 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 (Len(package) > 0) + 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); + Printv(f_swigtype, swigtype, NIL); + + Close(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 *proxyClassName = 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) { + Node *n = classLookup(t); + if (n) { + // Found a struct/class parameter passed by value, reference, pointer, or pointer reference + proxyClassName = Getattr(n, "sym:name"); + } else { + // 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) { + proxyClassName = symname; + } + } + } + } + } + Delete(jstype); + } + } + } + } + Delete(jtype); + return proxyClassName; + } + + /*---------------------------------------------------------------------- + * 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, " static jclass jclass_%s = NULL;\n", imclass_name); + Printf(f_runtime, " static jmethodID director_methids[%d];\n", n_methods); + 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_methids[i] = jenv->GetStaticMethodID(jcls, methods[i].method, methods[i].signature);\n"); + Printf(w->code, " if (!Swig::director_methids[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 $javaclassname_director_connect 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 = NewStringf("%s_director_connect", proxy_class_name); + String *swig_director_connect_jni = makeValidJniName(swig_director_connect); + String *sym_name = Getattr(n, "sym:name"); + 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, 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); + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself), " + "(jswig_mem_own == JNI_TRUE), (jweak_global == JNI_TRUE));\n"); + Printf(code_wrap->code, " }\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 = NewStringf("%s_change_ownership", proxy_class_name); + 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, 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); + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + Printf(code_wrap->code, " (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(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); + } + + /* --------------------------------------------------------------- + * Canonicalize the JNI field descriptor + * + * Replace the $javapackage 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) { + String *pkg_path = Swig_typemap_lookup("javapackage", p, "", 0); + SwigType *type = Getattr(p, "type"); + + if (pkg_path && Len(pkg_path) != 0) { + Replaceall(pkg_path, ".", "/"); + } else + pkg_path = package_path; + + String *descriptor_out = Copy(descriptor_in); + + if (Len(pkg_path) > 0) { + Replaceall(descriptor_out, "$packagepath", pkg_path); + } else { + Replaceall(descriptor_out, "$packagepath/", empty_string); + Replaceall(descriptor_out, "$packagepath", empty_string); + } + + substituteClassname(type, descriptor_out, true); + + if (pkg_path != package_path) + Delete(pkg_path); + + 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 *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *returntype = Getattr(n, "returntype"); + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *tm; + Parm *p; + int i; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(returntype, "void")); + String *qualified_return = NewString(""); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + int status = SWIG_OK; + bool output_director = true; + String *dirclassname = 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 gencomma = 0; + int classmeth_off = curr_class_dmethod - first_class_dmethod; + 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(classname, overloaded_name)); + + if (returntype) { + + 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, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default - if a Java exception occurs, then the pointer returns + something other than a NULL-initialized reference. */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= &result_default", NIL); + + Delete(non_ref_type); + } + + Delete(base_typename); + Delete(resolved_typename); + } + } else { + SwigType *vt; + + vt = cplus_value_type(returntype); + if (!vt) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); + Delete(vt); + } + } + } + + /* Create the intermediate class wrapper */ + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + tm = Swig_typemap_lookup("jtype", tp, "", 0); + if (tm) { + Printf(callback_def, " public static %s %s(%s self", tm, imclass_dmethod, 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 = NewParmFromNode(adjustedreturntype, empty_str, n); + + if ((tm = 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 */ + + Parm *retpm = NewParmFromNode(returntype, empty_str, n); + + if ((c_ret_type = Swig_typemap_lookup("jni", retpm, "", 0))) { + Parm *tp = NewParmFromNode(c_ret_type, empty_str, 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 ((tm = 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); + Delete(retpm); + } + + /* Go through argument list, attach lnames for arguments */ + for (i = 0, p = l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + /* Attach the standard typemaps */ + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("jni", l, 0); + Swig_typemap_attach_parms("jtype", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("javadirectorin", l, 0); + + 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 self object) */ + Parm *tp = NewParmFromNode(c_classname, empty_str, 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(type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + + /* Go through argument list, convert from native to Java */ + for (p = l; p; /* empty */ ) { + /* Is this superfluous? */ + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Copy(Getattr(p, "name")); + String *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 = NewParmFromNode(c_param_type, empty_str, 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); + + Replaceall(tm, "$input", arg); + Replaceall(tm, "$owner", "0"); + + if (Len(tm)) + if (!ignored_method) + Printf(w->code, "%s\n", tm); + + Delete(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 (++gencomma > 1) + 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; + } + + 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(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + } + + /* header declaration, start wrapper definition */ + String *target; + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Add any exception specifications to the methods in the director class + // Get any Java exception classes in the throws typemap + ParmList *throw_parm_list = NULL; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + 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("self.%s(%s)", symname, imcall_args); + + if (!is_void) { + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + if ((tm = Swig_typemap_lookup("javadirectorout", tp, "", 0))) { + addThrows(n, "tmap:javadirectorout", tp); + substituteClassname(returntype, tm); + Replaceall(tm, "$javacall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + if ((tm = Swig_typemap_lookup("out", tp, "", 0))) + addThrows(n, "tmap:out", tp); + + Delete(tm); + Delete(tp); + } 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_methids[%s], %s);\n", methop, imclass_name, methid, jupcall_args); + + Printf(w->code, "if (jenv->ExceptionOccurred()) return $null;\n"); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("c_result"); + Parm *tp = NewParmFromNode(returntype, result_str, n); + + /* Copy jresult into c_result... */ + if ((tm = Swig_typemap_lookup("directorout", tp, result_str, w))) { + addThrows(n, "tmap:directorout", tp); + Replaceall(tm, "$input", jresult_str); + Replaceall(tm, "$result", result_str); + Printf(w->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s used in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } + + 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\");\n"); + 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 code */ + 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")) { + 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; + } + + /* ------------------------------------------------------------ + * 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 = NewParmFromNode(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 *classname = 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 = NewParmFromNode(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, classname, parms, 0, 0); + String *call = Swig_csuperclass_call(0, basetype, superparms); + String *classtype = SwigType_namestr(Getattr(n, "name")); + + Printf(f_directors, "%s::%s : %s, %s {\n", classname, target, call, Getattr(parent, "director:ctor")); + Printf(f_directors, "}\n\n"); + + Delete(classtype); + Delete(target); + Delete(call); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(supername); + Delete(jenv_type); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + Wrapper *w = NewWrapper(); + + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(JNIEnv *jenv) : %s {", classname, classname, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " SwigDirector_%s(JNIEnv *jenv);\n", classname); + DelWrapper(w); + Delete(classtype); + Delete(classname); + 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"); + + Java_director_declaration(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); + Wrapper *w = NewWrapper(); + + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() throw () {\n", classname, classname); + } else { + Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); + } + + /* Ensure that correct directordisconnect typemap's method name is called + * here: */ + + const String *disconn_tm = NULL; + Node *disconn_attr = NewHash(); + String *disconn_methodname = NULL; + + disconn_tm = 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); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + String *classname = Getattr(n, "sym:name"); + 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); + + 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, " bool swig_override[%d];\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"); + 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; + } + + /*---------------------------------------------------------------------- + * Java_director_declaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void Java_director_declaration(Node *n) { + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director(jenv)"); + + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + 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); + } + +}; /* 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 = (char *) "\ +Java Options (available with -java)\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/Source/Modules/lang.cxx b/Source/Modules/lang.cxx new file mode 100644 index 0000000..d4715ee --- /dev/null +++ b/Source/Modules/lang.cxx @@ -0,0 +1,3431 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * lang.cxx + * + * Language base class functions. Default C++ handling is also implemented here. + * ----------------------------------------------------------------------------- */ + +char cvsroot_lang_cxx[] = "$Id: lang.cxx 11482 2009-07-30 18:48:14Z wsfulton $"; + +#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 *ClassPrefix = 0; /* Class prefix */ +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 +#define IMPORT_MODULE 2 + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_one() + * + * Dispatch a single node + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_one(Node *n) { + String *wrn; + 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 */ + 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); + } + + /* =============================================================== + * 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 { + Printf(stderr, "%s:%d. Unrecognized parse tree node type '%s'\n", input_file, line_number, 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::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), +symbols(NewHash()), +classtypes(NewHash()), +enumtypes(NewHash()), +overloading(0), +multiinput(0), +cplus_runtime(0), +directors(0) { + 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; +} + +Language::~Language() { + Delete(symbols); + Delete(classtypes); + Delete(enumtypes); + Delete(director_ctor_code); + Delete(none_comparison); + this_ = 0; +} + +/* ---------------------------------------------------------------------- + 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; + } + } +} + +/* -------------------------------------------------------------------------- + * use_naturalvar_mode() + * -------------------------------------------------------------------------- */ +int use_naturalvar_mode(Node *n) { + if (Getattr(n, "unnamed")) + return 0; + int nvar = naturalvar_mode || GetFlag(n, "feature:naturalvar"); + if (!nvar) { + /* look for feature in the class */ + SwigType *ty = Getattr(n, "type"); + SwigType *fullty = SwigType_typedef_resolve_all(ty); + if (SwigType_isclass(fullty)) { + Node *m = Copy(n); + SwigType *tys = SwigType_strip_qualifiers(fullty); + Swig_features_get(Swig_cparse_features(), 0, tys, 0, m); + nvar = GetFlag(m, "feature:naturalvar"); + Delete(tys); + Delete(m); + } + Delete(fullty); + } + return 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; + } + if (Getattr(options, "nonaturalvar")) { + naturalvar_mode = 0; + } + } + } + classhash = Getattr(n, "classes"); + return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::extendDirective() + * ---------------------------------------------------------------------- */ + +int Language::extendDirective(Node *n) { + int oldam = Extend; + AccessMode oldmode = cplus_mode; + Extend = CWRAP_EXTEND; + cplus_mode = PUBLIC; + + emit_children(n); + + Extend = oldam; + cplus_mode = oldmode; + 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) { + 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.\n"); + } + } + 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; + + /* 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 = storage && (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)) || is_non_virtual_protected_access(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 (symname && !validIdentifier(symname)) { + Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap '%s' unless renamed to a valid identifier.\n", 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); + 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 ((Cmp(storage, "extern") == 0) || (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 (Cmp(storage, "externc") == 0) { + /* 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); + if (GetFlag(n, "feature:onlychildren") && !GetFlag(n, "feature:ignore")) { + // Found an unignored templated method that has a an empty template instantiation (%template()) + // Ignore it unless it has been %rename'd + if (Strncmp(symname, "__dummy_", 8) == 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)); + } + } + if (!GetFlag(n, "feature:ignore")) + 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 (Getattr(n, "nested")) + SetFlag(n, "feature:immutable"); + if (!CurrentClass) { + if ((Cmp(storage, "extern") == 0) || ForceExtern) { + f_header = Swig_filebyname("header"); + if (AddExtern) { + if (f_header) { + String *str = SwigType_str(ty, name); + Printf(f_header, "extern %s;\n", 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 && Cmp(storage, "static") == 0 && !(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) { + globalfunctionHandler(n); + } else { + 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 *call = Swig_cfunction_call(name, parms); + String *cres = Swig_cresult(type, "result", 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 *symname = Getattr(n, "sym:name"); + String *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *parms = Getattr(n, "parms"); + String *cb = GetFlagAttr(n, "feature:callback"); + 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); + + if (!cbname) { + cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", cbname); + } + + Setattr(n, "sym:name", cbname); + Setattr(n, "type", cbty); + Setattr(n, "value", calltype); + + Node *ns = Getattr(symbols, cbname); + if (!ns) + constantWrapper(n); + + Delete(cbname); + 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); + + memberconstantHandler(cbn); + Setattr(n, "feature:callback:name", Swig_name_member(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(ClassPrefix, symname); + if (Extend && SmartPointer) { + if (!Getattr(n, "classname")) { + Setattr(n, "classname", Getattr(CurrentClass, "allocate:smartpointerbase")); + } + } + // 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") || is_non_virtual_protected_access(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; + + Swig_MethodToFunction(n, ClassType, Getattr(n, "template") ? SmartPointer : Extend | SmartPointer | DirectorExtraCall, director_type, + is_member_director(CurrentClass, n)); + Setattr(n, "sym:name", fname); + + 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 (is_non_virtual_protected_access(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(mname, name); + Delete(mname); + } + mrename = Swig_name_member(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 */ + Swig_add_extension_code(n, cname, parms, type, code, CPlusPlus, 0); + } + } + + Setattr(n, "name", cname); + Setattr(n, "sym:name", mrename); + + if (cb) { + String *cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", Swig_name_member(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 { + String *storage = Getattr(n, "storage"); + Swig_save("variableHandler", n, "feature:immutable", NIL); + if (SmartPointer) { + /* If a smart-pointer and it's a constant access, we have to set immutable */ + if (Getattr(CurrentClass, "allocate:smartpointerconst")) { + SetFlag(n, "feature:immutable"); + } + } + if ((Cmp(storage, "static") == 0) && !(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(ClassPrefix, symname); + String *mrename_get = Swig_name_get(mname); + String *mrename_set = Swig_name_set(mname); + Delete(mname); + + /* Create a function to set the value of the variable */ + + int assignable = is_assignable(n); + + if (SmartPointer) { + if (Getattr(CurrentClass, "allocate:smartpointerconst")) { + assignable = 0; + } + } + + if (assignable) { + int make_set_wrapper = 1; + String *tm = 0; + String *target = 0; + if (!Extend) { + if (SmartPointer) { + if (checkAttribute(n, "storage", "static")) { + 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 = is_non_virtual_protected_access(n) ? NewString("darg") : Swig_cparm_name(0, 0); + target = NewStringf("%s->%s", pname, name); + Delete(pname); + } + } else { + target = NewStringf("$extendgetcall"); // member variable access expanded later + } + tm = Swig_typemap_lookup("memberin", n, target, 0); + int flags = Extend | SmartPointer | use_naturalvar_mode(n); + if (is_non_virtual_protected_access(n)) + flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + + String *call = 0; + Swig_MembersetToFunction(n, ClassType, flags, &call); + Setattr(n, "memberset", "1"); + + 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); + Replace(tm, "$extendgetcall", call, DOH_REPLACE_ANY); + Setattr(n, "wrap:action", tm); + Delete(tm); + Delete(pname0); + Delete(pname1); + } + Delete(call); + 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); + + /* 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 (is_non_virtual_protected_access(n)) + flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + Swig_MembergetToFunction(n, ClassType, flags); + Setattr(n, "sym:name", mrename_get); + Setattr(n, "memberget", "1"); + functionWrapper(n); + } + 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); + 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(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(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 ? (is_non_virtual_protected_access(n) ? DirectorClassName : ClassName) : Getattr(CurrentClass, "allocate:smartpointerbase"); + + 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(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 (!ImportMode) { + emit_children(n); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumvalueDeclaration(Node *n) { + if (CurrentClass && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*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); + + 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; + 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 *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + + String *mrename = Swig_name_member(ClassPrefix, symname); + Setattr(n, "sym:name", mrename); + + String *new_name = 0; + if (Extend) + new_name = Copy(value); + else + new_name = NewStringf("%s::%s", is_non_virtual_protected_access(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 */ + if (!checkAttribute(ni, "storage", "virtual")) + continue; + nodeType = Getattr(ni, "nodeType"); + /* we need to add methods(cdecl) and destructor (to check for throw decl) */ + int is_destructor = (Cmp(nodeType, "destructor") == 0); + if ((Cmp(nodeType, "cdecl") == 0) || is_destructor) { + decl = Getattr(ni, "decl"); + /* extra check for function type and proper access */ + if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(ni)) || need_nonpublic_member(ni))) { + String *name = Getattr(ni, "name"); + Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(ni); + /* 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(ni); + + /* 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); + + 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' + an 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(symname); //Getattr(n, "name")); + String *type = NewString(ClassType); + String *name = NewString("self"); + SwigType_add_pointer(type); + Parm *p = NewParm(type, name); + Delete(name); + Delete(type); + type = NewString("void"); + String *action = NewString(""); + Printv(action, "{\n", "Swig::Director *director = dynamic_cast<Swig::Director *>(arg1);\n", "if (director) director->swig_disown();\n", "}\n", NULL); + 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) { + 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 compileable code (Example2 in director_abastract.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")) + continue; + + String *type = Getattr(method, "nodeType"); + if (!Cmp(type, "destructor")) { + classDirectorDestructor(method); + } else { + if (classDirectorMethod(method, n, fqdname) == SWIG_OK) { + Setattr(item, "director", "1"); + } + } + } + + 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"); + bool cdeclaration = (Cmp(nodeType, "cdecl") == 0); + if (cdeclaration && !GetFlag(ni, "feature:ignore")) { + if (is_non_virtual_protected_access(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 *last = Swig_scopename_last(cname); + String *name = NewStringf("%s::%s", cname, last); + String *cc = NewStringf("r.q(const).%s", type); + String *decl = NewStringf("f(%s).", cc); + String *csymname = Getattr(n, "sym:name"); + String *oldname = csymname; + + 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, last, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + if (!symname) { + symname = Copy(csymname); + } + Parm *p = NewParm(cc, "other"); + + 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_symbol_setscope(oldscope); + Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); + + 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(last); + 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 *last = Swig_scopename_last(cname); + String *name = NewStringf("%s::%s", cname, last); + String *decl = NewString("f()."); + String *csymname = Getattr(n, "sym:name"); + String *oldname = csymname; + String *symname = Swig_name_make(cn, cname, last, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + if (!symname) { + symname = Copy(csymname); + } + + 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_symbol_setscope(oldscope); + Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); + + 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(last); + 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 *last = Swig_scopename_last(cname); + Insert(last, 0, "~"); + String *name = NewStringf("%s::%s", cname, last); + String *decl = NewString("f()."); + String *symname = Swig_name_make(cn, cname, last, decl, 0); + if (Strcmp(symname, "$ignore") != 0) { + if (!symname) { + 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 *on = Swig_symbol_add(symname, cn); + Swig_symbol_setscope(oldscope); + Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); + + if (on == cn) { + 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(cn); + Delete(last); + 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; + } + + String *kind = Getattr(n, "kind"); + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *symname = Getattr(n, "sym:name"); + + char *classname = tdname ? Char(tdname) : Char(name); + char *iname = Char(symname); + int strip = (tdname || CPlusPlus) ? 1 : 0; + + + if (!classname) { + 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; + } + + Swig_save("classDeclaration", n, "name", NIL); + Setattr(n, "name", classname); + + if (Cmp(kind, "class") == 0) { + cplus_mode = PRIVATE; + } else { + cplus_mode = PUBLIC; + } + + ClassName = NewString(classname); + ClassPrefix = NewString(iname); + if (strip) { + ClassType = NewString(classname); + } else { + ClassType = NewStringf("%s %s", kind, classname); + } + Setattr(n, "classtypeobj", Copy(ClassType)); + Setattr(n, "classtype", SwigType_namestr(ClassType)); + + InClass = 1; + CurrentClass = n; + + + /* Call classHandler() here */ + if (!ImportMode) { + int dir = 0; + 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 = NewStringf("SwigDirector_%s", symname); + classDirector(n); + } + /* check for abstract after resolving directors */ + Abstract = abstractClassTest(n); + + classHandler(n); + } else { + Abstract = abstractClassTest(n); + Language::classHandler(n); + } + + InClass = 0; + CurrentClass = 0; + Delete(ClassType); + ClassType = 0; + Delete(ClassPrefix); + ClassPrefix = 0; + Delete(ClassName); + ClassName = 0; + Delete(DirectorClassName); + DirectorClassName = 0; + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classHandler() + * ---------------------------------------------------------------------- */ + +int Language::classHandler(Node *n) { + + 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; + 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"); + 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 (!Getattr(symbols, 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 overidden 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); + } + cplus_mode = old_mode; + } + } + + 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 { + if (name && (Cmp(Swig_scopename_last(name), Swig_scopename_last(ClassName))) && !(Getattr(n, "template"))) { + Swig_warning(WARN_LANG_RETURN_TYPE, input_file, line_number, "Function %s must have a return type.\n", SwigType_namestr(name)); + 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 *&abstract) { + String *director_ctor = director_ctor_code; + int use_director = Swig_directorclass(n); + if (use_director) { + Node *pn = Swig_methodclass(n); + abstract = Getattr(pn, "abstract"); + if (director_prot_ctor_code) { + int is_notabstract = GetFlag(pn, "feature:notabstract"); + int is_abstract = abstract && !is_notabstract; + if (is_protected(n) || is_abstract) { + director_ctor = director_prot_ctor_code; + Delattr(pn, "abstract"); + } else { + if (is_notabstract) { + Delattr(pn, "abstract"); + } else { + abstract = 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(symname); + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + List *abstract = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstract); + if (!constructor) { + /* if not originally a constructor, still handle it as one */ + Setattr(n, "handled_as_constructor", "1"); + } + + Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 : Extend); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + if (abstract) + Setattr(Swig_methodclass(n), "abstract", abstract); + 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(symname); + List *abstract = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstract); + Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 : Extend); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + if (abstract) + Setattr(Swig_methodclass(n), "abstract", abstract); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::destructorDeclaration(Node *n) { + + if (!CurrentClass) + return SWIG_NOWRAP; + if (cplus_mode != PUBLIC) + return SWIG_NOWRAP; + if (ImportMode) + return SWIG_NOWRAP; + + if (Extend) { + /* extend destructor can be safetly ignored if there is already one */ + if (Getattr(CurrentClass, "has_destructor")) { + return SWIG_NOWRAP; + } + } + + Swig_save("destructorDeclaration", n, "name", "sym:name", NIL); + + char *c = GetChar(n, "name"); + if (c && (*c == '~')) + Setattr(n, "name", c + 1); + + c = GetChar(n, "sym:name"); + if (c && (*c == '~')) + Setattr(n, "sym:name", c + 1); + + /* Name adjustment for %name */ + + 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); + } + + 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 == '~')) + csymname += 1; + + mrename = Swig_name_destroy(csymname); + + Swig_DestructorToFunction(n, 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)) { + 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", NIL); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + + /* 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(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) { + functionWrapper(n); + } + /* Restore parameters */ + Setattr(n, "sym:name", symname); + Setattr(n, "type", type); + Setattr(n, "name", name); + + /* 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(symname); + Setattr(n, "sym:name", gname); + Delete(gname); + functionWrapper(n); + Swig_restore(n); + 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. Returns 1 if the symbol is added successfully. + * Prints an error message and returns 0 if a conflict occurs. + * ----------------------------------------------------------------------------- */ + +int +Language::addSymbol(const String *s, const Node *n) { + Node *c = Getattr(symbols, s); + if (c && (c != n)) { + Swig_error(input_file, line_number, "'%s' is multiply defined in the generated module.\n", s); + Swig_error(Getfile(c), Getline(c), "Previous declaration of '%s'\n", s); + return 0; + } + Setattr(symbols, s, n); + return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolLookup() + * ----------------------------------------------------------------------------- */ + +Node *Language::symbolLookup(String *s) { + return Getattr(symbols, s); +} + +/* ----------------------------------------------------------------------------- + * Language::classLookup() + * + * Tries to locate a class from a type definition + * ----------------------------------------------------------------------------- */ + +Node *Language::classLookup(SwigType *s) { + Node *n = 0; + + /* Look in hash of cached values */ + n = Getattr(classtypes, s); + if (!n) { + Symtab *stab = 0; + SwigType *ty1 = SwigType_typedef_resolve_all(s); + SwigType *ty2 = SwigType_strip_qualifiers(ty1); + Delete(ty1); + ty1 = 0; + + 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; + 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 where we want a proxy class for the particular type */ + if ((Len(prefix) == 0) || // simple type (pass by value) + (Strcmp(prefix, "p.") == 0) || // pointer + (Strcmp(prefix, "r.") == 0) || // reference + (Strcmp(prefix, "r.p.") == 0) || // pointer by reference + SwigType_prefix_is_simple_1D_array(prefix)) { // Simple 1D array (not arrays of pointers/references) + SwigType *cs = Copy(s); + Setattr(classtypes, cs, n); + Delete(cs); + } else { + n = 0; + } + } + Delete(ty2); + Delete(base); + Delete(prefix); + } + 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) { + Node *n = 0; + + /* Look in hash of cached values */ + n = Getattr(enumtypes, s); + if (!n) { + Symtab *stab = 0; + SwigType *lt = SwigType_ltype(s); + SwigType *ty1 = SwigType_typedef_resolve_all(lt); + SwigType *ty2 = SwigType_strip_qualifiers(ty1); + Delete(lt); + Delete(ty1); + lt = 0; + ty1 = 0; + + 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 (Strcmp(nodeType(n), "enum") == 0) + 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 */ + Setattr(enumtypes, Copy(s), n); + } else { + n = 0; + } + } + Delete(ty2); + Delete(base); + Delete(prefix); + } + 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 whan 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()) { + 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::extraDirectorProtectedCPPMethodsRequired() + * ----------------------------------------------------------------------------- */ + +bool Language::extraDirectorProtectedCPPMethodsRequired() const { + return true; +} + +/* ----------------------------------------------------------------------------- + * Language::is_wrapping_class() + * ----------------------------------------------------------------------------- */ + +int Language::is_wrapping_class() { + return InClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getCurrentClass() + * ----------------------------------------------------------------------------- */ + +Node *Language::getCurrentClass() const { + return CurrentClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassName() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassName() const { + return ClassName; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassPrefix() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassPrefix() const { + return ClassPrefix; +} + +/* ----------------------------------------------------------------------------- + * 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; + /* now check for the rest */ + List *abstract = Getattr(n, "abstract"); + if (!abstract) + return 0; + int labs = Len(abstract); +#ifdef SWIG_DEBUG + List *bases = Getattr(n, "allbases"); + Printf(stderr, "testing %s %d %d\n", Getattr(n, "name"), labs, Len(bases)); +#endif + if (!labs) + return 0; /*strange, but need to be fixed */ + if (abstract && !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(abstract, 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 accesible, 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 dirabstract ? 1 : 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/Source/Modules/lua.cxx b/Source/Modules/lua.cxx new file mode 100644 index 0000000..8835667 --- /dev/null +++ b/Source/Modules/lua.cxx @@ -0,0 +1,1226 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * 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) + + +*/ + +char cvsroot_lua_cxx[] = "$Id: lua.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.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 (DohIterator it = DohFirst(d); it.item; it = DohNext(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); + } +} + + + +/* 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 = (char *) "\ + Lua Options (available with -lua)\n\ + (coming soon.)\n\n"; + + + +/* 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 *PrefixPlusUnderscore; + String *s_cmd_tab; // table of command names + String *s_var_tab; // table of global variables + String *s_const_tab; // table of global constants + String *s_methods_tab; // table of class methods + String *s_attr_tab; // table of class atributes + String *s_luacode; // luacode to be called during init + + int have_constructor; + int have_destructor; + String *destructor_action; + String *class_name; + String *constructor_name; + + enum { + NO_CPP, + VARIABLE, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }current; + +public: + + /* --------------------------------------------------------------------- + * LUA() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + LUA() { + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_initbeforefunc = 0; + PrefixPlusUnderscore = 0; + + s_cmd_tab = s_var_tab = s_const_tab = s_luacode = 0; + current=NO_CPP; + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is called to initalise 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, stderr); + } + } + } + + /* 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 */ + String *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); + + /* NEW LANGUAGE NOTE:*********************************************** + s_cmd_tab,s_var_tab & s_const_tab hold the names of the fns for + registering with SWIG. + These will be filled in when the functions/variables are wrapped & + then added to the end of the wrappering code + just before it is written to file + NEW LANGUAGE NOTE:END ************************************************/ + // Initialize some variables for the object interface + s_cmd_tab = NewString(""); + s_var_tab = NewString(""); + // s_methods_tab = NewString(""); + s_const_tab = NewString(""); + + s_luacode = NewString(""); + Swig_register_filebyname("luacode", s_luacode); + + current=NO_CPP; + + /* Standard stuff for the SWIG runtime section */ + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGLUA\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\n", module); + + Printf(s_cmd_tab, "\nstatic const struct luaL_reg swig_commands[] = {\n"); + Printf(s_var_tab, "\nstatic swig_lua_var_info swig_variables[] = {\n"); + Printf(s_const_tab, "\nstatic swig_lua_const_info swig_constants[] = {\n"); + 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"); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + // Done. Close up the module & write to the wrappers + Printv(s_cmd_tab, tab4, "{0,0}\n", "};\n", NIL); + Printv(s_var_tab, tab4, "{0,0,0}\n", "};\n", NIL); + Printv(s_const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); + Printv(f_wrappers, s_cmd_tab, s_var_tab, s_const_tab, NIL); + 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 excaped 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(s_cmd_tab); + Delete(s_var_tab); + Delete(s_const_tab); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_initbeforefunc); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + /* Done */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + return Language::importDirective(n); + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is it! + you get this one right, and most of your work is done + but its going to take soem file to get it working right + quite a bit of this is generally boilerplate code + (or stuff I dont understand) + that which matters will have extra added comments + NEW LANGUAGE NOTE:END ************************************************/ + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + REPORT("functionWrapper",n); + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + //Printf(stdout,"functionWrapper %s %s\n",name,iname); + Parm *p; + String *tm; + int i; + //Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); + // int returnval=0; // number of arguments returned + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + Printf(stderr,"addSymbol(%s) failed\n",iname); + return SWIG_ERROR; + } + } + + /* NEW LANGUAGE NOTE:*********************************************** + the wrapper object holds all the wrappering 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); + } + + /* NEW LANGUAGE NOTE:*********************************************** + the format of a lua fn is: + static int wrap_XXX(lua_State* L){...} + this line adds this into the wrappering 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"); + } + + + /* Which input argument to start with? */ + // int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; + + /* Offset to skip over the attribute name */ + // int offset = (current == MEMBER_VAR) ? 1 : 0; + + /* 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 on 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; + // String *numoutputs=NULL; + char source[64]; + //Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",name,num_required,num_arguments); + Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",name,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", name, 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 dont 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", "result"); + 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 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, "result", 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", "result"); + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + 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", "result"); + + /* Dump the function out */ + /* in Lua we will not emit the destructor as a wrappered 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. */ + if (!Getattr(n, "sym:overloaded")) { + // add_method(n, iname, wname, description); + if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns + Printv(s_cmd_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(iname), "},\n", NIL); + // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), "},\n", NIL); + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + Delete(argument_check); + Delete(argument_parse); + + Delete(cleanup); + Delete(outarg); + // Delete(description); + Delete(wname); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * 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 + nost of the real work in again typemaps: + look for %typecheck(SWIG_TYPECHECK_*) in the .swg file + NEW LANGUAGE NOTE:END ************************************************/ + void dispatchFunction(Node *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 *wname = Swig_name_wrapper(symname); + + //Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); + + 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 { + Printf(protoTypes, "\n\" %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms"))); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(f->code, "lua_pushstring(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); + //add_method(symname,wname,0); + if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wname, "},\n", NIL); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + + /* ------------------------------------------------------------ + * 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 *iname = Getattr(n, "sym:name"); + current=VARIABLE; + // let SWIG generate the wrappers + int result = Language::variableWrapper(n); + current=NO_CPP; + // normally SWIG will generate 2 wrappers, a get and a set + // but in certain scenarios (immutable, or if its arrays), it will not + String *getName = Swig_name_wrapper(Swig_name_get(iname)); + String *setName = 0; + // checking whether it can be set to or not appears to be a very error prone issue + // I refered to the Language::variableWrapper() to find this out + bool assignable=is_assignable(n) ? true : false; + SwigType *type = Getattr(n, "type"); + String *tm = Swig_typemap_lookup("globalin", n, iname, 0); + if (!tm && SwigType_isarray(type)) + assignable=false; + Delete(tm); + + if (assignable) { + setName = Swig_name_wrapper(Swig_name_set(iname)); + } else { + // how about calling a 'this is not settable' error message? + setName = NewString("SWIG_Lua_set_immutable"); // error message + //setName = NewString("0"); + } + // register the variable + Printf(s_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, iname, getName, setName); + Delete(getName); + Delete(setName); + return result; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + virtual int constantWrapper(Node *n) { + // REPORT("constantWrapper", n); + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + //String *nsname = !nspace ? Copy(iname) : NewStringf("%s::%s",ns_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; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + //if (nspace) 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(s_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) { + // REPORT("nativeWrapper", n); + String *symname = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); + // return Language::nativeWrapper(n); // this does nothing... + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + //REPORT("classHandler", n); + + String *mangled_classname = 0; + String *real_classname = 0; + + constructor_name = 0; + have_constructor = 0; + have_destructor = 0; + destructor_action = 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); + + // not sure exactly how this workswhat 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 (Getattr(emitted, mangled_classname)) + return SWIG_NOWRAP; + Setattr(emitted, mangled_classname, "1"); + + s_attr_tab = NewString(""); + Printf(s_attr_tab, "static swig_lua_attribute swig_"); + Printv(s_attr_tab, mangled_classname, "_attributes[] = {\n", NIL); + + s_methods_tab = NewString(""); + Printf(s_methods_tab, "static swig_lua_method swig_"); + Printv(s_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' + String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); + SwigType_remember_clientdata(t, wrap_class); + + String *rt = Copy(Getattr(n, "classtype")); + 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); + + // emit a function to be called to delete the object + if (have_destructor) { + Printv(f_wrappers, "static 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(s_methods_tab, " {0,0}\n};\n"); + Printv(f_wrappers, s_methods_tab, NIL); + + Printf(s_attr_tab, " {0,0,0}\n};\n"); + Printv(f_wrappers, s_attr_tab, NIL); + + Delete(s_methods_tab); + Delete(s_attr_tab); + + // Handle inheritance + // note: with the idea of class hireachied 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; + } + // old code: (used the pointer to the base class) + //String *bmangle = Swig_name_mangle(bname); + //Printf(base_class, "&_wrap_class_%s", bmangle); + //Putc(',', base_class); + //Delete(bmangle); + // new code: stores a null pointer & the name + Printf(base_class, "0,"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + + b = Next(b); + index++; + } + } + + Printv(f_wrappers, "static swig_lua_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); + Delete(base_class); + Printv(f_wrappers, "static const char *swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); + Delete(base_class_names); + + Printv(f_wrappers, "static swig_lua_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(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"); + } + Printf(f_wrappers, ", swig_%s_methods, swig_%s_attributes, swig_%s_bases, swig_%s_base_names };\n\n", mangled_classname, mangled_classname, mangled_classname, mangled_classname); + + // Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases };\n\n", NIL); + // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, &_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"); + //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(Getattr(n, "sym:name"), "__unm") == 0) { + //Printf(stdout, "unary minus: ignore one argument\n"); + SetInt(n, "lua:ignore_args", 1); + } + + String *realname, *rname; + + current = MEMBER_FUNC; + Language::memberfunctionHandler(n); + current = NO_CPP; + + realname = iname ? iname : name; + rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + if (!Getattr(n, "sym:nextSibling")) { + Printv(s_methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); + } + Delete(rname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + // REPORT("membervariableHandler",n); + String *symname = Getattr(n, "sym:name"); + String *gname, *sname; + + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + gname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + if (!GetFlag(n, "feature:immutable")) { + sname = Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + } else { + //sname = NewString("0"); + sname = NewString("SWIG_Lua_set_immutable"); // error message + } + Printf(s_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,gname,sname); + Delete(gname); + Delete(sname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * + * Method for adding C++ member constructor + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + // REPORT("constructorHandler", n); + current = CONSTRUCTOR; + Language::constructorHandler(n); + current = NO_CPP; + constructor_name = NewString(Getattr(n, "sym:name")); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + REPORT("destructorHandler", n); + current = DESTRUCTOR; + Language::destructorHandler(n); + current = NO_CPP; + have_destructor = 1; + destructor_action = Getattr(n, "wrap:action"); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + current = STATIC_FUNC; + return Language::staticmemberfunctionHandler(n); + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * + * Create a C++ constant + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + // REPORT("memberconstantHandler",n); + return Language::memberconstantHandler(n); + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + // REPORT("staticmembervariableHandler",n); + current = STATIC_VAR; + return Language::staticmembervariableHandler(n); + } + + /* --------------------------------------------------------------------- + * 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 termiated + String *sfile; + 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 + * --------------------------------------------------------------------- */ + + /* This is to convert the string of Lua code into a proper string, which can then be + emitted into the C/C++ code. + Basically is 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); + } +}; + +/* 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/Source/Modules/main.cxx b/Source/Modules/main.cxx new file mode 100644 index 0000000..477d83b --- /dev/null +++ b/Source/Modules/main.cxx @@ -0,0 +1,1251 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * main.cxx + * + * Main entry point to the SWIG core. + * ----------------------------------------------------------------------------- */ + +char cvsroot_main_cxx[] = "$Id: main.cxx 11135 2009-02-20 20:55:16Z wsfulton $"; + +#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 <limits.h> // for INT_MAX + +// Global variables + +Language *lang; // 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_TYPE_ABSTRACT 403 + WARN_LANG_OVERLOAD_CONST 512 + WARN_PARSE_BUILTIN_NAME 321 + WARN_PARSE_REDUNDANT 322 + */ +#define EXTRA_WARNINGS "202,309,403,512,321,322" + +extern "C" { + extern String *ModuleName; +} + +/* 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\ + -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-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 information for debugging typemaps\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\ + -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\ +"; + +static const char *usage2 = (const char *) "\ + -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 - This output\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\ + -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\ + -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\ +"; + +static const char *usage3 = (const char *) "\ + -notemplatereduce - Disable reduction of the typedefs in templates\n\ + -O - Enable the optimization options: \n\ + -fastdispatch -fvirtual \n\ + -o <outfile> - Set name of the output file to <outfile>\n\ + -oh <headfile> - Set name of the output header file to <headfile>\n\ + -outcurrentdir - Set default output dir to current dir instead of input file's path\n\ + -outdir <dir> - Set language specific files output directory to <dir>\n\ + -small - Compile in virtual elimination & compact mode\n\ + -swiglib - Report location of SWIG library and exit\n\ + -templatereduce - Reduce all the typedefs in templates\n\ + -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\ +\n"; + +// Local variables +static String *LangSubDir = 0; // Target language library subdirectory +static char *SwigLib = 0; // Library directory +static String *SwigLibWin = 0; // Extra Library directory for Windows +static int freeze = 0; +static String *lang_config = 0; +static char *hpp_extension = (char *) "h"; +static char *cpp_extension = (char *) "cxx"; +static char *depends_extension = (char *) "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 char *outfile_name = 0; +static char *outfile_name_h = 0; +static int tm_debug = 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 memory_debug = 0; +static int allkw = 0; +static DOH *libfiles = 0; +static DOH *cpps = 0; +static String *dependencies_file = 0; +static File *f_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 *all_output_files = 0; + +// ----------------------------------------------------------------------------- +// check_suffix() +// +// Checks the suffix of a file to see if we should emit extern declarations. +// ----------------------------------------------------------------------------- + +static int check_suffix(String *filename) { + const char *name = Char(filename); + const char *c; + if (!name) + return 0; + c = Swig_file_suffix(name); + 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)) { + return 1; + } + return 0; +} + +// ----------------------------------------------------------------------------- +// install_opts(int argc, char *argv[]) +// 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(String *numlist) +// 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 if not set and +// adds trailing file separator if necessary. +// ----------------------------------------------------------------------------- + +static void set_outdir(const String *c_wrapper_file_dir) { + + // Add file delimiter if not present in output directory name + if (outdir && 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); + } + // Use the C wrapper file's directory if the output directory has not been set by user + if (!outdir) + outdir = NewString(c_wrapper_file_dir); +} + +/* 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 = (char *) 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"); + Close(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"); + Close(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"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + s = Swig_include_sys("swigrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swigrun.swg'\n"); + Close(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"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + Close(runtime); + Delete(runtime); + SWIG_exit(EXIT_SUCCESS); +} + +void SWIG_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, (char *) "=", (char *) " ", 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], "-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], "-nonaturalvar") == 0) { + Wrapper_naturalvar_mode_set(0); + 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], "-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) { + if (SwigLibWin) + printf("%s\n", Char(SwigLibWin)); + printf("%s\n", SwigLib); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-o") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outfile_name = Swig_copy_string(argv[i + 1]); + if (!outfile_name_h || !dependencies_file) { + char *ext = strrchr(outfile_name, '.'); + String *basename = ext ? NewStringWithSize(outfile_name, ext - 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 = Swig_copy_string(Char(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 = Swig_copy_string(argv[i + 1]); + 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, "Please 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], "-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], "-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], "-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-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); + Swig_mark_arg(i); + help = 1; + } + } + } +} + + + + + +int SWIG_main(int argc, char *argv[], Language *l) { + char *c; + extern void Swig_print_xml(Node *obj, String *filename); + + /* Initialize the SWIG core */ + Swig_init(); + + // Default warning suppression + Swig_warnfilter(EXTRA_WARNINGS, 1); + + // Initialize the preprocessor + Preprocessor_init(); + + lang = l; + + // 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); +#ifdef MACSWIG + Preprocessor_define((DOH *) "SWIGMAC 1", 0); +#endif +#ifdef SWIGWIN32 + Preprocessor_define((DOH *) "SWIGWIN32 1", 0); +#endif + + // 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 = 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); + + // 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'; + SwigLibWin = NewStringf("%sLib", buf); // Native windows installation path + } + SwigLib = Swig_copy_string(SWIG_LIB_WIN_UNIX); // Unix installation path using a drive letter (for msys/mingw) +#else + SwigLib = Swig_copy_string(SWIG_LIB); +#endif + } else { + SwigLib = Swig_copy_string(c); + } + + libfiles = NewList(); + all_output_files = NewList(); + + /* Check for SWIG_FEATURES environment variable */ + + SWIG_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); + + 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 (SwigLibWin) { + rl = NewString(""); + Printf(rl, "%s%s%s", SwigLibWin, 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 (SwigLibWin) + Swig_add_directory((String *) SwigLibWin); + Swig_add_directory((String *) SwigLib); + + if (Verbose) { + printf("LangSubDir: %s\n", Char(LangSubDir)); + printf("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; + char *outfile = Char(input_file); + if (outfile_name) + outfile = outfile_name; + + if (Verbose) + printf("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); + Close(f_outfile); + } + } + } + } else { + // Run the preprocessor + if (Verbose) + printf("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 (!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_last_file()); + for (i = 0; i < Len(libfiles); i++) { + Printf(fs, "\n%%include \"%s\"\n", 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; + + char *basename = Swig_file_basename(outcurrentdir ? Swig_file_filename(input_file): Char(input_file)); + 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: ", dependencies_target); + } else { + Printf(f_dependencies_file, "%s: ", outfile); + } + List *files = Preprocessor_depend(); + for (int i = 0; i < Len(files); i++) { + if ((depend != 2) || ((depend == 2) && (Strncmp(Getitem(files, i), SwigLib, Len(SwigLib)) != 0))) { + Printf(f_dependencies_file, "\\\n %s ", Getitem(files, i)); + } + } + Printf(f_dependencies_file, "\n"); + if (f_dependencies_file != stdout) + Close(f_dependencies_file); + if (depend_only) + SWIG_exit(EXIT_SUCCESS); + } 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 (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 (dump_top & STAGE3) { + Printf(stdout, "debug-top stage 3\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE3) { + Printf(stdout, "debug-module stage 3\n"); + Swig_print_tree(Getattr(top, "module")); + } + + if (Verbose) { + Printf(stdout, "Generating wrappers...\n"); + } + + if (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(0); + } + + 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); + + char *basename = Swig_file_basename(outcurrentdir ? Swig_file_filename(infile): Char(infile)); + 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); + } + set_outdir(Swig_file_dirname(Getattr(top, "outfile"))); + if (Swig_contract_mode_get()) { + Swig_contracts(top); + } + + // Check the suffix for a c/c++ file. If so, we're going to declare everything we see as "extern" + ForceExtern = check_suffix(input_file); + + lang->top(top); + + if (browse) { + Swig_browser(top, 0); + } + } + } + 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) { + 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)); + Close(f_outfiles); + } + } + + // Deletes + Delete(libfiles); + Preprocessor_delete(); + + while (freeze) { + } + + if ((werror) && (Swig_warn_count())) { + return Swig_warn_count(); + } + return Swig_error_count(); +} + +// -------------------------------------------------------------------------- +// SWIG_exit(int exit_code) +// +// Cleanup and either freeze or exit +// -------------------------------------------------------------------------- + +void SWIG_exit(int exit_code) { + while (freeze) { + } + exit(exit_code); +} diff --git a/Source/Modules/modula3.cxx b/Source/Modules/modula3.cxx new file mode 100644 index 0000000..40f275a --- /dev/null +++ b/Source/Modules/modula3.cxx @@ -0,0 +1,3987 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * modula3.cxx + * + * Modula3 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_modula3_cxx[] = "$Id: modula3.cxx 11584 2009-08-16 00:04:29Z wsfulton $"; + +/* + Text formatted with + indent -sob -br -ce -nut -npsl +*/ + +/* + Report: + - It's not a good concept to use member variables or global variables + for passing parameters to functions. + It's not a good concept to use functions of superclasses for specific services. + E.g. For SWIG this means: Generating accessor functions for member variables + is the most common but no general task to be processed in membervariableHandler. + Better provide a service function which generates accessor function code + and equip this service function with all parameters needed for input (parse node) + and output (generated code). + - How can I make globalvariableHandler not to generate + interface functions to two accessor functions + (that don't exist) ? + - How can I generate a typemap that turns every C reference argument into + its Modula 3 counterpart, that is + void test(Complex &z); + PROCEDURE test(VAR z:Complex); + - neither $*n_mangle nor $*n_type nor $*n_ltype return the type without + pointer converted to Modula3 equivalent, + $*n_mangle is the variant closest to what I expect + - using a typemap like + typemap(m3wrapintype) int * %{VAR $1_name: INTEGER%} + has the advantages: + - one C parameter can be turned into multiple M3 parameters + - the argument can be renamed + - using typemaps like + typemap(m3wrapinmode) int * "VAR" + typemap(m3wrapintype) int * "INTEGER" + has the advantages: + - multiple parameters with same type and default value can be bundled + - more conform to the other language modules + - Where takes the reduction of multi-typemaps place? + How can I preserve all parameters for functions of the intermediary class? + The answer is Getattrs(n,"tmap:m3rawintype:next") + - Char() can be used to transform a String to (char *) + which can be used for output with printf + - What is the while (checkAttribute()) loop in functionWrapper good for? + Appearently for skipping (numinputs=0) typemaps. + - SWIGTYPE const * - typemap is ignored, whereas + SWIGTYPE * - typemap is invoked, why? + Had it been (const SWIGTYPE *) instead? + - enumeration items should definitely be equipped + with its plain numerical value + One could add tag 'numvalue' in CParse/parser.y, + but it is still possible that someone declares an + enumeration using a symbolic constant. + I have quickly hacked + that the successive number is assigned + if "enumvalue" has suffix "+1". + The ultimate solution would be to generate a C program + which includes the header and outputs all constants. + This program might be compiled and run + by 'make' or by SWIG and the resulting output is fed back to SWIG. + - It's a bad idea to interpret feature value "" + 'disable feature' because the value "" + might be sensible in case of feature:modula3:oldprefix. + - What's the difference between "sym:name" and "name" ? + "name" is the original name and + "sym:name" is probably modified by the user using %rename + - Is it possible for 'configure' to find out if m3pp is installed + and to invoke it for generated Modula3 files? + - It would be better to separate an arguments purpose and its name, + because an output variable with name "OUTPUT" is not very descriptive. + In case of PLPlot this could be solved by typedefs + that assign special purposes to the array types. + - Can one interpret $n_basetype as the identifier matched with SWIGTYPE ? + + Swig's odds: + - arguments of type (Node *) for SWIG functions + should be most often better (const Node *): + Swig_symbol_qualified, Getattr, nodeType, parentNode + - unique identifier style instead of + NewString, Getattr, firstChild + - 'class'.name is qualified, + 'enum'.name and 'enumitem'.name is not + - Swig_symbol_qualified() returns NIL for enumeration nodes + + - Is there a function that creates a C representation of a SWIG type string? + + ToDo: + - create WeakRefs only for resources returned by function marked with %newobject + -> part of output conversion + - clean typemap conception + - should a multi-typemap for m3wrapouttype skip the corresponding input parameters? + when yes - How to handle inout-arguments? In this case like in-argument. + - C++ classes + - C++ exceptions + - allow for moving RECORD and OBJECT definitions + to separate files, with the main type called T + - call-back functions + - special option: fast access to class members by pointer arithmetic, + member offsets can be determined by a C++ program that print them. + - emit enumeration definitions when its first item is declared, + currently enumerations are emitted at the beginning of the file + + Done: + - addThrow should convert the typemap by itself + - not possible because routine for attaching mapped types to parameter nodes + won't work for the function node + - turning error codes into exceptions + -> part of output value checking + - create WeakRefs for resources allocated by the library + -> part of output conversion + - TRY..FINALLY..END; can be omitted + - if there is no m3wrapfreearg + - no exception can be raised in the body (empty RAISES) list +*/ + +#include "swigmod.h" + +#include <limits.h> // for INT_MAX +#include <ctype.h> + +#define USAGE_ARG_DIR "m3wrapargdir typemap expect values: in, out, inout\n" + +class MODULA3:public Language { +public: + enum block_type { no_block, constant, variable, blocktype, revelation }; + +private: + struct M3File { + String *f; + Hash *import; + block_type bt; + /* VC++ 6 doesn't allow the access to 'no_block' + if it is a private member of MODULA3 class */ + M3File():f(NewString("")), import(NewHash()), bt(no_block) { + } + ~M3File() { + Delete(f); + Delete(import); + } + + /* ----------------------------------------------------------------------------- + * enterBlock() + * + * Make sure that a given declaration is written to the right declaration block, + * that is constants are written after "CONST" and so on ... + * ----------------------------------------------------------------------------- */ + void enterBlock(block_type newbt) { + static const char *ident[] = { "", "\nCONST\n", "\nVAR\n", "\nTYPE\n", "\nREVEAL\n" }; +#ifdef DEBUG + if ((bt < 0) || (4 < bt)) { + printf("bt %d out of range\n", bt); + } +#endif + if (newbt != bt) { + Append(f, ident[newbt]); + bt = newbt; + } + } + + }; + + static const char *usage; + const String *empty_string; + + Hash *swig_types_hash; + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + + bool proxy_flag; // Flag for generating proxy classes + bool have_default_constructor_flag; + 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 unsafe_module; + + String *m3raw_name; // raw interface name + M3File m3raw_intf; // raw interface + M3File m3raw_impl; // raw implementation (usually empty) + String *m3wrap_name; // wrapper module + M3File m3wrap_intf; + M3File m3wrap_impl; + String *m3makefile; + String *targetlibrary; + String *proxy_class_def; + String *proxy_class_code; + String *proxy_class_name; + String *variable_name; //Name of a variable being wrapped + String *variable_type; //Type of this variable + String *enumeration_name; //Name of the current enumeration type + Hash *enumeration_items; //and its members + int enumeration_max; + Hash *enumeration_coll; //Collection of all enumerations. + /* The items are nodes with members: + "items" - hash of with key 'itemname' and content 'itemvalue' + "max" - maximum value in item list + */ + String *constant_values; + String *constantfilename; + String *renamefilename; + String *typemapfilename; + String *m3raw_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *m3raw_baseclass; //inheritance for intermediary class class from %pragma + String *module_baseclass; //inheritance for module class from %pragma + String *m3raw_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *m3raw_class_modifiers; //class modifiers for intermediary class overriden by %pragma + String *m3wrap_modifiers; //class modifiers for module class overriden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *m3raw_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *destructor_call; //C++ destructor call if any + String *outfile; + + enum type_additions { none, pointer, reference }; + +public: + + /* ----------------------------------------------------------------------------- + * MODULA3() + * ----------------------------------------------------------------------------- */ + +MODULA3(): + empty_string(NewString("")), + swig_types_hash(NULL), + f_begin(NULL), + f_runtime(NULL), + f_header(NULL), + f_wrappers(NULL), + f_init(NULL), + proxy_flag(true), + have_default_constructor_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), + unsafe_module(false), + m3raw_name(NULL), + m3raw_intf(), + m3raw_impl(), + m3wrap_name(NULL), + m3wrap_intf(), + m3wrap_impl(), + m3makefile(NULL), + targetlibrary(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + proxy_class_name(NULL), + variable_name(NULL), + variable_type(NULL), + enumeration_name(NULL), + enumeration_items(NULL), + enumeration_max(0), + enumeration_coll(NULL), + constant_values(NULL), + constantfilename(NULL), + renamefilename(NULL), + typemapfilename(NULL), + m3raw_imports(NULL), + module_imports(NULL), + m3raw_baseclass(NULL), + module_baseclass(NULL), + m3raw_interfaces(NULL), + module_interfaces(NULL), + m3raw_class_modifiers(NULL), + m3wrap_modifiers(NULL), + upcasts_code(NULL), + m3raw_cppcasts_code(NULL), + destructor_call(NULL), + outfile(NULL) { + } + + /************** some utility functions ***************/ + + /* ----------------------------------------------------------------------------- + * getMappedType() + * + * Return the type of 'p' mapped by 'map'. + * Print a standard warning if 'p' can't be mapped. + * ----------------------------------------------------------------------------- */ + + String *getMappedType(Node *p, const char *map) { + String *mapattr = NewString("tmap:"); + Append(mapattr, map); + + String *tm = Getattr(p, mapattr); + if (tm == NIL) { + Swig_warning(WARN_MODULA3_TYPEMAP_TYPE_UNDEF, input_file, line_number, + "No '%s' typemap defined for type '%s'\n", map, SwigType_str(Getattr(p, "type"), 0)); + } + Delete(mapattr); + return tm; + } + + /* ----------------------------------------------------------------------------- + * getMappedTypeNew() + * + * Similar to getMappedType but uses Swig_type_lookup_new. + * ----------------------------------------------------------------------------- */ + + String *getMappedTypeNew(Node *n, const char *map, const char *lname = "", bool warn = true) { + String *tm = Swig_typemap_lookup(map, n, lname, 0); + if ((tm == NIL) && warn) { + Swig_warning(WARN_MODULA3_TYPEMAP_TYPE_UNDEF, input_file, line_number, + "No '%s' typemap defined for type '%s'\n", map, SwigType_str(Getattr(n, "type"), 0)); + } + return tm; + } + + /* ----------------------------------------------------------------------------- + * attachMappedType() + * + * Obtain the type mapped by 'map' and attach it to the node + * ----------------------------------------------------------------------------- */ + + void attachMappedType(Node *n, const char *map, const char *lname = "") { + String *tm = Swig_typemap_lookup(map, n, lname, 0); + if (tm != NIL) { + String *attr = NewStringf("tmap:%s", map); + Setattr(n, attr, tm); + Delete(attr); + } + } + + /* ----------------------------------------------------------------------------- + * skipIgnored() + * + * Skip all parameters that have 'numinputs=0' + * with respect to a given typemap. + * ----------------------------------------------------------------------------- */ + + Node *skipIgnored(Node *p, const char *map) { + String *niattr = NewStringf("tmap:%s:numinputs", map); + String *nextattr = NewStringf("tmap:%s:next", map); + + while ((p != NIL) && checkAttribute(p, niattr, "0")) { + p = Getattr(p, nextattr); + } + + Delete(nextattr); + Delete(niattr); + return p; + } + + /* ----------------------------------------------------------------------------- + * isInParam() + * isOutParam() + * + * Check if the parameter is intended for input or for output. + * ----------------------------------------------------------------------------- */ + + bool isInParam(Node *p) { + String *dir = Getattr(p, "tmap:m3wrapargdir"); +//printf("dir for %s: %s\n", Char(Getattr(p,"name")), Char(dir)); + if ((dir == NIL) || (Strcmp(dir, "in") == 0) + || (Strcmp(dir, "inout") == 0)) { + return true; + } else if (Strcmp(dir, "out") == 0) { + return false; + } else { + printf("%s", USAGE_ARG_DIR); + return false; + } + } + + bool isOutParam(Node *p) { + String *dir = Getattr(p, "tmap:m3wrapargdir"); + if ((dir == NIL) || (Strcmp(dir, "in") == 0)) { + return false; + } else if ((Strcmp(dir, "out") == 0) || (Strcmp(dir, "inout") == 0)) { + return true; + } else { + printf("%s", USAGE_ARG_DIR); + return false; + } + } + + /* ----------------------------------------------------------------------------- + * printAttrs() + * + * For debugging: Show all attributes of a node and their values. + * ----------------------------------------------------------------------------- */ + void printAttrs(Node *n) { + Iterator it; + for (it = First(n); it.key != NIL; it = Next(it)) { + printf("%s = %s\n", Char(it.key), Char(Getattr(n, it.key))); + } + } + + /* ----------------------------------------------------------------------------- + * hasPrefix() + * + * Check if a string have a given prefix. + * ----------------------------------------------------------------------------- */ + bool hasPrefix(const String *str, const String *prefix) { + int len_prefix = Len(prefix); + return (Len(str) > len_prefix) + && (Strncmp(str, prefix, len_prefix) == 0); + } + + /* ----------------------------------------------------------------------------- + * getQualifiedName() + * + * Return fully qualified identifier of n. + * ----------------------------------------------------------------------------- */ +#if 0 + // Swig_symbol_qualified returns NIL for enumeration nodes + String *getQualifiedName(Node *n) { + String *qual = Swig_symbol_qualified(n); + String *name = Getattr(n, "name"); + if (hasContent(qual)) { + return NewStringf("%s::%s", qual, name); + } else { + return name; + } + } +#else + String *getQualifiedName(Node *n) { + String *name = Copy(Getattr(n, "name")); + n = parentNode(n); + while (n != NIL) { + const String *type = nodeType(n); + if ((Strcmp(type, "class") == 0) || (Strcmp(type, "struct") == 0) || (Strcmp(type, "namespace") == 0)) { + String *newname = NewStringf("%s::%s", Getattr(n, "name"), name); + Delete(name); + //name = newname; + // Hmpf, the class name is already qualified. + return newname; + } + n = parentNode(n); + } + //printf("qualified name: %s\n", Char(name)); + return name; + } +#endif + + /* ----------------------------------------------------------------------------- + * nameToModula3() + * + * Turn usual C identifiers like "this_is_an_identifier" + * into usual Modula 3 identifier like "thisIsAnIdentifier" + * ----------------------------------------------------------------------------- */ + String *nameToModula3(const String *sym, bool leadingCap) { + int len_sym = Len(sym); + char *csym = Char(sym); + char *m3sym = new char[len_sym + 1]; + int i, j; + bool cap = leadingCap; + for (i = 0, j = 0; j < len_sym; j++) { + char c = csym[j]; + if ((c == '_') || (c == ':')) { + cap = true; + } else { + if (isdigit(c)) { + m3sym[i] = c; + cap = true; + } else { + if (cap) { + m3sym[i] = (char)toupper(c); + } else { + m3sym[i] = (char)tolower(c); + } + cap = false; + } + i++; + } + } + m3sym[i] = 0; + String *result = NewString(m3sym); + delete[]m3sym; + return result; + } + + /* ----------------------------------------------------------------------------- + * capitalizeFirst() + * + * Make the first character upper case. + * ----------------------------------------------------------------------------- */ + String *capitalizeFirst(const String *str) { + return NewStringf("%c%s", toupper(*Char(str)), Char(str) + 1); + } + + /* ----------------------------------------------------------------------------- + * prefixedNameToModula3() + * + * If feature modula3:oldprefix and modula3:newprefix is present + * and the C identifier has leading 'oldprefix' + * then it is replaced by the 'newprefix'. + * The rest is converted to Modula style. + * ----------------------------------------------------------------------------- */ + String *prefixedNameToModula3(Node *n, const String *sym, bool leadingCap) { + String *oldPrefix = Getattr(n, "feature:modula3:oldprefix"); + String *newPrefix = Getattr(n, "feature:modula3:newprefix"); + String *result = NewString(""); + char *short_sym = Char(sym); + // if at least one prefix feature is present + // the replacement takes place + if ((oldPrefix != NIL) || (newPrefix != NIL)) { + if ((oldPrefix == NIL) || hasPrefix(sym, oldPrefix)) { + short_sym += Len(oldPrefix); + if (newPrefix != NIL) { + Append(result, newPrefix); + } + } + } + String *suffix = nameToModula3(short_sym, leadingCap || hasContent(newPrefix)); + Append(result, suffix); + Delete(suffix); + return result; + } + + /* ----------------------------------------------------------------------------- + * hasContent() + * + * Check if the string exists and contains something. + * ----------------------------------------------------------------------------- */ + bool hasContent(const String *str) { + return (str != NIL) && (Strcmp(str, "") != 0); + } + + /* ----------------------------------------------------------------------------- + * openWriteFile() + * + * Caution: The file must be freshly allocated and will be destroyed + * by this routine. + * ----------------------------------------------------------------------------- */ + + File *openWriteFile(String *name) { + File *file = NewFile(name, "w", SWIG_output_files()); + if (!file) { + FileErrorDisplay(name); + SWIG_exit(EXIT_FAILURE); + } + Delete(name); + return file; + } + + /* ----------------------------------------------------------------------------- + * aToL() + * + * like atol but with additional user warning + * ----------------------------------------------------------------------------- */ + + long aToL(const String *value) { + char *endptr; + long numvalue = strtol(Char(value), &endptr, 0); + if (*endptr != 0) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The string <%s> does not denote a numeric value.\n", value); + } + return numvalue; + } + + /* ----------------------------------------------------------------------------- + * strToL() + * + * like strtol but returns if the conversion was successful + * ----------------------------------------------------------------------------- */ + + bool strToL(const String *value, long &numvalue) { + char *endptr; + numvalue = strtol(Char(value), &endptr, 0); + return (*endptr == 0); + } + + /* ----------------------------------------------------------------------------- + * evalExpr() + * + * Evaluate simple expression as they may occur in "enumvalue" attributes. + * ----------------------------------------------------------------------------- */ + + bool evalExpr(String *value, long &numvalue) { + // Split changes file status of String and thus cannot receive 'const' strings +//printf("evaluate <%s>\n", Char(value)); + List *summands = Split(value, '+', INT_MAX); + Iterator sm = First(summands); + numvalue = 0; + for (; sm.item != NIL; sm = Next(sm)) { + String *smvalue = Getattr(constant_values, sm.item); + long smnumvalue; + if (smvalue != NIL) { + if (!strToL(smvalue, smnumvalue)) { +//printf("evaluation: abort 0 <%s>\n", Char(smvalue)); + return false; + } + } else { + if (!strToL(sm.item, smnumvalue)) { +//printf("evaluation: abort 1 <%s>\n", Char(sm)); + return false; + } + } + numvalue += smnumvalue; + } +//printf("evaluation: return %ld\n", numvalue); + return true; + } + + /* ----------------------------------------------------------------------------- + * log2() + * + * Determine the position of the single bit of a power of two. + * Returns true if the given number is a power of two. + * ----------------------------------------------------------------------------- */ + + bool log2(long n, long &exp) { + exp = 0; + while (n > 0) { + if ((n & 1) != 0) { + return n == 1; + } + exp++; + n >>= 1; + } + return false; + } + + /* ----------------------------------------------------------------------------- + * writeArg + * + * Write a function argument or RECORD entry definition. + * Bundles arguments of same type and default value. + * 'name.next==NIL' denotes the end of the entry or argument list. + * ----------------------------------------------------------------------------- */ + + bool equalNilStr(const String *str0, const String *str1) { + if (str0 == NIL) { + return (str1 == NIL); + //return (str0==NIL) == (str1==NIL); + } else { + return (str1 != NIL) && (Cmp(str0, str1) == 0); + //return Cmp(str0,str1)==0; + } + } + + struct writeArgState { + String *mode, *name, *type, *value; + bool hold; + writeArgState():mode(NIL), name(NIL), type(NIL), value(NIL), hold(false) { + } + }; + + void writeArg(File *f, writeArgState & state, String *mode, String *name, String *type, String *value) { + /* skip the first argument, + only store the information for the next call in this case */ + if (state.name != NIL) { + if ((!state.hold) && (state.mode != NIL)) { + Printf(f, "%s ", state.mode); + } + if ((name != NIL) && equalNilStr(state.mode, mode) && equalNilStr(state.type, type) && (state.value == NIL) && (value == NIL) + /* the same expression may have different values + due to side effects of the called function */ + /*equalNilStr(state.value,value) */ + ) { + Printf(f, "%s, ", state.name); + state.hold = true; + } else { + Append(f, state.name); + if (state.type != NIL) { + Printf(f, ": %s", state.type); + } + if (state.value != NIL) { + Printf(f, ":= %s", state.value); + } + Append(f, ";\n"); + state.hold = false; + } + } + /* at the next call the current argument will be the previous one */ + state.mode = mode; + state.name = name; + state.type = type; + state.value = value; + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class + * Return NULL if not otherwise the proxy class name + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /*************** language processing ********************/ + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("modula3"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-generateconst") == 0) { + if (argv[i + 1]) { + constantfilename = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-generaterename") == 0) { + if (argv[i + 1]) { + renamefilename = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-generatetypemap") == 0) { + if (argv[i + 1]) { + typemapfilename = NewString(argv[i + 1]); + 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], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGMODULA3 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("modula3"); + SWIG_config_file("modula3.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + if (hasContent(constantfilename) || hasContent(renamefilename) || hasContent(typemapfilename)) { + int result = SWIG_OK; + if (hasContent(constantfilename)) { + result = generateConstantTop(n) && result; + } + if (hasContent(renamefilename)) { + result = generateRenameTop(n) && result; + } + if (hasContent(typemapfilename)) { + result = generateTypemapTop(n) && result; + } + return result; + } else { + return generateM3Top(n); + } + } + + void scanConstant(File *file, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *constname = NIL; + String *type = nodeType(child); + if ((Strcmp(type, "enumitem") == 0) + || (Strcmp(type, "constant") == 0)) { +#if 1 + constname = getQualifiedName(child); +#else + constname = Getattr(child, "value"); + if ((!hasContent(constname)) + || (('0' <= *Char(constname)) && (*Char(constname) <= '9'))) { + constname = Getattr(child, "name"); + } +#endif + } + if (constname != NIL) { + Printf(file, " printf(\"%%%%constnumeric(%%Lg) %s;\\n\", (long double)%s);\n", constname, constname); + } + scanConstant(file, child); + child = nextSibling(child); + } + } + + int generateConstantTop(Node *n) { + File *file = openWriteFile(NewStringf("%s.c", constantfilename)); + if (CPlusPlus) { + Printf(file, "#include <cstdio>\n"); + } else { + Printf(file, "#include <stdio.h>\n"); + } + Printf(file, "#include \"%s\"\n", input_file); + Printf(file, "\n"); + Printf(file, "int main (int argc, char *argv[]) {\n"); + Printf(file, "\ +/*This progam must work for floating point numbers and integers.\n\ + Thus all numbers are converted to double precision floating point format.*/\n"); + scanConstant(file, n); + Printf(file, " return 0;\n"); + Printf(file, "}\n"); + Close(file); + return SWIG_OK; + } + + void scanRename(File *file, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *type = nodeType(child); + if (Strcmp(type, "cdecl") == 0) { + ParmList *p = Getattr(child, "parms"); + if (p != NIL) { + String *name = getQualifiedName(child); + String *m3name = nameToModula3(name, true); + /*don't know how to get the original C type identifiers */ + //String *arguments = createCSignature (child); + Printf(file, "%%rename(\"%s\") %s;\n", m3name, name); + /*Printf(file, "%%rename(\"%s\") %s %s(%s);\n", + m3name, Getattr(n,"type"), name, arguments); */ + Delete(name); + Delete(m3name); + //Delete (arguments); + } + } + scanRename(file, child); + child = nextSibling(child); + } + } + + int generateRenameTop(Node *n) { + File *file = openWriteFile(NewStringf("%s.i", renamefilename)); + Printf(file, "\ +/* This file was generated from %s\n\ + by SWIG with option -generaterename. */\n\ +\n", input_file); + scanRename(file, n); + Close(file); + return SWIG_OK; + } + + void scanTypemap(File *file, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *type = nodeType(child); + //printf("nodetype %s\n", Char(type)); + String *storage = Getattr(child, "storage"); + if ((Strcmp(type, "class") == 0) || ((Strcmp(type, "cdecl") == 0) && (storage != NIL) + && (Strcmp(storage, "typedef") == 0))) { + String *name = getQualifiedName(child); + String *m3name = nameToModula3(name, true); + Printf(file, "%%typemap(\"m3wrapintype\") %s %%{%s%%}\n", name, m3name); + Printf(file, "%%typemap(\"m3rawintype\") %s %%{%s%%}\n", name, m3name); + Printf(file, "\n"); + } + scanTypemap(file, child); + child = nextSibling(child); + } + } + + int generateTypemapTop(Node *n) { + File *file = openWriteFile(NewStringf("%s.i", typemapfilename)); + Printf(file, "\ +/* This file was generated from %s\n\ + by SWIG with option -generatetypemap. */\n\ +\n", input_file); + scanTypemap(file, n); + Close(file); + return SWIG_OK; + } + + int generateM3Top(Node *n) { + /* Initialize all of the output files */ + 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(""); + + m3makefile = 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("m3rawintf", m3raw_intf.f); + Swig_register_filebyname("m3rawimpl", m3raw_impl.f); + Swig_register_filebyname("m3wrapintf", m3wrap_intf.f); + Swig_register_filebyname("m3wrapimpl", m3wrap_impl.f); + Swig_register_filebyname("m3makefile", m3makefile); + + swig_types_hash = NewHash(); + + String *name = Getattr(n, "name"); + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + if (optionsnode != NIL) { + String *m3raw_name_tmp = Getattr(optionsnode, "m3rawname"); + if (m3raw_name_tmp != NIL) { + m3raw_name = Copy(m3raw_name_tmp); + } + } + if (m3raw_name == NIL) { + m3raw_name = NewStringf("%sRaw", name); + } + Setattr(m3wrap_impl.import, m3raw_name, ""); + + m3wrap_name = Copy(name); + + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + m3raw_baseclass = NewString(""); + m3raw_interfaces = NewString(""); + m3raw_class_modifiers = NewString(""); // package access only to the intermediary class by default + m3raw_imports = NewString(""); + m3raw_cppcasts_code = NewString(""); + m3wrap_modifiers = NewString("public"); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + upcasts_code = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGMODULA3\n"); + Printf(f_runtime, "\n"); + + Swig_name_register((char *) "wrapper", (char *) "Modula3_%f"); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%v"); + } + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + constant_values = NewHash(); + scanForConstPragmas(n); + enumeration_coll = NewHash(); + collectEnumerations(enumeration_coll, n); + + /* Emit code */ + Language::top(n); + + // Generate m3makefile + // This will be unnecessary if SWIG is invoked from Quake. + { + File *file = openWriteFile(NewStringf("%sm3makefile", Swig_file_dirname(outfile))); + + Printf(file, "%% automatically generated quake file for %s\n\n", name); + + /* Write the fragments written by '%insert' + collected while 'top' processed the parse tree */ + Printv(file, m3makefile, NIL); + + Printf(file, "import(\"libm3\")\n"); + //Printf(file, "import_lib(\"%s\",\"/usr/lib\")\n", name); + Printf(file, "module(\"%s\")\n", m3raw_name); + Printf(file, "module(\"%s\")\n\n", m3wrap_name); + + if (targetlibrary != NIL) { + Printf(file, "library(\"%s\")\n", targetlibrary); + } else { + Printf(file, "library(\"m3%s\")\n", name); + } + Close(file); + } + + // Generate the raw interface + { + File *file = openWriteFile(NewStringf("%s%s.i3", Swig_file_dirname(outfile), m3raw_name)); + + emitBanner(file); + + Printf(file, "INTERFACE %s;\n\n", m3raw_name); + + emitImportStatements(m3raw_intf.import, file); + Printf(file, "\n"); + + // Write the interface generated within 'top' + Printv(file, m3raw_intf.f, NIL); + + Printf(file, "\nEND %s.\n", m3raw_name); + Close(file); + } + + // Generate the raw module + { + File *file = openWriteFile(NewStringf("%s%s.m3", Swig_file_dirname(outfile), m3raw_name)); + + emitBanner(file); + + Printf(file, "MODULE %s;\n\n", m3raw_name); + + emitImportStatements(m3raw_impl.import, file); + Printf(file, "\n"); + + // will be empty usually + Printv(file, m3raw_impl.f, NIL); + + Printf(file, "BEGIN\nEND %s.\n", m3raw_name); + Close(file); + } + + // Generate the interface for the comfort wrappers + { + File *file = openWriteFile(NewStringf("%s%s.i3", Swig_file_dirname(outfile), m3wrap_name)); + + emitBanner(file); + + Printf(file, "INTERFACE %s;\n", m3wrap_name); + + emitImportStatements(m3wrap_intf.import, file); + Printf(file, "\n"); + + { + Iterator it = First(enumeration_coll); + if (it.key != NIL) { + Printf(file, "TYPE\n"); + } + for (; it.key != NIL; it = Next(it)) { + Printf(file, "\n"); + emitEnumeration(file, it.key, it.item); + } + } + + // Add the wrapper methods + Printv(file, m3wrap_intf.f, NIL); + + // Finish off the class + Printf(file, "\nEND %s.\n", m3wrap_name); + Close(file); + } + + // Generate the wrapper routines implemented in Modula 3 + { + File *file = openWriteFile(NewStringf("%s%s.m3", Swig_file_dirname(outfile), m3wrap_name)); + + emitBanner(file); + + if (unsafe_module) { + Printf(file, "UNSAFE "); + } + Printf(file, "MODULE %s;\n\n", m3wrap_name); + + emitImportStatements(m3wrap_impl.import, file); + Printf(file, "\n"); + + // Add the wrapper methods + Printv(file, m3wrap_impl.f, NIL); + + Printf(file, "\nBEGIN\nEND %s.\n", m3wrap_name); + Close(file); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a Modula 3 type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.item != NIL; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + Delete(swig_types_hash); + swig_types_hash = NULL; + Delete(constant_values); + constant_values = NULL; + Delete(enumeration_coll); + enumeration_coll = NULL; + Delete(m3raw_name); + m3raw_name = NULL; + Delete(m3raw_baseclass); + m3raw_baseclass = NULL; + Delete(m3raw_interfaces); + m3raw_interfaces = NULL; + Delete(m3raw_class_modifiers); + m3raw_class_modifiers = NULL; + Delete(m3raw_imports); + m3raw_imports = NULL; + Delete(m3raw_cppcasts_code); + m3raw_cppcasts_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(m3wrap_name); + m3wrap_name = NULL; + Delete(m3wrap_modifiers); + m3wrap_modifiers = NULL; + Delete(targetlibrary); + targetlibrary = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(constantfilename); + constantfilename = NULL; + Delete(renamefilename); + renamefilename = NULL; + Delete(typemapfilename); + typemapfilename = NULL; + + /* 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); + Close(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"); + } + + /* ---------------------------------------------------------------------- + * 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 { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, Getattr(n, "wrap:name")); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + String *type = nodeType(n); + String *funcType = Getattr(n, "modula3:functype"); + String *rawname = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *capname = capitalizeFirst(symname); + //String *wname = Swig_name_wrapper(symname); + + //printf("function: %s\n", Char(symname)); + //printf(" purpose: %s\n", Char(funcType)); + + if (Strcmp(type, "cdecl") == 0) { + if (funcType == NIL) { + // no wrapper needed for plain functions + emitM3RawPrototype(n, rawname, symname); + emitM3Wrapper(n, symname); + } else if (Strcmp(funcType, "method") == 0) { + Setattr(n, "modula3:funcname", capname); + emitCWrapper(n, capname); + emitM3RawPrototype(n, capname, capname); + emitM3Wrapper(n, capname); + } else if (Strcmp(funcType, "accessor") == 0) { + /* + * 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 function name + Setattr(n, "proxyfuncname", capname); + Setattr(n, "imfuncname", symname); + if (hasPrefix(capname, "Set")) { + Setattr(n, "modula3:setname", capname); + } else { + Setattr(n, "modula3:getname", capname); + } + + emitCWrapper(n, capname); + emitM3RawPrototype(n, capname, capname); + emitM3Wrapper(n, capname); + //proxyClassFunctionHandler(n); + } +#ifdef DEBUG + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Function type <%s> unknown.\n", Char(funcType)); +#endif + } + } else if ((Strcmp(type, "constructor") == 0) || (Strcmp(type, "destructor") == 0)) { + emitCWrapper(n, capname); + emitM3RawPrototype(n, capname, capname); + emitM3Wrapper(n, capname); + } +// a Java relict +#if 0 + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + emitM3Wrapper(n, capname); + } +#endif + + Delete(capname); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * emitCWrapper() + * + * Generate the wrapper in C which calls C++ methods. + * ---------------------------------------------------------------------- */ + + virtual int emitCWrapper(Node *n, const String *wname) { + String *rawname = Getattr(n, "name"); + String *c_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + Hash *throws_hash = NewHash(); + ParmList *l = Getattr(n, "parms"); + SwigType *t = Getattr(n, "type"); + String *symname = Getattr(n, "sym:name"); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(wname, n)) { + return SWIG_ERROR; + } + } + // A new wrapper function object + Wrapper *f = NewWrapper(); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("ctype", l, f); + + /* Get return types */ + { + String *tm = getMappedTypeNew(n, "ctype", ""); + if (tm != NIL) { + Printf(c_return_type, "%s", tm); + } + } + + bool is_void_return = (Cmp(c_return_type, "void") == 0); + if (!is_void_return) { + Wrapper_add_localv(f, "cresult", c_return_type, "cresult = 0", 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); + Setattr(n, "wrap:parms", l); + + // Generate signature and argument conversion for C wrapper + { + Parm *p; + attachParameterNames(n, "tmap:name", "c:wrapname", "m3arg%d"); + bool gencomma = false; + for (p = skipIgnored(l, "in"); p != NULL; p = skipIgnored(p, "in")) { + + String *arg = Getattr(p, "c:wrapname"); + { + /* Get the ctype types of the parameter */ + String *c_param_type = getMappedType(p, "ctype"); + // Add parameter to C function + Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + Delete(c_param_type); + gencomma = true; + } + + // Get typemap for this argument + String *tm = getMappedType(p, "in"); + if (tm != NIL) { + addThrows(throws_hash, "in", p); + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); /*??? */ + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Insert constraint checking code */ + { + Parm *p; + for (p = l; p;) { + String *tm = Getattr(p, "tmap:check"); + if (tm != NIL) { + addThrows(throws_hash, "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 */ + { + Parm *p; + for (p = l; p;) { + String *tm = Getattr(p, "tmap:freearg"); + if (tm != NIL) { + addThrows(throws_hash, "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 */ + { + Parm *p; + for (p = l; p;) { + String *tm = Getattr(p, "tmap:argout"); + if (tm != NIL) { + addThrows(throws_hash, "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", "cresult"); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + } + + // Get any Modula 3 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); + Parm *p; + for (p = throw_parm_list; p; p = nextSibling(p)) { + addThrows(throws_hash, "throws", p); + } + } + + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Setattr(n, "wrap:name", wname); + + // Now write code to make the function call + if (!native_function_flag) { + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) { + Swig_restore(n); + } + + /* Return value if necessary */ + String *tm; + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + addThrows(throws_hash, "out", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Replaceall(tm, "$target", "cresult"); /* deprecated */ + Replaceall(tm, "$result", "cresult"); + Printf(f->code, "%s", tm); + if (hasContent(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), rawname); + } + 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")) { + String *tm = Swig_typemap_lookup("newfree", n, "result", 0); + if (tm != NIL) { + addThrows(throws_hash, "newfree", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if (!native_function_flag) { + String *tm = Swig_typemap_lookup("ret", n, "result", 0); + if (tm != NIL) { + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C wrapper */ + Printf(f->def, ") {"); + + if (!is_void_return) + Printv(f->code, " return cresult;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + 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); + } + + Delete(c_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(throws_hash); + DelWrapper(f); + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * emitM3RawPrototype() + * + * Generate an EXTERNAL procedure declaration in Modula 3 + * which is the interface to an existing C routine or a C wrapper. + * ---------------------------------------------------------------------- */ + + virtual int emitM3RawPrototype(Node *n, const String *cname, const String *m3name) { + String *im_return_type = NewString(""); + //String *symname = Getattr(n,"sym:name"); + ParmList *l = Getattr(n, "parms"); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("m3rawinmode", l, NULL); + Swig_typemap_attach_parms("m3rawintype", l, NULL); + + /* Get return types */ + bool has_return; + { + String *tm = getMappedTypeNew(n, "m3rawrettype", ""); + if (tm != NIL) { + Printf(im_return_type, "%s", tm); + } + has_return = hasContent(tm); + } + + /* cname is the original name if 'n' denotes a C function + and it is the relabeled name (sym:name) if 'n' denotes a C++ method or similar */ + m3raw_intf.enterBlock(no_block); + Printf(m3raw_intf.f, "\n<* EXTERNAL %s *>\nPROCEDURE %s (", cname, m3name); + + // Generate signature for raw interface + { + Parm *p; + writeArgState state; + attachParameterNames(n, "tmap:rawinname", "modula3:rawname", "arg%d"); + for (p = skipIgnored(l, "m3rawintype"); p != NULL; p = skipIgnored(p, "m3rawintype")) { + + /* Get argument passing mode, should be one of VALUE, VAR, READONLY */ + String *mode = Getattr(p, "tmap:m3rawinmode"); + String *argname = Getattr(p, "modula3:rawname"); + String *im_param_type = getMappedType(p, "m3rawintype"); + addImports(m3raw_intf.import, "m3rawintype", p); + + writeArg(m3raw_intf.f, state, mode, argname, im_param_type, NIL); + if (im_param_type != NIL) { + p = Getattr(p, "tmap:m3rawintype:next"); + } else { + p = nextSibling(p); + } + } + writeArg(m3raw_intf.f, state, NIL, NIL, NIL, NIL); + } + + /* Finish M3 raw prototype */ + Printf(m3raw_intf.f, ")"); + // neither a C wrapper nor a plain C function may throw an exception + //generateThrowsClause(throws_hash, m3raw_intf.f); + if (has_return) { + Printf(m3raw_intf.f, ": %s", im_return_type); + } + Printf(m3raw_intf.f, ";\n"); + + Delete(im_return_type); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + Language::variableWrapper(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * globalvariableHandler() + * ----------------------------------------------------------------------- */ + + virtual int globalvariableHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + + variable_name = Getattr(n, "sym:name"); + variable_type = Copy(tm); + + // Get the variable type expressed in terms of Modula 3 equivalents of C types + if ((tm = getMappedTypeNew(n, "m3rawtype", ""))) { + m3raw_intf.enterBlock(no_block); + Printf(m3raw_intf.f, "\n<* EXTERNAL *> VAR %s: %s;\n", variable_name, tm); + } + // Output the property's accessor methods + /* + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + */ + + Printf(m3wrap_impl.f, "\n\n"); + + //return ret; + return 1; + } + + long getConstNumeric(Node *n) { + String *constnumeric = Getfeature(n, "constnumeric"); + String *name = Getattr(n, "name"); + long numvalue; + if (constnumeric == NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Feature 'constnumeric' is necessary to obtain value of %s.\n", name); + return 0; + } else if (!strToL(constnumeric, numvalue)) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, + "The feature 'constnumeric' of %s specifies value <%s> which is not an integer constant.\n", name, constnumeric); + return 0; + } else { + return numvalue; + } + } + + /* ------------------------------------------------------------------------ + * generateIntConstant() + * + * Considers node as an integer constant definition + * and generate a Modula 3 constant definition. + * ------------------------------------------------------------------------ */ + void generateIntConstant(Node *n, String *name) { + String *value = Getattr(n, "value"); + String *type = Getfeature(n, "modula3:constint:type"); + String *conv = Getfeature(n, "modula3:constint:conv"); + + if (name == NIL) { + name = Getattr(n, "sym:name"); + } + + long numvalue; + bool isSimpleNum = strToL(value, numvalue); + if (!isSimpleNum) { + numvalue = getConstNumeric(n); + } + + String *m3value; + if ((conv == NIL) || ((Strcmp(conv, "set:int") != 0) && (Strcmp(conv, "int:set") != 0))) { + /* The original value of the constant has precedence over + 'constnumeric' feature since we like to keep + the style (that is the base) of simple numeric constants */ + if (isSimpleNum) { + if (hasPrefix(value, "0x")) { + m3value = NewStringf("16_%s", Char(value) + 2); + } else if ((Len(value) > 1) && (*Char(value) == '0')) { + m3value = NewStringf("8_%s", Char(value) + 1); + } else { + m3value = Copy(value); + } + /* If we cannot easily obtain the value of a numeric constant, + we use the results given by a C compiler. */ + } else { + m3value = Copy(Getfeature(n, "constnumeric")); + } + } else { + // if the value can't be converted, it is ignored + if (convertInt(numvalue, numvalue, conv)) { + m3value = NewStringf("%d", numvalue); + } else { + m3value = NIL; + } + } + + if (m3value != NIL) { + m3wrap_intf.enterBlock(constant); + Printf(m3wrap_intf.f, "%s", name); + if (hasContent(type)) { + Printf(m3wrap_intf.f, ": %s", type); + } + Printf(m3wrap_intf.f, " = %s;\n", m3value); + Delete(m3value); + } + } + + /* ----------------------------------------------------------------------- + * generateSetConstant() + * + * Considers node as a set constant definition + * and generate a Modula 3 constant definition. + * ------------------------------------------------------------------------ */ + void generateSetConstant(Node *n, String *name) { + String *value = Getattr(n, "value"); + String *type = Getfeature(n, "modula3:constset:type"); + String *setname = Getfeature(n, "modula3:constset:set"); + String *basename = Getfeature(n, "modula3:constset:base"); + String *conv = Getfeature(n, "modula3:constset:conv"); + + m3wrap_intf.enterBlock(constant); + + Printf(m3wrap_intf.f, "%s", name); + if (type != NIL) { + Printf(m3wrap_intf.f, ":%s ", type); + } + Printf(m3wrap_intf.f, " = %s{", setname); + + long numvalue = 0; + if (!strToL(value, numvalue)) { + numvalue = getConstNumeric(n); + } + convertInt(numvalue, numvalue, conv); + + bool isIntType = Strcmp(basename, "CARDINAL") == 0; + Hash *items = NIL; + if (!isIntType) { + Hash *enumeration = Getattr(enumeration_coll, basename); + if (enumeration == NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "There is no enumeration <%s> as needed for the set.\n", setname); + isIntType = true; + } else { + items = Getattr(enumeration, "items"); + } + } + + bool gencomma = false; + int bitpos = 0; + while (numvalue > 0) { + if ((numvalue & 1) != 0) { + if (isIntType) { + if (gencomma) { + Printv(m3wrap_intf.f, ",", NIL); + } + gencomma = true; + Printf(m3wrap_intf.f, "%d", bitpos); + } else { + char bitval[15]; + sprintf(bitval, "%d", bitpos); + String *bitname = Getattr(items, bitval); + if (bitname == NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Enumeration <%s> has no value <%s>.\n", setname, bitval); + } else { + if (gencomma) { + Printv(m3wrap_intf.f, ",", NIL); + } + gencomma = true; + Printf(m3wrap_intf.f, "%s.%s", basename, bitname); + } + } + } + numvalue >>= 1; + bitpos++; + } + Printf(m3wrap_intf.f, "};\n"); + } + + void generateConstant(Node *n) { + // any of the special interpretation disables the default behaviour + String *enumitem = Getfeature(n, "modula3:enumitem:name"); + String *constset = Getfeature(n, "modula3:constset:name"); + String *constint = Getfeature(n, "modula3:constint:name"); + if (hasContent(enumitem) || hasContent(constset) || hasContent(constint)) { + if (hasContent(constset)) { + generateSetConstant(n, constset); + } + if (hasContent(constint)) { + generateIntConstant(n, constint); + } + } else { + String *value = Getattr(n, "value"); + String *name = Getattr(n, "sym:name"); + if (name == NIL) { + name = Getattr(n, "name"); + } + m3wrap_intf.enterBlock(constant); + Printf(m3wrap_intf.f, "%s = %s;\n", name, value); + } + } + +#if 0 + void generateEnumerationItem(const String *name, const String *value, int numvalue) { + String *oldsymname = Getattr(enumeration_items, value); + if (oldsymname != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The value <%s> is already assigned to <%s>.\n", value, oldsymname); + } + Setattr(enumeration_items, value, name); + if (enumeration_max < numvalue) { + enumeration_max = numvalue; + } + } +#endif + + void emitEnumeration(File *file, String *name, Node *n) { + Printf(file, "%s = {", name); + int i; + bool gencomma = false; + int max = aToL(Getattr(n, "max")); + Hash *items = Getattr(n, "items"); + for (i = 0; i <= max; i++) { + if (gencomma) { + Printf(file, ","); + } + Printf(file, "\n"); + gencomma = true; + char numstr[15]; + sprintf(numstr, "%d", i); + String *name = Getattr(items, numstr); + if (name != NIL) { + Printv(file, name, NIL); + } else { + Printf(file, "Dummy%d", i); + } + } + Printf(file, "\n};\n"); + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * + * Handles constants and enumeration items. + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + generateConstant(n); + return SWIG_OK; + } + +#if 0 +// enumerations are handled like constant definitions + /* ----------------------------------------------------------------------------- + * enumDeclaration() + * ----------------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + String *symname = nameToModula3(Getattr(n, "sym:name"), true); + enumerationStart(symname); + int result = Language::enumDeclaration(n); + enumerationStop(); + Delete(symname); + return result; + } +#endif + + /* ----------------------------------------------------------------------------- + * enumvalueDeclaration() + * ----------------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + generateConstant(n); + /* + This call would continue processing in the constantWrapper + which cannot handle values like "RED+1". + return Language::enumvalueDeclaration(n); + */ + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * imclassbase - base (extends) for the intermediary class + * imclassclassmodifiers - class modifiers for the intermediary class + * imclasscode - text (Modula 3 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 (Modula 3 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, "modula3") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); +/* + bool isEnumItem = Strcmp(code, "enumitem") == 0; + bool isSetItem = Strcmp(code, "setitem") == 0; +*/ + if (Strcmp(code, "imclassbase") == 0) { + Delete(m3raw_baseclass); + m3raw_baseclass = Copy(strvalue); + } else if (Strcmp(code, "imclassclassmodifiers") == 0) { + Delete(m3raw_class_modifiers); + m3raw_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "imclasscode") == 0) { + Printf(m3raw_intf.f, "%s\n", strvalue); + } else if (Strcmp(code, "imclassimports") == 0) { + Delete(m3raw_imports); + m3raw_imports = Copy(strvalue); + } else if (Strcmp(code, "imclassinterfaces") == 0) { + Delete(m3raw_interfaces); + m3raw_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(m3wrap_modifiers); + m3wrap_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(m3wrap_impl.f, "%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, "unsafe") == 0) { + unsafe_module = true; + } else if (Strcmp(code, "library") == 0) { + if (targetlibrary != NULL) { + Delete(targetlibrary); + } + targetlibrary = Copy(strvalue); + } else if (Strcmp(code, "enumitem") == 0) { + } else if (Strcmp(code, "constset") == 0) { + } else if (Strcmp(code, "constint") == 0) { + } else if (Strcmp(code, "makesetofenum") == 0) { + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%sSet = SET OF %s;\n", value, value); + } else { + Swig_warning(WARN_MODULA3_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", code); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + void Setfeature(Node *n, const char *feature, const String *value, bool warn = false) { + //printf("tag feature <%s> with value <%s>\n", feature, Char(value)); + String *attr = NewStringf("feature:%s", feature); + if ((Setattr(n, attr, value) != 0) && warn) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Feature <%s> of %s did already exist.\n", feature, Getattr(n, "name")); + } + Delete(attr); + } + + String *Getfeature(Node *n, const char *feature) { + //printf("retrieve feature <%s> with value <%s>\n", feature, Char(value)); + String *attr = NewStringf("feature:%s", feature); + String *result = Getattr(n, attr); + Delete(attr); + return result; + } + + bool convertInt(long in, long &out, const String *mode) { + if ((mode == NIL) || (Strcmp(mode, "int:int") == 0) || (Strcmp(mode, "set:set") == 0)) { + out = in; + return true; + } else if (Strcmp(mode, "set:int") == 0) { + return log2(in, out); + } else if (Strcmp(mode, "int:set") == 0) { + out = 1L << in; + return unsigned (in) < (sizeof(out) * 8); + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown integer conversion method <%s>.\n", mode); + return false; + } + } + + void collectEnumerations(Hash *enums, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *name = Getattr(child, "name"); + const bool isConstant = Strcmp(nodeType(child), "constant") == 0; + const bool isEnumItem = Strcmp(nodeType(child), "enumitem") == 0; + if (isConstant || isEnumItem) { +//printf("%s%s name %s\n", isConstant?"constant":"", isEnumItem?"enumitem":"", Char(name)); + { + String *m3name = Getfeature(child, "modula3:enumitem:name"); + String *m3enum = Getfeature(child, "modula3:enumitem:enum"); + String *conv = Getfeature(child, "modula3:enumitem:conv"); + + if (m3enum != NIL) { +//printf("m3enum %s\n", Char(m3enum)); + if (m3name == NIL) { + m3name = name; + } + + long max = -1; + Hash *items; + Hash *enumnode = Getattr(enums, m3enum); + if (enumnode == NIL) { + enumnode = NewHash(); + items = NewHash(); + Setattr(enumnode, "items", items); + Setattr(enums, m3enum, enumnode); + } else { + String *maxstr = Getattr(enumnode, "max"); + if (maxstr != NIL) { + max = aToL(maxstr); + } + items = Getattr(enumnode, "items"); + } + long numvalue; + String *value = Getattr(child, "value"); +//printf("value: %s\n", Char(value)); + if ((value == NIL) || (!strToL(value, numvalue))) { + value = Getattr(child, "enumvalue"); + if ((value == NIL) || (!evalExpr(value, numvalue))) { + numvalue = getConstNumeric(child); + } +//printf("constnumeric: %s\n", Char(value)); + } + Setattr(constant_values, name, NewStringf("%d", numvalue)); + if (convertInt(numvalue, numvalue, conv)) { + String *newvalue = NewStringf("%d", numvalue); + String *oldname = Getattr(items, newvalue); + if (oldname != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The value <%s> is already assigned to <%s>.\n", value, oldname); + } +//printf("items %lx, set %s = %s\n", (long) items, Char(newvalue), Char(m3name)); + Setattr(items, newvalue, m3name); + if (max < numvalue) { + max = numvalue; + } + Setattr(enumnode, "max", NewStringf("%d", max)); + } + } + } + } + + collectEnumerations(enums, child); + child = nextSibling(child); + } + } + + enum const_pragma_type { cpt_none, cpt_constint, cpt_constset, cpt_enumitem }; + + struct const_id_pattern { + String *prefix, *parentEnum; + }; + + void tagConstants(Node *first, String *parentEnum, const const_id_pattern & pat, const String *pragma, List *convdesc) { + Node *n = first; + while (n != NIL) { + String *name = getQualifiedName(n); + bool isConstant = Strcmp(nodeType(n), "constant") == 0; + bool isEnumItem = Strcmp(nodeType(n), "enumitem") == 0; + if ((isConstant || isEnumItem) && ((pat.prefix == NIL) || (hasPrefix(name, pat.prefix))) && ((pat.parentEnum == NIL) || ((parentEnum != NIL) + && + (Strcmp + (pat.parentEnum, parentEnum) + == 0)))) { + //printf("tag %s\n", Char(name)); + String *srctype = Getitem(convdesc, 1); + String *relationstr = Getitem(convdesc, 3); + List *relationdesc = Split(relationstr, ',', 2); + + // transform name from C to Modula3 style + String *srcstyle = NIL; + String *newprefix = NIL; + { + //printf("name conversion <%s>\n", Char(Getitem(convdesc,2))); + List *namedesc = Split(Getitem(convdesc, 2), ',', INT_MAX); + Iterator nameit = First(namedesc); + for (; nameit.item != NIL; nameit = Next(nameit)) { + List *nameassign = Split(nameit.item, '=', 2); + String *tag = Getitem(nameassign, 0); + String *data = Getitem(nameassign, 1); + //printf("name conv <%s> = <%s>\n", Char(tag), Char(data)); + if (Strcmp(tag, "srcstyle") == 0) { + srcstyle = Copy(data); + } else if (Strcmp(tag, "prefix") == 0) { + newprefix = Copy(data); + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown name conversion tag <%s> with value <%s>.\n", tag, data); + } + Delete(nameassign); + } + Delete(namedesc); + } + const char *stem = Char(name); + if (pat.prefix != NIL) { + //printf("pat.prefix %s for %s\n", Char(pat.prefix), Char(name)); + stem += Len(pat.prefix); + } + String *newname; + if (Strcmp(srcstyle, "underscore") == 0) { + if (newprefix != NIL) { + String *newstem = nameToModula3(stem, true); + newname = NewStringf("%s%s", newprefix, newstem); + Delete(newstem); + } else { + newname = nameToModula3(stem, true); + } + } else { + if (srcstyle != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown C identifier style <%s>.\n", srcstyle); + } + newname = Copy(name); + } + + if (Strcmp(pragma, "enumitem") == 0) { + if (Len(relationdesc) != 1) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <enumeration>, got <%s>.\n", relationstr); + } + Setfeature(n, "modula3:enumitem:name", newname, true); + Setfeature(n, "modula3:enumitem:enum", relationstr, true); + Setfeature(n, "modula3:enumitem:conv", NewStringf("%s:int", srctype), true); + } else if (Strcmp(pragma, "constint") == 0) { + if (Len(relationdesc) != 1) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <ordinal type>, got <%s>.\n", relationstr); + } + Setfeature(n, "modula3:constint:name", newname, true); + Setfeature(n, "modula3:constint:type", Getitem(relationdesc, 0), true); + Setfeature(n, "modula3:constint:conv", NewStringf("%s:int", srctype), true); + } else if (Strcmp(pragma, "constset") == 0) { + if (Len(relationdesc) != 2) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <set type,base type>, got <%s>.\n", relationstr); + } + String *settype = Getitem(relationdesc, 0); + Setfeature(n, "modula3:constset:name", newname, true); + //Setfeature(n,"modula3:constset:type",settype,true); + Setfeature(n, "modula3:constset:set", settype, true); + Setfeature(n, "modula3:constset:base", Getitem(relationdesc, 1), true); + Setfeature(n, "modula3:constset:conv", NewStringf("%s:set", srctype), true); + } + + Delete(newname); + Delete(relationdesc); + } + + if (Strcmp(nodeType(n), "enum") == 0) { + //printf("explore enum %s, qualification %s\n", Char(name), Char(Swig_symbol_qualified(n))); + tagConstants(firstChild(n), name, pat, pragma, convdesc); + } else { + tagConstants(firstChild(n), NIL, pat, pragma, convdesc); + } + n = nextSibling(n); + } + } + + void scanForConstPragmas(Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + const String *type = nodeType(child); + if (Strcmp(type, "pragma") == 0) { + const String *lang = Getattr(child, "lang"); + const String *code = Getattr(child, "name"); + String *value = Getattr(child, "value"); + + if (Strcmp(lang, "modula3") == 0) { + const_pragma_type cpt = cpt_none; + if (Strcmp(code, "constint") == 0) { + cpt = cpt_constint; + } else if (Strcmp(code, "constset") == 0) { + cpt = cpt_constset; + } else if (Strcmp(code, "enumitem") == 0) { + cpt = cpt_enumitem; + } + if (cpt != cpt_none) { + const_id_pattern pat = { NIL, NIL }; + + List *convdesc = Split(value, ';', 4); + List *patterndesc = Split(Getitem(convdesc, 0), ',', INT_MAX); + Iterator patternit; + for (patternit = First(patterndesc); patternit.item != NIL; patternit = Next(patternit)) { + List *patternassign = Split(patternit.item, '=', 2); + String *tag = Getitem(patternassign, 0); + String *data = Getitem(patternassign, 1); + if (Strcmp(tag, "prefix") == 0) { + pat.prefix = Copy(data); + } else if (Strcmp(tag, "enum") == 0) { + pat.parentEnum = Copy(data); + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown identification tag <%s> with value <%s>.\n", tag, data); + } + Delete(patternassign); + } + tagConstants(child, NIL, pat, code, convdesc); + + Delete(patterndesc); + } + } + } + scanForConstPragmas(child); + child = nextSibling(child); + } + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + String *classDeclarationName = Getattr(n, "classDeclaration:name"); + + /* Deal with inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist != NIL) { + Iterator base = First(baselist); + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) { + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + } + base = Next(base); + if (base.item != NIL) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", + classDeclarationName, Getattr(base.item, "name")); + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (!baseclass) + baseclass = NewString(""); + + // Inheritance from pure Modula 3 classes + const String *pure_baseclass = typemapLookup(n, "m3base", classDeclarationName, WARN_NONE); + if (hasContent(pure_baseclass) && hasContent(baseclass)) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", classDeclarationName, pure_baseclass); + } + // Pure Modula 3 interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "m3interfaces_derived" : "m3interfaces", + classDeclarationName, WARN_NONE); + + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "m3imports", classDeclarationName, WARN_NONE), // Import statements + "\n", typemapLookup(n, "m3classmodifiers", classDeclarationName, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " class $m3classname", // Class name and bases + (derived || *Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", baseclass, pure_baseclass, ((derived || *Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", // Member variables for memory handling + derived ? "" : " protected bool swigCMemOwn;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", classDeclarationName, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers + " $m3classname(IntPtr cPtr, bool cMemoryOwn) ", // Constructor used for wrapping pointers + derived ? + ": base($imclassname.$m3classnameTo$baseclass(cPtr), cMemoryOwn) {\n" + : "{\n swigCMemOwn = cMemoryOwn;\n", " swigCPtr = cPtr;\n", " }\n", NIL); + + if (!have_default_constructor_flag) { // All proxy classes need a constructor + Printv(proxy_class_def, "\n", " protected $m3classname() : this(IntPtr.Zero, false) {\n", " }\n", NIL); + } + // C++ destructor is wrapped by the Dispose method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + Node *attributes = NewHash(); + String *destruct_methodname = NULL; + if (derived) { + tm = typemapLookup(n, "m3destruct_derived", classDeclarationName, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:m3destruct_derived:methodname"); + } else { + tm = typemapLookup(n, "m3destruct", classDeclarationName, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:m3destruct:methodname"); + } + if (!destruct_methodname) { + Swig_error(input_file, line_number, "No methodname attribute defined in m3destruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + // Emit the Finalize and Dispose methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "m3finalize", classDeclarationName, WARN_NONE), NIL); + } + // Dispose method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$imcall", destructor_call); + else + Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) + Printv(proxy_class_def, "\n public ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", NIL); + } + Delete(attributes); + Delete(destruct); + + // Emit various other methods + Printv(proxy_class_def, typemapLookup(n, "m3getcptr", classDeclarationName, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method + typemapLookup(n, "m3code", classDeclarationName, WARN_NONE), // extra Modula 3 code + "\n", NIL); + + // Substitute various strings into the above template + Replaceall(proxy_class_def, "$m3classname", proxy_class_name); + Replaceall(proxy_class_code, "$m3classname", proxy_class_name); + + Replaceall(proxy_class_def, "$baseclass", baseclass); + Replaceall(proxy_class_code, "$baseclass", baseclass); + + Replaceall(proxy_class_def, "$imclassname", m3raw_name); + Replaceall(proxy_class_code, "$imclassname", m3raw_name); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(m3raw_cppcasts_code, "\n [DllImport(\"", m3wrap_name, "\", EntryPoint=\"Modula3_", proxy_class_name, "To", baseclass, "\")]\n", NIL); + Printv(m3raw_cppcasts_code, " public static extern IntPtr ", "$m3classnameTo$baseclass(IntPtr objectRef);\n", NIL); + + Replaceall(m3raw_cppcasts_code, "$m3classname", proxy_class_name); + Replaceall(m3raw_cppcasts_code, "$baseclass", baseclass); + + Printv(upcasts_code, + "SWIGEXPORT long Modula3_$imclazznameTo$imbaseclass", + "(long objectRef) {\n", + " long baseptr = 0;\n" " *($cbaseclass **)&baseptr = *($cclass **)&objectRef;\n" " return baseptr;\n" "}\n", "\n", NIL); + + Replaceall(upcasts_code, "$imbaseclass", baseclass); + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", proxy_class_name); + Replaceall(upcasts_code, "$cclass", c_classname); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * getAttrString() + * + * If necessary create and return the string + * associated with a certain attribute of 'n'. + * ---------------------------------------------------------------------- */ + + String *getAttrString(Node *n, const char *attr) { + String *str = Getattr(n, attr); + if (str == NIL) { + str = NewString(""); + Setattr(n, attr, str); + } + return str; + } + + /* ---------------------------------------------------------------------- + * getMethodDeclarations() + * + * If necessary create and return the handle + * where the methods of the current access can be written to. + * 'n' must be a member of a struct or a class. + * ---------------------------------------------------------------------- */ + + String *getMethodDeclarations(Node *n) { + String *acc_str = Getattr(n, "access"); + String *methodattr; + if (acc_str == NIL) { + methodattr = NewString("modula3:method:public"); + } else { + methodattr = NewStringf("modula3:method:%s", acc_str); + } + String *methods = getAttrString(parentNode(n), Char(methodattr)); + Delete(methodattr); + return methods; + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + proxy_class_name = Copy(Getattr(n, "sym:name")); + //String *rawname = Getattr(n,"name"); + + if (proxy_flag) { + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + if (Cmp(proxy_class_name, m3raw_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, m3wrap_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + String *filen = NewStringf("%s%s.m3", Swig_file_dirname(outfile), proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Delete(filen); + filen = NULL; + + emitBanner(f_proxy); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + have_default_constructor_flag = false; + destructor_call = NewString(""); + } + + /* This will invoke memberfunctionHandler, membervariableHandler ... + and finally it may invoke functionWrapper + for wrappers and member variable accessors. + It will invoke Language:constructorDeclaration + which decides whether to call MODULA3::constructorHandler */ + Language::classHandler(n); + + { + String *kind = Getattr(n, "kind"); + if (Cmp(kind, "struct") == 0) { + String *entries = NewString(""); + Node *child; + writeArgState state; + for (child = firstChild(n); child != NIL; child = nextSibling(child)) { + String *childType = nodeType(child); + if (Strcmp(childType, "cdecl") == 0) { + String *member = Getattr(child, "sym:name"); + ParmList *pl = Getattr(child, "parms"); + if (pl == NIL) { + // Get the variable type in Modula 3 type equivalents + String *m3ct = getMappedTypeNew(child, "m3rawtype", ""); + + writeArg(entries, state, NIL, member, m3ct, NIL); + } + } + } + writeArg(entries, state, NIL, NIL, NIL, NIL); + + m3raw_intf.enterBlock(blocktype); + Printf(m3raw_intf.f, "%s =\nRECORD\n%sEND;\n", proxy_class_name, entries); + + Delete(entries); + + } else if (Cmp(kind, "class") == 0) { + enum access_privilege { acc_public, acc_protected, acc_private }; + int max_acc = acc_public; + + const char *acc_name[3] = { "public", "protected", "private" }; + String *methods[3]; + int acc; + for (acc = acc_public; acc <= acc_private; acc++) { + String *methodattr = NewStringf("modula3:method:%s", acc_name[acc]); + methods[acc] = Getattr(n, methodattr); + Delete(methodattr); + max_acc = max_acc > acc ? max_acc : acc; + } + + /* Determine the name of the base class */ + String *baseclassname = NewString(""); + { + List *baselist = Getattr(n, "bases"); + if (baselist) { + /* Look for the first (principal?) base class - + Modula 3 does not support multiple inheritance */ + Iterator base = First(baselist); + Append(baseclassname, Getattr(base.item, "sym:name")); + base = Next(base); + if (base.item != NIL) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", + proxy_class_name, Getattr(base.item, "name")); + } + } + } + + /* the private class of the base class and only this + need a pointer to the C++ object */ + bool need_private = !hasContent(baseclassname); + max_acc = need_private ? acc_private : max_acc; + + /* Declare C++ object as abstract pointer in Modula 3 */ + /* The revelation system does not allow us + to imitate the whole class hierarchy of the C++ library, + but at least we can distinguish between classes of different roots. */ + if (hasContent(baseclassname)) { + m3raw_intf.enterBlock(blocktype); + Printf(m3raw_intf.f, "%s = %s;\n", proxy_class_name, baseclassname); + } else { + m3raw_intf.enterBlock(blocktype); + Printf(m3raw_intf.f, "%s <: ADDRESS;\n", proxy_class_name); + m3raw_impl.enterBlock(revelation); + Printf(m3raw_impl.f, "%s = UNTRACED BRANDED REF RECORD (*Dummy*) END;\n", proxy_class_name); + } + + String *superclass; + m3wrap_intf.enterBlock(blocktype); + if (hasContent(methods[acc_public])) { + superclass = NewStringf("%sPublic", proxy_class_name); + } else if (hasContent(baseclassname)) { + superclass = Copy(baseclassname); + } else { + superclass = NewString("ROOT"); + } + Printf(m3wrap_intf.f, "%s <: %s;\n", proxy_class_name, superclass); + Delete(superclass); + + { + static const char *acc_m3suffix[] = { "Public", "Protected", "Private" }; + int acc; + for (acc = acc_public; acc <= acc_private; acc++) { + bool process_private = (acc == acc_private) && need_private; + if (hasContent(methods[acc]) || process_private) { + String *subclass = NewStringf("%s%s", proxy_class_name, acc_m3suffix[acc]); + /* + m3wrap_intf.enterBlock(revelation); + Printf(m3wrap_intf.f, "%s <: %s;\n", proxy_class_name, subclass); + */ + if (acc == max_acc) { + m3wrap_intf.enterBlock(revelation); + Printf(m3wrap_intf.f, "%s =\n", proxy_class_name); + } else { + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%s =\n", subclass); + } + Printf(m3wrap_intf.f, "%s BRANDED OBJECT\n", baseclassname); + if (process_private) { + Setattr(m3wrap_intf.import, m3raw_name, ""); + Printf(m3wrap_intf.f, "cxxObj:%s.%s;\n", m3raw_name, proxy_class_name); + } + if (hasContent(methods[acc])) { + Printf(m3wrap_intf.f, "METHODS\n%s", methods[acc]); + } + if (acc == max_acc) { + String *overrides = Getattr(n, "modula3:override"); + Printf(m3wrap_intf.f, "OVERRIDES\n%s", overrides); + } + Printf(m3wrap_intf.f, "END;\n"); + Delete(baseclassname); + baseclassname = subclass; + } + } + } + + Delete(methods[acc_public]); + Delete(methods[acc_protected]); + Delete(methods[acc_private]); + + } else { + Swig_warning(WARN_MODULA3_TYPECONSTRUCTOR_UNKNOWN, input_file, line_number, "Unknown type constructor %s\n", kind); + } + } + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + Printf(f_proxy, "}\n"); + Close(f_proxy); + f_proxy = NULL; + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + //printf("begin memberfunctionHandler(%s)\n", Char(Getattr(n,"name"))); + Setattr(n, "modula3:functype", "method"); + Language::memberfunctionHandler(n); + + { + /* Language::memberfunctionHandler will remove the mapped types + that emitM3Wrapper may attach */ + ParmList *pl = Getattr(n, "parms"); + Swig_typemap_attach_parms("m3wrapinmode", pl, NULL); + Swig_typemap_attach_parms("m3wrapinname", pl, NULL); + Swig_typemap_attach_parms("m3wrapintype", pl, NULL); + Swig_typemap_attach_parms("m3wrapindefault", pl, NULL); + attachParameterNames(n, "tmap:m3wrapinname", "autoname", "arg%d"); + String *rettype = getMappedTypeNew(n, "m3wrapouttype", ""); + + String *methodname = Getattr(n, "sym:name"); +/* + if (methodname==NIL) { + methodname = Getattr(n,"name"); + } +*/ + String *arguments = createM3Signature(n); + String *storage = Getattr(n, "storage"); + String *overridden = Getattr(n, "override"); + bool isVirtual = (storage != NIL) && (Strcmp(storage, "virtual") == 0); + bool isOverridden = (overridden != NIL) + && (Strcmp(overridden, "1") == 0); + if ((!isVirtual) || (!isOverridden)) { + { + String *methods = getMethodDeclarations(n); + Printf(methods, "%s(%s)%s%s;%s\n", + methodname, arguments, + hasContent(rettype) ? ": " : "", hasContent(rettype) ? (const String *) rettype : "", isVirtual ? " (* base method *)" : ""); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:funcname"); + String *overrides = getAttrString(parentNode(n), "modula3:override"); + Printf(overrides, "%s := %s;\n", methodname, fname); + } + } + } + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + //printf("end memberfunctionHandler(%s)\n", Char(Getattr(n,"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(proxy_class_name, 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 Modula 3 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 Modula 3 static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the Modula 3 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"); + Hash *throws_hash = NewHash(); + 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; + + if (!proxy_flag) + 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("m3wraptype", l, NULL); + Swig_typemap_attach_parms("m3in", l, NULL); + + /* Get return types */ + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } + + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Properties + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) + == 0); + } + + /* Start generating the proxy function */ + Printf(function_code, " %s ", Getattr(n, "feature:modula3:methodmodifiers")); + if (static_flag) + Printf(function_code, "static "); + if (Getattr(n, "override")) + Printf(function_code, "override "); + else if (checkAttribute(n, "storage", "virtual")) + Printf(function_code, "virtual "); + + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + Printv(imcall, m3raw_name, ".", intermediary_function_name, "(", NIL); + if (!static_flag) + Printv(imcall, "swigCPtr", NIL); + + 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(""); + + /* Get the Modula 3 parameter type */ + if ((tm = getMappedType(p, "m3wraptype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = variable_wrapper_flag ? NewString("value") : makeParameterName(n, + p, + i); + + // Use typemaps to transform type used in Modula 3 wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = getMappedType(p, "in"))) { + addThrows(throws_hash, "in", p); + substituteClassname(pt, tm); + Replaceall(tm, "$input", arg); + Printv(imcall, tm, NIL); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in Modula 3 wrapper function (in proxy class) + if ((tm = getMappedTypeNew(n, "m3out", ""))) { + addThrows(throws_hash, "m3out", n); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + } + + generateThrowsClause(throws_hash, function_code); + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Properties + if (setter_flag) { + // Setter method + if ((tm = getMappedTypeNew(n, "m3varin", ""))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + Printf(proxy_class_code, "%s", tm); + } + } else { + // Getter method + if ((tm = getMappedTypeNew(n, "m3varout", ""))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + Printf(proxy_class_code, "%s", tm); + } + } + } else { + // Normal function call + Printv(proxy_class_code, function_code, NIL); + } + + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(throws_hash); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + // this invokes functionWrapper + Language::constructorHandler(n); + + if (proxy_flag) { + ParmList *l = Getattr(n, "parms"); + + Hash *throws_hash = NewHash(); + String *overloaded_name = getOverloadedName(n); + String *imcall = NewString(""); + + Printf(proxy_class_code, " %s %s(", Getattr(n, "feature:modula3:methodmodifiers"), proxy_class_name); + Printv(imcall, " : this(", m3raw_name, ".", Swig_name_construct(overloaded_name), "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("m3wraptype", l, NULL); + Swig_typemap_attach_parms("m3in", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + String *tm; + Parm *p = l; + int i; + + /* Output each parameter */ + for (i = 0; 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 Modula 3 parameter type */ + if ((tm = getMappedType(p, "m3wraptype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i); + + // Use typemaps to transform type used in Modula 3 wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = getMappedType(p, "in"))) { + addThrows(throws_hash, "in", p); + substituteClassname(pt, tm); + Replaceall(tm, "$input", arg); + Printv(imcall, tm, NIL); + } + + /* Add parameter to proxy function */ + if (gencomma) + Printf(proxy_class_code, ", "); + Printf(proxy_class_code, "%s %s", param_type, arg); + gencomma = 1; + + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, "), true)"); + + Printf(proxy_class_code, ")"); + Printf(proxy_class_code, "%s", imcall); + generateThrowsClause(throws_hash, proxy_class_code); + Printf(proxy_class_code, " {\n"); + Printf(proxy_class_code, " }\n\n"); + + if (!gencomma) // We must have a default constructor + have_default_constructor_flag = true; + + Delete(overloaded_name); + Delete(imcall); + Delete(throws_hash); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, m3raw_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + //printf("begin membervariableHandler(%s)\n", Char(Getattr(n,"name"))); + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + + variable_name = Getattr(n, "sym:name"); + //printf("member variable: %s\n", Char(variable_name)); + + // Output the property's field declaration and accessor methods + Printf(proxy_class_code, " public %s %s {", tm, variable_name); + + Setattr(n, "modula3:functype", "accessor"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + + Printf(proxy_class_code, "\n }\n\n"); + + { + String *methods = getMethodDeclarations(n); + String *overrides = getAttrString(parentNode(n), "modula3:override"); + SwigType *type = Getattr(n, "type"); + String *m3name = capitalizeFirst(variable_name); + //String *m3name = nameToModula3(variable_name,true); + if (!SwigType_isconst(type)) { + { + String *inmode = getMappedTypeNew(n, "m3wrapinmode", "", false); + String *intype = getMappedTypeNew(n, "m3wrapintype", ""); + Printf(methods, "set%s(%s val:%s);\n", m3name, (inmode != NIL) ? (const String *) inmode : "", intype); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:setname"); + Printf(overrides, "set%s := %s;\n", m3name, fname); + } + } + { + { + String *outtype = getMappedTypeNew(n, "m3wrapouttype", ""); + Printf(methods, "get%s():%s;\n", m3name, outtype); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:getname"); + Printf(overrides, "get%s := %s;\n", m3name, fname); + } + } + Delete(m3name); + } + //printf("end membervariableHandler(%s)\n", Char(Getattr(n,"name"))); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + + bool static_const_member_flag = (Getattr(n, "value") == 0); + if (static_const_member_flag) { + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + // Output the property's field declaration and accessor methods + Printf(proxy_class_code, " public static %s %s {", tm, Getattr(n, "sym:name")); + } + + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_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) { + String *overloaded_name = Copy(Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * emitM3Wrapper() + * It is also used for set and get methods of global variables. + * ----------------------------------------------------------------------------- */ + + void emitM3Wrapper(Node *n, const String *func_name) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Hash *throws_hash = NewHash(); + int num_exceptions = 0; + int num_returns = 0; + String *rawcall = NewString(""); + String *reccall = NewString(""); + String *local_variables = NewString(""); + String *local_constants = NewString(""); + String *incheck = NewString(""); + String *outcheck = NewString(""); + String *setup = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); /* don't mix up with 'autark' :-] */ + String *storeout = NewString(""); + String *result_name = NewString(""); + String *return_variables = NewString(""); + const char *result_return = "ret"; + String *function_code = NewString(""); + /*several names for the same function */ + String *raw_name = Getattr(n, "name"); /*original C function name */ + //String *func_name = Getattr(n,"sym:name"); /*final Modula3 name chosen by the user*/ + bool setter_flag = false; + int multiretval = GetFlag(n, "feature:modula3:multiretval"); + + 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("m3wrapargvar", l, NULL); + Swig_typemap_attach_parms("m3wrapargconst", l, NULL); + Swig_typemap_attach_parms("m3wrapargraw", l, NULL); + Swig_typemap_attach_parms("m3wrapargdir", l, NULL); + Swig_typemap_attach_parms("m3wrapinmode", l, NULL); + Swig_typemap_attach_parms("m3wrapinname", l, NULL); + Swig_typemap_attach_parms("m3wrapintype", l, NULL); + Swig_typemap_attach_parms("m3wrapindefault", l, NULL); + Swig_typemap_attach_parms("m3wrapinconv", l, NULL); + Swig_typemap_attach_parms("m3wrapincheck", l, NULL); + Swig_typemap_attach_parms("m3wrapoutname", l, NULL); + Swig_typemap_attach_parms("m3wrapouttype", l, NULL); + Swig_typemap_attach_parms("m3wrapoutconv", l, NULL); + Swig_typemap_attach_parms("m3wrapoutcheck", l, NULL); + + attachMappedType(n, "m3wrapretraw"); + attachMappedType(n, "m3wrapretname"); + attachMappedType(n, "m3wraprettype"); + attachMappedType(n, "m3wrapretvar"); + attachMappedType(n, "m3wrapretconv"); + attachMappedType(n, "m3wrapretcheck"); + + Swig_typemap_attach_parms("m3wrapfreearg", l, NULL); + +/* + Swig_typemap_attach_parms("m3wrapargvar:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapargraw:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapinconv:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapincheck:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapoutconv:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapoutcheck:throws", l, NULL); + + attachMappedType(n, "m3wrapretvar:throws"); + attachMappedType(n, "m3wrapretconv:throws"); + attachMappedType(n, "m3wrapretcheck:throws"); + + Swig_typemap_attach_parms("m3wrapfreearg:throws", l, NULL); +*/ + + /* Attach argument names to the parameter list */ + /* should be a separate procedure making use of hashes */ + attachParameterNames(n, "tmap:m3wrapinname", "autoname", "arg%d"); + + /* Get return types */ + String *result_m3rawtype = Copy(getMappedTypeNew(n, "m3rawrettype", "")); + String *result_m3wraptype = Copy(getMappedTypeNew(n, "m3wraprettype", "")); + bool has_return_raw = hasContent(result_m3rawtype); + bool has_return_m3 = hasContent(result_m3wraptype); + if (has_return_m3) { + num_returns++; + //printf("%s: %s\n", Char(func_name),Char(result_m3wraptype)); + } + + String *arguments = createM3Signature(n); + + /* Create local variables or RECORD fields for return values + and determine return type that might result from a converted VAR argument. */ + { + writeArgState state; + if (multiretval && has_return_m3) { + writeArg(return_variables, state, NIL, NewString(result_return), result_m3wraptype, NIL); + } + + Parm *p = skipIgnored(l, "m3wrapouttype"); + while (p != NIL) { + + String *arg = Getattr(p, "tmap:m3wrapoutname"); + if (arg == NIL) { + arg = Getattr(p, "name"); + } + + String *tm = Getattr(p, "tmap:m3wrapouttype"); + if (tm != NIL) { + if (isOutParam(p)) { + if (!multiretval) { + if (num_returns == 0) { + Printv(result_name, arg, NIL); + Clear(result_m3wraptype); + Printv(result_m3wraptype, tm, NIL); + } else { + Swig_warning(WARN_MODULA3_TYPEMAP_MULTIPLE_RETURN, input_file, line_number, + "Typemap m3wrapargdir set to 'out' for %s implies a RETURN value, but the routine %s has already one.\nUse %%multiretval feature.\n", + SwigType_str(Getattr(p, "type"), 0), raw_name); + } + } + num_returns++; + addImports(m3wrap_intf.import, "m3wrapouttype", p); + writeArg(return_variables, state, NIL, arg, tm, NIL); + } + p = skipIgnored(Getattr(p, "tmap:m3wrapouttype:next"), "m3wrapouttype"); + } else { + p = nextSibling(p); + } + } + writeArg(return_variables, state, NIL, NIL, NIL, NIL); + + if (multiretval) { + Printv(result_name, "result", NIL); + Printf(result_m3wraptype, "%sResult", func_name); + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%s =\nRECORD\n%sEND;\n", result_m3wraptype, return_variables); + Printf(local_variables, "%s: %s;\n", result_name, result_m3wraptype); + } else { + Append(local_variables, return_variables); + } + } + + /* Declare local constants e.g. for storing argument names. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapargconst"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapargconst", p); + Replaceall(tm, "$input", arg); + Printv(local_constants, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapargconst:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Declare local variables e.g. for converted input values. */ + { + String *tm = getMappedTypeNew(n, "m3wrapretvar", "", false); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapretvar", n); + addThrows(throws_hash, "m3wrapretvar", n); + Printv(local_variables, tm, "\n", NIL); + } + + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + tm = Getattr(p, "tmap:m3wrapargvar"); + if (tm != NIL) { + /* exceptions that may be raised but can't be catched, + thus we won't count them in num_exceptions */ + addImports(m3wrap_impl.import, "m3wrapargvar", p); + addThrows(throws_hash, "m3wrapargvar", p); + Replaceall(tm, "$input", arg); + Printv(local_variables, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapargvar:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Convert input values from Modula 3 to C. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapinconv"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapinconv", p); + num_exceptions += addThrows(throws_hash, "m3wrapinconv", p); + Replaceall(tm, "$input", arg); + Printv(setup, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapinconv:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Generate checks for input value integrity. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapincheck"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapincheck", p); + num_exceptions += addThrows(throws_hash, "m3wrapincheck", p); + Replaceall(tm, "$input", arg); + Printv(incheck, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapincheck:next"); + } else { + p = nextSibling(p); + } + + } + } + + Printv(rawcall, m3raw_name, ".", func_name, "(", NIL); + /* Arguments to the raw C function */ + { + bool gencomma = false; + Parm *p = l; + while (p != NIL) { + if (gencomma) { + Printf(rawcall, ", "); + } + gencomma = true; + addImports(m3wrap_impl.import, "m3wrapargraw", p); + num_exceptions += addThrows(throws_hash, "m3wrapargraw", p); + + String *arg = Getattr(p, "autoname"); + String *qualarg = NewString(""); + if (!isInParam(p)) { + String *tmparg = Getattr(p, "tmap:m3wrapoutname"); + if (tmparg != NIL) { + arg = tmparg; + } + if (multiretval /*&& isOutParam(p) - automatically fulfilled */ ) { + Printf(qualarg, "%s.", result_name); + } + } + Append(qualarg, arg); + Setattr(p, "m3outarg", qualarg); + + String *tm = Getattr(p, "tmap:m3wrapargraw"); + if (tm != NIL) { + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", qualarg); + Printv(rawcall, tm, NIL); + p = Getattr(p, "tmap:m3wrapargraw:next"); + } else { + //Printv(rawcall, Getattr(p,"lname"), NIL); + Printv(rawcall, qualarg, NIL); + p = nextSibling(p); + } + Delete(qualarg); + } + } + Printf(rawcall, ")"); + + /* Check for error codes and integrity of results */ + { + String *tm = getMappedTypeNew(n, "m3wrapretcheck", "", false); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapretcheck", n); + num_exceptions += addThrows(throws_hash, "m3wrapretcheck", n); + Printv(outcheck, tm, "\n", NIL); + } + + Parm *p = l; + while (p != NIL) { + tm = Getattr(p, "tmap:m3wrapoutcheck"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapoutcheck", p); + num_exceptions += addThrows(throws_hash, "m3wrapoutcheck", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printv(outcheck, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapoutcheck:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Convert the results to Modula 3 data structures and + put them in the record prepared for returning */ + { + /* m3wrapretconv is processed + when it is clear if there is some output conversion and checking code */ + Parm *p = l; + while (p != NIL) { + String *tm = Getattr(p, "tmap:m3wrapoutconv"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapoutconv", n); + num_exceptions += addThrows(throws_hash, "m3wrapoutconv", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printf(storeout, "%s := %s;\n", outarg, tm); + p = Getattr(p, "tmap:m3wrapoutconv:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Generate cleanup code */ + { + Parm *p = l; + while (p != NIL) { + String *tm = Getattr(p, "tmap:m3wrapfreearg"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapfreearg", p); + num_exceptions += addThrows(throws_hash, "m3wrapfreearg", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapfreearg:next"); + } else { + p = nextSibling(p); + } + } + } + + { + /* Currently I don't know how a typemap similar to the original 'out' typemap + could help returning the return value. */ + /* Receive result from call to raw library function */ + if (!has_return_raw) { + /* + rawcall(arg1); + result.val := arg1; + RETURN result; + */ + /* + rawcall(arg1); + RETURN arg1; + */ + Printf(reccall, "%s;\n", rawcall); + + if (hasContent(result_name)) { + Printf(outarg, "RETURN %s;\n", result_name); + } + } else { + /* + arg0 := rawcall(arg1); + result.ret := Convert(arg0); + result.val := arg1; + RETURN result; + */ + /* + arg0 := rawcall(); + RETURN Convert(arg0); + */ + /* + RETURN rawcall(); + */ + String *return_raw = getMappedTypeNew(n, "m3wrapretraw", "", false); + String *return_conv = getMappedTypeNew(n, "m3wrapretconv", "", false); + + /* immediate RETURN would skip result checking */ + if ((hasContent(outcheck) || hasContent(storeout) + || hasContent(cleanup)) && (!hasContent(result_name)) + && (return_raw == NIL)) { + Printv(result_name, "result", NIL); + Printf(local_variables, "%s: %s;\n", result_name, result_m3wraptype); + } + + String *result_lvalue = Copy(result_name); + if (multiretval) { + Printf(result_lvalue, ".%s", result_return); + } + if (return_raw != NIL) { + Printf(reccall, "%s := %s;\n", return_raw, rawcall); + } else if (hasContent(result_name)) { + Printf(reccall, "%s := %s;\n", result_lvalue, rawcall); + } else { + Printf(outarg, "RETURN %s;\n", rawcall); + } + if (return_conv != NIL) { + addImports(m3wrap_impl.import, "m3wrapretconv", n); + num_exceptions += addThrows(throws_hash, "m3wrapretconv", n); + if (hasContent(result_name)) { + Printf(reccall, "%s := %s;\n", result_lvalue, return_conv); + Printf(outarg, "RETURN %s;\n", result_name); + } else { + Printf(outarg, "RETURN %s;\n", return_conv); + } + } else { + if (hasContent(result_name)) { + Printf(outarg, "RETURN %s;\n", result_name); + } + } + } + } + + /* Create procedure header */ + { + String *header = NewStringf("PROCEDURE %s (%s)", + func_name, arguments); + + if ((num_returns > 0) || multiretval) { + Printf(header, ": %s", result_m3wraptype); + } + generateThrowsClause(throws_hash, header); + + Append(function_code, header); + + m3wrap_intf.enterBlock(no_block); + Printf(m3wrap_intf.f, "%s;\n\n", header); + } + + { + String *body = NewStringf("%s%s%s%s%s", + incheck, + setup, + reccall, + outcheck, + storeout); + + String *exc_handler; + if (hasContent(cleanup) && (num_exceptions > 0)) { + exc_handler = NewStringf("TRY\n%sFINALLY\n%sEND;\n", body, cleanup); + } else { + exc_handler = NewStringf("%s%s", body, cleanup); + } + + Printf(function_code, " =\n%s%s%s%sBEGIN\n%s%sEND %s;\n\n", + hasContent(local_constants) ? "CONST\n" : "", local_constants, + hasContent(local_variables) ? "VAR\n" : "", local_variables, exc_handler, outarg, func_name); + + Delete(exc_handler); + Delete(body); + } + + m3wrap_impl.enterBlock(no_block); + if (proxy_flag && global_variable_flag) { + // Properties + if (setter_flag) { + // Setter method + String *tm = getMappedTypeNew(n, "m3varin", ""); + if (tm != NIL) { + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "true"); + } else { + Replaceall(tm, "$owner", "false"); + } + substituteClassname(t, tm); + Replaceall(tm, "$rawcall", rawcall); + Replaceall(tm, "$vartype", variable_type); /* $type is already replaced by some super class */ + Replaceall(tm, "$var", variable_name); + Printf(m3wrap_impl.f, "%s", tm); + } + } else { + // Getter method + String *tm = getMappedTypeNew(n, "m3varout", ""); + if (tm != NIL) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$rawcall", rawcall); + Replaceall(tm, "$vartype", variable_type); + Replaceall(tm, "$var", variable_name); + Printf(m3wrap_impl.f, "%s", tm); + } + } + } else { + // Normal function call + Printv(m3wrap_impl.f, function_code, NIL); + } + + Delete(arguments); + Delete(return_variables); + Delete(local_variables); + Delete(local_constants); + Delete(outarg); + Delete(incheck); + Delete(outcheck); + Delete(setup); + Delete(cleanup); + Delete(storeout); + Delete(function_code); + Delete(result_name); + Delete(result_m3wraptype); + Delete(reccall); + Delete(rawcall); + Delete(throws_hash); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $m3classname with the proxy class name for classes/structs/unions + * that SWIG knows about. + * Otherwise use the $descriptor name for the Modula 3 class name. Note that the $&m3classname 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; + if (Strstr(tm, "$m3classname") || Strstr(tm, "$&m3classname")) { + String *classname = getProxyName(pt); + if (classname) { + Replaceall(tm, "$&m3classname", classname); // getProxyName() works for pointers to classes too + Replaceall(tm, "$m3classname", classname); + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NULL; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + + if (Strstr(tm, "$&m3classname")) { + SwigType_add_pointer(type); + descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); + Replaceall(tm, "$&m3classname", descriptor); + } else { // $m3classname + descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); + Replaceall(tm, "$m3classname", descriptor); + } + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, type); + Delete(descriptor); + Delete(type); + } + substitution_performed = true; + } + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num) { + + // Use C parameter name unless it is a duplicate or an empty parameter name + String *pn = Getattr(p, "name"); + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *arg = (!pn || (count > 1)) ? NewStringf("arg%d", + arg_num) : Copy(Getattr(p, + "name")); + + return arg; + } + + /* ----------------------------------------------------------------------------- + * attachParameterNames() + * + * Inputs: + * n - Node of a function declaration + * tmid - attribute name for overriding C argument names, + * e.g. "tmap:m3wrapinname", + * don't forget to attach the mapped types before + * nameid - attribute for attaching the names, + * e.g. "modula3:inname" + * fmt - format for the argument name containing %d + * e.g. "arg%d" + * ----------------------------------------------------------------------------- */ + + void attachParameterNames(Node *n, const char *tmid, const char *nameid, const char *fmt) { + /* Use C parameter name if present and unique, + otherwise create an 'arg%d' name */ + Hash *hash = NewHash(); + Parm *p = Getattr(n, "parms"); + int count = 0; + while (p != NIL) { + String *name = Getattr(p, tmid); + if (name == NIL) { + name = Getattr(p, "name"); + } + String *newname; + if ((!hasContent(name)) || (Getattr(hash, name) != NIL)) { + newname = NewStringf(fmt, count); + } else { + newname = Copy(name); + } + if (1 == Setattr(hash, newname, "1")) { + Swig_warning(WARN_MODULA3_DOUBLE_ID, input_file, line_number, "Argument '%s' twice.\n", newname); + } + Setattr(p, nameid, newname); +// Delete(newname); + p = nextSibling(p); + count++; + } + Delete(hash); + } + + /* ----------------------------------------------------------------------------- + * createM3Signature() + * + * Create signature of M3 wrapper procedure + * Call attachParameterNames and attach mapped types before! + * m3wrapintype, m3wrapinmode, m3wrapindefault + * ----------------------------------------------------------------------------- */ + + String *createM3Signature(Node *n) { + String *arguments = NewString(""); + Parm *p = skipIgnored(Getattr(n, "parms"), "m3wrapintype"); + writeArgState state; + while (p != NIL) { + + /* Get the M3 parameter type */ + String *tm = getMappedType(p, "m3wrapintype"); + if (tm != NIL) { + if (isInParam(p)) { + addImports(m3wrap_intf.import, "m3wrapintype", p); + addImports(m3wrap_impl.import, "m3wrapintype", p); + String *mode = Getattr(p, "tmap:m3wrapinmode"); + String *deflt = Getattr(p, "tmap:m3wrapindefault"); + String *arg = Getattr(p, "autoname"); + SwigType *pt = Getattr(p, "type"); + substituteClassname(pt, tm); /* do we need this ? */ + + writeArg(arguments, state, mode, arg, tm, deflt); + } + p = skipIgnored(Getattr(p, "tmap:m3wrapintype:next"), "m3wrapintype"); + } else { + p = nextSibling(p); + } + } + writeArg(arguments, state, NIL, NIL, NIL, NIL); + return (arguments); + } + +/* not used any longer + - try SwigType_str if required again */ +#if 0 + /* ----------------------------------------------------------------------------- + * createCSignature() + * + * Create signature of C function + * ----------------------------------------------------------------------------- */ + + String *createCSignature(Node *n) { + String *arguments = NewString(""); + bool gencomma = false; + Node *p; + for (p = Getattr(n, "parms"); p != NIL; p = nextSibling(p)) { + if (gencomma) { + Append(arguments, ","); + } + gencomma = true; + String *type = Getattr(p, "type"); + String *ctype = getMappedTypeNew(type, "ctype"); + Append(arguments, ctype); + } + return arguments; + } +#endif + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *filen = NewStringf("%s%s.m3", Swig_file_dirname(outfile), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + String *swigtype = NewString(""); + + // Emit banner name + emitBanner(f_swigtype); + + // Pure Modula 3 baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "m3base", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "m3interfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "m3imports", type, WARN_NONE), // Import statements + "\n", typemapLookup(n, "m3classmodifiers", type, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " class $m3classname", // Class name and bases + *Char(pure_baseclass) ? " : " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " : " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", type, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers + " $m3classname(IntPtr cPtr, bool bFutureUse) {\n", // Constructor used for wrapping pointers + " swigCPtr = cPtr;\n", " }\n", "\n", " protected $m3classname() {\n", // Default constructor + " swigCPtr = IntPtr.Zero;\n", " }\n", typemapLookup(n, "m3getcptr", type, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method + typemapLookup(n, "m3code", type, WARN_NONE), // extra Modula 3 code + "}\n", "\n", NIL); + + Replaceall(swigtype, "$m3classname", classname); + Printv(f_swigtype, swigtype, NIL); + + Close(f_swigtype); + Delete(filen); + Delete(swigtype); + } + + /* ----------------------------------------------------------------------------- + * 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() + * + * Add all exceptions to a hash that are associated with the 'typemap'. + * Return number the number of these exceptions. + * ----------------------------------------------------------------------------- */ + + int addThrows(Hash *throws_hash, const String *typemap, Node *parameter) { + // Get the comma separated throws clause - held in "throws" attribute in the typemap passed in + int len = 0; + String *throws_attribute = NewStringf("%s:throws", typemap); + + addImports(m3wrap_intf.import, throws_attribute, parameter); + addImports(m3wrap_impl.import, throws_attribute, parameter); + + String *throws = getMappedTypeNew(parameter, Char(throws_attribute), "", false); + //printf("got exceptions %s for %s\n", Char(throws), Char(throws_attribute)); + + if (throws) { + // Put the exception classes in the throws clause into a temporary List + List *temp_classes_list = Split(throws, ',', INT_MAX); + len = Len(temp_classes_list); + + // Add the exception classes to the node throws list, but don't duplicate if already in list + if (temp_classes_list /*&& hasContent(temp_classes_list) */ ) { + for (Iterator cls = First(temp_classes_list); cls.item != NIL; cls = Next(cls)) { + String *exception_class = NewString(cls.item); + Replaceall(exception_class, " ", ""); // remove spaces + Replaceall(exception_class, "\t", ""); // remove tabs + if (hasContent(exception_class)) { + // $m3classname substitution + SwigType *pt = Getattr(parameter, "type"); + substituteClassname(pt, exception_class); + // Don't duplicate the exception class in the throws clause + //printf("add exception %s\n", Char(exception_class)); + Setattr(throws_hash, exception_class, "1"); + } + Delete(exception_class); + } + } + Delete(temp_classes_list); + } + Delete(throws_attribute); + return len; + } + + /* ----------------------------------------------------------------------------- + * generateThrowsClause() + * ----------------------------------------------------------------------------- */ + + void generateThrowsClause(Hash *throws_hash, String *code) { + // Add the throws clause into code + if (Len(throws_hash) > 0) { + Iterator cls = First(throws_hash); + Printf(code, " RAISES {%s", cls.key); + for (cls = Next(cls); cls.key != NIL; cls = Next(cls)) { + Printf(code, ", %s", cls.key); + } + Printf(code, "}"); + } + } + + /* ----------------------------------------------------------------------------- + * addImports() + * + * Add all imports that are needed for contents of 'typemap'. + * ----------------------------------------------------------------------------- */ + + void addImports(Hash *imports_hash, const String *typemap, Node *node) { + // Get the comma separated throws clause - held in "throws" attribute in the typemap passed in + String *imports_attribute = NewStringf("%s:import", typemap); + String *imports = getMappedTypeNew(node, Char(imports_attribute), "", false); + //printf("got imports %s for %s\n", Char(imports), Char(imports_attribute)); + + if (imports != NIL) { + List *import_list = Split(imports, ',', INT_MAX); + + // Add the exception classes to the node imports list, but don't duplicate if already in list + if (import_list != NIL) { + for (Iterator imp = First(import_list); imp.item != NIL; imp = Next(imp)) { + List *import_pair = Split(imp.item, ' ', 3); + if (Len(import_pair) == 1) { + Setattr(imports_hash, Getitem(import_pair, 0), ""); + } else if ((Len(import_pair) == 3) + && Strcmp(Getitem(import_pair, 1), "AS") == 0) { + Setattr(imports_hash, Getitem(import_pair, 0), Getitem(import_pair, 2)); + } else { + Swig_warning(WARN_MODULA3_BAD_IMPORT, input_file, line_number, + "Malformed import '%s' for typemap '%s' defined for type '%s'\n", imp, typemap, SwigType_str(Getattr(node, "type"), 0)); + } + Delete(import_pair); + } + } + Delete(import_list); + } + Delete(imports_attribute); + } + + /* ----------------------------------------------------------------------------- + * emitImportStatements() + * ----------------------------------------------------------------------------- */ + + void emitImportStatements(Hash *imports_hash, String *code) { + // Add the imports statements into code + Iterator imp = First(imports_hash); + while (imp.key != NIL) { + Printf(code, "IMPORT %s", imp.key); + String *imp_as = imp.item; + if (hasContent(imp_as)) { + Printf(code, " AS %s", imp_as); + } + Printf(code, ";\n"); + imp = Next(imp); + } + } + +}; /* class MODULA3 */ + +/* ----------------------------------------------------------------------------- + * swig_modula3() - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_modula3(void) { + return new MODULA3(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *MODULA3::usage = (char *) "\ +Modula 3 Options (available with -modula3)\n\ + -generateconst <file> - generate code for computing numeric values of constants\n\ + -generaterename <file> - generate suggestions for %rename\n\ + -generatetypemap <file> - generate templates for some basic typemaps\n\ + -oldvarnames - old intermediary method names for variable wrappers\n\ +\n"; + +/* + -generateconst <file> - stem of the .c source file for computing the numeric values of constants\n\ + -generaterename <file> - stem of the .i source file containing %rename suggestions\n\ + -generatetypemap <file> - stem of the .i source file containing typemap patterns\n\ +*/ diff --git a/Source/Modules/module.cxx b/Source/Modules/module.cxx new file mode 100644 index 0000000..bd82b9e --- /dev/null +++ b/Source/Modules/module.cxx @@ -0,0 +1,57 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * module.cxx + * + * This file is responsible for the module system. + * ----------------------------------------------------------------------------- */ + +char cvsroot_module_cxx[] = "$Id: module.cxx 10003 2007-10-17 21:42:11Z wsfulton $"; + +#include "swigmod.h" + +struct Module { + ModuleFactory fac; + char *name; + Module *next; + Module(const char *n, ModuleFactory f) { + fac = f; + name = new char[strlen(n) + 1]; + strcpy(name, n); + next = 0; + } ~Module() { + delete[]name; + } +}; + +static Module *modules = 0; + +/* ----------------------------------------------------------------------------- + * void Swig_register_module() + * + * Register a module. + * ----------------------------------------------------------------------------- */ + +void Swig_register_module(const char *n, ModuleFactory f) { + Module *m = new Module(n, f); + m->next = modules; + modules = m; +} + +/* ----------------------------------------------------------------------------- + * Language *Swig_find_module() + * + * Given a command line option, locates the factory function. + * ----------------------------------------------------------------------------- */ + +ModuleFactory Swig_find_module(const char *name) { + Module *m = modules; + while (m) { + if (strcmp(m->name, name) == 0) { + return m->fac; + } + m = m->next; + } + return 0; +} diff --git a/Source/Modules/mzscheme.cxx b/Source/Modules/mzscheme.cxx new file mode 100644 index 0000000..a40f00d --- /dev/null +++ b/Source/Modules/mzscheme.cxx @@ -0,0 +1,834 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * mzscheme.cxx + * + * Mzscheme language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_mzscheme_cxx[] = "$Id: mzscheme.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +static const char *usage = (char *) "\ +Mzscheme Options (available with -mzscheme)\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -declaremodule - Create extension that declares a module\n\ + -noinit - Do not emit scheme_initialize, scheme_reload,\n\ + scheme_module_name functions\n\ + -dynamic-load <library>,[library,...] - Do not link with these libraries, dynamic load\n\ + them\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 char *prefix = 0; +static bool declaremodule = false; +static bool noinit = false; +//DLOPEN PATCH +static char *load_libraries = NULL; +//DLOPEN PATCH +static String *module = 0; +static char *mzscheme_path = (char *) "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 = new char[strlen(argv[i + 1]) + 2]; + strcpy(prefix, 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); + } +// DLOPEN PATCH + else if (strcmp(argv[i], "-dynamic-load") == 0) { + load_libraries = new char[strlen(argv[i + 1]) + 2]; + strcpy(load_libraries, argv[i + 1]); + Swig_mark_arg(i++); + Swig_mark_arg(i); + } +// DLOPEN PATCH + } + } + + // If a prefix has been specified make sure it ends in a '_' + + if (prefix) { + if (prefix[strlen(prefix)] != '_') { + prefix[strlen(prefix) + 1] = 0; + prefix[strlen(prefix)] = '_'; + } + } else + prefix = (char *) "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"); + Printf(f_runtime, "#define SWIGMZSCHEME\n"); + Printf(f_runtime, "\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"); + + // DLOPEN PATCH + if (load_libraries) { + Printf(f_init, "mz_set_dlopen_libraries(\"%s\");\n", load_libraries); + } + // DLOPEN PATCH + + 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); + Close(f_begin); + 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 *source = NewString(""); + String *target = NewString(""); + String *arg = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *build = NewString(""); + String *tm; + int argout_set = 0; + int i = 0; + int numargs; + int numreq; + String *overname = 0; + + // PATCH DLOPEN + if (load_libraries) { + ParmList *parms = Getattr(n, "parms"); + SwigType *type = Getattr(n, "type"); + String *name = NewString("caller"); + Setattr(n, "wrap:action", Swig_cresult(type, "result", Swig_cfunction_call(name, parms))); + } + // PATCH DLOPEN + + // 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); + + // DLOPEN PATCH + /* 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)()")); */ + } + } + // DLOPEN PATCH + + // adds local variables + Wrapper_add_local(f, "lenv", "int lenv = 1"); + Wrapper_add_local(f, "values", "Scheme_Object *values[MAXVALUES]"); + + // DLOPEN PATCH + 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"); + } + // DLOPEN PATCH + + // 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(source); + Clear(target); + Clear(arg); + Printf(source, "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"); + } + } + + /* 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"); + argout_set = 1; + } 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, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + 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); + } else { + 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); + 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(source); + 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]"); + /* Printv(f->code, tm, "\n",NIL); */ + 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)); + if ((SwigType_type(type) == T_STRING)) { + Printf(f_header, "\"%s\";\n", value); + } else if (SwigType_type(type) == T_CHAR) { + 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 *n = NewHash(); + Setattr(n, "name", var_name); + Setattr(n, "sym:name", iname); + Setattr(n, "type", type); + SetFlag(n, "feature:immutable"); + variableWrapper(n); + Delete(n); + } + } + 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", Getattr(n, "classtype")); + + 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, ""), ")&((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; + } + + + /* ------------------------------------------------------------ + * validIdentifer() + * ------------------------------------------------------------ */ + + 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/Source/Modules/ocaml.cxx b/Source/Modules/ocaml.cxx new file mode 100644 index 0000000..5b0e78a --- /dev/null +++ b/Source/Modules/ocaml.cxx @@ -0,0 +1,1866 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * ocaml.cxx + * + * Ocaml language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_ocaml_cxx[] = "$Id: ocaml.cxx 11246 2009-06-05 17:19:29Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +static const char *usage = (char *) + ("Ocaml Options (available with -ocaml)\n" + "-prefix <name> - Set a prefix <name> to be prepended to all names\n" + "-where - Emit library location\n" + "-suffix <name> - Change .cxx to something else\n" "-oldvarnames - old intermediary method names for variable wrappers\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 char *prefix = 0; +static char *ocaml_path = (char *) "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 String *name_qualifier = 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", " 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 = new char[strlen(argv[i + 1]) + 2]; + strcpy(prefix, 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]) { + 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 '_' + + if (prefix) { + if (prefix[strlen(prefix)] != '_') { + prefix[strlen(prefix) + 1] = 0; + prefix[strlen(prefix)] = '_'; + } + } else + prefix = (char *) "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; + } + + /* ------------------------------------------------------------ + * 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. + */ + { + 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; + } + } + } + } + + /* 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", "%v__set__"); + Swig_name_register("get", "%v__get__"); + } + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGOCAML\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); + } + + Language::top(n); + + 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.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); + Close(f_begin); + 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); + Close(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); + Close(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)); + } + + /* ------------------------------------------------------------ + * 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 *source = NewString(""); + String *target = NewString(""); + String *arg = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *build = NewString(""); + String *tm; + int argout_set = 0; + 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; + + // 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) { // 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) { + String *opname = Copy(Getattr(n, "memberfunctionHandler:sym:name")); + + Replaceall(opname, "operator ", ""); + + if (strstr(Char(mangled_name), "__get__")) { + String *set_name = Copy(mangled_name); + if (!GetFlag(n, "feature:immutable")) { + Replaceall(set_name, "__get__", "__set__"); + Printf(f_class_ctors, " \"%s\", (fun args -> " "if args = (C_list [ raw_ptr ]) then %s args else %s args) ;\n", opname, mangled_name, set_name); + Delete(set_name); + } else { + Printf(f_class_ctors, " \"%s\", (fun args -> " "if args = (C_list [ raw_ptr ]) then %s args else C_void) ;\n", opname, mangled_name); + } + } else if (strstr(Char(mangled_name), "__set__")) { + ; /* Nothing ... handled by the case above */ + } else { + 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)"); + Wrapper_add_local(f, "_v", "int _v = 0"); + if (isOverloaded) { + Wrapper_add_local(f, "i", "int i"); + Wrapper_add_local(f, "argc", "int argc = caml_list_length(args)"); + Wrapper_add_local(f, "argv", "CAML_VALUE *argv"); + + Printv(f->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); + } + 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); + + 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(source); + Clear(target); + Clear(arg); + Printf(source, "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"); + } + } + + /* 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"); + argout_set = 1; + } 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 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"); + 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, "result", 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, "result", 0))) { + Replaceall(tm, "$source", "swig_result"); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + + if ((tm = Swig_typemap_lookup("swig_result", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + 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); + if (isOverloaded) + Printv(f->code, "free(argv);\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, "_v", "int _v = 0"); + 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, "\n", NIL); + Printf(df->code, "failwith(\"No matching function for overloaded '%s'\");\n", iname); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + + DelWrapper(df); + Delete(dispatch); + } + } + + Printf(f_mlbody, + "external %s_f : c_obj list -> c_obj list = \"%s\" ;;\n" + "let %s arg = match %s_f (fnhelper arg) with\n" + " [] -> 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", mangled_name, wname, mangled_name, mangled_name, newobj ? "true" : "false"); + + if (!classmode || in_constructor || in_destructor || static_member_function) + Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name); + + Delete(proc_name); + Delete(source); + 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. In the set case we return C_void. + * + * 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; + String *tm2 = NewString("");; + String *argnum = NewString("0"); + String *arg = NewString("SWIG_Field(args,0)"); + 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 scheme. + 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, "swig_result", "CAML_VALUE swig_result"); + + 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"); + /* Printv(f->code, tm, "\n",NIL); */ + 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"); + Printv(f->code, tm, "\n", NIL); + } 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"); + Printf(f->code, "%s\n", tm); + } else { + throw_unhandled_ocaml_type_error(t, "varout/out"); + } + + Printf(f->code, "\nreturn 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); + Delete(argnum); + Delete(arg); + Delete(tm2); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler -- + * Overridden to set static_member_function + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + int rv; + static_member_function = 1; + rv = 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 *value = Getattr(n, "value"); + String *qvalue = Getattr(n, "qualified:value"); + String *rvalue = NewString(""); + String *temp = 0; + + if (qvalue) + value = qvalue; + + if (!name) { + name = mangleNameForCaml(Getattr(n, "name")); + Insert(name, 0, "_swig_wrap_"); + Setattr(n, "feature:symname", name); + } + // 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); + Delete(temp); + } + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 0)) { + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "'", temp, "'", NIL); + Delete(temp); + } + // Create variable and assign it a value + + Printf(f_header, "static %s = ", SwigType_lstr(type, name)); + if ((SwigType_type(type) == T_STRING)) { + Printf(f_header, "\"%s\";\n", value); + } else if (SwigType_type(type) == T_CHAR) { + Printf(f_header, "\'%s\';\n", value); + } else { + Printf(f_header, "%s;\n", 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 = 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, 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"); + + if (!name) + return SWIG_OK; + + String *mangled_sym_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); + + + classname = mangled_sym_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_sym_name, name_normalized); + + Printf(f_mlbody, "external __%s_sizeof : unit -> int = " "\"_wrap_%s_sizeof\"\n", classname, mangled_sym_name); + } + + + /* Insert sizeof operator for concrete classes */ + if (sizeof_feature) { + Printv(f_class_ctors, "\"sizeof\" , (fun args -> C_int (__", classname, "_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", classname); + 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", classname); + + 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; + } + + String *fully_qualify_enum_name(Node *n, String *name) { + Node *parent = 0; + String *qualification = NewString(""); + String *fully_qualified_name = NewString(""); + String *parent_type = 0; + String *normalized_name; + + parent = parentNode(n); + while (parent) { + parent_type = nodeType(parent); + if (Getattr(parent, "name")) { + String *parent_copy = NewStringf("%s::", Getattr(parent, "name")); + if (!Cmp(parent_type, "class") || !Cmp(parent_type, "namespace")) + Insert(qualification, 0, parent_copy); + Delete(parent_copy); + } + if (!Cmp(parent_type, "class")) + break; + parent = parentNode(parent); + } + + Printf(fully_qualified_name, "%s%s", qualification, name); + + normalized_name = normalizeTemplatedClassName(fully_qualified_name); + if (!strncmp(Char(normalized_name), "enum ", 5)) { + Insert(normalized_name, 5, qualification); + } + + return normalized_name; + } + + /* Benedikt Grundmann inspired --> Enum wrap styles */ + + int enumvalueDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *qvalue = 0; + + if (name_qualifier) { + qvalue = Copy(name_qualifier); + Printv(qvalue, name, NIL); + } + + if (const_enum && 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 + + if (qvalue) + Setattr(n, "qualified:value", qvalue); + + String *evname = SwigType_manglestr(qvalue); + 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) { + 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) + Delete(name_qualifier); + char *strip_position; + name_qualifier = fully_qualify_enum_name(n, NewString("")); + + 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. + * Original: + * C++/Python polymorphism demo code, copyright (C) 2002 Mark Rose + * <mrose@stm.lbl.gov> + * + * 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; + String *value; + String *decl; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_type; + int status = SWIG_OK; + int idx; + bool pure_virtual = false; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + storage = Getattr(n, "storage"); + value = Getattr(n, "value"); + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + w = NewWrapper(); + declaration = NewString(""); + Wrapper_add_local(w, "swig_result", "CAMLparam0();\n" "SWIG_CAMLlocal2(swig_result,args)"); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s {", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s;", target); + Delete(target); + + /* 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) { + if (!(ignored_method && !pure_virtual)) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), 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++ -> Ocaml) */ + String *arglist = NewString(""); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + 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) { + 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 Python 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, "swig_result = " "callback3(*caml_named_value(\"swig_runmethod\")," "swig_get_self(),copy_string(\"%s\"),args);\n", Getattr(n, "name")); + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Printf(w->code, "if (result == NULL) {\n"); + 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 aruments, 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(""); + + idx = 0; + + /* this seems really silly. the node's type excludes + * qualifier/pointer/reference markers, which have to be retrieved + * from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and + * out the correct type. it's not just me, similar silliness also + * occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "c_result", w); + Setattr(n, "type", type); + 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, "$input", "swig_result"); + Replaceall(tm, "$result", Getattr(p, "name")); + 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. return_type 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(return_type)) { + Printf(w->code, "CAMLreturn_type((%s)c_result);\n", SwigType_lstr(return_type, "")); + } else { + Printf(w->code, "CAMLreturn_type(*c_result);\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")) { + 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(return_type); + 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")); + 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, 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, 0, 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")); + q = Copy(p); + set_nextSibling(p, parms); + parms = p; + + { + 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("ocaml.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'ocaml.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/Source/Modules/octave.cxx b/Source/Modules/octave.cxx new file mode 100644 index 0000000..aeb72f7 --- /dev/null +++ b/Source/Modules/octave.cxx @@ -0,0 +1,1425 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * octave.cxx + * + * Octave language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_octave_cxx[] = "$Id$"; + +#include "swigmod.h" + +static const char *usage = (char *) "\ +Octave Options (available with -octave)\n\ + -api <N> - Generate code that assumes Octave API N [default: 37]\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; + + int api_version; + + Hash *docs; + +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) { + /* 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(); + api_version = 0; + } + + 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, stderr); + } else if (strcmp(argv[i], "-api") == 0) { + if (argv[i + 1]) { + api_version = atoi(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } + } + } + + SWIG_library_directory("octave"); + Preprocessor_define("SWIGOCTAVE 1", 0); + SWIG_config_file("octave.swg"); + SWIG_typemap_lang("octave"); + allow_overloading(); + } + + 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"); + Printf(f_runtime, "#define SWIGOCTAVE\n"); + Printf(f_runtime, "#define SWIG_name_d \"%s\"\n", module); + Printf(f_runtime, "#define SWIG_name %s\n", module); + Printf(f_runtime, "#define OCTAVE_API_VERSION_OPTION %i\n", api_version); + + 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 void 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.swg", f_runtime); + + Printf(f_init, "}\n"); + Printf(s_global_tab, "{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); + Close(f_begin); + 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,"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) { + 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, "0"); + 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")) { + type = SwigType_base(type); + Node *lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + Append(decl_info, "@var{retval} = "); + String *type_str = NewString(""); + Printf(type_str, "@var{retval} is of type %s. ", type); + Append(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, "feval(\"%s\",octave_value_list(),0);\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"; + } + + void make_autodocParmList(Node *n, String *decl_str, String *args_str) { + String *pdocs = Copy(Getattr(n, "feature:pdocs")); + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + Node *lookup; + + if (pdocs) + Append(pdocs, "\n"); + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + for (p = plist; p; p = pnext) { + String *name = 0; + String *type = 0; + String *value = 0; + String *ptype = 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"); + ptype = Getattr(p, "tmap:doc:pytype"); + } + + name = name ? name : Getattr(p, "name"); + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + String *tex_name = NewString(""); + if (name) + Printf(tex_name, "@var{%s}", name); + else + Printf(tex_name, "@var{?}"); + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + } else { + pnext = nextSibling(p); + } + + if (Len(decl_str)) + Append(decl_str, ", "); + Append(decl_str, tex_name); + + if (value) { + if (Strcmp(value, "NULL") == 0) + value = NewString("nil"); + else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0) + value = NewString("true"); + else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0) + value = NewString("false"); + else { + lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(decl_str, " = %s", value); + } + + if (type) { + String *type_str = NewString(""); + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + Printf(type_str, "%s is of type %s. ", tex_name, type); + Append(args_str, type_str); + Delete(type_str); + } + + Delete(tex_name); + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + } + + virtual int functionWrapper(Node *n) { + Wrapper *f = NewWrapper(); + 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")); + + Printv(f->def, "static octave_value_list ", overname, " (const octave_value_list& args, int nargout) {", NIL); + + 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, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$result", "_outv"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printf(f->code, "fail:\n"); // we should free locals etc if this happens + Printf(f->code, "return _out;\n"); + Printf(f->code, "}\n"); + + Replaceall(f->code, "$symname", iname); + Wrapper_print(f, f_wrappers); + DelWrapper(f); + + if (last_overload) + dispatchFunction(n); + + if (!overloaded || last_overload) { + process_autodoc(n); + 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(""); + + Printv(f->def, "static octave_value_list ", wname, " (const octave_value_list& args, int nargout) {", NIL); + 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(iname); + String *setname = Swig_name_set(iname); + + Printf(setf->def, "static octave_value_list _wrap_%s(const octave_value_list& args,int nargout) {", setname); + Printf(setf->def, "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, "fail:\n"); + Printf(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; + Printf(getf->def, "static octave_value_list _wrap_%s(const octave_value_list& args,int nargout) {", getname); + 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,_wrap_%s,_wrap_%s,2,0},\n", iname, getname, setname); + + 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 *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", 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); + + 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 *disown_shadow = NewString(""); + Printf(disown_shadow, "static octave_value_list _wrap_disown_%s_shadow " "(const octave_value_list& args, int nargout) {\n", class_name); + Printf(disown_shadow, " if (args.length()!=1) {\n"); + Printf(disown_shadow, " error(\"disown takes no arguments\");\n"); + Printf(disown_shadow, " return octave_value_list();\n"); + Printf(disown_shadow, " }\n"); + Printf(disown_shadow, " _wrap_disown_%s (args, nargout);\n", class_name); + Printf(disown_shadow, " return args;\n"); + Printf(disown_shadow, "}\n"); + Printv(f_wrappers, disown_shadow, NIL); + Delete(disown_shadow); + Printf(s_members_tab, "{\"__disown\",_wrap_disown_%s_shadow,0,0,0,0},\n", class_name); + } + + Printf(s_members_tab, "{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 *cname = Swig_name_construct(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) + Printv(f_wrappers, "_wrap_delete_", class_name, ",", NIL); + 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(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 *rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + + if (!Getattr(n, "sym:nextSibling")) { + String *tname = texinfo_name(n); + Printf(s_members_tab, "{\"%s\",%s,0,0,0,%s},\n", + realname, rname, tname); + Delete(tname); + } + + Delete(rname); + 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_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + String *setname = GetFlag(n, "feature:immutable") ? + NewString("octave_set_immutable") : Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + assert(s_members_tab); + + Printf(s_members_tab, "{\"%s\",0,%s,%s,0,0},\n", symname, getname, setname); + + Delete(getname); + Delete(setname); + 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); + 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 *rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + + if (!Getattr(n, "sym:nextSibling")) { + String *tname = texinfo_name(n); + Printf(s_members_tab, "{\"%s\",%s,0,0,1,%s},\n", + realname, rname, tname); + Delete(tname); + } + + Delete(rname); + 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_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + String *setname = GetFlag(n, "feature:immutable") ? + NewString("octave_set_immutable") : Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + assert(s_members_tab); + + Printf(s_members_tab, "{\"%s\",0,%s,%s,1,0},\n", symname, getname, setname); + + Delete(getname); + Delete(setname); + } + 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")); + 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, 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, 0, 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; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_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; + } + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + // determine if the method returns a pointer + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + // form complete return type + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + // virtual method definition + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + + // header declaration + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + 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 ((tm = 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) { + if (!(ignored_method && !pure_virtual)) { + String *cres = SwigType_lstr(return_type, "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++ -> Python) + String *parse_args = NewString(""); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + 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; + int use_parse = 0; + while (p != NULL) { + 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) { + 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 { + use_parse = 1; + Append(parse_args, parse); + 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"); + + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + 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(return_type, 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, "$input", temp); + Replaceall(tm, "$result", Getattr(p, "name")); + 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(return_type, 0); + if (!SwigType_isreference(return_type)) { + 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")) { + 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(return_type); + 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/Source/Modules/overload.cxx b/Source/Modules/overload.cxx new file mode 100644 index 0000000..38cb729 --- /dev/null +++ b/Source/Modules/overload.cxx @@ -0,0 +1,792 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * 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. + * ----------------------------------------------------------------------------- */ + +char cvsroot_overload_cxx[] = "$Id: overload.cxx 11455 2009-07-26 21:29:55Z wsfulton $"; + +#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 */ +}; + +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; +} + +/* ----------------------------------------------------------------------------- + * 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. + * ----------------------------------------------------------------------------- */ + +static 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; + 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 (no type checking rule 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 (no type checking rule 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. Non-const method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(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. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(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. Non-const method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(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. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(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 is shadowed by %s at %s:%d.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(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. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(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; +} + +// /* ----------------------------------------------------------------------------- +// * print_typecheck() +// * ----------------------------------------------------------------------------- */ + +static bool print_typecheck(String *f, int j, Parm *pj) { + char tmp[256]; + sprintf(tmp, Char(argv_template_string), j); + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + Replaceid(tm, Getattr(pj, "lname"), "_v"); + String *conv = Getattr(pj, "implicitconv"); + if (conv) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, tm, "\n", NIL); + 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 = 1; + for (i = 0; i < nfunc; i++) { + int fn = 0; + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (num_arguments > *maxargs) + *maxargs = num_arguments; + int varargs = emit_isvarargs(pi); + + if (!varargs) { + 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); + } + } else { + Printf(f, "if (%s >= %d) {\n", argc_template_string, num_required); + } + 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) { + /* 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 = 1; + //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) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, "{\n", tm, "}\n", NIL); + 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); + + 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). +*/ +String *Swig_overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *maxargs) { + 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"); + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (num_arguments > *maxargs) + *maxargs = num_arguments; + int varargs = emit_isvarargs(pi); + + if (!varargs) { + 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); + } + } else { + Printf(f, "if (%s >= %d) {\n", argc_template_string, num_required); + } + + /* 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 = (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) { + /* 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 */ + bool emitcheck = 0; + 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 = 1; + //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) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, "{\n", tm, "}\n", NIL); + 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"); + + + String *lfmt = ReplaceFormat(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); + + Delete(lfmt); + Delete(coll); + } + Delete(dispatch); + return f; +} + +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxargs) { + + if (fast_dispatch_mode || GetFlag(n, "feature:fastdispatch")) { + return Swig_overload_dispatch_fast(n, fmt, maxargs); + } + + 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"); + 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; + int varargs = emit_isvarargs(pi); + + if (!varargs) { + 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); + } + } else { + Printf(f, "if (%s >= %d) {\n", argc_template_string, num_required); + } + + 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)) { + 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 */ + } + Delete(dispatch); + return f; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_check() + * ----------------------------------------------------------------------------- */ +void Swig_overload_check(Node *n) { + Swig_overload_rank(n, false); +} diff --git a/Source/Modules/perl5.cxx b/Source/Modules/perl5.cxx new file mode 100644 index 0000000..34b2701 --- /dev/null +++ b/Source/Modules/perl5.cxx @@ -0,0 +1,1768 @@ +/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=2:tabstop=8:smarttab: + */ + +/* ---------------------------------------------------------------------------- + * 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. + * + * perl5.cxx + * + * Perl5 language module for SWIG. + * ------------------------------------------------------------------------- */ + +char cvsroot_perl5_cxx[] = "$Id: perl5.cxx 11397 2009-07-15 07:43:16Z olly $"; + +#include "swigmod.h" +#include "cparse.h" +static int treduce = SWIG_cparse_template_reduce(0); + +#include <ctype.h> + +static const char *usage = (char *) "\ +Perl5 Options (available with -perl5)\n\ + -static - Omit code related to dynamic loading\n\ + -nopm - Do not generate the .pm file\n\ + -proxy - Create proxy classes\n\ + -noproxy - Don't create proxy classes\n\ + -const - Wrap constants as constants and not variables (implies -proxy)\n\ + -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ + -cppcast - Enable C++ casting operators\n\ + -compat - Compatibility mode\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_header = 0; +static File *f_wrappers = 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); + } + + /* 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' --> '%x'\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; + int cppcast = 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], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-compat") == 0) { + compat = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + 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) { + + /* 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); + + 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"); + Printf(f_runtime, "#define SWIGPERL\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")); + + 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"); + } + } + String *underscore_module = Copy(module); + Replaceall(underscore_module,":","_"); + + if (verbose > 0) { + fprintf(stdout, "top: using namespace_module: %s\n", Char(namespace_module)); + } + + /* 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 == NULL) { + 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); + + 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"); + Close(f_pm); + 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); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * 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; + + 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. */ + i = 0; + 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); + } + + /* 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, "result", f, actioncode))) { + SwigType *t = Getattr(n, "type"); + Replaceall(tm, "$source", "result"); + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", 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, "++PL_markstack_ptr; 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(iname); + String *setname = Swig_name_set(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)); + 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) { + String *tm = NewStringf("&SWIGTYPE%s", SwigType_manglestr(t)); + if (Replaceall(tt, "$1_descriptor", tm)) { + SwigType_remember(t); + } + Delete(tm); + SwigType *st = Copy(t); + SwigType_add_pointer(st); + tm = NewStringf("&SWIGTYPE%s", SwigType_manglestr(st)); + if (Replaceall(tt, "$&1_descriptor", tm)) { + SwigType_remember(st); + } + Delete(tm); + Delete(st); + } else { + tt = (String *) "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); + + 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 */ + + Printv(pm, + "sub DISOWN {\n", + tab4, "my $self = shift;\n", + 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); + + /* Only output the following methods if a class has member data */ + + Delete(operators); + operators = 0; + } + 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(class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(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(Swig_name_member(class_name, symname)), ";\n", NIL); + Printv(pcode, "*swig_", symname, "_set = *", cmodule, "::", Swig_name_set(Swig_name_member(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; + Language::constructorHandler(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(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(symname), " {\n", NIL); + } + + Printv(pcode, + tab4, "my $pkg = shift;\n", + tab4, "my $self = ", cmodule, "::", Swig_name_construct(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(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(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(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(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(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) { + Printf(stderr, "%s : Line %d. Unable to locate file %s\n", input_file, line_number, value); + } else { + char buffer[4096]; + while (fgets(buffer, 4095, f)) { + Printf(pragma_include, "%s", buffer); + } + } + fclose(f); + } + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + } + } + 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 = DohSplitLines(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"); + } +}; + +/* ----------------------------------------------------------------------------- + * 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/Source/Modules/php.cxx b/Source/Modules/php.cxx new file mode 100644 index 0000000..a0c9e24 --- /dev/null +++ b/Source/Modules/php.cxx @@ -0,0 +1,2739 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * php.cxx + * + * PHP language module for SWIG. + * ----------------------------------------------------------------------------- + */ + +/* FIXME: PHP5 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...) + */ + +char cvsroot_php_cxx[] = "$Id: php.cxx 11637 2009-08-18 16:23:23Z vmiklos $"; + +#include "swigmod.h" + +#include <ctype.h> +#include <errno.h> + +static const char *usage = (char *) "\ +PHP Options (available with -php)\n\ + -cppext - cpp file extension (default to .cpp)\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_entry; +static String *cs_entry; +static String *all_cs_entry; +static String *pragma_incl; +static String *pragma_code; +static String *pragma_phpinfo; +static String *s_oowrappers; +static String *s_fakeoowrappers; +static String *s_phpclasses; + +/* 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) (SwigType *t, String *mangled, String *clientdata) = 0; +} + +static void SwigPHP_emit_resource_registrations() { + Iterator ki; + + 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; + + // Write out destructor function header + Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(_wrap_destroy%s) {\n", key); + + // 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) { + Printf(s_wrappers, " %s(rsrc, SWIGTYPE%s->name TSRMLS_CC);\n", destructor, key); + } else { + Printf(s_wrappers, " /* No destructor for class %s */\n", human_name); + Printf(s_wrappers, " efree(rsrc->ptr);\n"); + } + } else { + Printf(s_wrappers, " /* No destructor for simple type %s */\n", key); + Printf(s_wrappers, " efree(rsrc->ptr);\n"); + } + + // close function + Printf(s_wrappers, "}\n"); + + // 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" + "(_wrap_destroy%s,NULL,(char *)(SWIGTYPE%s->name),module_number);\n", key, key, key); + + // store php type in class struct + Printf(s_oinit, "SWIG_TypeClientData(SWIGTYPE%s,&le_swig_%s);\n", key, key); + + ki = Next(ki); + } +} + +class PHP : public Language { +public: + PHP() { + director_language = 1; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + SWIG_library_directory("php"); + SWIG_config_cppext("cpp"); + + 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], "-cppext") == 0) { + if (argv[i + 1]) { + 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], "-noshadow") == 0) || (strcmp(argv[i], "-noproxy") == 0)) { + shadow = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } else if (strcmp(argv[i], "-make") == 0 || + strcmp(argv[i], "-withc") == 0 || + strcmp(argv[i], "-withcxx") == 0) { + Printf(stderr, "*** %s is no longer supported.\n", argv[i]); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-phpfull") == 0 || + strcmp(argv[i], "-withlibs") == 0 || + strcmp(argv[i], "-withincs") == 0) { + Printf(stderr, "*** %s is no longer supported.\n*** We recommend building as a dynamically loadable module.\n", argv[i]); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-dlname") == 0) { + Printf(stderr, "*** -dlname is no longer supported.\n*** If you want to change the module name, use -module instead.\n"); + SWIG_exit(EXIT_FAILURE); + } + } + + Preprocessor_define("SWIGPHP 1", 0); + // SWIGPHP5 is deprecated, and no longer documented. + Preprocessor_define("SWIGPHP5 1", 0); + SWIG_typemap_lang("php"); + SWIG_config_file("php.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + String *filen; + String *s_type; + + /* 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("$arg->type != 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 = NewString("/* init section */\n"); + r_init = NewString("/* rinit section */\n"); + s_shutdown = NewString("/* shutdown section */\n"); + r_shutdown = NewString("/* rshutdown section */\n"); + s_header = NewString("/* header section */\n"); + s_wrappers = NewString("/* wrapper section */\n"); + s_type = NewStringEmpty(); + /* subsections of the init section */ + s_vinit = NewString("/* vinit subsection */\n"); + 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"); + Printf(f_runtime, "#define SWIGPHP\n"); + Printf(f_runtime, "\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(); + + 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); + + Printf(f_directors, "\n#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + /* 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(); + + /* Initialize the rest of the module */ + + Printf(s_oinit, "ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, %s_destroy_globals);\n", module, 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, "#ifdef ZTS\n"); + Printf(s_header, "#define SWIG_ErrorMsg() TSRMG(%s_globals_id, zend_%s_globals *, error_msg )\n", module, module); + Printf(s_header, "#define SWIG_ErrorCode() TSRMG(%s_globals_id, zend_%s_globals *, error_code )\n", module, module); + Printf(s_header, "#else\n"); + Printf(s_header, "#define SWIG_ErrorMsg() (%s_globals.error_msg)\n", module); + Printf(s_header, "#define SWIG_ErrorCode() (%s_globals.error_code)\n", module); + Printf(s_header, "#endif\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 %s_destroy_globals(zend_%s_globals * globals) { (void)globals; }\n", module, module); + + Printf(s_header, "\n"); + Printf(s_header, "static void SWIG_ResetError() {\n"); + Printf(s_header, " TSRMLS_FETCH();\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, " int type;\n"); + Append(s_header, " int thisown;\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 *) zend_list_find((*args[0])->value.lval, &type);\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, " int type;\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 *) zend_list_find((*args[0])->value.lval, &type);\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 HAVE_CONFIG_H\n"); + Printf(s_header,"#include \"config.h\"\n"); + Printf(s_header,"#endif\n\n"); + */ + 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.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"); + Printf(f_h, "#ifdef ZTS\n"); + Printf(f_h, "#include \"TSRM.h\"\n"); + Printf(f_h, "#endif\n\n"); + Printf(f_h, "PHP_MINIT_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_MSHUTDOWN_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_RINIT_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_RSHUTDOWN_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_MINFO_FUNCTION(%s);\n\n", module); + + /* 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); + + /* start the init section */ + Append(s_init, "#if ZEND_MODULE_API_NO <= 20090626\n"); + Append(s_init, "#undef ZEND_MODULE_BUILD_ID\n"); + Append(s_init, "#define ZEND_MODULE_BUILD_ID (char*)\"API\" ZEND_TOSTR(ZEND_MODULE_API_NO) ZEND_BUILD_TS ZEND_BUILD_DEBUG ZEND_BUILD_SYSTEM ZEND_BUILD_EXTRA\n"); + Append(s_init, "#endif\n"); + Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n" "#if ZEND_MODULE_API_NO > 20010900\n" " STANDARD_MODULE_HEADER,\n" "#endif\n", NIL); + Printf(s_init, " (char*)\"%s\",\n", module); + Printf(s_init, " %s_functions,\n", module); + Printf(s_init, " PHP_MINIT(%s),\n", module); + Printf(s_init, " PHP_MSHUTDOWN(%s),\n", module); + Printf(s_init, " PHP_RINIT(%s),\n", module); + Printf(s_init, " PHP_RSHUTDOWN(%s),\n", module); + Printf(s_init, " PHP_MINFO(%s),\n", module); + Printf(s_init, "#if ZEND_MODULE_API_NO > 20010900\n"); + Printf(s_init, " NO_VERSION_YET,\n"); + Printf(s_init, "#endif\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 PHP5 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"); + + /* 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 + */ + Printf(s_init, "#define SWIG_php_minit PHP_MINIT_FUNCTION(%s)\n", module); + + /* Emit all of the code */ + Language::top(n); + + SwigPHP_emit_resource_registrations(); + // 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 + Printf(s_init, "PHP_RINIT_FUNCTION(%s)\n{\n", module); + Printf(s_init, "%s\n", r_init); + + /* finish our init section which will have been used by class wrappers */ + Printf(s_vinit, "/* end vinit subsection */\n"); + Printf(s_init, "%s\n", s_vinit); + Clear(s_vinit); + Delete(s_vinit); + + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + + Printv(s_init, "PHP_MSHUTDOWN_FUNCTION(", module, ")\n" + "{\n", + s_shutdown, + "#ifdef ZTS\n" + " ts_free_id(", module, "_globals_id);\n" + "#endif\n" + " return SUCCESS;\n" + "}\n\n", NIL); + + Printf(s_init, "PHP_RSHUTDOWN_FUNCTION(%s)\n{\n", module); + Printf(s_init, "%s\n", r_shutdown); + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + + 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, "#endif /* PHP_%s_H */\n", cap_module); + + Close(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"); + Close(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_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" + "{NULL, NULL, NULL}\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); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + 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?>\n", s_phpclasses); + Close(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) { + // This is for the single main zend_function_entry record + Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname); + String * s = cs_entry; + if (!s) s = s_entry; + Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,NULL)\n", cname, iname); + } + + /* ------------------------------------------------------------ + * 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, "return %s(INTERNAL_FUNCTION_PARAM_PASSTHRU);", &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); + 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, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\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(); + numopt = 0; + + String *outarg = NewStringEmpty(); + String *cleanup = NewStringEmpty(); + + // Not issued for overloaded functions. + if (!overloaded) { + create_command(iname, wname); + } + Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL); + + emit_parameter_variables(l, f); + /* Attach standard typemaps */ + + emit_attach_parmmaps(l, f); + + // 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; + } + if (is_member_director(n)) { + 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"); + Printf(f->code, "upcall = !director->is_overriden_method((char *)\"%s\", (char *)\"%s\");\n", + Swig_class_name(Swig_methodclass(n)), name); + } + + // 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); + } + + 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 */ + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:argout"))) { + 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, "result", f, actioncode))) { + Replaceall(tm, "$input", "result"); + Replaceall(tm, "$source", "result"); + 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, "result", 0))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printf(f->code, "return;\n"); + + /* Error handling code */ + Printf(f->code, "fail:\n"); + Printv(f->code, cleanup, NIL); + Printv(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());", NIL); + + 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, iname); + } 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; + // 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(Swig_methodclass(n), "sym:name"), ':'); + if (ptr) { + ptr++; + } else { + ptr = GetChar(Swig_methodclass(n), "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); + + // For a function with default arguments, we end up with the fullest + // parmlist in full_parmlist. + ParmList *full_parmlist = l; + Hash *ret_types = NewHash(); + Setattr(ret_types, d, d); + + 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); + } + + 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; + full_parmlist = l2; + } + 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 (l != full_parmlist) { + l = full_parmlist; + if (wrapperType == memberfn) + l = nextSibling(l); + } + } + } + + 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"); + exit(1); + } + for (i = 0; i < max_num_of_arguments; ++i) { + arg_names[i] = NULL; + } + + arg_values = (String **) malloc(max_num_of_arguments * sizeof(String *)); + if (!arg_values) { + /* FIXME: How should this be handled? The rest of SWIG just seems + * to not bother checking for malloc failing! */ + fprintf(stderr, "Malloc failed!\n"); + exit(1); + } + for (i = 0; i < max_num_of_arguments; ++i) { + arg_values[i] = NULL; + } + + 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); + 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 == NULL) { + 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; + int 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: { + char *p; + errno = 0; + unsigned int 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: { + 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:{ + 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), '.') == NULL) { + // 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_REFERENCE: + case T_USER: + case T_ARRAY: + 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, "0") == 0 || + Strcmp(value, "0L") == 0) { + Clear(value); + Append(value, "null"); + } else { + 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); + /* We use $r to store the return value, so disallow that as a parameter + * name in case the user uses the "call-time pass-by-reference" feature + * (it's deprecated and off by default in PHP5, but we want to be + * maximally portable). Similarly we use $c for the classname or new + * stdClass object. + */ + Setattr(seen, "r", seen); + Setattr(seen, "c", 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, ","); + 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 { + 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); + 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 (Cmp(d, "void") != 0) { + if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) { + Append(prepare, "$r="); + } else { + Printf(prepare, "$this->%s=", SWIG_PTR); + } + } + if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) { + 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 (Cmp(d, "void") != 0) { + if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) { + Append(prepare, "$r="); + } else { + Printf(prepare, "$this->%s=", SWIG_PTR); + } + } + + if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) { + 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) { + if (Strcmp(Getattr(j, "name"), 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 = NewString("public"); + Swig_warning(WARN_PHP_PUBLIC_BASE, input_file, line_number, Char(warnmsg)); + Delete(warnmsg); + } + } + if (Cmp(acc, "") != 0) { + Append(acc, " "); + } + if (constructor) { + const char * arg0; + if (max_num_of_arguments > 0) { + arg0 = Char(arg_names[0]); + } else { + arg0 = "res"; + Delete(args); + args = NewString("$res=null"); + } + SwigType *t = Getattr(current_class, "classtype"); + String *mangled_type = SwigType_manglestr(SwigType_ltype(t)); + Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args); + Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '_p%s') {\n", arg0, arg0, mangled_type); + Printf(output, "\t\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 (!newobject) + Printf(output, "%s", prepare); + if (constructor) { + if (!directorsEnabled() || !Swig_directorclass(n)) { + 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);\n", 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 (Cmp(d, "void") == 0) { + 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 it has an abstract base, then we can't create a new + * base object. */ + int hasabstractbase = 0; + Node *bases = Getattr(Swig_methodclass(n), "bases"); + if (bases) { + Iterator i = First(bases); + while(i.item) { + if (Getattr(i.item, "abstract")) { + hasabstractbase = 1; + break; + } + i = Next(i); + } + } + if (newobject || !hasabstractbase) { + /* + * _p_Foo -> Foo, _p_ns__Bar -> Bar + * TODO: do this in a more elegant way + */ + Printf(output, "\t\tif (is_resource($r)) {\n"); + if (Getattr(classLookup(Getattr(n, "type")), "module")) { + 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)) {\n"); + Printf(output, "\t\t\t\treturn new %s($r);\n", Getattr(classLookup(d), "sym:name")); + Printf(output, "\t\t\t}\n"); + Printf(output, "\t\t\treturn new $c($r);\n"); + } else { + Printf(output, "\t\t\t$c = new stdClass();\n"); + Printf(output, "\t\t\t$c->_cPtr = $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"); + Printf(output, "\t\tswitch (get_resource_type($r)) {\n"); + Iterator i = First(ret_types); + while (i.item) { + SwigType *ret_type = i.item; + i = Next(i); + Printf(output, "\t\t"); + 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. */ + class_node = current_class; + Delete(mangled); + mangled = NewString(SwigType_manglestr(ret_type)); + class_node = Getattr(zend_types, mangled); + } + if (i.item) { + Printf(output, "case '%s': ", mangled); + } else { + Printf(output, "default: "); + } + const char *classname = GetChar(class_node, "sym:name"); + if (!classname) + classname = GetChar(class_node, "name"); + if (classname) + Printf(output, "return new %s%s($r);\n", prefix, classname); + else + Printf(output, "return $r;\n"); + Delete(mangled); + } + Printf(output, "\t\t}\n"); + } + } else { + Printf(output, "\t\treturn %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; + + SwigType_remember(t); + + /* 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 { + Printf(stderr, "%s: Line %d, Unable to link with type %s\n", input_file, line_number, 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 { + Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, 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 { + Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, 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) { + // 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 || Strcmp(lang, "php4") == 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 { + 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; + //SwigType *t = Getattr(n, "classtype"); + current_class = n; + // String *use_class_name=SwigType_manglestr(SwigType_ltype(t)); + + 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 proxy: 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) { + DOH *key; + 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, "abstract") && !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 "); + } + 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. + while (ki.key) { + key = ki.key; + Printf(s_phpclasses, "\t\tif ($var === '%s') return %s($this->%s,$value);\n", key, ki.item, SWIG_PTR); + ki = Next(ki); + } + } 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"); + + /* Create __isset for PHP 5.1 and later; PHP 5.0 will just ignore it. */ + Printf(s_phpclasses, "\n\tfunction __isset($var) {\n"); + Printf(s_phpclasses, "\t\tif (function_exists('%s_'.$var.'_set')) 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 __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"); + 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"); + } + // Write property GET handlers + ki = First(shadow_get_vars); + + if (ki.key) { + // This class has getters. + Printf(s_phpclasses, "\n\tfunction __get($var) {\n"); + // FIXME: Currently we always use call_user_func for __get, so we can + // check and wrap the result. This is needless if all the properties + // are primitive types. Also this doesn't handle all the cases which + // a method returning an object does. + Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_get';\n", shadow_classname); + Printf(s_phpclasses, "\t\tif (function_exists($func)) {\n"); + Printf(s_phpclasses, "\t\t\t$r = call_user_func($func,$this->%s);\n", SWIG_PTR); + Printf(s_phpclasses, "\t\t\tif (!is_resource($r)) return $r;\n"); + if (Len(prefix) == 0) { + Printf(s_phpclasses, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n"); + } else { + Printf(s_phpclasses, "\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(s_phpclasses, "\t\t\treturn new $c($r);\n"); + Printf(s_phpclasses, "\t\t}\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 { + // 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"); + } 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"); + } + + 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 ( arg0->type == IS_NULL ) { /* not subclassed */\n"); + Printf(director_prot_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n"); + Printf(director_ctor_code, " result = (%s *)new %s(%s);\n", 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 result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args); + Printf(director_prot_ctor_code, "} else {\n result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", 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_rsrc_list_entry *rsrc, const char *type_name TSRMLS_DC) {\n", destructorname); + + Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) rsrc->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_ZTS_ConvertResourceData(ptr,type_name,SWIGTYPE%s TSRMLS_CC);\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); + + Append(f->code, "return;\n"); + Append(f->code, "fail:\n"); + Append(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, s_wrappers); + + 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")); + 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, 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, 0, 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; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewStringEmpty(); + String *return_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; + } + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewStringEmpty(); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (Cmp(type, "void") == 0 && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + 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 ((tm = 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) { + if (!(ignored_method && !pure_virtual)) { + String *cres = SwigType_lstr(return_type, "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(); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + 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 != NULL) { + 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) { + sprintf(source, "obj%d", idx++); + String *input = NewStringf("&%s", source); + Replaceall(tm, "$input", input); + Delete(input); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, "zval ", source, ";\n", NIL); + Printf(wrap_args, "args[%d] = &%s;\n", idx - 1, source); + + Printv(wrap_args, tm, "\n", NIL); + Putc('O', parse_args); + } else { + use_parse = 1; + Append(parse_args, parse); + 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); + } + Append(w->code, "int error;\n"); + if (!idx) { + Printf(w->code, "zval **args = NULL;\n", idx); + } else { + Printf(w->code, "zval *args[%d];\n", idx); + } + Append(w->code, "zval *result, funcname;\n"); + Append(w->code, "MAKE_STD_ZVAL(result);\n"); + Printf(w->code, "ZVAL_STRING(&funcname, (char *)\"%s\", 0);\n", name); + Append(w->code, "if (!swig_self) {\n"); + Append(w->code, " SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");"); + Append(w->code, "}\n\n"); + + /* wrap complex arguments to zvals */ + Printv(w->code, wrap_args, NIL); + + Append(w->code, "call_user_function(EG(function_table), (zval**)&swig_self, &funcname,\n"); + Printf(w->code, " result, %d, args TSRMLS_CC);\n", idx); + + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Replaceall(tm, "$error", "error"); + 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) { + /* this seems really silly. the node's type excludes + * qualifier/pointer/reference markers, which have to be retrieved + * from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and + * out the correct type. it's not just me, similar silliness also + * occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + Replaceall(tm, "$input", "&result"); + 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(return_type, 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, "$input", "result"); + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Append(w->code, "FREE_ZVAL(result);\n"); + + Delete(parse_args); + Delete(cleanup); + Delete(outarg); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(return_type, 0); + if (!SwigType_isreference(return_type)) { + 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, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); + Append(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + 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")) { + 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(return_type); + 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" void typetrace(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_php4(void) { + Printf(stderr, "*** -php4 is no longer supported.\n" + "*** Either upgrade to PHP5 or use SWIG 1.3.36 or earlier.\n"); + SWIG_exit(EXIT_FAILURE); + return NULL; // To avoid compiler warnings. +} + +extern "C" Language *swig_php(void) { + return new_swig_php(); +} diff --git a/Source/Modules/pike.cxx b/Source/Modules/pike.cxx new file mode 100644 index 0000000..00e7500 --- /dev/null +++ b/Source/Modules/pike.cxx @@ -0,0 +1,903 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * pike.cxx + * + * Pike language module for SWIG. + * ----------------------------------------------------------------------------- */ + +/* + * Notes: + * + * - The current approach used for "out" typemaps is inconsistent with + * how "out" typemaps are handled by other language modules. Instead + * of converting the C/C++ type ($1) to a Pike object type (e.g. a + * struct svalue), we're just calling the appropriate push_XXX + * (e.g. push_int) to push the return value onto the stack. + * + * - Pike classes can't have static member functions or data, so we need + * to find some other appropriate mapping for C++ static member functions + * and data. + * + * - Pike doesn't seem to provide any default way to print the memory + * address, etc. for extension objects. Should we do something here? + * + */ + +char cvsroot_pike_cxx[] = "$Id: pike.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> // for isalnum() + +static const char *usage = (char *) "\ +Pike Options (available with -pike)\n\ + [None]\n\ +\n"; + +class PIKE:public Language { +private: + + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_classInit; + + String *PrefixPlusUnderscore; + int current; + + // Wrap modes + enum { + NO_CPP, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }; + +public: + + /* --------------------------------------------------------------------- + * PIKE() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + PIKE() { + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_classInit = 0; + PrefixPlusUnderscore = 0; + current = NO_CPP; + } + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + /* Set location of SWIG library */ + SWIG_library_directory("pike"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGPIKE 1", 0); + + /* Set language-specific configuration file */ + SWIG_config_file("pike.swg"); + + /* Set typemap language */ + SWIG_typemap_lang("pike"); + + /* Enable overloaded methods support */ + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + /* Get the module name */ + String *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_classInit = 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); + Swig_register_filebyname("classInit", f_classInit); + + /* Standard stuff for the SWIG runtime section */ + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGPIKE\n"); + Printf(f_runtime, "\n"); + + Printf(f_header, "#define SWIG_init pike_module_init\n"); + Printf(f_header, "#define SWIG_name \"%s\"\n\n", module); + + /* Change naming scheme for constructors and destructors */ + Swig_name_register("construct", "%c_create"); + Swig_name_register("destroy", "%c_destroy"); + + /* Current wrap type */ + current = NO_CPP; + + /* Emit code for children */ + Language::top(n); + + /* Close the initialization 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); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_classInit); + + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + /* Done */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + const char *c0 = c; + const char *c1 = c0 + 1; + while (*c) { + if (*c == '`' && c == c0) { + c++; + continue; + } + if ((*c == '+' || *c == '-' || *c == '*' || *c == '/') && c == c1) { + c++; + continue; + } + if (!(isalnum(*c) || (*c == '_'))) + return 0; + c++; + } + return 1; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname) { + Printf(f_init, "pike_require(\"%s\");\n", modname); + } + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * strip() + * + * For names that begin with the current class prefix plus an + * underscore (e.g. "Foo_enum_test"), return the base function + * name (i.e. "enum_test"). + * ------------------------------------------------------------ */ + + String *strip(const DOHconst_String_or_char_ptr name) { + String *s = Copy(name); + if (Strncmp(name, PrefixPlusUnderscore, Len(PrefixPlusUnderscore)) != 0) { + return s; + } + Replaceall(s, PrefixPlusUnderscore, ""); + return s; + } + + /* ------------------------------------------------------------ + * add_method() + * ------------------------------------------------------------ */ + + void add_method(const DOHconst_String_or_char_ptr name, const DOHconst_String_or_char_ptr function, const DOHconst_String_or_char_ptr description) { + String *rename = NULL; + switch (current) { + case NO_CPP: + rename = NewString(name); + Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); + break; + case STATIC_FUNC: + case STATIC_VAR: + rename = NewString(name); + Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); + break; + case CONSTRUCTOR: + case DESTRUCTOR: + case MEMBER_FUNC: + case MEMBER_VAR: + rename = strip(name); + Printf(f_classInit, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); + break; + case CLASS_CONST: + assert(false); // shouldn't have gotten here for CLASS_CONST nodes + default: + assert(false); // what is this? + } + Delete(rename); + } + + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + 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"); + + Parm *p; + String *tm; + int i; + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + Wrapper *f = NewWrapper(); + + // 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 */ + int num_arguments = emit_num_arguments(l); + int varargs = emit_isvarargs(l); + + /* Which input argument to start with? */ + int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; + + /* Offset to skip over the attribute name */ + // int offset = (current == MEMBER_VAR) ? 1 : 0; + int offset = 0; + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + Printv(f->def, "static void ", wname, "(INT32 args) {", NIL); + + /* Generate code for argument marshalling */ + String *description = NewString(""); + char source[64]; + 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"); + + if (i < start) { + String *lstr = SwigType_lstr(pt, 0); + Printf(f->code, "%s = (%s) THIS;\n", ln, lstr); + Delete(lstr); + } else { + /* Look for an input typemap */ + sprintf(source, "Pike_sp[%d-args]", i - start + offset); + 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); + String *pikedesc = Getattr(p, "tmap:in:pikedesc"); + if (pikedesc) { + Printv(description, pikedesc, " ", NIL); + } + 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; + } + } + p = nextSibling(p); + } + + /* 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"))) { + 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); + } + } + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* Clear the return stack */ + Printf(actioncode, "pop_n_elems(args);\n"); + + /* Return the function value */ + if (current == CONSTRUCTOR) { + Printv(actioncode, "THIS = (void *) result;\n", NIL); + Printv(description, ", tVoid", NIL); + } else if (current == DESTRUCTOR) { + Printv(description, ", tVoid", NIL); + } else { + Printv(description, ", ", NIL); + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + actioncode = 0; + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + String *pikedesc = Getattr(n, "tmap:out:pikedesc"); + if (pikedesc) { + Printv(description, pikedesc, NIL); + } + 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); + } + } + if (actioncode) { + Append(f->code, actioncode); + Delete(actioncode); + } + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + /* Close the function */ + 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", "resultobj"); + + /* Dump the function out */ + Wrapper_print(f, f_wrappers); + + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + add_method(iname, wname, description); + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + Delete(cleanup); + Delete(outarg); + Delete(description); + Delete(wname); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * + * Emit overloading dispatch function + * ------------------------------------------------------------ */ + + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "%s(args); 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); + + Printf(f->def, "static void %s(INT32 args) {", wname); + + Wrapper_add_local(f, "argc", "INT32 argc"); + Printf(tmp, "struct svalue argv[%d]", maxargs); + Wrapper_add_local(f, "argv", tmp); + Wrapper_add_local(f, "ii", "INT32 ii"); + + Printf(f->code, "argc = args;\n"); + Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs); + Printf(f->code, "argv[ii] = Pike_sp[ii-args];\n"); + Printf(f->code, "}\n"); + + Replaceall(dispatch, "$args", "self, args"); + Printv(f->code, dispatch, "\n", NIL); + Printf(f->code, "Pike_error(\"No matching function for overloaded '%s'.\");\n", symname); + Printv(f->code, "}\n", NIL); + + Wrapper_print(f, f_wrappers); + + String *description = NewString(""); + Printf(description, "tAny,"); + if (current == CONSTRUCTOR || current == DESTRUCTOR) { + Printf(description, " tVoid"); + } else { + String *pd = Getattr(n, "tmap:out:pikedesc"); + if (pd) + Printf(description, " %s", pd); + } + add_method(symname, wname, description); + Delete(description); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + return Language::variableWrapper(n); + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + + Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL); + + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(symname); + Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); + value = wname; + } + + /* Perform constant typemap substitution */ + String *tm = Swig_typemap_lookup("constant", n, value, 0); + if (tm) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", symname); + Replaceall(tm, "$symname", symname); + Replaceall(tm, "$value", value); + 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; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + // return Language::nativeWrapper(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); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + + String *symname = Getattr(n, "sym:name"); + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + PrefixPlusUnderscore = NewStringf("%s_", getClassPrefix()); + + Printf(f_classInit, "start_new_program();\n"); + + /* Handle inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist) > 0) { + Iterator base = First(baselist); + while (base.item) { + String *basename = Getattr(base.item, "name"); + SwigType *basetype = NewString(basename); + SwigType_add_pointer(basetype); + SwigType_remember(basetype); + String *basemangle = SwigType_manglestr(basetype); + Printf(f_classInit, "low_inherit((struct program *) SWIGTYPE%s->clientdata, 0, 0, 0, 0, 0);\n", basemangle); + Delete(basemangle); + Delete(basetype); + base = Next(base); + } + } else { + Printf(f_classInit, "ADD_STORAGE(swig_object_wrapper);\n"); + } + + Language::classHandler(n); + + /* Accessors for member variables */ + /* + List *membervariables = Getattr(n,"membervariables"); + if (membervariables && Len(membervariables) > 0) { + membervariableAccessors(membervariables); + } + */ + + /* Done, close the class and dump its definition to the init function */ + Printf(f_classInit, "add_program_constant(\"%s\", pr = end_program(), 0);\n", symname); + Dump(f_classInit, f_init); + Clear(f_classInit); + + SwigType *tt = NewString(symname); + SwigType_add_pointer(tt); + SwigType_remember(tt); + String *tm = SwigType_manglestr(tt); + Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) pr);\n", tm); + Delete(tm); + Delete(tt); + + Delete(PrefixPlusUnderscore); + PrefixPlusUnderscore = 0; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * + * Method for adding C++ member function + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + current = MEMBER_FUNC; + Language::memberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * + * Method for adding C++ member constructor + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + current = CONSTRUCTOR; + Language::constructorHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + current = DESTRUCTOR; + Language::destructorHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableAccessors() + * ------------------------------------------------------------ */ + + void membervariableAccessors(List *membervariables) { + String *name; + Iterator i; + bool need_setter; + String *funcname; + + /* If at least one of them is mutable, we need a setter */ + need_setter = false; + i = First(membervariables); + while (i.item) { + if (!GetFlag(i.item, "feature:immutable")) { + need_setter = true; + break; + } + i = Next(i); + } + + /* Create a function to set the values of the (mutable) variables */ + if (need_setter) { + Wrapper *wrapper = NewWrapper(); + String *setter = Swig_name_member(getClassPrefix(), (char *) "`->="); + String *wname = Swig_name_wrapper(setter); + Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL); + Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n"); + + i = First(membervariables); + while (i.item) { + if (!GetFlag(i.item, "feature:immutable")) { + name = Getattr(i.item, "name"); + funcname = Swig_name_wrapper(Swig_name_set(Swig_name_member(getClassPrefix(), name))); + Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name); + Printf(wrapper->code, "%s(args);\n", funcname); + Printf(wrapper->code, "return;\n"); + Printf(wrapper->code, "}\n"); + Delete(funcname); + } + i = Next(i); + } + + /* Close the function */ + Printf(wrapper->code, "pop_n_elems(args);\n"); + Printf(wrapper->code, "}\n"); + + /* Dump wrapper code to the output file */ + Wrapper_print(wrapper, f_wrappers); + + /* Register it with Pike */ + String *description = NewString("tStr tFloat, tVoid"); + add_method("`->=", wname, description); + Delete(description); + + /* Clean up */ + Delete(wname); + Delete(setter); + DelWrapper(wrapper); + } + + /* Create a function to get the values of the (mutable) variables */ + Wrapper *wrapper = NewWrapper(); + String *getter = Swig_name_member(getClassPrefix(), (char *) "`->"); + String *wname = Swig_name_wrapper(getter); + Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL); + Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n"); + + i = First(membervariables); + while (i.item) { + name = Getattr(i.item, "name"); + funcname = Swig_name_wrapper(Swig_name_get(Swig_name_member(getClassPrefix(), name))); + Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name); + Printf(wrapper->code, "%s(args);\n", funcname); + Printf(wrapper->code, "return;\n"); + Printf(wrapper->code, "}\n"); + Delete(funcname); + i = Next(i); + } + + /* Close the function */ + Printf(wrapper->code, "pop_n_elems(args);\n"); + Printf(wrapper->code, "}\n"); + + /* Dump wrapper code to the output file */ + Wrapper_print(wrapper, f_wrappers); + + /* Register it with Pike */ + String *description = NewString("tStr, tMix"); + add_method("`->", wname, description); + Delete(description); + + /* Clean up */ + Delete(wname); + Delete(getter); + DelWrapper(wrapper); + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + List *membervariables = Getattr(getCurrentClass(), "membervariables"); + if (!membervariables) { + membervariables = NewList(); + Setattr(getCurrentClass(), "membervariables", membervariables); + } + Append(membervariables, n); + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + current = STATIC_FUNC; + Language::staticmemberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * + * Create a C++ constant + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + current = CLASS_CONST; + constantWrapper(n); + current = NO_CPP; + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + current = STATIC_VAR; + Language::staticmembervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } +}; + +/* ----------------------------------------------------------------------------- + * swig_pike() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_pike() { + return new PIKE(); +} +extern "C" Language *swig_pike(void) { + return new_swig_pike(); +} diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx new file mode 100644 index 0000000..83df3aa --- /dev/null +++ b/Source/Modules/python.cxx @@ -0,0 +1,4067 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * python.cxx + * + * Python language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_python_cxx[] = "$Id: python.cxx 11518 2009-08-08 22:56:10Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" + +static int treduce = SWIG_cparse_template_reduce(0); + +#include <ctype.h> + +#define PYSHADOW_MEMBER 0x2 + +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 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_imports = 0; +static String *f_shadow_stubs = 0; + +static String *methods; +static String *class_name; +static String *shadow_indent = 0; +static int in_class = 0; +static int classic = 0; +static int modern = 0; +static int new_repr = 1; +static int no_header_file = 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; +static int classptr = 0; +/* Other options */ +static int shadowimport = 1; +static int buildnone = 0; +static int nobuildnone = 0; +static int safecstrings = 0; +static int dirvtable = 0; +static int proxydel = 1; +static int fastunpack = 0; +static int fastproxy = 0; +static int fastquery = 0; +static int fastinit = 0; +static int olddefs = 0; +static int modernargs = 0; +static int aliasobj0 = 0; +static int castmode = 0; +static int extranative = 0; +static int outputtuple = 0; +static int nortti = 0; + +/* flags for the make_autodoc function */ +enum autodoc_t { + AUTODOC_CLASS, + AUTODOC_CTOR, + AUTODOC_DTOR, + AUTODOC_STATICFUNC, + AUTODOC_FUNC, + AUTODOC_METHOD +}; + + +static const char *usage1 = (char *) "\ +Python Options (available with -python)\n\ + -aliasobj0 - Alias obj0 when using fastunpack, needed for some old typemaps \n\ + -buildnone - Use Py_BuildValue(" ") to obtain Py_None (default in Windows)\n\ + -castmode - Enable the casting mode, which allows implicit cast between types in python\n\ + -classic - Use classic classes only\n\ + -classptr - Generate shadow 'ClassPtr' as in older swig versions\n\ + -cppcast - Enable C++ casting operators (default) \n\ + -dirvtable - Generate a pseudo virtual table for directors for faster dispatch \n\ + -extranative - Return extra native C++ wraps for std containers when possible \n\ + -fastinit - Use fast init mechanism for classes (default)\n\ + -fastunpack - Use fast unpack mechanism to parse the argument functions \n\ + -fastproxy - Use fast proxy mechanism for member methods \n\ + -fastquery - Use fast query mechanism for types \n\ + -globals <name> - Set <name> used to access C global variable [default: 'cvar']\n\ + -interface <lib>- Set the lib name to <lib>\n\ + -keyword - Use keyword arguments\n\ + -modern - Use modern python features only, without compatibility code\n\ + -modernargs - Use \"modern\" args mechanism to pack/unpack the function arguments\n"; +static const char *usage2 = (char *) "\ + -newrepr - Use more informative version of __repr__ in proxy classes (default) \n\ + -newvwm - New value wrapper mode, use only when everything else fails \n\ + -noaliasobj0 - Don't generate an obj0 alias when using fastunpack (default) \n\ + -nobuildnone - Access Py_None directly (default in non-Windows systems)\n\ + -nocastmode - Disable the casting mode (default)\n\ + -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ + -nodirvtable - Don't use the virtual table feature, resolve the python method each time (default)\n\ + -noexcept - No automatic exception handling\n\ + -noextranative - Don't use extra native C++ wraps for std containers when possible (default) \n\ + -nofastinit - Use traditional init mechanism for classes \n\ + -nofastunpack - Use traditional UnpackTuple method to parse the argument functions (default) \n\ + -nofastproxy - Use traditional proxy mechanism for member methods (default) \n\ + -nofastquery - Use traditional query mechanism for types (default) \n\ + -noh - Don't generate the output header file\n\ + -nomodern - Don't use modern python features which are not back compatible \n\ + -nomodernargs - Use classic ParseTuple/CallFunction methods to pack/unpack the function arguments (default) \n"; +static const char *usage3 = (char *) "\ + -noolddefs - Don't emit the old method definitions even when using fastproxy (default) \n\ + -nooutputtuple - Use a PyList for appending output values (default) \n\ + -noproxy - Don't generate proxy classes \n\ + -noproxydel - Don't generate the redundant __del__ method \n\ + -noproxyimport - Don't insert proxy import statements derived from the %import directive \n\ + -nortti - Disable the use of the native C++ RTTI with directors\n\ + -nosafecstrings - Avoid extra strings copies when possible (default)\n\ + -nothreads - Disable thread support for the entire interface\n\ + -olddefs - Keep the old method definitions even when using fastproxy\n\ + -oldrepr - Use shorter and old version of __repr__ in proxy classes\n\ + -outputtuple - Use a PyTuple for outputs instead of a PyList (use carefully with legacy interfaces) \n\ + -proxydel - Generate a __del__ method even though it is now redundant (default) \n\ + -safecstrings - Use safer (but slower) C string mapping, generating copies from Python -> C/C++\n\ + -threads - Add thread support for all the interface\n\ + -O - Enable all the optimization options: \n\ + -modern -fastdispatch -dirvtable -nosafecstrings -fvirtual -noproxydel \n\ + -fastproxy -fastinit -fastunpack -fastquery -modernargs -nobuildnone \n\ + -py3 - Generate code with Python 3 specific features:\n\ + Function annotation \n\ +\n"; + +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; + } + + /* ------------------------------------------------------------ + * 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"); + 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"); + if (eb) { + Append(f, eb); + } else { + Append(f, "SWIG_PYTHON_THREAD_END_ALLOW;\n"); + } + } + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int cppcast = 1; + + SWIG_library_directory("python"); + + 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], "-new_repr") == 0) || (strcmp(argv[i], "-newrepr") == 0)) { + new_repr = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-old_repr") == 0) || (strcmp(argv[i], "-oldrepr") == 0)) { + new_repr = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-classptr") == 0) { + classptr = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + shadow = 0; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxyimport") == 0)) { + shadowimport = 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], "-classic") == 0) { + classic = 1; + modernargs = 0; + modern = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-outputtuple") == 0) { + outputtuple = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nooutputtuple") == 0) { + outputtuple = 0; + 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 suppor mode */ + nothreads = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-safecstrings") == 0) { + safecstrings = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nosafecstrings") == 0) { + safecstrings = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-buildnone") == 0) { + buildnone = 1; + nobuildnone = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nobuildnone") == 0) { + buildnone = 0; + nobuildnone = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dirvtable") == 0) { + dirvtable = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nodirvtable") == 0) { + dirvtable = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastunpack") == 0) { + fastunpack = 1; + 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], "-nofastproxy") == 0) { + fastproxy = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastquery") == 0) { + fastquery = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastquery") == 0) { + fastquery = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastinit") == 0) { + fastinit = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastinit") == 0) { + fastinit = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-olddefs") == 0) { + olddefs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noolddefs") == 0) { + olddefs = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-castmode") == 0) { + castmode = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocastmode") == 0) { + castmode = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-extranative") == 0) { + extranative = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noextranative") == 0) { + extranative = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-modernargs") == 0) { + modernargs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nomodernargs") == 0) { + modernargs = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-aliasobj0") == 0) { + aliasobj0 = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noaliasobj0") == 0) { + aliasobj0 = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-proxydel") == 0) { + proxydel = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noproxydel") == 0) { + proxydel = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-modern") == 0) { + classic = 0; + modern = 1; + modernargs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nomodern") == 0) { + modern = 0; + modernargs = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noh") == 0) { + no_header_file = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-new_vwm") == 0) || (strcmp(argv[i], "-newvwm") == 0)) { + /* Turn on new value wrapper mpde */ + Swig_value_wrapper_mode(1); + no_header_file = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-O") == 0) { + classic = 0; + modern = 1; + dirvtable = 1; + safecstrings = 0; + buildnone = 0; + nobuildnone = 1; + classptr = 0; + proxydel = 0; + fastunpack = 1; + fastproxy = 1; + fastinit = 1; + fastquery = 1; + modernargs = 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; + Swig_mark_arg(i); + } + + } + } /* for */ + + if (py3) { + /* force disable features that not compatible with Python 3.x */ + classic = 0; + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + 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; + { + 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")) { + castmode = 0; + } + if (Getattr(options, "extranative")) { + extranative = 1; + } + if (Getattr(options, "noextranative")) { + extranative = 0; + } + if (Getattr(options, "outputtuple")) { + outputtuple = 1; + } + if (Getattr(options, "nooutputtuple")) { + outputtuple = 0; + } + mod_docstring = Getattr(options, "docstring"); + package = Getattr(options, "package"); + } + } + } + + /* 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(""); + + 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(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGPYTHON\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 (safecstrings) { + Printf(f_runtime, "#define SWIG_PYTHON_SAFE_CSTRINGS\n"); + } + + if (buildnone) { + Printf(f_runtime, "#define SWIG_PYTHON_BUILD_NONE\n"); + } + + if (nobuildnone) { + Printf(f_runtime, "#define SWIG_PYTHON_NO_BUILD_NONE\n"); + } + + if (!dirvtable) { + Printf(f_runtime, "#define SWIG_PYTHON_DIRECTOR_NO_VTABLE\n"); + } + + if (outputtuple) { + Printf(f_runtime, "#define SWIG_PYTHON_OUTPUT_TUPLE\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 (classic) { + Printf(f_runtime, "#define SWIG_PYTHON_CLASSIC\n"); + } + + Printf(f_runtime, "\n"); + + Printf(f_header, "#if (PY_VERSION_HEX <= 0x02000000)\n"); + Printf(f_header, "# if !defined(SWIG_PYTHON_CLASSIC)\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-classic' option\"\n"); + Printf(f_header, "# endif\n"); + Printf(f_header, "#endif\n"); + + if (modern) { + Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodern' option\"\n"); + Printf(f_header, "#endif\n"); + } + + if (modernargs) { + Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodernargs' option\"\n"); + Printf(f_header, "#endif\n"); + } + + if (fastunpack) { + Printf(f_header, "#ifndef METH_O\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-nofastunpack' option\"\n"); + Printf(f_header, "#endif\n"); + } + + if (fastquery) { + 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) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + /* If shadow classing is enabled, we're going to change the module name to "_module" */ + 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_imports = NewString(""); + f_shadow_stubs = NewString(""); + + Swig_register_filebyname("shadow", f_shadow); + Swig_register_filebyname("python", f_shadow); + + Swig_banner_target_lang(f_shadow, "#"); + + if (!modern) { + Printv(f_shadow, "# This file is compatible with both classic and new-style classes.\n", NIL); + } + + if (mod_docstring && Len(mod_docstring)) { + Printv(f_shadow, "\n\"\"\"\n", mod_docstring, "\n\"\"\"\n", NIL); + Delete(mod_docstring); + mod_docstring = NULL; + } + + Printv(f_shadow, "\nfrom sys import version_info\n", NULL); + + if(fastproxy) + { + Printv(f_shadow, "if version_info >= (3,0,0):\n", NULL); + Printf(f_shadow, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module); + Printv(f_shadow, "else:\n", NULL); + Printv(f_shadow, tab4, "from new import instancemethod as new_instancemethod\n", NULL); + } + /* Import the C-extension 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 C-extension is on + * sys.path. Relative imports must be explicitly specified from 2.6.0 + * onwards (implicit relative imports will raise a DeprecationWarning + * in 2.6, and fail in 2.7 onwards), but the relative import syntax + * isn't available in python 2.4 or earlier, so we have to write some + * code conditional on the python version. + */ + Printv(f_shadow, "if version_info >= (2,6,0):\n", NULL); + Printv(f_shadow, tab4, "def swig_import_helper():\n", NULL); + Printv(f_shadow, tab8, "from os.path import dirname\n", NULL); + Printv(f_shadow, tab8, "import imp\n", NULL); + Printv(f_shadow, tab8, "fp = None\n", NULL); + Printv(f_shadow, tab8, "try:\n", NULL); + Printf(f_shadow, tab4 tab8 "fp, pathname, description = imp.find_module('%s', [dirname(__file__)])\n", module); + Printf(f_shadow, tab8 "except ImportError:\n"); + /* At here, the module may already loaded, so simply import it. */ + Printf(f_shadow, tab4 tab8 "import %s\n", module); + Printf(f_shadow, tab4 tab8 "return %s\n", module); + Printv(f_shadow, tab8 "if fp is not None:\n", NULL); + Printv(f_shadow, tab4 tab8 "try:\n", NULL); + Printf(f_shadow, tab8 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module); + Printv(f_shadow, tab4 tab8, "finally:\n", NULL); + Printv(f_shadow, tab8 tab8, "fp.close()\n", NULL); + Printv(f_shadow, tab4 tab8, "return _mod\n", NULL); + Printf(f_shadow, tab4 "%s = swig_import_helper()\n", module); + Printv(f_shadow, tab4, "del swig_import_helper\n", NULL); + Printv(f_shadow, "else:\n", NULL); + Printf(f_shadow, tab4 "import %s\n", module); + + /* Delete the version_info symbol since we don't use it elsewhere in the + * module. */ + Printv(f_shadow, "del version_info\n", NULL); + + if (modern || !classic) { + Printv(f_shadow, "try:\n", tab4, "_swig_property = property\n", "except NameError:\n", tab4, "pass # Python < 2.2 doesn't have 'property'.\n", NULL); + } + /* if (!modern) */ + /* always needed, a class can be forced to be no-modern, such as an exception */ + { + // Python-2.2 object hack + Printv(f_shadow, + "def _swig_setattr_nondynamic(self,class_type,name,value,static=1):\n", + tab4, "if (name == \"thisown\"): return self.this.own(value)\n", + tab4, "if (name == \"this\"):\n", tab4, tab4, "if type(value).__name__ == 'SwigPyObject':\n", tab4, tab8, "self.__dict__[name] = value\n", +#ifdef USE_THISOWN + tab4, tab8, "if hasattr(value,\"thisown\"): self.__dict__[\"thisown\"] = value.thisown\n", tab4, tab8, "del value.thisown\n", +#endif + tab4, tab8, "return\n", tab4, "method = class_type.__swig_setmethods__.get(name,None)\n", tab4, "if method: return method(self,value)\n", +#ifdef USE_THISOWN + tab4, "if (not static) or hasattr(self,name) or (name == \"thisown\"):\n", +#else + tab4, "if (not static) or hasattr(self,name):\n", +#endif + tab4, tab4, "self.__dict__[name] = value\n", + tab4, "else:\n", + tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n\n", + "def _swig_setattr(self,class_type,name,value):\n", tab4, "return _swig_setattr_nondynamic(self,class_type,name,value,0)\n\n", NIL); + + Printv(f_shadow, + "def _swig_getattr(self,class_type,name):\n", + tab4, "if (name == \"thisown\"): return self.this.own()\n", + tab4, "method = class_type.__swig_getmethods__.get(name,None)\n", + tab4, "if method: return method(self)\n", tab4, "raise AttributeError(name)\n\n", NIL); + + Printv(f_shadow, + "def _swig_repr(self):\n", + tab4, "try: strthis = \"proxy of \" + self.this.__repr__()\n", + tab4, "except: strthis = \"\"\n", tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); + + if (!classic) { + /* Usage of types.ObjectType is deprecated. + * But don't sure wether this would broken old Python? + */ + Printv(f_shadow, +// "import types\n", + "try:\n", +// " _object = types.ObjectType\n", + " _object = object\n", + " _newclass = 1\n", "except AttributeError:\n", " class _object : pass\n", " _newclass = 0\n", +// "del types\n", + "\n\n", NIL); + } + } + if (modern) { + Printv(f_shadow, "def _swig_setattr_nondynamic_method(set):\n", tab4, "def set_attr(self,name,value):\n", +#ifdef USE_THISOWN + tab4, tab4, "if hasattr(self,name) or (name in (\"this\", \"thisown\")):\n", +#else + tab4, tab4, "if (name == \"thisown\"): return self.this.own(value)\n", tab4, tab4, "if hasattr(self,name) or (name == \"this\"):\n", +#endif + tab4, tab4, tab4, "set(self,name,value)\n", + tab4, tab4, "else:\n", + tab4, tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n", tab4, "return set_attr\n\n\n", NIL); + } + + if (directorsEnabled()) { + // Try loading weakref.proxy, which is only available in Python 2.1 and higher + Printv(f_shadow, + "try:\n", tab4, "import weakref\n", tab4, "weakref_proxy = weakref.proxy\n", "except:\n", tab4, "weakref_proxy = lambda x: x\n", "\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"); + + /* the method exported for replacement of new.instancemethod in Python 3 */ + add_pyinstancemethod_new(); + + /* 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.swg", f_runtime); + } + + /* Close language module */ + Append(methods, "\t { NULL, NULL, 0, NULL }\n"); + Append(methods, "};\n"); + Printf(f_wrappers, "%s\n", methods); + + 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) { + Printv(f_shadow_py, f_shadow, "\n", NIL); + Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); + + Close(f_shadow_py); + 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) + Close(f_runtime_h); + 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); + + Close(f_begin); + 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"); + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, NULL},\n", name, name); + Delete(name); + return 0; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + if (shadow) { + String *modname = Getattr(n, "module"); + + if (modname) { + String *import = NewString("import "); + + // 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); + + // 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 *options = Getattr(mod, "options"); + String *pkg = options ? Getattr(options, "package") : 0; + if (pkg && (!package || Strcmp(pkg, package) != 0)) { + Printf(import, "%s.", pkg); + } + // finally, output the name of the imported module + if (shadowimport) { + if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) { + Printf(import, "_%s\n", modname); + if (!Strstr(f_shadow_imports, import)) { + if (pkg && (!package || Strcmp(pkg, package) != 0)) { + Printf(f_shadow, "import %s.%s\n", pkg, modname); + } else { + Printf(f_shadow, "import %s\n", modname); + } + Printv(f_shadow_imports, import, NULL); + } + } + } + + 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; + } + + + /* ------------------------------------------------------------ + * pythoncode() - Output python code into the shadow file + * ------------------------------------------------------------ */ + + String *pythoncode(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 = DohSplitLines(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; + } + + + /* ------------------------------------------------------------ + * 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; + if (autodoc) { + char *c = Char(autodoc); + if (c && 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 != NULL && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + } + + /* ------------------------------------------------------------ + * docstring() + * Get the docstring text, stripping off {} if neccessary, + * 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 use_triple = true) { + String *str = Getattr(n, "feature:docstring"); + bool have_ds = (str != NULL && Len(str) > 0); + bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + const char *triple_double = use_triple ? "\"\"\"" : ""; + 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 != NULL && Len(autodoc) > 0); + } + // 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 (have_auto && have_ds) { // Both autodoc and docstring are present + doc = NewString(""); + Printv(doc, triple_double, "\n", pythoncode(autodoc, indent), "\n", pythoncode(str, indent), indent, triple_double, NIL); + } else if (!have_auto && have_ds) { // only docstring + if (Strchr(str, '\n') == NULL) { + doc = NewStringf("%s%s%s", triple_double, str, triple_double); + } else { + doc = NewString(""); + Printv(doc, triple_double, "\n", pythoncode(str, indent), indent, triple_double, NIL); + } + } else if (have_auto && !have_ds) { // only autodoc + if (Strchr(autodoc, '\n') == NULL) { + doc = NewStringf("%s%s%s", triple_double, autodoc, triple_double); + } else { + doc = NewString(""); + Printv(doc, triple_double, "\n", pythoncode(autodoc, indent), indent, triple_double, NIL); + } + } else + doc = NewString(""); + + // Save the generated strings in the parse tree in case they are used later + // by post processing tools + Setattr(n, "python:docstring", doc); + Setattr(n, "python:autodoc", autodoc); + return doc; + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * Note: the generated name should consist with that in kwnames[] + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(ParmList *plist, Parm *p, int arg_num) { + String *arg = 0; + String *pn = Swig_name_make(p, 0, Getattr(p, "name"), 0, 0); + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + if ( SwigType_isvarargs(Getattr(p, "type")) ) { + return NewString("*args"); + } + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + arg = (!pn || !Len(pn) || (count > 1)) ? NewStringf("arg%d", arg_num) : Copy(pn); + return arg; + } + + + /* ------------------------------------------------------------ + * make_autodocParmList() + * Generate the documentation for the function parameters + * Parameters: + * func_annotation: Function annotation support + * ------------------------------------------------------------ */ + + String *make_autodocParmList(Node *n, bool showTypes, bool calling=false, bool func_annotation=false) { + + + String *doc = NewString(""); + String *pdocs = Copy(Getattr(n, "feature:pdocs")); + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + Node *lookup; + + + int lines = 0; + int arg_num = 0; + const int maxwidth = 50; + + if(calling) + func_annotation = false; + + if (pdocs) + Append(pdocs, "\n"); + + 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 *ptype = 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"); + ptype = Getattr(p, "tmap:doc:pytype"); + } + + name = name ? name : Getattr(p, "name"); + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + name = makeParameterName(plist, p, arg_num); + // Reset it for convinient in further use. (mainly for makeParameterName()) + // Since the plist is created by CopyParmList, + // we can hope that the set would have no side effect + Setattr(p, "name", name); + + arg_num++; + + + 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; + } + } + + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + + // Do the param type too? + if (showTypes) + Printf(doc, "%s ", type); + + + Append(doc, name); + if (pdoc) { + if (!pdocs) + pdocs = NewString("Parameters:\n"); + Printf(pdocs, " %s\n", pdoc); + } + + // Write the function annoation + if (func_annotation) + Printf(doc, " : '%s'", type); + + // Write default value + if (value && !calling) { + String* pv = pyvalue(value, Getattr(p, "type")); + if (pv) + value = pv; + else { + lookup = Swig_symbol_clookup(value, 0); + if (lookup) { + value = Getattr(lookup, "sym:name"); + } + } + Printf(doc, " = %s", value); + } + } + 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 funciton 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) { + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + + if (type) { + if (Strcmp(type, "void") == 0) + type = NULL; + else { + type = SwigType_base(type); + Node *lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + } + } + + 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 == NULL || Len(str) == 0) { + if (CPlusPlus) { + Printf(doc, "Proxy of C++ %s class", real_classname); + } else { + Printf(doc, "Proxy of C %s struct", real_classname); + } + } + } + break; + case AUTODOC_CTOR: + if (Strcmp(class_name, symname) == 0) { + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, "__init__(self, %s) -> %s", paramList, class_name); + else + Printf(doc, "__init__(self) -> %s", class_name); + } else + Printf(doc, "%s(%s) -> %s", symname, make_autodocParmList(n, showTypes), class_name); + break; + + case AUTODOC_DTOR: + Append(doc, "__del__(self)"); + break; + + case AUTODOC_STATICFUNC: + Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); + if (type) + Printf(doc, " -> %s", type); + break; + + case AUTODOC_FUNC: + Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); + if (type) + Printf(doc, " -> %s", type); + break; + + case AUTODOC_METHOD: + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, "%s(self, %s)", symname, paramList); + else + Printf(doc, "%s(self)", symname); + if (type) + Printf(doc, " -> %s", type); + break; + } + } + if (extended) { + 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) + Append(doc, "\n"); + } + + return doc; + } + + /* ------------------------------------------------------------ + * pyvalue() + * Check if string v can be a Python value literal, + * (eg. number or string), or translate it to a Python literal. + * ------------------------------------------------------------ */ + String* pyvalue(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, "true")==0 || Strcmp(v, "FALSE")==0) + return NewString("True"); + if (Strcmp(v, "false")==0 || Strcmp(v, "FALSE")==0) + return NewString("False"); + if (Strcmp(v, "NULL")==0) + return NewString("None"); + } + return 0; + } + /* ------------------------------------------------------------ + * is_primitive_defaultargs() + * Check if all the default args have primitive type. + * (So we can generate proper parameter list with default + * values..) + * ------------------------------------------------------------ */ + bool is_primitive_defaultargs(Node *n) + { + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + + Swig_typemap_attach_parms("in", plist, 0); + 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 *type = Getattr(p, "type"); + String *value = Getattr(p, "value"); + if (!pyvalue(value, type)) + return false; + } + return true; + } + + + /* ------------------------------------------------------------ + * is_real_overloaded() + * Check if the function is overloaded, but not just have some + * siblings generated due to the original function have + * 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) + { + /* Get the original function for a defaultargs copy, + * see default_arguments() in parser.y. */ + Node *nn = Getattr(n, "defaultargs"); + if (nn) n = nn; + + /* For overloaded function, just use *args */ + if (is_real_overloaded(n) || + GetFlag(n, "feature:compactdefaultargs") || + !is_primitive_defaultargs(n)) + { + 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, 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 != NULL && Len(str) > 0); + } + + /* ------------------------------------------------------------ + * pythonprepend() + * Get the %pythonprepend code, stripping off {} if neccessary + * ------------------------------------------------------------ */ + + 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 != NULL && Len(str) > 0); + } + + /* ------------------------------------------------------------ + * pythonappend() + * Get the %pythonappend code, stripping off {} if neccessary + * ------------------------------------------------------------ */ + + 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) || have_docstring(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); + /* Make a wrapper function to insert the code into */ + Printv(f_dest, "\ndef ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_dest, " ", docstring(n, AUTODOC_FUNC, tab4), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_dest, pythoncode(pythonprepend(n), " "), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_dest, " val = ", funcCall(name, callParms), "\n", NIL); + Printv(f_dest, pythoncode(pythonappend(n), " "), "\n", NIL); + Printv(f_dest, " return val\n", NIL); + } else { + Printv(f_dest, " return ", funcCall(name, callParms), "\n", NIL); + } + + if (Getattr(n, "feature:python:callback") || !have_addtofunc(n)) { + /* 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) { + 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) { + if (!kw) { + if (n && funpack) { + if (num_required == 0 && num_arguments == 0) { + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_NOARGS, ", name, function); + } else if (num_required == 1 && num_arguments == 1) { + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, ", name, function); + } else { + Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function); + } + } else { + Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function); + } + } else { + Printf(methods, "\t { (char *)\"%s\", (PyCFunction) %s, METH_VARARGS | METH_KEYWORDS, ", name, function); + } + + if (!n) { + Append(methods, "NULL"); + } else if (Getattr(n, "feature:callback")) { + if (have_docstring(n)) { + String *ds = docstring(n, AUTODOC_FUNC, "", false); + Replaceall(ds, "\\", "\\\\"); + Replaceall(ds, "\"", "\\\""); + Replaceall(ds, "\n", "\\n\"\n\t\t\""); + Printf(methods, "(char *)\"%s\\nswig_ptr: %s\"", ds, Getattr(n, "feature:callback:name")); + } else { + Printf(methods, "(char *)\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + } + } else if (have_docstring(n)) { + String *ds = docstring(n, AUTODOC_FUNC, "", false); + Replaceall(ds, "\\", "\\\\"); + Replaceall(ds, "\"", "\\\""); + Replaceall(ds, "\n", "\\n\"\n\t\t\""); + Printf(methods, "(char *)\"%s\"", ds); + } else { + Append(methods, "NULL"); + } + + Append(methods, "},\n"); + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + void dispatchFunction(Node *n, int funpack = 0) { + /* Last node in overloaded chain */ + + int maxargs; + + String *tmp = NewString(""); + String *dispatch; + const char *dispatch_code = funpack ? "return %s(self, argc, argv);" : "return %s(self, args);"; + + if (castmode) { + dispatch = Swig_overload_dispatch_cast(n, dispatch_code, &maxargs); + } else { + dispatch = Swig_overload_dispatch(n, dispatch_code, &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 PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "PyObject *argv[%d]", maxargs + 1); + Wrapper_add_local(f, "argv", tmp); + + if (!fastunpack) { + Wrapper_add_local(f, "ii", "int ii"); + Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n"); + Append(f->code, "argc = (int)PyObject_Length(args);\n"); + Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs); + Append(f->code, "argv[ii] = PyTuple_GET_ITEM(args,ii);\n"); + Append(f->code, "}\n"); + } else { + String *iname = Getattr(n, "sym:name"); + Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args,\"%s\",0,%d,argv))) SWIG_fail;\n", iname, maxargs); + 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 { + Printf(protoTypes, "\n\" %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms"))); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Append(f->code, "fail:\n"); + Printf(f->code, "SWIG_SetErrorMsg(PyExc_NotImplementedError," + "\"Wrong number of arguments for overloaded function '%s'.\\n\"" "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); + Append(f->code, "return NULL;\n"); + Delete(protoTypes); + } + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + Node *p = Getattr(n, "sym:previousSibling"); + add_method(symname, wname, 0, p); + + /* Create a shadow for this function (if enabled and not in a member function) */ + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + emitFunctionShadowHelper(n, f_shadow_stubs, symname, 0); + } + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + + 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"); + int director_method = 0; + + Parm *p; + int i; + char source[64]; + Wrapper *f; + 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 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(sname); + handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); + Delete(cname); + } + + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + 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 */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self"))) + allow_kwargs = 0; + varargs = emit_isvarargs(l); + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + + if (!allow_kwargs || Getattr(n, "sym:overloaded")) { + if (!varargs) { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + } else { + Printv(f->def, "SWIGINTERN PyObject *", wname, "__varargs__", "(PyObject *SWIGUNUSEDPARM(self), 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, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {", NIL); + } + if (!allow_kwargs) { + Append(parse_args, " if (!PyArg_ParseTuple(args,(char *)\""); + } else { + Append(parse_args, " if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)\""); + Append(arglist, ",kwnames"); + } + + int funpack = modernargs && fastunpack && !varargs && !allow_kwargs; + int noargs = funpack && (num_required == 0 && num_arguments == 0); + int onearg = funpack && (num_required == 1 && num_arguments == 1); + + /* Generate code for argument marshalling */ + if (funpack) { + if (overname) { + if (aliasobj0) { + Append(f->code, "#define obj0 (swig_obj[0])\n"); + } + } else if (num_arguments) { + sprintf(source, "PyObject *swig_obj[%d]", num_arguments); + Wrapper_add_localv(f, "swig_obj", source, NIL); + if (aliasobj0) { + Append(f->code, "#define obj0 (swig_obj[0])\n"); + } + } + } + + + 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); + } + } + } + + 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 *pn = Getattr(p, "name"); + String *ln = Getattr(p, "lname"); + if (funpack) { + sprintf(source, "swig_obj[%d]", i); + } else { + sprintf(source, "obj%d", i); + } + + + Putc(',', arglist); + if (i == num_required) + Putc('|', parse_args); /* Optional argument separator */ + + /* Keyword argument handling */ + if (allow_kwargs) { + if (Len(pn)) { + String *tmp = 0; + String *name = pn; + if (!Getattr(p,"hidden")) { + name = tmp = Swig_name_make(p, 0, pn, 0, 0); + } + Printf(kwargs, "(char *) \"%s\",", name); + if (tmp) + Delete(tmp); + } else { + Printf(kwargs, "(char *)\"arg%d\",", i + 1); + } + } + + /* Look for an input typemap */ + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + 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); + } + + Putc('O', parse_args); + if (!funpack) { + 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); + 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 || !modernargs) { + 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, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); + } else { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) {", NIL); + } + Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); + } else { + if (noargs) { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + } else { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + } + if (onearg) { + Printf(parse_args, "if (!args) SWIG_fail;\n"); + Printf(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_required, num_arguments); + } else if (noargs) { + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args,\"%s\",%d,%d,0)) SWIG_fail;\n", iname, num_required, num_arguments); + } + } + } else { + Printf(parse_args, "if(!PyArg_UnpackTuple(args,(char *)\"%s\",%d,%d", iname, num_required, num_arguments); + Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + } + } + + /* Now piece together the first part of the wrapper function */ + Printv(f->code, 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 (!checkAttribute(p,"tmap:in:numinputs","0") && !Getattr(p,"tmap:in:parse")) { + 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) { + Append(f->code, "upcall = (director && (director->swig_get_self()==swig_obj[0]));\n"); + } else { + Append(f->code, "upcall = (director && (director->swig_get_self()==obj0));\n"); + } + } + + /* Emit the function call */ + if (director_method) { + Append(f->code, "try {\n"); + } else { + if (allow_thread) { + Append(f->code, "{\n"); + thread_begin_allow(n, f->code); + } + } + + 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"); + } else { + if (allow_thread) { + thread_end_allow(n, actioncode); + Append(actioncode, "}\n"); + } + } + + /* This part below still needs cleanup */ + + /* Return the function value */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + if (funpack) { + Replaceall(tm, "$self", "swig_obj[0]"); + } else { + Replaceall(tm, "$self", "obj0"); + } + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + 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 *parent = Swig_methodclass(n); + 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"); + Append(f->code, "director = SWIG_DIRECTOR_CAST(result);\n"); + 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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, "result", 0))) { + Replaceall(tm, "$input", "result"); + Replaceall(tm, "$result", "resultobj"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + Append(f->code, " return resultobj;\n"); + + /* Error handling code */ + + Append(f->code, "fail:\n"); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, " return NULL;\n", NIL); + + + if (funpack) { + if (aliasobj0) { + Append(f->code, "#if defined(obj0)\n"); + Append(f->code, "#undef obj0\n"); + Append(f->code, "#endif\n"); + } + } + + + 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 (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(); + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL); + Wrapper_add_local(f, "resultobj", "PyObject *resultobj"); + Wrapper_add_local(f, "varargs", "PyObject *varargs"); + Wrapper_add_local(f, "newargs", "PyObject *newargs"); + Printf(f->code, "newargs = PyTuple_GetSlice(args,0,%d);\n", num_arguments); + Printf(f->code, "varargs = PyTuple_GetSlice(args,%d,PyTuple_Size(args)+1);\n", num_arguments); + Printf(f->code, "resultobj = %s__varargs__(self,newargs,varargs);\n", wname); + 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")) { + 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 ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, iname, allow_kwargs); + } + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n, funpack); + } + } + Delete(parse_args); + Delete(arglist); + Delete(get_pointers); + Delete(cleanup); + Delete(outarg); + Delete(kwargs); + Delete(wname); + 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"); + + 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 PyDict_SetItemString(d,(char*)\"%s\", SWIG_globals());\n", global_name); + have_globals = 1; + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + Printf(f_shadow_stubs, "%s = %s.%s\n", global_name, module, global_name); + } + } + int assignable = is_assignable(n); + + if ((shadow) && !assignable) { + if (!in_class) { + Printf(f_shadow_stubs, "%s = %s.%s\n", iname, global_name, iname); + } + } + + String *getname = Swig_name_get(iname); + String *setname = Swig_name_set(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); + 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); + int addfail = 0; + Printf(getf->def, "SWIGINTERN PyObject *%s(void) {", vargetname); + Wrapper_add_local(getf, "pyobj", "PyObject *pyobj = 0"); + 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(SWIG_globals(),(char*)\"%s\",%s, %s);\n", iname, vargetname, varsetname); + + Delete(vargetname); + Delete(varsetname); + Delete(getname); + Delete(setname); + DelWrapper(setf); + DelWrapper(getf); + 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; + int have_tm = 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 ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Printf(f_init, "%s\n", tm); + Delete(tm); + have_tm = 1; + } + if (!have_tm) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if (!in_class) { + Printv(f_shadow, iname, " = ", module, ".", iname, "\n", NIL); + } else { + if (!(Getattr(n, "feature:python:callback"))) { + Printv(f_shadow_stubs, iname, " = ", module, ".", iname, "\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 (shadow) { + Printv(f_shadow_stubs, name, " = ", module, ".", name, "\n", NIL); + } + return SWIG_OK; + } + + + +/* ---------------------------------------------------------------------------- + * BEGIN C++ Director Class modifications + * ------------------------------------------------------------------------- */ + +/* C++/Python polymorphism demo code, copyright (C) 2002 Mark Rose <mrose@stm.lbl.gov> + * + * 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")); + 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, 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, 0, 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\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* name) const {\n"); + Printf(f_directors_h, " std::map<std::string, bool>::const_iterator iv = inner.find(name);\n"); + Printf(f_directors_h, " return (iv != inner.end() ? iv->second : false);\n"); + Printf(f_directors_h, " }\n\n"); + + Printf(f_directors_h, " void swig_set_inner(const char* name, bool val) const\n"); + Printf(f_directors_h, " { inner[name] = val;}\n\n"); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " mutable std::map<std::string, bool> inner;\n"); + + } + if (director_method_index) { + Printf(f_directors_h, "\n\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 == NULL) {\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) { + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_disown(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 *importname = NewString(""); + String *modname = Getattr(mod, "name"); + if (Strcmp(modname, mainmodule) != 0) { + // check if the module has a package option + Node *options = Getattr(mod, "options"); + String *pkg = options ? Getattr(options, "package") : 0; + if (pkg && (!package || Strcmp(pkg, package) != 0)) { + Printf(importname, "%s.", pkg); + } + Printf(importname, "%s.", modname); + } + Append(importname, Getattr(n, "sym:name")); + Setattr(n, "python:proxy", importname); + } + } + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + int oldclassic = classic; + int oldmodern = modern; + File *f_shadow_file = f_shadow; + + if (shadow) { + + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + have_repr = 0; + + if (GetFlag(n, "feature:classic")) { + classic = 1; + modern = 0; + } + if (GetFlag(n, "feature:modern")) { + classic = 0; + modern = 1; + } + if (GetFlag(n, "feature:exceptionclass")) { + classic = 1; + modern = 0; + } + + shadow_indent = (String *) tab4; + + class_name = Getattr(n, "sym:name"); + real_classname = Getattr(n, "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 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, input_file, line_number, + "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) { + Putc(',', base_class); + } + } + } + + /* dealing with abstract base class */ + String *abcs = Getattr(n, "feature:python:abc"); + if (py3 && abcs) { + if (Len(base_class)) { + Putc(',', base_class); + } + Printv(base_class, abcs, NIL); + } + + Printv(f_shadow, "class ", class_name, NIL); + + if (Len(base_class)) { + Printf(f_shadow, "(%s)", base_class); + } else { + if (!classic) { + Printf(f_shadow, modern ? "(object)" : "(_object)"); + } + if (GetFlag(n, "feature:exceptionclass") ) { + Printf(f_shadow, "(Exception)"); + } + } + Printf(f_shadow, ":\n"); + if (have_docstring(n)) { + String *str = docstring(n, AUTODOC_CLASS, tab4); + if (str != NULL && Len(str)) + Printv(f_shadow, tab4, str, "\n", NIL); + } + if (!modern) { + Printv(f_shadow, tab4, "__swig_setmethods__ = {}\n", NIL); + if (Len(base_class)) { + Printf(f_shadow, "%sfor _s in [%s]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))\n", tab4, base_class); + } + + if (!GetFlag(n, "feature:python:nondynamic")) { + Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr(self, ", class_name, ", name, value)\n", NIL); + } else { + Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr_nondynamic(self, ", class_name, ", name, value)\n", NIL); + } + + Printv(f_shadow, tab4, "__swig_getmethods__ = {}\n", NIL); + if (Len(base_class)) { + Printf(f_shadow, "%sfor _s in [%s]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))\n", tab4, base_class); + } + + Printv(f_shadow, tab4, "__getattr__ = lambda self, name: _swig_getattr(self, ", class_name, ", name)\n", NIL); + } else { + Printv(f_shadow, tab4, "thisown = _swig_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_method(object.__setattr__)\n", + tab4, "class __metaclass__(type):\n", tab4, tab4, "__setattr__ = _swig_setattr_nondynamic_method(type.__setattr__)\n", NIL); + } + } + } + + /* Emit all of the members */ + + in_class = 1; + + /* Overide the shadow file so we can capture its methods */ + f_shadow = NewString(""); + + Language::classHandler(n); + in_class = 0; + + /* Complete the class */ + if (shadow) { + /* Generate a class registration function */ + { + String *smartptr = Getattr(n, "feature:smartptr"); // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) + SwigType *smart = 0; + if (smartptr) { + SwigType *cpt = Swig_cparse_type(smartptr); + if (cpt) { + smart = SwigType_typedef_resolve_all(cpt); + Delete(cpt); + } else { + // TODO: report line number of where the feature comes from + Swig_error(Getfile(n), Getline(n), "Invalid type (%s) in 'smartptr' feature for class %s.\n", smartptr, real_classname); + } + } + SwigType *ct = Copy(smart ? smart : real_classname); + SwigType_add_pointer(ct); + SwigType *realct = Copy(real_classname); + SwigType_add_pointer(realct); + SwigType_remember(realct); + Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); + Printv(f_wrappers, " PyObject *obj;\n", NIL); + if (modernargs) { + if (fastunpack) { + Printv(f_wrappers, " if (!SWIG_Python_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); + } else { + Printv(f_wrappers, " if (!PyArg_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); + } + } else { + Printv(f_wrappers, " if (!PyArg_ParseTuple(args,(char*)\"O:swigregister\", &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); + Delete(smart); + Delete(cname); + Delete(ct); + Delete(realct); + } + if (!have_constructor) { + Printv(f_shadow_file, tab4, "def __init__(self, *args, **kwargs): raise AttributeError(\"", "No constructor defined", (Getattr(n, "abstract") ? " - class is abstract" : ""), "\")\n", NIL); + } else if (fastinit) { + + 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) { + /* Supply a repr method for this class */ + String *rname = SwigType_namestr(real_classname); + if (new_repr) { + Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL); + } else { + Printv(f_shadow_file, tab4, "def __repr__(self):\n", tab8, "return \"<C ", rname, " instance at 0x%x>\" % (self.this,)\n", NIL); + } + Delete(rname); + } + + + /* Now emit methods */ + Printv(f_shadow_file, f_shadow, NIL); + + /* Now the Ptr class */ + if (classptr) { + Printv(f_shadow_file, "\nclass ", class_name, "Ptr(", class_name, "):\n", tab4, "def __init__(self, this):\n", NIL); + if (!modern) { + Printv(f_shadow_file, + tab8, "try: self.this.append(this)\n", + tab8, "except: self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL); + } else { + Printv(f_shadow_file, + tab8, "try: self.this.append(this)\n", + tab8, "except: self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL); + } + } + + if (fastproxy) { + List *shadow_list = Getattr(n, "shadow_methods"); + for (int i = 0; i < Len(shadow_list); ++i) { + String *symname = Getitem(shadow_list, i); + Printf(f_shadow_file, "%s.%s = new_instancemethod(%s.%s,None,%s)\n", class_name, symname, module, Swig_name_member(class_name, symname), class_name); + } + } + Printf(f_shadow_file, "%s_swigregister = %s.%s_swigregister\n", class_name, module, class_name); + Printf(f_shadow_file, "%s_swigregister(%s)\n", class_name, class_name); + + shadow_indent = 0; + Printf(f_shadow_file, "%s\n", f_shadow_stubs); + Clear(f_shadow_stubs); + } + classic = oldclassic; + modern = oldmodern; + + /* 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; + + /* 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 (!Getattr(n, "sym:nextSibling")) { + if (shadow) { + int allow_kwargs = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; + int fproxy = fastproxy; + if (Strcmp(symname, "__repr__") == 0) { + have_repr = 1; + } + if (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4); + String *pyaction = NewStringf("%s.%s", module, Swig_name_member(class_name, symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + fproxy = 0; + } else { + 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, tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":", NIL); + Printv(f_shadow, " return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); + } + } else { + Printv(f_shadow, tab4, "def ", symname, "(",parms , ")", returnTypeAnnotation(n), ":", NIL); + Printv(f_shadow, "\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, pythoncode(pythonprepend(n), tab8), "\n", NIL); + } + if (have_pythonappend(n)) { + fproxy = 0; + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n", NIL); + Printv(f_shadow, tab8, "return val\n\n", NIL); + } else { + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n\n", NIL); + } + } + } + if (fproxy) { + List *shadow_list = Getattr(getCurrentClass(), "shadow_methods"); + if (!shadow_list) { + shadow_list = NewList(); + Setattr(getCurrentClass(), "shadow_methods", shadow_list); + Delete(shadow_list); + } + Append(shadow_list, symname); + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + Language::staticmemberfunctionHandler(n); + + if (Getattr(n, "sym:nextSibling")) { + return SWIG_OK; + } + + if (shadow) { + if (!classic && !Getattr(n, "feature:python:callback") && have_addtofunc(n)) { + 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, 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, pythoncode(pythonprepend(n), tab8), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n", NIL); + Printv(f_shadow, tab8, "return val\n\n", NIL); + } else { + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n\n", NIL); + } + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", symname, ")\n", NIL); + + if (!modern) { + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", symname, "\n", NIL); + } + + } else { + if (!modern) { + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", module, ".", Swig_name_member(class_name, symname), "\n", NIL); + } + if (!classic) { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", module, ".", Swig_name_member(class_name, symname), ")\n", NIL); + } + } + } + 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); + 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(sname); + handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); + Delete(cname); + } + + if (!have_constructor && handled_as_init) { + if (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4); + String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(symname)); + 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); + + 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, 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, pythoncode(pythonprepend(n), tab8), "\n", NIL); + Printv(f_shadow, pass_self, NIL); + if (fastinit) { + Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self,", funcCall(Swig_name_construct(symname), callParms), ")\n", NIL); + } else { + Printv(f_shadow, + tab8, "this = ", funcCall(Swig_name_construct(symname), callParms), "\n", + tab8, "try: self.this.append(this)\n", tab8, "except: self.this = this\n", NIL); + } + if (have_pythonappend(n)) + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\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 (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), ""); + String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow_stubs, pycode, "\n", NIL); + Delete(pycode); + } else { + String *parms = make_pyParmList(n, true, false, allow_kwargs); + String *callParms = make_pyParmList(n, true, 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, pythoncode(pythonprepend(n), tab4), "\n", NIL); + Printv(f_shadow_stubs, tab4, "val = ", funcCall(Swig_name_construct(symname), 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, pythoncode(pythonappend(n), tab4), "\n", NIL); + Printv(f_shadow_stubs, tab4, "return val\n", NIL); + } + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow = shadow; + + 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 = pythoncode(Getattr(n, "feature:shadow"), tab4); + String *pyaction = NewStringf("%s.%s", module, Swig_name_destroy(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(symname), "\n", NIL); + if (!have_pythonprepend(n) && !have_pythonappend(n)) { + if (proxydel) { + Printv(f_shadow, tab4, "__del__ = lambda self : None;\n", NIL); + } + 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, pythoncode(pythonprepend(n), tab8), "\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow, tab8, "try:\n", NIL); + Printv(f_shadow, tab8, tab4, "if self.thisown: ", module, ".", Swig_name_destroy(symname), "(self)\n", NIL); + Printv(f_shadow, tab8, "except: pass\n", NIL); +#else +#endif + if (have_pythonappend(n)) + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\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) { + String *mname = Swig_name_member(class_name, symname); + String *setname = Swig_name_set(mname); + String *getname = Swig_name_get(mname); + if (shadow) { + int assignable = is_assignable(n); + if (!modern) { + if (assignable) { + Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL); + } + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL); + } + if (!classic) { + if (!assignable) { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ")\n", NIL); + } else { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ", ", module, ".", setname, ")\n", NIL); + } + } + } + Delete(mname); + Delete(setname); + Delete(getname); + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + Language::staticmembervariableHandler(n); + + if (shadow && !GetFlag(n, "wrappedasconstant")) { + String *symname = Getattr(n, "sym:name"); + if (GetFlag(n, "hasconsttype")) { + String *mname = Swig_name_member(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(class_name, symname); + String *getname = Swig_name_get(mname); + String *wrapgetname = Swig_name_wrapper(getname); + String *vargetname = NewStringf("Swig_var_%s", getname); + String *setname = Swig_name_set(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) { + Wrapper *f = NewWrapper(); + Printv(f->def, "SWIGINTERN PyObject *", wrapsetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + Wrapper_add_local(f, "value", "PyObject *value"); + Wrapper_add_local(f, "res", "int res"); + Append(f->code, "if (!PyArg_ParseTuple(args,(char *)\"O:set\",&value)) return NULL;\n"); + Printv(f->code, "res = ", varsetname, "(value);\n", NIL); + Append(f->code, "return !res ? SWIG_Py_Void() : NULL;\n"); + Append(f->code, "}\n"); + Wrapper_print(f, f_wrappers); + add_method(setname, wrapsetname, 0); + DelWrapper(f); + } + if (!modern) { + if (assignable) { + Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL); + } + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL); + } + if (!classic) { + if (!assignable) { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ")\n", NIL); + } else { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ", ", module, ".", setname, ")\n", NIL); + } + } + 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"); + int oldshadow = shadow; + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::memberconstantHandler(n); + shadow = oldshadow; + + if (shadow) { + Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(class_name, symname), "\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 = pythoncode(code, shadow_indent); + Printv(f_shadow, 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"); + } + +}; + +/* --------------------------------------------------------------- + * 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; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_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; + } + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + 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 ((tm = 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) { + if (!(ignored_method && !pure_virtual)) { + String *cres = SwigType_lstr(return_type, "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++ -> Python) */ + String *arglist = NewString(""); + String *parse_args = NewString(""); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + 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 != NULL) { + 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); + 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); + 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_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, "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_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); + } + 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 || !modernargs) { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", parse_args, arglist); + } else { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunctionObjArgs(method %s, NULL);\n", arglist); + } + } else { + if (modernargs) { + Append(w->code, "swig::SwigVar_PyObject args = PyTuple_New(0);\n"); + Append(w->code, "swig::SwigVar_PyObject result = PyObject_Call(method, (PyObject*) args, NULL);\n"); + } else { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunction(method, NULL, NULL);\n"); + } + } + Append(w->code, "#else\n"); + if (Len(parse_args) > 0) { + if (use_parse || !modernargs) { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", + pyname, parse_args, arglist); + } else { + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", arglist); + } + } else { + if (!modernargs) { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *) \"%s\", NULL);\n", pyname); + } else { + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); + Append(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n"); + } + } + 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, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + Append(w->code, "if (result == NULL) {\n"); + 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 != NULL) {\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 aruments, 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"); + Append(w->code, "if (!PyTuple_Check(result)) {\n"); + 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) { + /* this seems really silly. the node's type excludes + * qualifier/pointer/reference markers, which have to be retrieved + * from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and + * out the correct type. it's not just me, similar silliness also + * occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + 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(return_type, 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(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + Replaceall(tm, "$result", Getattr(p, "name")); + 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(return_type, 0); + if (!SwigType_isreference(return_type)) { + 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")) { + 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(return_type); + 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/Source/Modules/r.cxx b/Source/Modules/r.cxx new file mode 100644 index 0000000..966feb7 --- /dev/null +++ b/Source/Modules/r.cxx @@ -0,0 +1,2745 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * r.cxx + * + * R language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_r_cxx[] = "$Id: r.cxx 11454 2009-07-26 21:21:26Z wsfulton $"; + +#include "swigmod.h" + +#define UNUSED(a) (void)a + +static const double DEFAULT_NUMBER = .0000123456712312312323; +static const int MAX_OVERLOAD_ARGS = 5; + +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); + + /* Printf(stderr, "<getRTypeName> %s,base = %s\n", t, b); + for(i = 0; i < Len(els); i++) + Printf(stderr, "%d) %s, ", i, Getitem(els,i)); + Printf(stderr, "\n"); */ + + 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; + + /* + if(count) + return(b); + + Delete(b); + return(NewString("")); + */ +} + +#if 0 +static String * getRType(Node *n) { + SwigType *elType = Getattr(n, "type"); + SwigType *elDecl = Getattr(n, "decl"); + //XXX How can we tell if this is already done. + SwigType_push(elType, elDecl); + String *ans; + + String *rtype = Swig_typemap_lookup("rtype", n, "", 0); + String *i = getRTypeName(elType); + + if(Len(i) == 0) { + SwigType *td = SwigType_typedef_resolve(elType); + if(td) { + // Printf(stderr, "Resolving typedef %s -> %s\n", elType, td); + i = getRTypeName(td); + } + } + // Printf(stderr, "<getRType> i = %s, rtype = %s (for %s)\n", + // i, rtype, elType); + if(rtype) { + ans = NewString(""); + Printf(ans, "%s", rtype); + Replaceall(ans, "$R_class", Char(i)); + // Printf(stderr, "Found r type in typemap for %s (for %s) => %s (%s) => %s\n", + // SwigType_str(elType, 0), Getattr(n, "name"), rtype, i, ans); + } else { + ans = i; + } + + return(ans); +} +#endif + +/********************* + 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 *getRClassName(String *retType, int /*addRef*/ = 1, int upRef=0) { + String *tmp = NewString(""); + SwigType *resolved = SwigType_typedef_resolve_all(retType); + char *retName = Char(SwigType_manglestr(resolved)); + if (upRef) { + Printf(tmp, "_p%s", retName); + } else{ + Insert(tmp, 0, retName); + } + + return tmp; +/* +#if 1 + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + if (debugMode) + Printf(stderr, "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"); + } + } + +#else + char *retName = Char(SwigType_manglestr(retType)); + if(!retName) + return(tmp); + + if(addRef) { + while(retName && strlen(retName) > 1 && strncmp(retName, "_p", 2) == 0) { + retName += 2; + Printf(tmp, "Ref"); + } + } + if(retName[0] == '_') + retName ++; + Insert(tmp, 0, retName); +#endif + + 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(""); + +#if 1 + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + Printf(stderr, "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"); + } + } + +#else + char *retName = Char(SwigType_manglestr(retType)); + if(!retName) + return(tmp); + + if(addRef) { + while(retName && strlen(retName) > 1 && + strncmp(retName, "_p", 2) == 0) { + retName += 2; + Printf(tmp, "Ref"); + } + } + + if(retName[0] == '_') + retName ++; + Insert(tmp, 0, retName); +#endif + + 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 = (char *)"\ +R Options (available with -r)\n\ + -copystruct - Emit R code to copy C structs (on by default)\n\ + -cppcast - Enable C++ casting operators (default) \n\ + -debug - Output debug\n\ + -dll <name> - Name of the DLL (without the .dll or .so suffix). 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 (registration information still generated)\n\ + -package <name> - Package name for the PACKAGE argument of the R .Call() 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); + String *tmp_base = getRClassName(type, 0); + String *tmp_ref = getRClassName(type, 1, 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); +} + +static double getNumber(String *value, String *type) { + UNUSED(type); + + double d = DEFAULT_NUMBER; + if(Char(value)) { + // Printf(stderr, "getNumber %s %s\n", Char(value), type); + if(sscanf(Char(value), "%lf", &d) != 1) + return(DEFAULT_NUMBER); + } + return(d); +} + +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 variableWrapper(Node *n); + + int classDeclaration(Node *n); + int enumDeclaration(Node *n); + + int membervariableHandler(Node *n); + + int typedefHandler(Node *n); + + int memberfunctionHandler(Node *n) { + if (debugMode) + Printf(stderr, "<memberfunctionHandler> %s %s\n", + Getattr(n, "name"), + Getattr(n, "type")); + member_name = Getattr(n, "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 *el, File *out); + int OutputArrayMethod(String *className, List *el, File *out); + int OutputClassMemberTable(Hash *tb, File *out); + int OutputClassMethodsTable(File *out); + int OutputClassAccessInfo(Hash *tb, 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, int isSet = -1); + + static int getFunctionPointerNumArgs(Node *n, SwigType *tt); + +protected: + bool copyStruct; + bool memoryProfile; + bool aggressiveGc; + + // Strings into which we cumulate the generated code that is to be written + //vto the files. + 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; + + + int processing_class_member_function; + List *class_member_functions; + List *class_member_set_functions; + + /* */ + 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), + 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), + processing_class_member_function(0), + class_member_functions(0), + class_member_set_functions(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(stderr, "type: %s\n", n); +#if 0 + SwigType *tmp = SwigType_typedef_resolve(tt); + + n = SwigType_typedef_resolve(tt); +#endif + + ParmList *parms = Getattr(n, "parms"); + if (debugMode) + Printf(stderr, "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(stderr, "[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(stderr, "<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))); + + + // if (debugMode) { + Printf(stderr, "Type: %s\n", t); + Printf(stderr, "Return type: %s\n", SwigType_base(t)); + //} + + bool isVoidType = Strcmp(rettype, "void") == 0; + if (debugMode) + Printf(stderr, "%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 = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("s_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(stderr, "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"); + // String *lname = Getattr(p,"lname"); + Printf(f->def, "%s %s", SwigType_str(tt, 0), name); + String *tm = Getattr(p, "tmap:out"); + if(tm) { + Replaceall(tm, "$1", name); + Replaceall(tm, "$result", "r_tmp"); + replaceRClass(tm, Getattr(p,"type")); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + } + + 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? + */ + Node *bbase = NewHash(); + + Setattr(bbase, "type", rettype); + Setattr(bbase, "name", NewString("result")); + String *returnTM = Swig_typemap_lookup("in", bbase, "result", f); + if(returnTM) { + String *tm = returnTM; + Replaceall(tm,"$input", "r_swig_cb_data->retValue"); + Replaceall(tm,"$target", "result"); + replaceRClass(tm, rettype); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + 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(!isVoidType) + Printv(f->code, "return result;\n", NIL); + + Printv(f->code, "\n}\n", NIL); + + /* 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 the 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); + + 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(""); +} + + + +#if 0 +int R::cDeclaration(Node *n) { + SwigType *t = Getattr(n, "type"); + SwigType *name = Getattr(n, "name"); + if (debugMode) + Printf(stderr, "cDeclaration (%s): %s\n", name, SwigType_lstr(t, 0)); + return Language::cDeclaration(n); +} +#endif + + +/** + 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(!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); + } + + /* 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"); + Printf(f_runtime, "#define SWIGR\n"); + Printf(f_runtime, "\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); + Close(f_begin); + 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(stderr, "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); + + Close(scode); + // 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); + + Close(runtime); + 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(namespaceFunctions, ns, 1); + Printf(ns, ")\n"); + Close(ns); + Delete(ns); + Delete(s_namespace); + } + + return SWIG_OK; +} + + + +/* + 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(stderr, "%d) %s\n", i, key); + List *els = Getattr(tb, key); + int nels = Len(els); + Printf(stderr, "\t"); + for(int j = 0; j < nels; j+=2) { + Printf(stderr, "%s%s", Getitem(els, j), j < nels - 1 ? ", " : ""); + Printf(stderr, "%s\n", Getitem(els, j+1)); + } + Printf(stderr, "\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. */ + + 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); + ptr = &ptr[Len(key) - 3]; + int isSet = strcmp(ptr, "set") == 0; + + // OutputArrayMethod(className, el, out); + OutputMemberReferenceMethod(className, isSet, el, out); + + if(outputNamespaceInfo) + Printf(s_namespace, "\"%s\"%s", className, i < n-1 ? "," : ""); + } + if(n && outputNamespaceInfo) { + Printf(s_namespace, ")\n"); + } + + return n; +} + +/******************************************************************* + 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 *el, File *out) { + int numMems = Len(el), j; + int has_getitem = 0, has_setitem = 0, has_str = 0; + 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+=3) { + String *item = Getitem(el, j); + if (Getattr(itemList, item)) + continue; + Setattr(itemList, item, "1"); + if (!Strcmp(item, "__getitem__")) has_getitem = 1; + if (!Strcmp(item, "__setitem__")) has_setitem = 1; + if (!Strcmp(item, "__str__")) has_str = 1; + + String *dup = Getitem(el, j + 1); + char *ptr = Char(dup); + ptr = &ptr[Len(dup) - 3]; + + if (!strcmp(ptr, "get")) + varaccessor++; + + 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); + int vcount = 0; + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + String *dup = Getitem(el, j + 1); + char *ptr = Char(dup); + ptr = &ptr[Len(dup) - 3]; + + if (!strcmp(ptr, "get")) { + vcount++; + Printf(f->code, "'%s'%s", item, vcount < varaccessor ? ", " : ""); + } + } + Printf(f->code, ")\n"); + } + + + /* Printv(f->code, tab8, + "idx = pmatch(name, names(accessorFuns))\n", + tab8, + "if(is.na(idx)) {\n", + tab8, tab4, + "stop(\"No ", (isSet ? "modifiable" : "accessible"), " field named \", name, \" in ", className, + ": fields are \", paste(names(accessorFuns), sep = \", \")", + ")", "\n}\n", NIL); */ + 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 { + Printv(f->code, tab8, "formals(f)[[1]] = x\n", NIL); + if (varaccessor) { + Printv(f->code, tab8, + "if (is.na(match(name, vaccessors))) f else f(x)\n", NIL); + } else { + Printv(f->code, tab8, "f\n", NIL); + } + } + Printf(f->code, "}\n"); + + + Printf(out, "# Start of accessor method for %s\n", className); + 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"); + } + + DelWrapper(attr); + DelWrapper(f); + + Printf(out, "# end of accessor method for %s\n", className); + + return SWIG_OK; +} + +/******************************************************************* + 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) + 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::OutputArrayMethod(String *className, List *el, File *out) { + int numMems = Len(el), j; + + if(!el || numMems == 0) + return(0); + + Printf(out, "# start of array methods for %s\n", className); + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + String *dup = Getitem(el, j + 1); + if (!Strcmp(item, "__getitem__")) { + Printf(out, + "setMethod('[', '_p%s', function(x, i, j, ..., drop =TRUE) ", + getRClassName(className)); + Printf(out, " sapply(i, function (n) %s(x, as.integer(n-1))))\n\n", dup); + } + if (!Strcmp(item, "__setitem__")) { + Printf(out, "setMethod('[<-', '_p%s', function(x, i, j, ..., value)", + getRClassName(className)); + Printf(out, " sapply(1:length(i), function(n) %s(x, as.integer(i[n]-1), value[n])))\n\n", dup); + } + + } + + Printf(out, "# end of array methods for %s\n", className); + + 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) { + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + + /* Using name if tdname is empty. */ + + if(Len(tdname) == 0) + tdname = name; + + + if(!tdname || Strcmp(tdname, "") == 0) { + Language::enumDeclaration(n); + return SWIG_OK; + } + + String *mangled_tdname = SwigType_manglestr(tdname); + String *scode = NewString(""); + + Printv(scode, "defineEnumeration('", mangled_tdname, "'", + ",\n", tab8, tab8, tab4, ".values = c(\n", NIL); + + Node *c; + int value = -1; // First number is zero + for (c = firstChild(n); c; c = nextSibling(c)) { + // const char *tag = Char(nodeType(c)); + // if (Strcmp(tag,"cdecl") == 0) { + name = Getattr(c, "name"); + String *type = Getattr(c, "type"); + String *val = Getattr(c, "enumvalue"); + if(val && Char(val)) { + int inval = (int) getNumber(val, type); + if(inval == DEFAULT_NUMBER) + value++; + else + value = inval; + } else + value++; + + Printf(scode, "%s%s%s'%s' = %d%s\n", tab8, tab8, tab8, name, value, + nextSibling(c) ? ", " : ""); + // } + } + + Printv(scode, "))", NIL); + Printf(sfile, "%s\n", scode); + + Delete(scode); + Delete(mangled_tdname); + + return SWIG_OK; +} + + +/************************************************************* +**************************************************************/ +int R::variableWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + + processing_variable = 1; + Language::variableWrapper(n); // Force the emission of the _set and _get function wrappers. + processing_variable = 0; + + + SwigType *ty = Getattr(n, "type"); + int addCopyParam = addCopyParameter(ty); + + //XXX + processType(ty, n); + + 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; +} + + +void R::addAccessor(String *memberName, Wrapper *wrapper, String *name, + int isSet) { + if(isSet < 0) { + int n = Len(name); + char *ptr = Char(name); + isSet = Strcmp(NewString(&ptr[n-3]), "set") == 0; + } + + List *l = isSet ? class_member_set_functions : class_member_functions; + + if(!l) { + l = NewList(); + if(isSet) + class_member_set_functions = l; + else + class_member_functions = l; + } + + Append(l, memberName); + Append(l, name); + + String *tmp = NewString(""); + Wrapper_print(wrapper, tmp); + Append(l, tmp); + // if we could put the wrapper in directly: Append(l, Copy(sfun)); + if (debugMode) + Printf(stderr, "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 */ +}; + + +static List * 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; + } + /* 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")) { + 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)) { + // 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 (no type checking rule 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), + "xx Overloaded method %s not supported (no type checking rule 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 %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getfile(nodes[i].n), Getline(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(%s) ignored. Method %s(%s) const at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n,"name"), ParmList_errorstr(nodes[i].parms), + Getfile(nodes[i].n), Getline(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 %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getfile(nodes[i].n), Getline(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(%s) const ignored. Method %s(%s) at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n,"name"), ParmList_errorstr(nodes[i].parms), + Getfile(nodes[i].n), Getline(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 is shadowed by %s at %s:%d.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(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. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(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); + 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++) { + String *tm = Swig_typemap_lookup("rtype", p, "", 0); + if(tm) { + replaceRClass(tm, Getattr(p, "type")); + } + if (DohStrcmp(tm,"numeric")==0) { + Printf(f->code, "%sis.numeric(argv[[%d]])", + j == 0 ? "" : " && ", + j+1); + } + else { + Printf(f->code, "%sextends(argtypes[%d], '%s')", + j == 0 ? "" : " && ", + j+1, + tm); + } + 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) { + Printv(f->code, "}", NIL); + } + 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(stderr, + "<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(stderr, + "<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)) { + 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 (expandTypedef(resolved)) { + type = Copy(resolved); + Setattr(n, "type", type); + } + } + if (debugMode) + Printf(stderr, "<functionWrapper> unresolved_return_type %s\n", + unresolved_return_type); + if(processing_member_access_function) { + if (debugMode) + Printf(stderr, "<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. */ + + int n = Len(iname); + char *ptr = Char(iname); + bool isSet(Strcmp(NewString(&ptr[n-3]), "set") == 0); + + + String *tmp = NewString(""); + Printf(tmp, "%s_%s", class_name, isSet ? "set" : "get"); + + 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, num_required, varargs; + UNUSED(varargs); + + String *wname = Swig_name_wrapper(iname); + Replace(wname, "_wrap", "R_swig", DOH_REPLACE_FIRST); + 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); + + + // Can we get the nodeType() of the type node! and see if it is a struct. + // int addCopyParam = SwigType_isclass(rtype); + + // if(addCopyParam) + if (debugMode) + Printf(stderr, "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 + 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); + num_required = emit_num_required(l); + varargs = emit_isvarargs(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 && Swig_name_warning(p, 0, name, 0)) + name = 0; + + /* 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(stderr, "+++ parameter name with :: in it %s\n", name); + } + if (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", + "}\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")); + 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", "R_SWIG_EXTERNAL"); + + + 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, "result", f, actioncode))) { + SwigType *retType = Getattr(n, "type"); + //Printf(stderr, "Return Value for %s, array? %s\n", retType, SwigType_isarray(retType) ? "yes" : "no"); + /* if(SwigType_isarray(retType)) { + defineArrayAccessors(retType); + } */ + + + Replaceall(tm,"$1", "result"); + Replaceall(tm,"$result", "r_ans"); + replaceRClass(tm, retType); + + if (GetFlag(n,"feature:new")) { + Replaceall(tm, "$owner", "R_SWIG_OWNER"); + } else { + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + } + +#if 0 + if(addCopyParam) { + Printf(f->code, "if(LOGICAL(s_swig_copy)[0]) {\n"); + Printf(f->code, "/* Deal with returning a reference. */\nr_ans = R_NilValue;\n"); + Printf(f->code, "}\n else {\n"); + } +#endif + Printf(f->code, "%s\n", tm); +#if 0 + if(addCopyParam) + Printf(f->code, "}\n"); /* end of if(s_swig_copy) ... else { ... } */ +#endif + + } 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 */ + Printv(f->code, cleanup, NIL); + Delete(cleanup); + + + + Printv(f->code, UnProtectWrapupCode, NIL); + + /*If the user gave us something to convert the result in */ + if ((tm = Swig_typemap_lookup("scoerceout", n, + "result", sfun))) { + Replaceall(tm,"$source","ans"); + Replaceall(tm,"$result","ans"); + 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\nans\n", tm); + if (destructor) + Printv(f->code, "R_ClearExternalPtr(self);\n", NIL); + + Printv(f->code, "return r_ans;\n}\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"); + 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 potentialy insert + */ + if(processing_member_access_function || processing_class_member_function) { + String *tmp; + if(member_name) + tmp = member_name; + else + tmp = Getattr(n, "memberfunctionHandler:name"); + addAccessor(member_name, sfun, iname); + } + + 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; +} + +/***************************************************** + 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); + Printf(out, "SWIGEXPORT void R_init_%s(DllInfo *dll) {\n", Rpackage); + 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); + } + +} + +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") && Strcmp(Getattr(n, "storage"), "typedef") == 0 + && Getattr(n, "tdname") && Strcmp(Getattr(n, "tdname"), name) == 0) { + if (debugMode) + Printf(stderr, "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; + + + // OutputArrayMethod(name, class_member_functions, sfile); + if (class_member_functions) + OutputMemberReferenceMethod(name, 0, class_member_functions, sfile); + if (class_member_set_functions) + OutputMemberReferenceMethod(name, 1, class_member_set_functions, sfile); + + if(class_member_functions) { + Delete(class_member_functions); + class_member_functions = NULL; + } + if(class_member_set_functions) { + Delete(class_member_set_functions); + class_member_set_functions = NULL; + } + if (Getattr(n, "has_destructor")) { + Printf(sfile, "setMethod('delete', '_p%s', function(obj) {delete%s(obj)})\n", + getRClassName(Getattr(n, "name")), + getRClassName(Getattr(n, "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 (Strcmp(elKind, "variable") != 0) { + c = nextSibling(c); + continue; + } + if (!Len(elName)) { + c = nextSibling(c); + continue; + } +#if 0 + tp = getRType(c); +#else + 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(stderr, "<classDeclaration> elType %p\n", elType); + // tp = getRClassNameCopyStruct(Getattr(c, "type"), 1); +#endif + 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(stderr, "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 (Strcmp(elKind, "variable") != 0) { + Delete(elKind); + 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(stderr, "<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(stderr, "<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(stderr, "<membervariableHandler> name = %s, sym:name = %s\n", + Getattr(n, "name"), member_name); + + int status(Language::membervariableHandler(n)); + + if(opaqueClassDeclaration == NULL && debugMode) + Printf(stderr, "<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(stderr, "*** 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[]) { + bool cppcast = true; + 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],"-cppcast")) { + cppcast = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-nocppcast")) { + cppcast = false; + 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); + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + /// 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(stderr, "processType %s (tdname = %s)\n", Getattr(n, "name"), tmp); + + 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(stderr, "<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(stderr, + "<processType> Defining pointer handler %s\n", t); + + String *tmp = createFunctionPointerHandler(t, n, nargs); + return tmp; + } + +#if 0 + SwigType_isfunction(t) && SwigType_ispointer(t) +#endif + + return NULL; +} + + + + + + + + + +/*************************************************************************************/ + + + + + diff --git a/Source/Modules/ruby.cxx b/Source/Modules/ruby.cxx new file mode 100644 index 0000000..c9e935e --- /dev/null +++ b/Source/Modules/ruby.cxx @@ -0,0 +1,3427 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * ruby.cxx + * + * Ruby language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_ruby_cxx[] = "$Id: ruby.cxx 11246 2009-06-05 17:19:29Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +static int treduce = SWIG_cparse_template_reduce(0); + +#define SWIG_PROTECTED_TARGET_METHODS 1 + +#include <ctype.h> +#include <string.h> +#include <limits.h> /* for INT_MAX */ + +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 +}; + +static const char *usage = "\ +Ruby Options (available with -ruby)\n\ + -globalmodule - Wrap everything into the global module\n\ + -minherit - Attempt to support multiple inheritance\n\ + -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ + -cppcast - Enable C++ casting operators (default)\n\ + -autorename - Enable renaming of classes and methods to follow Ruby coding standards\n\ + -noautorename - Disable renaming of classes and methods (default)\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -initname <name> - Set entry function to Init_<name> (used by `require')\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; + if (autodoc) { + char *c = Char(autodoc); + if (c && 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 != NULL && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + } + + /* ------------------------------------------------------------ + * docstring() + * Get the docstring text, stripping off {} if neccessary, + * 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 != NULL && 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 != NULL && Len(autodoc) > 0); + } + // 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 (have_auto && have_ds) { // Both autodoc and docstring are present + doc = NewString(""); + Printv(doc, "\n", autodoc, "\n", str, NIL); + } else if (!have_auto && have_ds) { // only docstring + if (Strchr(str, '\n') == NULL) { + doc = NewString(str); + } else { + doc = NewString(""); + Printv(doc, str, NIL); + } + } else if (have_auto && !have_ds) { // only autodoc + if (Strchr(autodoc, '\n') == NULL) { + doc = NewStringf("%s", autodoc); + } else { + doc = NewString(""); + Printv(doc, "\n", autodoc, NIL); + } + } else + doc = NewString(""); + + // 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; + } + + /* ------------------------------------------------------------ + * make_autodocParmList() + * Generate the documentation for the function parameters + * ------------------------------------------------------------ */ + + String *make_autodocParmList(Node *n, bool showTypes) { + String *doc = NewString(""); + String *pdocs = Copy(Getattr(n, "feature:pdocs")); + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + Node *lookup; + int lines = 0; + const int maxwidth = 50; + + if (pdocs) + Append(pdocs, ".\n"); + + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + for (p = plist; p; p = pnext) { + String *name = 0; + String *type = 0; + String *value = 0; + String *ptype = 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"); + ptype = Getattr(p, "tmap:doc:pytype"); + } + + name = name ? name : Getattr(p, "name"); + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + } else { + pnext = nextSibling(p); + } + + // Skip ignored input attributes + if (checkAttribute(p, "tmap:in:numinputs", "0")) + continue; + + // 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? + if (showTypes) { + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + Printf(doc, "%s ", type); + } + + if (name) { + Append(doc, name); + if (pdoc) { + if (!pdocs) + pdocs = NewString("Parameters:\n"); + Printf(pdocs, " %s.\n", pdoc); + } + } else { + Append(doc, "?"); + } + + if (value) { + if (Strcmp(value, "NULL") == 0) + value = NewString("nil"); + else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0) + value = NewString("true"); + else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0) + value = NewString("false"); + else { + lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(doc, "=%s", value); + } + } + 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 funciton 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 (class_name && 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("/*\n"); + int counter = 0; + bool skipAuto = false; + Node* on = n; + for ( ; n; ++counter ) { + 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 = NULL; + else { + SwigType *qt = SwigType_typedef_resolve_all(type); + if (SwigType_isenum(qt)) + type = NewString("int"); + else { + type = SwigType_base(type); + Node *lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + } + } + } + + 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; + } + } + + + 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) + Printf(doc, " -> %s", type); + break; + } + case AUTODOC_SETTER: + { + Printf(doc, " %s=(x)", symname); + if (type) Printf(doc, " -> %s", type); + 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 == NULL || 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) + Printf(doc, " -> %s", type); + break; + } + case AUTODOC_SETTER: + { + Printf(doc, " call-seq:\n"); + Printf(doc, " %s=(x)", symname); + if (type) Printf(doc, " -> %s", type); + break; + } + } + } + + // if it's overloaded then get the next decl and loop around again + n = Getattr(n, "sym:nextSibling"); + if (n) + Append(doc, "\n"); + } + + 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; + } + } + + + n = on; + while ( n ) { + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + + symname = Getattr(n, "sym:name"); + if ( Getattr( special_methods, symname ) ) + symname = Getattr( special_methods, symname ); + + 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"); + } + + Append(doc, "\n*/\n"); + Delete(full_name); + Delete(class_name); + Delete(super_names); + Delete(methodName); + + return doc; + } + +public: + + /* --------------------------------------------------------------------- + * RUBY() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + RUBY() { + module = 0; + modvar = 0; + feature = 0; + prefix = 0; + last_autodoc = NewString(""); + current = NO_CPP; + classes = 0; + klass = 0; + special_methods = 0; + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_initbeforefunc = 0; + useGlobalModule = false; + multipleInheritance = false; + 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 cppcast = 1; + 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], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + 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); + } + } + } + + if (cppcast) { + /* Turn on cppcast mode */ + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + 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) { + + /** + * 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; + } + } + } + + /* 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"); + Printf(f_runtime, "#define SWIGRUBY\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, (char *) "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) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + + Delete(module_macro); + } + + Printf(f_header, "#define SWIG_init Init_%s\n", feature); + Printf(f_header, "#define SWIG_name \"%s\"\n\n", module); + 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.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"); + Close(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); + Close(f_begin); + 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 (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) { + 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: + assert(false); // Should not have gotten here for these types + default: + assert(false); + } + + 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) { + Printv(f->locals, tab4, "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 constructor; + bool destructor; + String *storage; + + 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"); + constructor = (!Cmp(nodeType, "constructor")); + destructor = (!Cmp(nodeType, "destructor")); + storage = Getattr(n, "storage"); + + /* 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) { + Printf(f->def, "#ifdef HAVE_RB_DEFINE_ALLOC_FUNC\n"); + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(VALUE self) {", NIL); + Printf(f->def, "#else\n"); + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); + Printf(f->def, "#endif\n"); + } 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 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"); + 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) { + Append(action, "\nDATA_PTR(self) = result;"); + if (GetFlag(pn, "feature:trackobjects")) { + Append(action, "\nSWIG_RubyAddTracking(result, self);"); + } + } + } + + /* 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 = (result ? Qtrue : Qfalse);\n", NIL); + } else { + tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode); + actioncode = 0; + if (tm) { + Replaceall(tm, "$result", "vresult"); + Replaceall(tm, "$source", "result"); + 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 *>(result);\n"); + 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) { + need_result = 1; + Printf(f->code, "VALUE vresult = SWIG_NewClassInstance(self, SWIGTYPE%s);\n", Char(SwigType_manglestr(t))); + 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"); + } else if (current == CONSTRUCTOR_INITIALIZE) { + need_result = 1; + // Printf(f->code, "DATA_PTR(self) = result;\n"); + } + 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, "result", 0); + if (tm) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + Delete(tm); + } + } + + /* Special processing on return value. */ + tm = Swig_typemap_lookup("ret", n, "result", 0); + if (tm) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, NIL); + Delete(tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, "result", 0))) { + Replaceall(tm, "$input", "result"); + 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; + + String* type = SwigType_str(Getattr(sibl,"type"),NULL); + + 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,"feature:new"), "1") == 0; + const bool isMethod = ( Cmp(Getattr(sibl, "ismember"), "1") == 0 && + (!isCtor) ); + + // Construct real method name + String* methodName = NewString(""); + if ( isMethod ) + Printv( methodName, Getattr(parentNode(sibl),"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 ) Printv( protoTypes, type, " ", NIL ); + 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(type); + 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; + + getf = NewWrapper(); + setf = NewWrapper(); + + /* create getter */ + int addfail = 0; + String *getname = Swig_name_get(iname); + getfname = Swig_name_wrapper(getname); + Setattr(n, "wrap:name", getfname); + Printv(getf->def, "SWIGINTERN VALUE\n", getfname, "(", NIL); + Printf(getf->def, "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 (!is_assignable(n)) { + setfname = NewString("NULL"); + } else { + /* create setter */ + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + String *setname = Swig_name_set(iname); + setfname = Swig_name_wrapper(setname); + Setattr(n, "wrap:name", setfname); + Printv(setf->def, "SWIGINTERN VALUE\n", setfname, "(VALUE self, ", NIL); + Printf(setf->def, "VALUE _val) {"); + 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)); + } + 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 method */ + if (CPlusPlus) { + Insert(getfname, 0, "VALUEFUNC("); + Append(getfname, ")"); + Insert(setfname, 0, "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 (!GetFlag(n, "feature:immutable")) { + 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 (!GetFlag(n, "feature:immutable")) { + Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "=\", ", setfname, ", 1);\n", NIL); + } + } else { + Printv(s, tab4, "rb_define_global_method(\"", iname, "\", ", getfname, ", 0);\n", NIL); + if (!GetFlag(n, "feature:immutable")) { + Printv(s, tab4, "rb_define_global_method(\"", iname, "=\", ", setfname, ", 1);\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 *tdname = Getattr(n, "tdname"); + + name = tdname ? tdname : 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); + if (multipleInheritance) { + String *bmangle = SwigType_manglestr(btype); + Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); + Append(bmangle, "->clientdata)->mImpl"); + Printv(klass->init, "rb_include_module(", klass->mImpl, ", ", bmangle, ");\n", NIL); + Delete(bmangle); + } else { + String *bmangle = SwigType_manglestr(btype); + Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); + Append(bmangle, "->clientdata)->klass"); + Replaceall(klass->init, "$super", bmangle); + Delete(bmangle); + } + 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, input_file, line_number, + "Warning for %s proxy: 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, "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); + String *tm = SwigType_manglestr(tt); + Printf(klass->init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) &SwigClass%s);\n", tm, valid_name); + Delete(tm); + 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((const_String_or_char_ptr ) "construct", (const_String_or_char_ptr ) "%c_allocate"); + + + Language::constructorHandler(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("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); + 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 */ + String* docs = docstring(n, AUTODOC_CTOR); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + current = CONSTRUCTOR_INITIALIZE; + Swig_name_register((const_String_or_char_ptr ) "construct", (const_String_or_char_ptr ) "new_%c"); + Language::constructorHandler(n); + + /* Restore original parameter list */ + Delattr(n, "wrap:self"); + Swig_restore(n); + + /* Done */ + Swig_name_unregister((const_String_or_char_ptr ) "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((const_String_or_char_ptr ) "construct", (const_String_or_char_ptr ) "%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, "(", klass->type, " *", pname0, ") {\n", 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")); + 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, 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, 0, 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, "result", 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, "result", "VALUE", "result", "= Qnil", NIL); + Printf(body->code, "%s++;\n", depthCountName); + Printv(body->code, "result = rb_funcall2(args->recv, args->id, args->argc, args->argv);\n", NIL); + Printf(body->code, "%s--;\n", depthCountName); + Printv(body->code, "return result;\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, "}", 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, "result = rb_protect(PROTECTFUNC(%s), reinterpret_cast<VALUE>(&args), &status);\n", 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, "result = rb_funcall(swig_get_self(), rb_intern(\"%s\"), %d%s);\n", methodName, argc, args); + } else { + Printf(w->code, "result = rb_funcall(swig_get_self(), rb_intern(\"%s\"), 0, NULL);\n", 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; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_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")); + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + 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 ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + 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) { + if (!(ignored_method && !pure_virtual)) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), 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++ -> Ruby) */ + String *arglist = NewString(""); + + /** + * For each parameter to 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 your "directorin" typemaps. + * Not sure if it's OK to leave it like this, but seems OK so far. + */ + typemap_copy_pname_to_lname(l); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + 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++); + Replaceall(tm, "$input", source); + Replaceall(tm, "$owner", "0"); + 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 */ + Wrapper_add_local(w, "result", "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(result) != T_ARRAY) {\n"); + 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) { + /* This seems really silly. The node's type excludes qualifier/pointer/reference markers, + * which have to be retrieved from the decl field to construct return_type. But the typemap + * lookup routine uses the node's type, so we have to swap in and out the correct type. + * It's not just me, similar silliness also occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + if (outputs > 1 && !asvoid ) { + Printf(w->code, "output = rb_ary_entry(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "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); + } 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(return_type, 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(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + Replaceall(tm, "$result", Getattr(p, "name")); + 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(return_type, 0); + if (!SwigType_isreference(return_type)) { + 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")) { + 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(return_type); + 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); + } + + void typemap_copy_pname_to_lname(ParmList *parms) { + Parm *p; + String *pname; + String *lname; + + p = parms; + while (p) { + pname = Getattr(p, "name"); + lname = Copy(pname); + Setattr(p, "lname", lname); + p = nextSibling(p); + } + } + + 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"); + } +}; /* 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/Source/Modules/s-exp.cxx b/Source/Modules/s-exp.cxx new file mode 100644 index 0000000..c87d18c --- /dev/null +++ b/Source/Modules/s-exp.cxx @@ -0,0 +1,394 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * s-exp.cxx + * + * A parse tree represented as Lisp s-expressions. + * ----------------------------------------------------------------------------- */ + +char cvsroot_s_exp_cxx[] = "$Id: s-exp.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" +#include "dohint.h" + +static const char *usage = "\ +S-Exp Options (available with -sexp)\n\ + -typemaplang <lang> - Typemap language\n\n"; + +//static Node *view_top = 0; +static File *out = 0; + +class Sexp:public Language { +public: + int indent_level; + Sexp():indent_level(0) { + } + + virtual ~ Sexp() { + } + + virtual void main(int argc, char *argv[]) { + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGSEXP 1", 0); + + SWIG_typemap_lang("sexp"); + for (int iX = 0; iX < argc; iX++) { + if (strcmp(argv[iX], "-typemaplang") == 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); + } + } + } + + DOHHash *print_circle_hash; + int print_circle_count; + int hanging_parens; + bool need_whitespace; + bool need_newline; + + /* Top of the parse tree */ + virtual int top(Node *n) { + if (out == 0) { + String *outfile = Getattr(n, "outfile"); + Replaceall(outfile, "_wrap.cxx", ".lisp"); + Replaceall(outfile, "_wrap.c", ".lisp"); + out = NewFile(outfile, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + } + String *f_sink = NewString(""); + Swig_register_filebyname("header", f_sink); + Swig_register_filebyname("wrapper", f_sink); + Swig_register_filebyname("begin", f_sink); + Swig_register_filebyname("runtime", f_sink); + Swig_register_filebyname("init", f_sink); + + Swig_banner_target_lang(out, ";;;"); + + Language::top(n); + Printf(out, "\n"); + Printf(out, ";;; Lisp parse tree produced by SWIG\n"); + print_circle_hash = DohNewHash(); + print_circle_count = 0; + hanging_parens = 0; + need_whitespace = 0; + need_newline = 0; + Sexp_print_node(n); + flush_parens(); + return SWIG_OK; + } + + void print_indent() { + int i; + for (i = 0; i < indent_level; i++) { + Printf(out, " "); + } + } + + void open_paren(const String *oper) { + flush_parens(); + Printf(out, "("); + if (oper) + Printf(out, "%s ", oper); + indent_level += 2; + } + + void close_paren(bool neednewline = false) { + hanging_parens++; + if (neednewline) + print_lazy_whitespace(); + indent_level -= 2; + } + + void flush_parens() { + int i; + if (hanging_parens) { + for (i = 0; i < hanging_parens; i++) + Printf(out, ")"); + hanging_parens = 0; + need_newline = true; + need_whitespace = true; + } + if (need_newline) { + Printf(out, "\n"); + print_indent(); + need_newline = false; + need_whitespace = false; + } else if (need_whitespace) { + Printf(out, " "); + need_whitespace = false; + } + } + + void print_lazy_whitespace() { + need_whitespace = 1; + } + + void print_lazy_newline() { + need_newline = 1; + } + + bool internal_key_p(DOH *key) { + return ((Cmp(key, "nodeType") == 0) + || (Cmp(key, "firstChild") == 0) + || (Cmp(key, "lastChild") == 0) + || (Cmp(key, "parentNode") == 0) + || (Cmp(key, "nextSibling") == 0) + || (Cmp(key, "previousSibling") == 0) + || (Cmp(key, "csym:nextSibling") == 0) + || (Cmp(key, "csym:previousSibling") == 0) + || (Cmp(key, "typepass:visit") == 0) + || (Cmp(key, "allocate:visit") == 0) + || (*(Char(key)) == '$')); + } + + bool boolean_key_p(DOH *key) { + return ((Cmp(key, "allocate:default_constructor") == 0) + || (Cmp(key, "allocate:default_destructor") == 0) + || (Cmp(key, "allows_typedef") == 0) + || (Cmp(key, "feature:immutable") == 0)); + } + + bool list_key_p(DOH *key) { + return ((Cmp(key, "parms") == 0) + || (Cmp(key, "baselist") == 0)); + } + + bool plist_key_p(DOH *key) + // true if KEY is the name of data that is a mapping from keys to + // values, which should be printed as a plist. + { + return ((Cmp(key, "typescope") == 0)); + } + + bool maybe_plist_key_p(DOH *key) { + return (Strncmp(key, "tmap:", 5) == 0); + } + + bool print_circle(DOH *obj, bool list_p) + // We have a complex object, which might be referenced several + // times, or even recursively. Use Lisp's reader notation for + // circular structures (#n#, #n=). + // + // An object can be printed in list-mode or object-mode; LIST_P toggles. + // return TRUE if OBJ still needs to be printed + { + flush_parens(); + // Following is a silly hack. It works around the limitation of + // DOH's hash tables that only work with string keys! + char address[32]; + sprintf(address, "%p%c", obj, list_p ? 'L' : 'O'); + DOH *placeholder = Getattr(print_circle_hash, address); + if (placeholder) { + Printv(out, placeholder, NIL); + return false; + } else { + String *placeholder = NewStringf("#%d#", ++print_circle_count); + Setattr(print_circle_hash, address, placeholder); + Printf(out, "#%d=", print_circle_count); + return true; + } + } + + void Sexp_print_value_of_key(DOH *value, DOH *key) { + if ((Cmp(key, "parms") == 0) || (Cmp(key, "wrap:parms") == 0) + || (Cmp(key, "kwargs") == 0) || (Cmp(key, "pattern") == 0)) + Sexp_print_parms(value); + else if (plist_key_p(key)) + Sexp_print_plist(value); + else if (maybe_plist_key_p(key)) { + if (DohIsMapping(value)) + Sexp_print_plist(value); + else + Sexp_print_doh(value); + } else if (list_key_p(key)) + Sexp_print_list(value); + else if (boolean_key_p(key)) + Sexp_print_boolean(value); + else + Sexp_print_doh(value); + } + + void Sexp_print_boolean(DOH *obj) { + flush_parens(); + /* See DOH/Doh/base.c, DohGetInt() */ + if (DohIsString(obj)) { + if (atoi(Char(obj)) != 0) + Printf(out, "t"); + else + Printf(out, "nil"); + } else + Printf(out, "nil"); + } + + void Sexp_print_list(DOH *obj) { + if (print_circle(obj, true)) { + open_paren(NIL); + for (; obj; obj = nextSibling(obj)) { + Sexp_print_doh(obj); + print_lazy_whitespace(); + } + close_paren(true); + } + } + + void Sexp_print_parms(DOH *obj) { + // print it as a list of plists + if (print_circle(obj, true)) { + open_paren(NIL); + for (; obj; obj = nextSibling(obj)) { + if (DohIsMapping(obj)) { + Iterator k; + open_paren(NIL); + for (k = First(obj); k.key; k = Next(k)) { + if (!internal_key_p(k.key)) { + DOH *value = Getattr(obj, k.key); + Sexp_print_as_keyword(k.key); + Sexp_print_value_of_key(value, k.key); + print_lazy_whitespace(); + } + } + close_paren(true); + } else + Sexp_print_doh(obj); + print_lazy_whitespace(); + } + close_paren(true); + } + } + + void Sexp_print_doh(DOH *obj) { + flush_parens(); + if (DohIsString(obj)) { + String *o = Str(obj); + Replaceall(o, "\\", "\\\\"); + Replaceall(o, "\"", "\\\""); + Printf(out, "\"%s\"", o); + Delete(o); + } else { + if (print_circle(obj, false)) { + // Dispatch type + if (nodeType(obj)) { + Sexp_print_node(obj); + } + + else if (DohIsMapping(obj)) { + Iterator k; + open_paren(NIL); + for (k = First(obj); k.key; k = Next(k)) { + if (!internal_key_p(k.key)) { + DOH *value = Getattr(obj, k.key); + flush_parens(); + open_paren(NIL); + Sexp_print_doh(k.key); + Printf(out, " . "); + Sexp_print_value_of_key(value, k.key); + close_paren(); + } + } + close_paren(); + } else if (strcmp(ObjType(obj)->objname, "List") == 0) { + int i; + open_paren(NIL); + for (i = 0; i < Len(obj); i++) { + DOH *item = Getitem(obj, i); + Sexp_print_doh(item); + } + close_paren(); + } else { + // What is it? + Printf(out, "#<DOH %s %x>", ObjType(obj)->objname, obj); + } + } + } + } + + void Sexp_print_as_keyword(const DOH *k) { + /* Print key, replacing ":" with "-" because : is CL's package prefix */ + flush_parens(); + String *key = NewString(k); + Replaceall(key, ":", "-"); + Replaceall(key, "_", "-"); + Printf(out, ":%s ", key); + Delete(key); + } + + void Sexp_print_plist_noparens(DOH *obj) { + /* attributes map names to objects */ + Iterator k; + bool first; + for (k = First(obj), first = true; k.key; k = Next(k), first = false) { + if (!internal_key_p(k.key)) { + DOH *value = Getattr(obj, k.key); + flush_parens(); + if (!first) { + Printf(out, " "); + } + Sexp_print_as_keyword(k.key); + /* Print value */ + Sexp_print_value_of_key(value, k.key); + } + } + } + + void Sexp_print_plist(DOH *obj) { + flush_parens(); + if (print_circle(obj, true)) { + open_paren(NIL); + Sexp_print_plist_noparens(obj); + close_paren(); + } + } + + void Sexp_print_attributes(Node *obj) { + Sexp_print_plist_noparens(obj); + } + + void Sexp_print_node(Node *obj) { + Node *cobj; + open_paren(nodeType(obj)); + /* A node has an attribute list... */ + Sexp_print_attributes(obj); + /* ... and child nodes. */ + cobj = firstChild(obj); + if (cobj) { + print_lazy_newline(); + flush_parens(); + Sexp_print_as_keyword("children"); + open_paren(NIL); + for (; cobj; cobj = nextSibling(cobj)) { + Sexp_print_node(cobj); + } + close_paren(); + } + close_paren(); + } + + + virtual int functionWrapper(Node *n) { + ParmList *l = Getattr(n, "parms"); + Wrapper *f = NewWrapper(); + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + DelWrapper(f); + return SWIG_OK; + } + +}; + + +static Language *new_swig_sexp() { + return new Sexp(); +} +extern "C" Language *swig_sexp(void) { + return new_swig_sexp(); +} diff --git a/Source/Modules/swigmain.cxx b/Source/Modules/swigmain.cxx new file mode 100644 index 0000000..aed915d --- /dev/null +++ b/Source/Modules/swigmain.cxx @@ -0,0 +1,202 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * Simplified Wrapper and Interface Generator (SWIG) + * + * swigmain.cxx + * + * 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. + * ----------------------------------------------------------------------------- */ + +char cvsroot_swigmain_cxx[] = "$Id: swigmain.cxx 10969 2008-12-06 23:15:20Z wsfulton $"; + +#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_tcl(void); + Language *swig_python(void); + Language *swig_perl5(void); + Language *swig_ruby(void); + Language *swig_guile(void); + Language *swig_modula3(void); + Language *swig_mzscheme(void); + Language *swig_java(void); + Language *swig_php(void); + Language *swig_php4(void); + Language *swig_ocaml(void); + Language *swig_octave(void); + Language *swig_pike(void); + Language *swig_sexp(void); + Language *swig_xml(void); + Language *swig_chicken(void); + Language *swig_csharp(void); + Language *swig_allegrocl(void); + Language *swig_lua(void); + Language *swig_clisp(void); + Language *swig_cffi(void); + Language *swig_uffi(void); + Language *swig_r(void); +} + +struct swig_module { + const char *name; + ModuleFactory fac; + const char *help; +}; + +/* Association of command line options to language modules. + Place an entry for new language modules here, keeping the + list sorted alphabetically. */ + +static swig_module modules[] = { + {"-allegrocl", swig_allegrocl, "ALLEGROCL"}, + {"-chicken", swig_chicken, "CHICKEN"}, + {"-clisp", swig_clisp, "CLISP"}, + {"-cffi", swig_cffi, "CFFI"}, + {"-csharp", swig_csharp, "C#"}, + {"-guile", swig_guile, "Guile"}, + {"-java", swig_java, "Java"}, + {"-lua", swig_lua, "Lua"}, + {"-modula3", swig_modula3, "Modula 3"}, + {"-mzscheme", swig_mzscheme, "Mzscheme"}, + {"-ocaml", swig_ocaml, "Ocaml"}, + {"-octave", swig_octave, "Octave"}, + {"-perl", swig_perl5, "Perl"}, + {"-perl5", swig_perl5, 0}, + {"-php", swig_php, "PHP"}, + {"-php4", swig_php4, 0}, + {"-php5", swig_php, 0}, + {"-pike", swig_pike, "Pike"}, + {"-python", swig_python, "Python"}, + {"-r", swig_r, "R (aka GNU S)"}, + {"-ruby", swig_ruby, "Ruby"}, + {"-sexp", swig_sexp, "Lisp S-Expressions"}, + {"-tcl", swig_tcl, "Tcl"}, + {"-tcl8", swig_tcl, 0}, + {"-uffi", swig_uffi, "Common Lisp / UFFI"}, + {"-xml", swig_xml, "XML"}, + {NULL, NULL, NULL} +}; + +#ifdef MACSWIG +#include <console.h> +#include <SIOUX.h> +#endif + +#ifndef SWIG_LANG +#define SWIG_LANG "-python" +#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 = oargv; + return; + } + + int argc = 1; + int arge = oargc + 1024; + char **argv = (char **) malloc(sizeof(char *) * (arge)); + 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]; + } + + *nargc = argc; + *nargv = argv; +} + +int main(int margc, char **margv) { + int i; + Language *dl = 0; + ModuleFactory fac = 0; + + int argc; + char **argv; + + SWIG_merge_envopt(getenv("SWIG_FEATURES"), margc, margv, &argc, &argv); + +#ifdef MACSWIG + SIOUXSettings.asktosaveonclose = false; + argc = ccommand(&argv); +#endif + + /* Register built-in modules */ + for (i = 0; modules[i].name; i++) { + Swig_register_module(modules[i].name, modules[i].fac); + } + + Swig_init_args(argc, argv); + + /* Get options */ + for (i = 1; i < argc; i++) { + if (argv[i]) { + fac = Swig_find_module(argv[i]); + if (fac) { + dl = (fac) (); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nolang") == 0) { + dl = new Language; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-dnone") == 0) || + (strcmp(argv[i], "-dhtml") == 0) || + (strcmp(argv[i], "-dlatex") == 0) || (strcmp(argv[i], "-dascii") == 0) || (strcmp(argv[i], "-stat") == 0)) { + Printf(stderr, "swig: Warning. %s option deprecated.\n", argv[i]); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0)) { + if (strcmp(argv[i], "--help") == 0) + strcpy(argv[i], "-help"); + Printf(stdout, "Target Language Options\n"); + for (int j = 0; modules[j].name; j++) { + if (modules[j].help) { + 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 + } + } + } + if (!dl) { + fac = Swig_find_module(SWIG_LANG); + if (fac) { + dl = (fac) (); + } + } + int res = SWIG_main(argc, argv, dl); + delete dl; + return res; +} diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h new file mode 100644 index 0000000..dbb62b2 --- /dev/null +++ b/Source/Modules/swigmod.h @@ -0,0 +1,391 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * swigmod.h + * + * Main header file for SWIG modules. + * ----------------------------------------------------------------------------- */ + +/* $Id: swigmod.h 11470 2009-07-29 20:50:39Z wsfulton $ */ + +#ifndef SWIG_SWIGMOD_H_ +#define SWIG_SWIGMOD_H_ + +#include "swig.h" +#include "preprocessor.h" +#include "swigwarn.h" + +#if !defined(HAVE_BOOL) +typedef int bool; +#define true ((bool)1) +#define false ((bool)0) +#endif + +#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); + + 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); + + /* 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); /* Add symbol */ + virtual Node *symbolLookup(String *s); /* Symbol lookup */ + virtual Node *classLookup(SwigType *s); /* Class lookup */ + virtual Node *enumLookup(SwigType *s); /* Enum lookup */ + virtual int abstractClassTest(Node *n); /* Is class really abstract? */ + virtual int is_assignable(Node *n); /* Is variable assignable? */ + 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(); + + /* Return the node for the current class */ + Node *getCurrentClass() const; + + /* Return C++ mode */ + int getCPlusMode() 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; + + /* 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; + + /* Some language modules require additional wrappers for virtual methods not declared in sub-classes */ + virtual bool extraDirectorProtectedCPPMethodsRequired() 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; + +private: + Hash *symbols; + Hash *classtypes; + Hash *enumtypes; + int overloading; + int multiinput; + int cplus_runtime; + int directors; + static Language *this_; +}; + +int SWIG_main(int, char **, Language *); +void emit_parameter_variables(ParmList *l, Wrapper *f); +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f); +void SWIG_exit(int); /* use EXIT_{SUCCESS,FAILURE} */ +void SWIG_config_file(const_String_or_char_ptr ); +const String *SWIG_output_directory(); +void SWIG_config_cppext(const char *ext); + +/* 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 *); +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 *); +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *); +String *Swig_overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *); +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 *rtype, SwigType *decl, const_String_or_char_ptr id, List *args, int strip, int values); +String *Swig_director_declaration(Node *n); +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f); +/* directors.cxx end */ + +extern "C" { + void SWIG_typemap_lang(const char *); + typedef Language *(*ModuleFactory) (void); +} + +void Swig_register_module(const char *name, ModuleFactory fac); +ModuleFactory Swig_find_module(const char *name); + +/* 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) */ +int use_naturalvar_mode(Node *n); + +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); + +/* 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); + + +#endif diff --git a/Source/Modules/tcl8.cxx b/Source/Modules/tcl8.cxx new file mode 100644 index 0000000..3ff69fe --- /dev/null +++ b/Source/Modules/tcl8.cxx @@ -0,0 +1,1306 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * tcl8.cxx + * + * Tcl8 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_tcl8_cxx[] = "$Id: tcl8.cxx 11518 2009-08-08 22:56:10Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +static int treduce = SWIG_cparse_template_reduce(0); + +static const char *usage = (char *) "\ +Tcl 8 Options (available with -tcl)\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 nspace = 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[]) { + int cppcast = 1; + + 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) { + nspace = 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], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + 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"); + Printf(f_runtime, "#define SWIGTCL\n"); + Printf(f_runtime, "\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_file_dirname(outfile), 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 (nspace) { + 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); + Close(f_shadow); + 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); + Close(f_begin); + 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, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); +#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, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + 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); + Printf(df->code, "Tcl_SetResult(interp,(char *) \"No matching function for overloaded '%s'\", TCL_STATIC);\n", iname); + 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(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(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 = !nspace ? 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 (nspace) + 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; + + 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); + + // t = Copy(Getattr(n,"classtype")); + // SwigType_add_pointer(t); + + String *rt = Copy(Getattr(n, "classtype")); + 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 (nspace) { + + 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, "abstract") ? " - 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(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 };\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(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 (nspace) { + 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 (nspace) { + 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(Swig_name_member(class_name, symname))); + Printv(attr_tab, rname, ", ", NIL); + Delete(rname); + if (!GetFlag(n, "feature:immutable")) { + rname = Swig_name_wrapper(Swig_name_set(Swig_name_member(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 (nspace) { + 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); + } + } + + 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 (nspace) { + 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/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx new file mode 100644 index 0000000..6cb7f0a --- /dev/null +++ b/Source/Modules/typepass.cxx @@ -0,0 +1,1164 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * 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. + * ----------------------------------------------------------------------------- */ + +char cvsroot_typepass_cxx[] = "$Id: typepass.cxx 11279 2009-06-16 19:29:08Z wsfulton $"; + +#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; + Hash *classhash; + List *normalize; + + TypePass() { + } + + /* 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; + } + } + if (Strcmp(nodeType(bcls), "classforward") != 0) { + Swig_error(Getfile(cls), Getline(cls), "'%s' does not have a valid base class.\n", Getattr(cls, "name")); + Swig_error(Getfile(bcls), Getline(bcls), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); + } else { + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(cls), Getline(cls), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname)); + clsforward = 1; + } + bcls = 0; + } else { + if (Getattr(bcls, "typepass:visit")) { + if (!ilist) + ilist = alist = NewList(); + Append(ilist, bcls); + } else { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Base class '%s' undefined.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(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) { + if (ispublic && !Getmeta(bname, "already_warned")) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); + if (Strchr(bname, '<')) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Maybe you forgot to instantiate '%s' using %%template.\n", + SwigType_namestr(bname)); + } + 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 (!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", 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; + 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"); + Node *oldinclass = inclass; + List *olist = normalize; + Symtab *symtab; + String *nname = 0; + String *fname = 0; + String *scopename = 0; + + normalize = NewList(); + + if (name) { + if (SwigType_istemplate(name)) { + // We need to fully resolve the name to make templates work correctly */ + Node *cn; + fname = SwigType_typedef_resolve_all(name); + if (Strcmp(fname, name) != 0 && (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); + 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); + } + } 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); + } + + if (nsname) { + nname = NewStringf("%s::%s", nsname, name); + String *tdname = Getattr(n, "tdname"); + if (tdname) { + tdname = NewStringf("%s::%s", nsname, tdname); + Setattr(n, "tdname", tdname); + } + } + SwigType_new_scope(scopename); + SwigType_attach_symtab(Getattr(n, "symtab")); + + /* Inherit type definitions into the class */ + if (name) { + 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); + + /* 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; + + inclass = oldinclass; + + /* If in a namespace, patch the class name */ + if (nname) { + Setattr(n, "name", nname); + Delete(nname); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * namespaceDeclaration() + * ------------------------------------------------------------ */ + + 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); */ + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classforwardDeclaration() + * ------------------------------------------------------------ */ + + virtual int classforwardDeclaration(Node *n) { + + /* Temporary hack. Can't do inside a class because it breaks + C nested structure wrapping */ + + if ((!inclass) || (CPlusPlus)) { + String *name = Getattr(n, "name"); + String *nname; + SwigType_typedef_class(name); + if (nsname) { + nname = NewStringf("%s::%s", nsname, name); + Setattr(n, "name", nname); + } + + } + 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) { + Node *ns; + /* Create a empty scope for the alias */ + ns = Getattr(n, "namespace"); + if (ns) { + 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; + nsname = Swig_symbol_qualified(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(nsname); + nsname = oldnsname; + return SWIG_OK; + } + } + + /* ------------------------------------------------------------ + * cDeclaration() + * ------------------------------------------------------------ */ + + virtual int cDeclaration(Node *n) { + if (NoExcept) { + Delattr(n, "throws"); + } + + /* Normalize types. */ + SwigType *ty = Getattr(n, "type"); + 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")); + + /* If in a namespace, patch the class name */ + if (nsname) { + String *nname = NewStringf("%s::%s", nsname, Getattr(n, "name")); + Setattr(n, "name", nname); + } + clean_overloaded(n); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int destructorDeclaration(Node *n) { + /* If in a namespace, patch the class name */ + if (nsname) { + String *nname = NewStringf("%s::%s", nsname, Getattr(n, "name")); + Setattr(n, "name", nname); + } + 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); + + // 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")) { + 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"); + if (!value) + value = name; + if (Strcmp(value, name) == 0) { + String *new_value; + if (((nsname) || (inclass)) && cparse_cplusplus) { + new_value = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); + } else { + new_value = NewString(value); + } + 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. + return enumDeclaration(n); + } + +#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); + exit (1); + } + + 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); + exit (1); + } + 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 (!(checkAttribute(c, "storage", "static") + || 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 + 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")) + { +#ifdef DEBUG_OVERLOADED +show_overloaded(n); +#endif + int cnt = 0; + Node *debugnode = n; + 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); + } + debugnode = firstoverloaded; + } + 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")); + } + } + } + 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/Source/Modules/uffi.cxx b/Source/Modules/uffi.cxx new file mode 100644 index 0000000..780b9e8 --- /dev/null +++ b/Source/Modules/uffi.cxx @@ -0,0 +1,398 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * uffi.cxx + * + * Uffi language module for SWIG. + * ----------------------------------------------------------------------------- */ + +// TODO: remove remnants of lisptype + +char cvsroot_uffi_cxx[] = "$Id: uffi.cxx 11380 2009-07-08 12:17:45Z wsfulton $"; + +#include "swigmod.h" + +class UFFI:public Language { +public: + + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int classHandler(Node *n); + virtual int membervariableHandler(Node *n); + +}; + +static File *f_cl = 0; + +static struct { + int count; + String **entries; +} defined_foreign_types; + +static const char *identifier_converter = "identifier-convert-null"; + +static int any_varargs(ParmList *pl) { + Parm *p; + + for (p = pl; p; p = nextSibling(p)) { + if (SwigType_isvarargs(Getattr(p, "type"))) + return 1; + } + + return 0; +} + + +/* utilities */ +/* returns new string w/ parens stripped */ +static String *strip_parens(String *string) { + char *s = Char(string), *p; + int len = Len(string); + String *res; + + if (len == 0 || s[0] != '(' || s[len - 1] != ')') { + return NewString(string); + } + + p = (char *) malloc(len - 2 + 1); + if (!p) { + Printf(stderr, "Malloc failed\n"); + SWIG_exit(EXIT_FAILURE); + } + + strncpy(p, s + 1, len - 1); + p[len - 2] = 0; /* null terminate */ + + res = NewString(p); + free(p); + + return res; +} + + +static String *convert_literal(String *num_param, String *type) { + String *num = strip_parens(num_param), *res; + char *s = Char(num); + + /* Make sure doubles use 'd' instead of 'e' */ + if (!Strcmp(type, "double")) { + String *updated = Copy(num); + if (Replace(updated, "e", "d", DOH_REPLACE_ANY) > 1) { + Printf(stderr, "Weird!! number %s looks invalid.\n", num); + SWIG_exit(EXIT_FAILURE); + } + Delete(num); + return updated; + } + + if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + return NewStringf("#\\%s", num_param); + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + return NewStringf("\"%s\"", num_param); + } + + if (Len(num) < 2 || s[0] != '0') { + return num; + } + + /* octal or hex */ + + res = NewStringf("#%c%s", s[1] == 'x' ? 'x' : 'o', s + 2); + Delete(num); + + return res; +} + +static void add_defined_foreign_type(String *type) { + if (!defined_foreign_types.count) { + /* Make fresh */ + defined_foreign_types.count = 1; + defined_foreign_types.entries = (String **) malloc(sizeof(String *)); + } else { + /* make room */ + defined_foreign_types.count++; + defined_foreign_types.entries = (String **) + realloc(defined_foreign_types.entries, defined_foreign_types.count * sizeof(String *)); + } + + if (!defined_foreign_types.entries) { + Printf(stderr, "Out of memory\n"); + SWIG_exit(EXIT_FAILURE); + } + + /* Fill in the new data */ + defined_foreign_types.entries[defined_foreign_types.count - 1] = Copy(type); + +} + + +static String *get_ffi_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setattr(node, "name", name); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("ffitype", node, "", 0); + Delete(node); + + if (tm) { + return NewString(tm); + } else { + SwigType *tr = SwigType_typedef_resolve_all(ty); + char *type_reduced = Char(tr); + int i; + + //Printf(stdout,"convert_type %s\n", ty); + if (SwigType_isconst(tr)) { + SwigType_pop(tr); + type_reduced = Char(tr); + } + + if (SwigType_ispointer(type_reduced) || SwigType_isarray(ty) || !strncmp(type_reduced, "p.f", 3)) { + return NewString(":pointer-void"); + } + + for (i = 0; i < defined_foreign_types.count; i++) { + if (!Strcmp(ty, defined_foreign_types.entries[i])) { + return NewStringf("#.(%s \"%s\" :type :type)", identifier_converter, ty); + } + } + + if (!Strncmp(type_reduced, "enum ", 5)) { + return NewString(":int"); + } + + Printf(stderr, "Unsupported data type: %s (was: %s)\n", type_reduced, ty); + SWIG_exit(EXIT_FAILURE); + } + return 0; +} + +static String *get_lisp_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setattr(node, "name", name); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("lisptype", node, "", 0); + Delete(node); + + return tm ? NewString(tm) : NewString(""); +} + +void UFFI::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGUFFI 1", 0); + SWIG_library_directory("uffi"); + SWIG_config_file("uffi.swg"); + + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-identifier-converter")) { + char *conv = argv[i + 1]; + + if (!conv) + Swig_arg_error(); + + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + + /* check for built-ins */ + if (!strcmp(conv, "lispify")) { + identifier_converter = "identifier-convert-lispify"; + } else if (!strcmp(conv, "null")) { + identifier_converter = "identifier-convert-null"; + } else { + /* Must be user defined */ + char *idconv = new char[strlen(conv) + 1]; + strcpy(idconv, conv); + identifier_converter = idconv; + } + } + + if (!strcmp(argv[i], "-help")) { + fprintf(stdout, "UFFI Options (available with -uffi)\n"); + fprintf(stdout, + " -identifier-converter <type or funcname>\n" + "\tSpecifies the type of conversion to do on C identifiers to convert\n" + "\tthem to symbols. There are two built-in converters: 'null' and\n" + "\t 'lispify'. The default is 'null'. If you supply a name other\n" + "\tthan one of the built-ins, then a function by that name will be\n" + "\tcalled to convert identifiers to symbols.\n"); + } + } +} + +int UFFI::top(Node *n) { + String *module = Getattr(n, "name"); + String *output_filename = NewString(""); + File *f_null = NewString(""); + + Printf(output_filename, "%s%s.cl", SWIG_output_directory(), module); + + + f_cl = NewFile(output_filename, "w", SWIG_output_files()); + if (!f_cl) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + + Swig_register_filebyname("header", f_null); + Swig_register_filebyname("begin", f_null); + Swig_register_filebyname("runtime", f_null); + Swig_register_filebyname("wrapper", f_cl); + + Swig_banner_target_lang(f_cl, ";;"); + + Printf(f_cl, "\n" + ";; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; package: %s -*-\n\n(defpackage :%s\n (:use :common-lisp :uffi))\n\n(in-package :%s)\n", + module, module, module); + Printf(f_cl, "(eval-when (compile load eval)\n (defparameter *swig-identifier-converter* '%s))\n", identifier_converter); + + Language::top(n); + + Close(f_cl); + Delete(f_cl); // Delete the handle, not the file + Close(f_null); + Delete(f_null); + + return SWIG_OK; +} + +int UFFI::functionWrapper(Node *n) { + String *funcname = Getattr(n, "sym:name"); + ParmList *pl = Getattr(n, "parms"); + Parm *p; + int argnum = 0, first = 1, varargs = 0; + + //Language::functionWrapper(n); + + Printf(f_cl, "(swig-defun \"%s\"\n", funcname); + Printf(f_cl, " ("); + + /* Special cases */ + + if (ParmList_len(pl) == 0) { + Printf(f_cl, ":void"); + } else if (any_varargs(pl)) { + Printf(f_cl, "#| varargs |#"); + varargs = 1; + } else { + for (p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + SwigType *argtype = Getattr(p, "type"); + String *ffitype = get_ffi_type(n, argtype, argname); + String *lisptype = get_lisp_type(n, argtype, argname); + int tempargname = 0; + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } + + if (!first) { + Printf(f_cl, "\n "); + } + Printf(f_cl, "(%s %s %s)", argname, ffitype, lisptype); + first = 0; + + Delete(ffitype); + Delete(lisptype); + if (tempargname) + Delete(argname); + + } + } + Printf(f_cl, ")\n"); /* finish arg list */ + Printf(f_cl, " :returning %s\n" + //" :strings-convert t\n" + //" :call-direct %s\n" + //" :optimize-for-space t" + ")\n", get_ffi_type(n, Getattr(n, "type"), "result") + //,varargs ? "nil" : "t" + ); + + + return SWIG_OK; +} + +int UFFI::constantWrapper(Node *n) { + String *type = Getattr(n, "type"); + String *converted_value = convert_literal(Getattr(n, "value"), type); + String *name = Getattr(n, "sym:name"); + +#if 0 + Printf(stdout, "constant %s is of type %s. value: %s\n", name, type, converted_value); +#endif + + Printf(f_cl, "(swig-defconstant \"%s\" %s)\n", name, converted_value); + + Delete(converted_value); + + return SWIG_OK; +} + +// Includes structs +int UFFI::classHandler(Node *n) { + + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + Node *c; + + if (Strcmp(kind, "struct")) { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_cl, "(swig-def-struct \"%s\"\n \n", name); + + for (c = firstChild(n); c; c = nextSibling(c)) { + SwigType *type = Getattr(c, "type"); + SwigType *decl = Getattr(c, "decl"); + type = Copy(type); + SwigType_push(type, decl); + String *lisp_type; + + if (Strcmp(nodeType(c), "cdecl")) { + Printf(stderr, "Structure %s has a slot that we can't deal with.\n", name); + Printf(stderr, "nodeType: %s, name: %s, type: %s\n", nodeType(c), Getattr(c, "name"), Getattr(c, "type")); + SWIG_exit(EXIT_FAILURE); + } + + + /* Printf(stdout, "Converting %s in %s\n", type, name); */ + lisp_type = get_ffi_type(n, type, Getattr(c, "sym:name")); + + Printf(f_cl, " (#.(%s \"%s\" :type :slot) %s)\n", identifier_converter, Getattr(c, "sym:name"), lisp_type); + + Delete(lisp_type); + } + + // Language::classHandler(n); + + Printf(f_cl, " )\n"); + + /* Add this structure to the known lisp types */ + //Printf(stdout, "Adding %s foreign type\n", name); + add_defined_foreign_type(name); + + return SWIG_OK; +} + +int UFFI::membervariableHandler(Node *n) { + Language::membervariableHandler(n); + return SWIG_OK; +} + + +extern "C" Language *swig_uffi(void) { + return new UFFI(); +} diff --git a/Source/Modules/utils.cxx b/Source/Modules/utils.cxx new file mode 100644 index 0000000..496700a --- /dev/null +++ b/Source/Modules/utils.cxx @@ -0,0 +1,98 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * utils.cxx + * + * Various utility functions. + * ----------------------------------------------------------------------------- */ + +char cvsroot_utils_cxx[] = "$Id: utils.cxx 10423 2008-05-07 20:59:00Z wsfulton $"; + +#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")) { + if (is_member_director_helper(Getattr(n, "parentNode"), n)) + 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"); + } +} diff --git a/Source/Modules/xml.cxx b/Source/Modules/xml.cxx new file mode 100644 index 0000000..a3d393a --- /dev/null +++ b/Source/Modules/xml.cxx @@ -0,0 +1,320 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * xml.cxx + * + * An Xml parse tree generator. + * ----------------------------------------------------------------------------- */ + +char cvsroot_xml_cxx[] = "$Id: xml.cxx 10898 2008-11-03 12:51:45Z wsfulton $"; + +#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"); + Replaceall(outfile, ".cxx", ".xml"); + Replaceall(outfile, ".cpp", ".xml"); + Replaceall(outfile, ".c", ".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=\"%x\" >\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 { + 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=\"%x\" />\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=\"%x\" id=\"%ld\" addr=\"%x\" />\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=\"%x\" >\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) { + + print_indent(0); + Printf(out, "<parmlist id=\"%ld\" addr=\"%x\" >\n", ++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, "</parmlist >\n"); + } + + void Xml_print_baselist(List *p) { + + print_indent(0); + Printf(out, "<baselist id=\"%ld\" addr=\"%x\" >\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=\"%x\" />\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=\"%x\" />\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=\"%x\" >\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=\"%x\" >\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(); +} |
