diff options
Diffstat (limited to 'Source/Swig/typesys.c')
| -rw-r--r-- | Source/Swig/typesys.c | 2074 |
1 files changed, 2074 insertions, 0 deletions
diff --git a/Source/Swig/typesys.c b/Source/Swig/typesys.c new file mode 100644 index 0000000..5778c45 --- /dev/null +++ b/Source/Swig/typesys.c @@ -0,0 +1,2074 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * typesys.c + * + * SWIG type system management. These functions are used to manage + * the C++ type system including typenames, typedef, type scopes, + * inheritance, and namespaces. Generation of support code for the + * run-time type checker is also handled here. + * ----------------------------------------------------------------------------- */ + +char cvsroot_typesys_c[] = "$Id: typesys.c 11097 2009-01-30 10:27:37Z bhy $"; + +#include "swig.h" +#include "cparse.h" + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * The purpose of this module is to manage type names and scoping issues related + * to the C++ type system. The primary use is tracking typenames through typedef + * and inheritance. + * + * New typenames are introduced by typedef, class, and enum declarations. + * Each type is declared in a scope. This is either the global scope, a + * class, or a namespace. For example: + * + * typedef int A; // Typename A, in global scope + * namespace Foo { + * typedef int A; // Typename A, in scope Foo:: + * } + * class Bar { // Typename Bar, in global scope + * typedef int A; // Typename A, in scope Bar:: + * } + * + * To manage scopes, the type system is constructed as a tree of hash tables. Each + * hash table contains the following attributes: + * + * "name" - Scope name + * "qname" - Fully qualified typename + * "typetab" - Type table containing typenames and typedef information + * "symtab" - Hash table of symbols defined in a scope + * "inherit" - List of inherited scopes + * "parent" - Parent scope + * + * Typedef information is stored in the "typetab" hash table. For example, + * if you have these declarations: + * + * typedef int A; + * typedef A B; + * typedef B *C; + * + * typetab is built as follows: + * + * "A" : "int" + * "B" : "A" + * "C" : "p.B" + * + * To resolve a type back to its root type, one repeatedly expands on the type base. + * For example: + * + * C *[40] ---> a(40).p.C (string type representation, see stype.c) + * ---> a(40).p.p.B (C --> p.B) + * ---> a(40).p.p.A (B --> A) + * ---> a(40).p.p.int (A --> int) + * + * For inheritance, SWIG tries to resolve types back to the base class. For instance, if + * you have this: + * + * class Foo { + * public: + * typedef int Integer; + * }; + * + * class Bar : public Foo { + * void blah(Integer x); + * } + * + * The argument type of Bar::blah will be set to Foo::Integer. + * + * The scope-inheritance mechanism is used to manage C++ namespace aliases. + * For example, if you have this: + * + * namespace Foo { + * typedef int Integer; + * } + * + * namespace F = Foo; + * + * In this case, "F::" is defined as a scope that "inherits" from Foo. Internally, + * "F::" will merely be an empty scope that refers to Foo. SWIG will never + * place new type information into a namespace alias---attempts to do so + * will generate a warning message (in the parser) and will place information into + * Foo instead. + * + *----------------------------------------------------------------------------- */ + +static Typetab *current_scope = 0; /* Current type scope */ +static Hash *current_typetab = 0; /* Current type table */ +static Hash *current_symtab = 0; /* Current symbol table */ +static Typetab *global_scope = 0; /* The global scope */ +static Hash *scopes = 0; /* Hash table containing fully qualified scopes */ + +/* Performance optimization */ +#define SWIG_TYPEDEF_RESOLVE_CACHE +static Hash *typedef_resolve_cache = 0; +static Hash *typedef_all_cache = 0; +static Hash *typedef_qualified_cache = 0; + +static Typetab *SwigType_find_scope(Typetab *s, String *nameprefix); + +/* common attribute keys, to avoid calling find_key all the times */ + +/* + Enable this one if your language fully support SwigValueWrapper<T>. + + Leaving at '0' keeps the old swig behavior, which is not + always safe, but is well known. + + Setting at '1' activates the new scheme, which is always safe but + it requires all the typemaps to be ready for that. + +*/ +static int value_wrapper_mode = 0; +int Swig_value_wrapper_mode(int mode) { + value_wrapper_mode = mode; + return mode; +} + + +static void flush_cache() { + typedef_resolve_cache = 0; + typedef_all_cache = 0; + typedef_qualified_cache = 0; +} + +/* Initialize the scoping system */ + +void SwigType_typesystem_init() { + if (global_scope) + Delete(global_scope); + if (scopes) + Delete(scopes); + + current_scope = NewHash(); + global_scope = current_scope; + + Setattr(current_scope, "name", ""); /* No name for global scope */ + current_typetab = NewHash(); + Setattr(current_scope, "typetab", current_typetab); + + current_symtab = 0; + scopes = NewHash(); + Setattr(scopes, "", current_scope); +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef() + * + * Defines a new typedef in the current scope. Returns -1 if the type name is + * already defined. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef(SwigType *type, const_String_or_char_ptr name) { + if (Getattr(current_typetab, name)) + return -1; /* Already defined */ + if (Strcmp(type, name) == 0) { /* Can't typedef a name to itself */ + return 0; + } + + /* Check if 'type' is already a scope. If so, we create an alias in the type + system for it. This is needed to make strange nested scoping problems work + correctly. */ + { + Typetab *t = SwigType_find_scope(current_scope, type); + if (t) { + SwigType_new_scope(name); + SwigType_inherit_scope(t); + SwigType_pop_scope(); + } + } + Setattr(current_typetab, name, type); + flush_cache(); + return 0; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_class() + * + * Defines a class in the current scope. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef_class(const_String_or_char_ptr name) { + String *cname; + /* Printf(stdout,"class : '%s'\n", name); */ + if (Getattr(current_typetab, name)) + return -1; /* Already defined */ + cname = NewString(name); + Setmeta(cname, "class", "1"); + Setattr(current_typetab, cname, cname); + Delete(cname); + flush_cache(); + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_scope_name() + * + * Returns the qualified scope name of a type table + * ----------------------------------------------------------------------------- */ + +String *SwigType_scope_name(Typetab *ttab) { + String *qname = NewString(Getattr(ttab, "name")); + ttab = Getattr(ttab, "parent"); + while (ttab) { + String *pname = Getattr(ttab, "name"); + if (Len(pname)) { + Insert(qname, 0, "::"); + Insert(qname, 0, pname); + } + ttab = Getattr(ttab, "parent"); + } + return qname; +} + +/* ----------------------------------------------------------------------------- + * SwigType_new_scope() + * + * Creates a new scope + * ----------------------------------------------------------------------------- */ + +void SwigType_new_scope(const_String_or_char_ptr name) { + Typetab *s; + Hash *ttab; + String *qname; + + if (!name) { + name = "<unnamed>"; + } + s = NewHash(); + Setattr(s, "name", name); + Setattr(s, "parent", current_scope); + ttab = NewHash(); + Setattr(s, "typetab", ttab); + + /* Build fully qualified name and */ + qname = SwigType_scope_name(s); + Setattr(scopes, qname, s); + Setattr(s, "qname", qname); + Delete(qname); + + current_scope = s; + current_typetab = ttab; + current_symtab = 0; + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_inherit_scope() + * + * Makes the current scope inherit from another scope. This is used for both + * C++ class inheritance, namespaces, and namespace aliases. + * ----------------------------------------------------------------------------- */ + +void SwigType_inherit_scope(Typetab *scope) { + List *inherits; + int i, len; + inherits = Getattr(current_scope, "inherit"); + if (!inherits) { + inherits = NewList(); + Setattr(current_scope, "inherit", inherits); + Delete(inherits); + } + assert(scope != current_scope); + + len = Len(inherits); + for (i = 0; i < len; i++) { + Node *n = Getitem(inherits, i); + if (n == scope) + return; + } + Append(inherits, scope); +} + +/* ----------------------------------------------------------------------------- + * SwigType_scope_alias() + * + * Creates a scope-alias. + * ----------------------------------------------------------------------------- */ + +void SwigType_scope_alias(String *aliasname, Typetab *ttab) { + String *q; + /* Printf(stdout,"alias: '%s' '%x'\n", aliasname, ttab); */ + q = SwigType_scope_name(current_scope); + if (Len(q)) { + Append(q, "::"); + } + Append(q, aliasname); + Setattr(scopes, q, ttab); + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_using_scope() + * + * Import another scope into this scope. + * ----------------------------------------------------------------------------- */ + +void SwigType_using_scope(Typetab *scope) { + SwigType_inherit_scope(scope); + { + List *ulist; + int i, len; + ulist = Getattr(current_scope, "using"); + if (!ulist) { + ulist = NewList(); + Setattr(current_scope, "using", ulist); + Delete(ulist); + } + assert(scope != current_scope); + len = Len(ulist); + for (i = 0; i < len; i++) { + Typetab *n = Getitem(ulist, i); + if (n == scope) + return; + } + Append(ulist, scope); + } + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop_scope() + * + * Pop off the last scope and perform a merge operation. Returns the hash + * table for the scope that was popped off. + * ----------------------------------------------------------------------------- */ + +Typetab *SwigType_pop_scope() { + Typetab *t, *old = current_scope; + t = Getattr(current_scope, "parent"); + if (!t) + t = global_scope; + current_scope = t; + current_typetab = Getattr(t, "typetab"); + current_symtab = Getattr(t, "symtab"); + flush_cache(); + return old; +} + +/* ----------------------------------------------------------------------------- + * SwigType_set_scope() + * + * Set the scope. Returns the old scope. + * ----------------------------------------------------------------------------- */ + +Typetab *SwigType_set_scope(Typetab *t) { + Typetab *old = current_scope; + if (!t) + t = global_scope; + current_scope = t; + current_typetab = Getattr(t, "typetab"); + current_symtab = Getattr(t, "symtab"); + flush_cache(); + return old; +} + +/* ----------------------------------------------------------------------------- + * SwigType_attach_symtab() + * + * Attaches a symbol table to a type scope + * ----------------------------------------------------------------------------- */ + +void SwigType_attach_symtab(Symtab *sym) { + Setattr(current_scope, "symtab", sym); + current_symtab = sym; +} + +/* ----------------------------------------------------------------------------- + * SwigType_print_scope() + * + * Debugging function for printing out current scope + * ----------------------------------------------------------------------------- */ + +void SwigType_print_scope(Typetab *t) { + Hash *ttab; + Iterator i, j; + + for (i = First(scopes); i.key; i = Next(i)) { + t = i.item; + ttab = Getattr(i.item, "typetab"); + + Printf(stdout, "Type scope '%s' (%x)\n", i.key, i.item); + { + List *inherit = Getattr(i.item, "inherit"); + if (inherit) { + Iterator j; + for (j = First(inherit); j.item; j = Next(j)) { + Printf(stdout, " Inherits from '%s' (%x)\n", Getattr(j.item, "qname"), j.item); + } + } + } + Printf(stdout, "-------------------------------------------------------------\n"); + for (j = First(ttab); j.key; j = Next(j)) { + Printf(stdout, "%40s -> %s\n", j.key, j.item); + } + } +} + +static Typetab *SwigType_find_scope(Typetab *s, String *nameprefix) { + Typetab *ss; + String *nnameprefix = 0; + static int check_parent = 1; + + /* Printf(stdout,"find_scope: %x(%s) '%s'\n", s, Getattr(s,"name"), nameprefix); */ + + if (SwigType_istemplate(nameprefix)) { + nnameprefix = SwigType_typedef_resolve_all(nameprefix); + nameprefix = nnameprefix; + } + + ss = s; + while (ss) { + String *full; + String *qname = Getattr(ss, "qname"); + if (qname) { + full = NewStringf("%s::%s", qname, nameprefix); + } else { + full = NewString(nameprefix); + } + if (Getattr(scopes, full)) { + s = Getattr(scopes, full); + } else { + s = 0; + } + Delete(full); + if (s) { + if (nnameprefix) + Delete(nnameprefix); + return s; + } + if (!s) { + /* Check inheritance */ + List *inherit; + inherit = Getattr(ss, "using"); + if (inherit) { + Typetab *ttab; + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + int oldcp = check_parent; + ttab = Getitem(inherit, i); + check_parent = 0; + s = SwigType_find_scope(ttab, nameprefix); + check_parent = oldcp; + if (s) { + if (nnameprefix) + Delete(nnameprefix); + return s; + } + } + } + } + if (!check_parent) + break; + ss = Getattr(ss, "parent"); + } + if (nnameprefix) + Delete(nnameprefix); + return 0; +} + +/* ----------------------------------------------------------------------------- + * typedef_resolve() + * + * Resolves a typedef and returns a new type string. Returns 0 if there is no + * typedef mapping. base is a name without qualification. + * Internal function. + * ----------------------------------------------------------------------------- */ + +static Typetab *resolved_scope = 0; + +/* Internal function */ + +static SwigType *_typedef_resolve(Typetab *s, String *base, int look_parent) { + Hash *ttab; + SwigType *type = 0; + List *inherit; + Typetab *parent; + + /* if (!s) return 0; *//* now is checked bellow */ + /* Printf(stdout,"Typetab %s : %s\n", Getattr(s,"name"), base); */ + + if (!Getmark(s)) { + Setmark(s, 1); + + ttab = Getattr(s, "typetab"); + type = Getattr(ttab, base); + if (type) { + resolved_scope = s; + Setmark(s, 0); + } else { + /* Hmmm. Not found in my scope. It could be in an inherited scope */ + inherit = Getattr(s, "inherit"); + if (inherit) { + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + type = _typedef_resolve(Getitem(inherit, i), base, 0); + if (type) { + Setmark(s, 0); + break; + } + } + } + if (!type) { + /* Hmmm. Not found in my scope. check parent */ + if (look_parent) { + parent = Getattr(s, "parent"); + type = parent ? _typedef_resolve(parent, base, 1) : 0; + } + } + Setmark(s, 0); + } + } + return type; +} + +static SwigType *typedef_resolve(Typetab *s, String *base) { + return _typedef_resolve(s, base, 1); +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_resolve() + * ----------------------------------------------------------------------------- */ + +/* #define SWIG_DEBUG */ +SwigType *SwigType_typedef_resolve(const SwigType *t) { + String *base; + String *type = 0; + String *r = 0; + Typetab *s; + Hash *ttab; + String *namebase = 0; + String *nameprefix = 0; + int newtype = 0; + + /* + if (!noscope) { + noscope = NewStringEmpty(); + } + */ + + resolved_scope = 0; + +#ifdef SWIG_TYPEDEF_RESOLVE_CACHE + if (!typedef_resolve_cache) { + typedef_resolve_cache = NewHash(); + } + r = Getattr(typedef_resolve_cache, t); + if (r) { + resolved_scope = Getmeta(r, "scope"); + return Copy(r); + } +#endif + + base = SwigType_base(t); + +#ifdef SWIG_DEBUG + Printf(stdout, "base = '%s' t='%s'\n", base, t); +#endif + + if (SwigType_issimple(base)) { + s = current_scope; + ttab = current_typetab; + if (strncmp(Char(base), "::", 2) == 0) { + s = global_scope; + ttab = Getattr(s, "typetab"); + Delitem(base, 0); + Delitem(base, 0); + } + /* Do a quick check in the local scope */ + type = Getattr(ttab, base); + if (type) { + resolved_scope = s; + } + if (!type) { + /* Didn't find in this scope. We need to do a little more searching */ + if (Swig_scopename_check(base)) { + /* A qualified name. */ + Swig_scopename_split(base, &nameprefix, &namebase); +#ifdef SWIG_DEBUG + Printf(stdout, "nameprefix = '%s'\n", nameprefix); +#endif + if (nameprefix) { + /* Name had a prefix on it. See if we can locate the proper scope for it */ + s = SwigType_find_scope(s, nameprefix); + + /* Couldn't locate a scope for the type. */ + if (!s) { + Delete(base); + Delete(namebase); + Delete(nameprefix); + r = 0; + goto return_result; + } + /* Try to locate the name starting in the scope */ +#ifdef SWIG_DEBUG + Printf(stdout, "namebase = '%s'\n", namebase); +#endif + type = typedef_resolve(s, namebase); + if (type) { + /* we need to look for the resolved type, this will also + fix the resolved_scope if 'type' and 'namebase' are + declared in different scopes */ + String *rtype = 0; + rtype = typedef_resolve(resolved_scope, type); + if (rtype) + type = rtype; + } +#ifdef SWIG_DEBUG + Printf(stdout, "%s type = '%s'\n", Getattr(s, "name"), type); +#endif + if ((type) && (!Swig_scopename_check(type)) && resolved_scope) { + Typetab *rtab = resolved_scope; + String *qname = Getattr(resolved_scope, "qname"); + /* If qualified *and* the typename is defined from the resolved scope, we qualify */ + if ((qname) && typedef_resolve(resolved_scope, type)) { + type = Copy(type); + Insert(type, 0, "::"); + Insert(type, 0, qname); +#ifdef SWIG_DEBUG + Printf(stdout, "qual %s \n", type); +#endif + newtype = 1; + } + resolved_scope = rtab; + } + } else { + /* Name is unqualified. */ + type = typedef_resolve(s, base); + } + } else { + /* Name is unqualified. */ + type = typedef_resolve(s, base); + } + } + + if (type && (Equal(base, type))) { + if (newtype) + Delete(type); + Delete(base); + Delete(namebase); + Delete(nameprefix); + r = 0; + goto return_result; + } + + /* If the type is a template, and no typedef was found, we need to check the + template arguments one by one to see if they can be resolved. */ + + if (!type && SwigType_istemplate(base)) { + List *tparms; + String *suffix; + int i, sz; + int rep = 0; + type = SwigType_templateprefix(base); + newtype = 1; + suffix = SwigType_templatesuffix(base); + Append(type, "<("); + tparms = SwigType_parmlist(base); + sz = Len(tparms); + for (i = 0; i < sz; i++) { + SwigType *tpr; + SwigType *tp = Getitem(tparms, i); + if (!rep) { + tpr = SwigType_typedef_resolve(tp); + } else { + tpr = 0; + } + if (tpr) { + Append(type, tpr); + Delete(tpr); + rep = 1; + } else { + Append(type, tp); + } + if ((i + 1) < sz) + Append(type, ","); + } + Append(type, ")>"); + Append(type, suffix); + Delete(suffix); + Delete(tparms); + if (!rep) { + Delete(type); + type = 0; + } + } + if (namebase) + Delete(namebase); + if (nameprefix) + Delete(nameprefix); + } else { + if (SwigType_isfunction(base)) { + List *parms; + int i, sz; + int rep = 0; + type = NewString("f("); + newtype = 1; + parms = SwigType_parmlist(base); + sz = Len(parms); + for (i = 0; i < sz; i++) { + SwigType *tpr; + SwigType *tp = Getitem(parms, i); + if (!rep) { + tpr = SwigType_typedef_resolve(tp); + } else { + tpr = 0; + } + if (tpr) { + Append(type, tpr); + Delete(tpr); + rep = 1; + } else { + Append(type, tp); + } + if ((i + 1) < sz) + Append(type, ","); + } + Append(type, ")."); + Delete(parms); + if (!rep) { + Delete(type); + type = 0; + } + } else if (SwigType_ismemberpointer(base)) { + String *rt; + String *mtype = SwigType_parm(base); + rt = SwigType_typedef_resolve(mtype); + if (rt) { + type = NewStringf("m(%s).", rt); + newtype = 1; + Delete(rt); + } + Delete(mtype); + } else { + type = 0; + } + } + r = SwigType_prefix(t); + if (!type) { + if (r && Len(r)) { + char *cr = Char(r); + if ((strstr(cr, "f(") || (strstr(cr, "m(")))) { + SwigType *rt = SwigType_typedef_resolve(r); + if (rt) { + Delete(r); + Append(rt, base); + Delete(base); + r = rt; + goto return_result; + } + } + } + Delete(r); + Delete(base); + r = 0; + goto return_result; + } + Delete(base); + Append(r, type); + if (newtype) { + Delete(type); + } + +return_result: +#ifdef SWIG_TYPEDEF_RESOLVE_CACHE + { + String *key = NewString(t); + if (r) { + SwigType *r1; + Setattr(typedef_resolve_cache, key, r); + Setmeta(r, "scope", resolved_scope); + r1 = Copy(r); + Delete(r); + r = r1; + } + Delete(key); + } +#endif + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_resolve_all() + * + * Fully resolve a type down to its most basic datatype + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_typedef_resolve_all(SwigType *t) { + SwigType *n; + SwigType *r; + + /* Check to see if the typedef resolve has been done before by checking the cache */ + if (!typedef_all_cache) { + typedef_all_cache = NewHash(); + } + r = Getattr(typedef_all_cache, t); + if (r) { + return Copy(r); + } + + /* Recursively resolve the typedef */ + r = NewString(t); + while ((n = SwigType_typedef_resolve(r))) { + Delete(r); + r = n; + } + + /* Add the typedef to the cache for next time it is looked up */ + { + String *key; + SwigType *rr = Copy(r); + key = NewString(t); + Setattr(typedef_all_cache, key, rr); + Delete(key); + Delete(rr); + } + return r; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_qualified() + * + * Given a type declaration, this function tries to fully qualify it according to + * typedef scope rules. + * Inconsistency to be fixed: ::Foo returns ::Foo, whereas ::Foo * returns Foo * + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_typedef_qualified(SwigType *t) { + List *elements; + String *result; + int i, len; + + if (strncmp(Char(t), "::", 2) == 0) { + return Copy(t); + } + + if (!typedef_qualified_cache) + typedef_qualified_cache = NewHash(); + result = Getattr(typedef_qualified_cache, t); + if (result) { + String *rc = Copy(result); + return rc; + } + + result = NewStringEmpty(); + elements = SwigType_split(t); + len = Len(elements); + for (i = 0; i < len; i++) { + String *ty = 0; + String *e = Getitem(elements, i); + if (SwigType_issimple(e)) { + if (!SwigType_istemplate(e)) { + String *isenum = 0; + if (SwigType_isenum(e)) { + isenum = NewString("enum "); + ty = NewString(Char(e) + 5); + e = ty; + } + resolved_scope = 0; + if (typedef_resolve(current_scope, e)) { + /* resolved_scope contains the scope that actually resolved the symbol */ + String *qname = Getattr(resolved_scope, "qname"); + if (qname) { + Insert(e, 0, "::"); + Insert(e, 0, qname); + } + } else { + if (Swig_scopename_check(e)) { + String *qlast; + String *qname; + Swig_scopename_split(e, &qname, &qlast); + if (qname) { + String *tqname = SwigType_typedef_qualified(qname); + Clear(e); + Printf(e, "%s::%s", tqname, qlast); + Delete(qname); + Delete(tqname); + } + Delete(qlast); + + /* Automatic template instantiation might go here??? */ + } else { + /* It's a bare name. It's entirely possible, that the + name is part of a namespace. We'll check this by unrolling + out of the current scope */ + + Typetab *cs = current_scope; + while (cs) { + String *qs = SwigType_scope_name(cs); + if (Len(qs)) { + Append(qs, "::"); + } + Append(qs, e); + if (Getattr(scopes, qs)) { + Clear(e); + Append(e, qs); + Delete(qs); + break; + } + Delete(qs); + cs = Getattr(cs, "parent"); + } + } + } + if (isenum) { + Insert(e, 0, isenum); + Delete(isenum); + } + } else { + /* Template. We need to qualify template parameters as well as the template itself */ + String *tprefix, *qprefix; + String *tsuffix; + Iterator pi; + Parm *p; + List *parms; + ty = Swig_symbol_template_deftype(e, current_symtab); + e = ty; + parms = SwigType_parmlist(e); + tprefix = SwigType_templateprefix(e); + tsuffix = SwigType_templatesuffix(e); + qprefix = SwigType_typedef_qualified(tprefix); + Append(qprefix, "<("); + pi = First(parms); + while ((p = pi.item)) { + String *qt = SwigType_typedef_qualified(p); + if (Equal(qt, p)) { /* && (!Swig_scopename_check(qt))) */ + /* No change in value. It is entirely possible that the parameter is an integer value. + If there is a symbol table associated with this scope, we're going to check for this */ + + if (current_symtab) { + Node *lastnode = 0; + String *value = Copy(p); + while (1) { + Node *n = Swig_symbol_clookup(value, current_symtab); + if (n == lastnode) + break; + lastnode = n; + if (n) { + char *ntype = Char(nodeType(n)); + if (strcmp(ntype, "enumitem") == 0) { + /* An enum item. Generate a fully qualified name */ + String *qn = Swig_symbol_qualified(n); + if (Len(qn)) { + Append(qn, "::"); + Append(qn, Getattr(n, "name")); + Delete(value); + value = qn; + continue; + } else { + Delete(qn); + break; + } + } else if ((strcmp(ntype, "cdecl") == 0) && (Getattr(n, "value"))) { + Delete(value); + value = Copy(Getattr(n, "value")); + continue; + } + } + break; + } + Append(qprefix, value); + Delete(value); + } else { + Append(qprefix, p); + } + } else { + Append(qprefix, qt); + } + Delete(qt); + pi = Next(pi); + if (pi.item) { + Append(qprefix, ","); + } + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(tsuffix); + Clear(e); + Append(e, qprefix); + Delete(tprefix); + Delete(qprefix); + Delete(parms); + } + if (strncmp(Char(e), "::", 2) == 0) { + Delitem(e, 0); + Delitem(e, 0); + } + Append(result, e); + Delete(ty); + } else if (SwigType_isfunction(e)) { + List *parms = SwigType_parmlist(e); + String *s = NewString("f("); + Iterator pi; + pi = First(parms); + while (pi.item) { + String *pq = SwigType_typedef_qualified(pi.item); + Append(s, pq); + Delete(pq); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + } + Append(s, ")."); + Append(result, s); + Delete(s); + Delete(parms); + } else if (SwigType_isarray(e)) { + String *ndim; + String *dim = SwigType_parm(e); + ndim = Swig_symbol_string_qualify(dim, 0); + Printf(result, "a(%s).", ndim); + Delete(dim); + Delete(ndim); + } else { + Append(result, e); + } + } + Delete(elements); + { + String *key, *cresult; + key = NewString(t); + cresult = NewString(result); + Setattr(typedef_qualified_cache, key, cresult); + Delete(key); + Delete(cresult); + } + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_istypedef() + * + * Checks a typename to see if it is a typedef. + * ----------------------------------------------------------------------------- */ + +int SwigType_istypedef(SwigType *t) { + String *type; + + type = SwigType_typedef_resolve(t); + if (type) { + Delete(type); + return 1; + } else { + return 0; + } +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_using() + * + * Processes a 'using' declaration to import types from one scope into another. + * Name is a qualified name like A::B. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef_using(const_String_or_char_ptr name) { + String *base; + String *td; + String *prefix; + Typetab *s; + Typetab *tt = 0; + + String *defined_name = 0; + + /* Printf(stdout,"using %s\n", name); */ + + if (!Swig_scopename_check(name)) + return -1; /* Not properly qualified */ + base = Swig_scopename_last(name); + + /* See if the base is already defined in this scope */ + if (Getattr(current_typetab, base)) { + Delete(base); + return -1; + } + + /* See if the using name is a scope */ + /* tt = SwigType_find_scope(current_scope,name); + Printf(stdout,"tt = %x, name = '%s'\n", tt, name); */ + + /* We set up a typedef B --> A::B */ + Setattr(current_typetab, base, name); + + /* Find the scope name where the symbol is defined */ + td = SwigType_typedef_resolve(name); + /* Printf(stdout,"td = '%s' %x\n", td, resolved_scope); */ + if (resolved_scope) { + defined_name = Getattr(resolved_scope, "qname"); + if (defined_name) { + defined_name = Copy(defined_name); + Append(defined_name, "::"); + Append(defined_name, base); + /* Printf(stdout,"defined_name = '%s'\n", defined_name); */ + tt = SwigType_find_scope(current_scope, defined_name); + } + } + if (td) + Delete(td); + + + /* Figure out the scope the using directive refers to */ + { + prefix = Swig_scopename_prefix(name); + s = SwigType_find_scope(current_scope, prefix); + if (s) { + Hash *ttab = Getattr(s, "typetab"); + if (!Getattr(ttab, base) && defined_name) { + Setattr(ttab, base, defined_name); + } + } + } + + if (tt) { + /* Using directive had its own scope. We need to create a new scope for it */ + SwigType_new_scope(base); + SwigType_inherit_scope(tt); + SwigType_pop_scope(); + } + + if (defined_name) + Delete(defined_name); + Delete(prefix); + Delete(base); + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_isclass() + * + * Determines if a type defines a class or not. A class is defined by + * its type-table entry maps to itself. Note: a pointer to a class is not + * a class. + * ----------------------------------------------------------------------------- */ + +int SwigType_isclass(SwigType *t) { + SwigType *qty, *qtys; + int isclass = 0; + + qty = SwigType_typedef_resolve_all(t); + qtys = SwigType_strip_qualifiers(qty); + if (SwigType_issimple(qtys)) { + String *td = SwigType_typedef_resolve(qtys); + if (td) { + Delete(td); + } + if (resolved_scope) { + isclass = 1; + } + /* Hmmm. Not a class. If a template, it might be uninstantiated */ + if (!isclass && SwigType_istemplate(qtys)) { + String *tp = SwigType_templateprefix(qtys); + if (Strcmp(tp, t) != 0) { + isclass = SwigType_isclass(tp); + } + Delete(tp); + } + } + Delete(qty); + Delete(qtys); + return isclass; +} + +/* ----------------------------------------------------------------------------- + * SwigType_type() + * + * Returns an integer code describing the datatype. This is only used for + * compatibility with SWIG1.1 language modules and is likely to go away once + * everything is based on typemaps. + * ----------------------------------------------------------------------------- */ + +int SwigType_type(SwigType *t) { + char *c; + /* Check for the obvious stuff */ + c = Char(t); + + if (strncmp(c, "p.", 2) == 0) { + if (SwigType_type(c + 2) == T_CHAR) + return T_STRING; + else + return T_POINTER; + } + if (strncmp(c, "a(", 2) == 0) + return T_ARRAY; + if (strncmp(c, "r.", 2) == 0) + return T_REFERENCE; + if (strncmp(c, "m(", 2) == 0) + return T_MPOINTER; + if (strncmp(c, "q(", 2) == 0) { + while (*c && (*c != '.')) + c++; + if (*c) + return SwigType_type(c + 1); + return T_ERROR; + } + if (strncmp(c, "f(", 2) == 0) + return T_FUNCTION; + + /* Look for basic types */ + if (strcmp(c, "int") == 0) + return T_INT; + if (strcmp(c, "long") == 0) + return T_LONG; + if (strcmp(c, "short") == 0) + return T_SHORT; + if (strcmp(c, "unsigned") == 0) + return T_UINT; + if (strcmp(c, "unsigned short") == 0) + return T_USHORT; + if (strcmp(c, "unsigned long") == 0) + return T_ULONG; + if (strcmp(c, "unsigned int") == 0) + return T_UINT; + if (strcmp(c, "char") == 0) + return T_CHAR; + if (strcmp(c, "signed char") == 0) + return T_SCHAR; + if (strcmp(c, "unsigned char") == 0) + return T_UCHAR; + if (strcmp(c, "float") == 0) + return T_FLOAT; + if (strcmp(c, "double") == 0) + return T_DOUBLE; + if (strcmp(c, "long double") == 0) + return T_LONGDOUBLE; + if (!cparse_cplusplus && (strcmp(c, "float complex") == 0)) + return T_FLTCPLX; + if (!cparse_cplusplus && (strcmp(c, "double complex") == 0)) + return T_DBLCPLX; + if (!cparse_cplusplus && (strcmp(c, "complex") == 0)) + return T_COMPLEX; + if (strcmp(c, "void") == 0) + return T_VOID; + if (strcmp(c, "bool") == 0) + return T_BOOL; + if (strcmp(c, "long long") == 0) + return T_LONGLONG; + if (strcmp(c, "unsigned long long") == 0) + return T_ULONGLONG; + if (strncmp(c, "enum ", 5) == 0) + return T_INT; + + if (strcmp(c, "v(...)") == 0) + return T_VARARGS; + /* Hmmm. Unknown type */ + if (SwigType_istypedef(t)) { + int r; + SwigType *nt = SwigType_typedef_resolve(t); + r = SwigType_type(nt); + Delete(nt); + return r; + } + return T_USER; +} + +/* ----------------------------------------------------------------------------- + * SwigType_alttype() + * + * 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 >'. + * + * This is the default behavior unless: + * + * 1.- swig detects a default_constructor and 'setallocate:default_constructor' + * attribute. + * + * 2.- swig doesn't mark 'type' as non-assignable. + * + * 3.- the user specify that the value wrapper is not needed by using + * the %feature("novaluewrapper"), in that case the user need to type + * + * %feature("novaluewrapper") MyOpaqueClass; + * class MyOpaqueClass; + * + * Users can also force the use of the value wrapper by using the + * %feature("valuewrapper"). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_alttype(SwigType *t, int local_tmap) { + Node *n; + SwigType *w = 0; + int use_wrapper = 0; + SwigType *td = 0; + + if (!cparse_cplusplus) + return 0; + + if (value_wrapper_mode == 0) { + /* old partial use of SwigValueTypes, it can fail for opaque types */ + if (local_tmap) + return 0; + if (SwigType_isclass(t)) { + SwigType *ftd = SwigType_typedef_resolve_all(t); + td = SwigType_strip_qualifiers(ftd); + Delete(ftd); + n = Swig_symbol_clookup(td, 0); + if (n) { + if (GetFlag(n, "feature:valuewrapper")) { + use_wrapper = 1; + } else { + if (Checkattr(n, "nodeType", "class") + && (!Getattr(n, "allocate:default_constructor") + || (Getattr(n, "allocate:noassign")))) { + use_wrapper = !GetFlag(n, "feature:novaluewrapper") || GetFlag(n, "feature:nodefault"); + } + } + } else { + if (SwigType_issimple(td) && SwigType_istemplate(td)) { + use_wrapper = !n || !GetFlag(n, "feature:novaluewrapper"); + } + } + } + } else { + /* safe use of SwigValueTypes, it can fail with some typemaps */ + SwigType *ftd = SwigType_typedef_resolve_all(t); + td = SwigType_strip_qualifiers(ftd); + Delete(ftd); + if (SwigType_type(td) == T_USER) { + use_wrapper = 1; + n = Swig_symbol_clookup(td, 0); + if (n) { + if ((Checkattr(n, "nodeType", "class") + && !Getattr(n, "allocate:noassign") + && (Getattr(n, "allocate:default_constructor"))) + || (GetFlag(n, "feature:novaluewrapper"))) { + use_wrapper = GetFlag(n, "feature:valuewrapper"); + } + } + } + } + + if (use_wrapper) { + /* Need a space before the type in case it starts "::" (since the <: + * token is a digraph for [ in C++. Also need a space after the + * type in case it ends with ">" since then we form the token ">>". + */ + w = NewStringf("SwigValueWrapper< %s >", td); + } + Delete(td); + return w; +} + +/* ---------------------------------------------------------------------------- + * * * * WARNING * * * *** + * *** + * Don't even think about modifying anything below this line unless you *** + * are completely on top of *EVERY* subtle aspect of the C++ type system *** + * and you are prepared to suffer endless hours of agony trying to *** + * debug the SWIG run-time type checker after you break it. *** + * ------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * SwigType_remember() + * + * This function "remembers" a datatype that was used during wrapper code generation + * so that a type-checking table can be generated later on. It is up to the language + * modules to actually call this function--it is not done automatically. + * + * Type tracking is managed through two separate hash tables. The hash 'r_mangled' + * is mapping between mangled type names (used in the target language) and + * fully-resolved C datatypes used in the source input. The second hash 'r_resolved' + * is the inverse mapping that maps fully-resolved C datatypes to all of the mangled + * names in the scripting languages. For example, consider the following set of + * typedef declarations: + * + * typedef double Real; + * typedef double Float; + * typedef double Point[3]; + * + * Now, suppose that the types 'double *', 'Real *', 'Float *', 'double[3]', and + * 'Point' were used in an interface file and "remembered" using this function. + * The hash tables would look like this: + * + * r_mangled { + * _p_double : [ p.double, a(3).double ] + * _p_Real : [ p.double ] + * _p_Float : [ p.double ] + * _Point : [ a(3).double ] + * + * r_resolved { + * p.double : [ _p_double, _p_Real, _p_Float ] + * a(3).double : [ _p_double, _Point ] + * } + * + * Together these two hash tables can be used to determine type-equivalency between + * mangled typenames. To do this, we view the two hash tables as a large graph and + * compute the transitive closure. + * ----------------------------------------------------------------------------- */ + +static Hash *r_mangled = 0; /* Hash mapping mangled types to fully resolved types */ +static Hash *r_resolved = 0; /* Hash mapping resolved types to mangled types */ +static Hash *r_ltype = 0; /* Hash mapping mangled names to their local c type */ +static Hash *r_clientdata = 0; /* Hash mapping resolved types to client data */ +static Hash *r_mangleddata = 0; /* Hash mapping mangled types to client data */ +static Hash *r_remembered = 0; /* Hash of types we remembered already */ + +static void (*r_tracefunc) (SwigType *t, String *mangled, String *clientdata) = 0; + +void SwigType_remember_mangleddata(String *mangled, const_String_or_char_ptr clientdata) { + if (!r_mangleddata) { + r_mangleddata = NewHash(); + } + Setattr(r_mangleddata, mangled, clientdata); +} + + +void SwigType_remember_clientdata(SwigType *t, const_String_or_char_ptr clientdata) { + String *mt; + SwigType *lt; + Hash *h; + SwigType *fr; + SwigType *qr; + String *tkey; + String *cd; + Hash *lthash; + + if (!r_mangled) { + r_mangled = NewHash(); + r_resolved = NewHash(); + r_ltype = NewHash(); + r_clientdata = NewHash(); + r_remembered = NewHash(); + } + + { + String *last; + last = Getattr(r_remembered, t); + if (last && (Cmp(last, clientdata) == 0)) + return; + } + + tkey = Copy(t); + cd = clientdata ? NewString(clientdata) : NewStringEmpty(); + Setattr(r_remembered, tkey, cd); + Delete(tkey); + Delete(cd); + + mt = SwigType_manglestr(t); /* Create mangled string */ + + if (r_tracefunc) { + (*r_tracefunc) (t, mt, (String *) clientdata); + } + + if (SwigType_istypedef(t)) { + lt = Copy(t); + } else { + lt = SwigType_ltype(t); + } + + lthash = Getattr(r_ltype, mt); + if (!lthash) { + lthash = NewHash(); + Setattr(r_ltype, mt, lthash); + } + Setattr(lthash, lt, "1"); + Delete(lt); + + fr = SwigType_typedef_resolve_all(t); /* Create fully resolved type */ + qr = SwigType_typedef_qualified(fr); + Delete(fr); + + /* Added to deal with possible table bug */ + fr = SwigType_strip_qualifiers(qr); + Delete(qr); + + /*Printf(stdout,"t = '%s'\n", t); + Printf(stdout,"fr= '%s'\n\n", fr); */ + + if (t) { + char *ct = Char(t); + if (strchr(ct, '<') && !(strstr(ct, "<("))) { + Printf(stdout, "Bad template type passed to SwigType_remember: %s\n", t); + assert(0); + } + } + + h = Getattr(r_mangled, mt); + if (!h) { + h = NewHash(); + Setattr(r_mangled, mt, h); + Delete(h); + } + Setattr(h, fr, mt); + + h = Getattr(r_resolved, fr); + if (!h) { + h = NewHash(); + Setattr(r_resolved, fr, h); + Delete(h); + } + Setattr(h, mt, fr); + + if (clientdata) { + String *cd = Getattr(r_clientdata, fr); + if (cd) { + if (Strcmp(clientdata, cd) != 0) { + Printf(stderr, "*** Internal error. Inconsistent clientdata for type '%s'\n", SwigType_str(fr, 0)); + Printf(stderr, "*** '%s' != '%s'\n", clientdata, cd); + assert(0); + } + } else { + String *cstr = NewString(clientdata); + Setattr(r_clientdata, fr, cstr); + Delete(cstr); + } + } + + /* If the remembered type is a reference, we also remember the pointer version. + This is to prevent odd problems with mixing pointers and references--especially + when different functions are using different typenames (via typedef). */ + + if (SwigType_isreference(t)) { + SwigType *tt = Copy(t); + SwigType_del_reference(tt); + SwigType_add_pointer(tt); + SwigType_remember_clientdata(tt, clientdata); + } +} + +void SwigType_remember(SwigType *ty) { + SwigType_remember_clientdata(ty, 0); +} + +void (*SwigType_remember_trace(void (*tf) (SwigType *, String *, String *))) (SwigType *, String *, String *) { + void (*o) (SwigType *, String *, String *) = r_tracefunc; + r_tracefunc = tf; + return o; +} + +/* ----------------------------------------------------------------------------- + * SwigType_equivalent_mangle() + * + * Return a list of all of the mangled typenames that are equivalent to another + * mangled name. This works as follows: For each fully qualified C datatype + * in the r_mangled hash entry, we collect all of the mangled names from the + * r_resolved hash and combine them together in a list (removing duplicate entries). + * ----------------------------------------------------------------------------- */ + +List *SwigType_equivalent_mangle(String *ms, Hash *checked, Hash *found) { + List *l; + Hash *h; + Hash *ch; + Hash *mh; + + if (found) { + h = found; + } else { + h = NewHash(); + } + if (checked) { + ch = checked; + } else { + ch = NewHash(); + } + if (Getattr(ch, ms)) + goto check_exit; /* Already checked this type */ + Setattr(h, ms, "1"); + Setattr(ch, ms, "1"); + mh = Getattr(r_mangled, ms); + if (mh) { + Iterator ki; + ki = First(mh); + while (ki.key) { + Hash *rh; + if (Getattr(ch, ki.key)) { + ki = Next(ki); + continue; + } + Setattr(ch, ki.key, "1"); + rh = Getattr(r_resolved, ki.key); + if (rh) { + Iterator rk; + rk = First(rh); + while (rk.key) { + Setattr(h, rk.key, "1"); + SwigType_equivalent_mangle(rk.key, ch, h); + rk = Next(rk); + } + } + ki = Next(ki); + } + } +check_exit: + if (!found) { + l = Keys(h); + Delete(h); + Delete(ch); + return l; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * SwigType_clientdata_collect() + * + * Returns the clientdata field for a mangled type-string. + * ----------------------------------------------------------------------------- */ + +static +String *SwigType_clientdata_collect(String *ms) { + Hash *mh; + String *clientdata = 0; + + if (r_mangleddata) { + clientdata = Getattr(r_mangleddata, ms); + if (clientdata) + return clientdata; + } + + mh = Getattr(r_mangled, ms); + if (mh) { + Iterator ki; + ki = First(mh); + while (ki.key) { + clientdata = Getattr(r_clientdata, ki.key); + if (clientdata) + break; + ki = Next(ki); + } + } + return clientdata; +} + + + + +/* ----------------------------------------------------------------------------- + * SwigType_inherit() + * + * Record information about inheritance. We keep a hash table that keeps + * a mapping between base classes and all of the classes that are derived + * from them. + * + * subclass is a hash that maps base-classes to all of the classes derived from them. + * + * derived - name of derived class + * base - name of base class + * cast - additional casting code when casting from derived to base + * conversioncode - if set, overrides the default code in the function when casting + * from derived to base + * ----------------------------------------------------------------------------- */ + +static Hash *subclass = 0; +static Hash *conversions = 0; + +void SwigType_inherit(String *derived, String *base, String *cast, String *conversioncode) { + Hash *h; + String *dd = 0; + String *bb = 0; + if (!subclass) + subclass = NewHash(); + + /* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */ + + if (SwigType_istemplate(derived)) { + String *ty = SwigType_typedef_resolve_all(derived); + dd = SwigType_typedef_qualified(ty); + derived = dd; + Delete(ty); + } + if (SwigType_istemplate(base)) { + String *ty = SwigType_typedef_resolve_all(base); + bb = SwigType_typedef_qualified(ty); + base = bb; + Delete(ty); + } + + /* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */ + + h = Getattr(subclass, base); + if (!h) { + h = NewHash(); + Setattr(subclass, base, h); + Delete(h); + } + if (!Getattr(h, derived)) { + Hash *c = NewHash(); + if (cast) + Setattr(c, "cast", cast); + if (conversioncode) + Setattr(c, "convcode", conversioncode); + Setattr(h, derived, c); + Delete(c); + } + + Delete(dd); + Delete(bb); +} + +/* ----------------------------------------------------------------------------- + * SwigType_issubtype() + * + * Determines if a t1 is a subtype of t2, ie, is t1 derived from t2 + * ----------------------------------------------------------------------------- */ + +int SwigType_issubtype(SwigType *t1, SwigType *t2) { + SwigType *ft1, *ft2; + String *b1, *b2; + Hash *h; + int r = 0; + + if (!subclass) + return 0; + + ft1 = SwigType_typedef_resolve_all(t1); + ft2 = SwigType_typedef_resolve_all(t2); + b1 = SwigType_base(ft1); + b2 = SwigType_base(ft2); + + h = Getattr(subclass, b2); + if (h) { + if (Getattr(h, b1)) { + r = 1; + } + } + Delete(ft1); + Delete(ft2); + Delete(b1); + Delete(b2); + /* Printf(stdout, "issubtype(%s,%s) --> %d\n", t1, t2, r); */ + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_inherit_equiv() + * + * Modify the type table to handle C++ inheritance + * ----------------------------------------------------------------------------- */ + +void SwigType_inherit_equiv(File *out) { + String *ckey; + String *prefix, *base; + String *mprefix, *mkey; + Hash *sub; + Hash *rh; + List *rlist; + Iterator rk, bk, ck; + + if (!conversions) + conversions = NewHash(); + if (!subclass) + subclass = NewHash(); + + rk = First(r_resolved); + while (rk.key) { + /* rkey is a fully qualified type. We strip all of the type constructors off of it just to get the base */ + base = SwigType_base(rk.key); + /* Check to see whether the base is recorded in the subclass table */ + sub = Getattr(subclass, base); + Delete(base); + if (!sub) { + rk = Next(rk); + continue; + } + + /* This type has subclasses. We now need to walk through these subtypes and generate pointer converion functions */ + + rh = Getattr(r_resolved, rk.key); + rlist = NewList(); + for (ck = First(rh); ck.key; ck = Next(ck)) { + Append(rlist, ck.key); + } + /* Printf(stdout,"rk.key = '%s'\n", rk.key); + Printf(stdout,"rh = %x '%s'\n", rh,rh); */ + + bk = First(sub); + while (bk.key) { + prefix = SwigType_prefix(rk.key); + Append(prefix, bk.key); + /* Printf(stdout,"set %x = '%s' : '%s'\n", rh, SwigType_manglestr(prefix),prefix); */ + mprefix = SwigType_manglestr(prefix); + Setattr(rh, mprefix, prefix); + mkey = SwigType_manglestr(rk.key); + ckey = NewStringf("%s+%s", mprefix, mkey); + if (!Getattr(conversions, ckey)) { + String *convname = NewStringf("%sTo%s", mprefix, mkey); + String *lkey = SwigType_lstr(rk.key, 0); + String *lprefix = SwigType_lstr(prefix, 0); + Hash *subhash = Getattr(sub, bk.key); + String *convcode = Getattr(subhash, "convcode"); + if (convcode) { + char *newmemoryused = Strstr(convcode, "newmemory"); /* see if newmemory parameter is used in order to avoid unused parameter warnings */ + String *fn = Copy(convcode); + Replaceall(fn, "$from", "x"); + Printf(out, "static void *%s(void *x, int *%s) {", convname, newmemoryused ? "newmemory" : "SWIGUNUSEDPARM(newmemory)"); + Printf(out, "%s", fn); + } else { + String *cast = Getattr(subhash, "cast"); + Printf(out, "static void *%s(void *x, int *SWIGUNUSEDPARM(newmemory)) {", convname); + Printf(out, "\n return (void *)((%s) ", lkey); + if (cast) + Printf(out, "%s", cast); + Printf(out, " ((%s) x));\n", lprefix); + } + Printf(out, "}\n"); + Setattr(conversions, ckey, convname); + Delete(ckey); + Delete(lkey); + Delete(lprefix); + + /* This inserts conversions for typedefs */ + { + Hash *r = Getattr(r_resolved, prefix); + if (r) { + Iterator rrk; + rrk = First(r); + while (rrk.key) { + Iterator rlk; + String *rkeymangle; + + /* Make sure this name equivalence is not due to inheritance */ + if (Cmp(prefix, Getattr(r, rrk.key)) == 0) { + rkeymangle = Copy(mkey); + ckey = NewStringf("%s+%s", rrk.key, rkeymangle); + if (!Getattr(conversions, ckey)) { + Setattr(conversions, ckey, convname); + } + Delete(ckey); + for (rlk = First(rlist); rlk.item; rlk = Next(rlk)) { + ckey = NewStringf("%s+%s", rrk.key, rlk.item); + Setattr(conversions, ckey, convname); + Delete(ckey); + } + Delete(rkeymangle); + /* This is needed to pick up other alternative names for the same type. + Needed to make templates work */ + Setattr(rh, rrk.key, rrk.item); + } + rrk = Next(rrk); + } + } + } + Delete(convname); + } + Delete(prefix); + Delete(mprefix); + Delete(mkey); + bk = Next(bk); + } + rk = Next(rk); + Delete(rlist); + } +} + +/* Helper function to sort the mangled list */ +static int SwigType_compare_mangled(const DOH *a, const DOH *b) { + return strcmp((char *) Data(a), (char *) Data(b)); +} + +/* ----------------------------------------------------------------------------- + * SwigType_get_sorted_mangled_list() + * + * Returns the sorted list of mangled type names that should be exported into the + * wrapper file. + * ----------------------------------------------------------------------------- */ +List *SwigType_get_sorted_mangled_list() { + List *l = Keys(r_mangled); + SortList(l, SwigType_compare_mangled); + return l; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_type_table() + * + * Generate the type-table for the type-checker. + * ----------------------------------------------------------------------------- */ + +void SwigType_emit_type_table(File *f_forward, File *f_table) { + Iterator ki; + String *types, *table, *cast, *cast_init, *cast_temp; + Hash *imported_types; + List *mangled_list; + List *table_list = NewList(); + int i = 0; + + if (!r_mangled) { + r_mangled = NewHash(); + r_resolved = NewHash(); + } + + Printf(f_table, "\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */\n\n"); + + SwigType_inherit_equiv(f_table); + + /*#define DEBUG 1*/ +#ifdef DEBUG + Printf(stdout, "---r_mangled---\n"); + Printf(stdout, "%s\n", r_mangled); + + Printf(stdout, "---r_resolved---\n"); + Printf(stdout, "%s\n", r_resolved); + + Printf(stdout, "---r_ltype---\n"); + Printf(stdout, "%s\n", r_ltype); + + Printf(stdout, "---subclass---\n"); + Printf(stdout, "%s\n", subclass); + + Printf(stdout, "---conversions---\n"); + Printf(stdout, "%s\n", conversions); + + Printf(stdout, "---r_clientdata---\n"); + Printf(stdout, "%s\n", r_clientdata); + +#endif + table = NewStringEmpty(); + types = NewStringEmpty(); + cast = NewStringEmpty(); + cast_init = NewStringEmpty(); + imported_types = NewHash(); + + Printf(table, "static swig_type_info *swig_type_initial[] = {\n"); + Printf(cast_init, "static swig_cast_info *swig_cast_initial[] = {\n"); + + Printf(f_forward, "\n/* -------- TYPES TABLE (BEGIN) -------- */\n\n"); + + mangled_list = SwigType_get_sorted_mangled_list(); + for (ki = First(mangled_list); ki.item; ki = Next(ki)) { + List *el; + Iterator ei; + SwigType *lt; + SwigType *rt = 0; + String *nt; + String *ln; + String *rn; + const String *cd; + Hash *lthash; + Iterator ltiter; + Hash *nthash; + + cast_temp = NewStringEmpty(); + + Printv(types, "static swig_type_info _swigt_", ki.item, " = {", NIL); + Append(table_list, ki.item); + Printf(cast_temp, "static swig_cast_info _swigc_%s[] = {", ki.item); + i++; + + cd = SwigType_clientdata_collect(ki.item); + if (!cd) + cd = "0"; + + lthash = Getattr(r_ltype, ki.item); + nt = 0; + nthash = NewHash(); + ltiter = First(lthash); + while (ltiter.key) { + lt = ltiter.key; + rt = SwigType_typedef_resolve_all(lt); + /* we save the original type and the fully resolved version */ + ln = SwigType_lstr(lt, 0); + rn = SwigType_lstr(rt, 0); + if (Equal(ln, rn)) { + Setattr(nthash, ln, "1"); + } else { + Setattr(nthash, rn, "1"); + Setattr(nthash, ln, "1"); + } + if (SwigType_istemplate(rt)) { + String *dt = Swig_symbol_template_deftype(rt, 0); + String *dn = SwigType_lstr(dt, 0); + if (!Equal(dn, rn) && !Equal(dn, ln)) { + Setattr(nthash, dn, "1"); + } + Delete(dt); + Delete(dn); + } + + ltiter = Next(ltiter); + } + + /* now build nt */ + ltiter = First(nthash); + nt = 0; + while (ltiter.key) { + if (nt) { + Printf(nt, "|%s", ltiter.key); + } else { + nt = NewString(ltiter.key); + } + ltiter = Next(ltiter); + } + Delete(nthash); + + Printf(types, "\"%s\", \"%s\", 0, 0, (void*)%s, 0};\n", ki.item, nt, cd); + + el = SwigType_equivalent_mangle(ki.item, 0, 0); + for (ei = First(el); ei.item; ei = Next(ei)) { + String *ckey; + String *conv; + ckey = NewStringf("%s+%s", ei.item, ki.item); + conv = Getattr(conversions, ckey); + if (conv) { + Printf(cast_temp, " {&_swigt_%s, %s, 0, 0},", ei.item, conv); + } else { + Printf(cast_temp, " {&_swigt_%s, 0, 0, 0},", ei.item); + } + Delete(ckey); + + if (!Getattr(r_mangled, ei.item) && !Getattr(imported_types, ei.item)) { + Printf(types, "static swig_type_info _swigt_%s = {\"%s\", 0, 0, 0, 0, 0};\n", ei.item, ei.item); + Append(table_list, ei.item); + + Printf(cast, "static swig_cast_info _swigc_%s[] = {{&_swigt_%s, 0, 0, 0},{0, 0, 0, 0}};\n", ei.item, ei.item); + i++; + + Setattr(imported_types, ei.item, "1"); + } + } + Delete(el); + Printf(cast, "%s{0, 0, 0, 0}};\n", cast_temp); + Delete(cast_temp); + Delete(nt); + Delete(rt); + } + /* print the tables in the proper order */ + SortList(table_list, SwigType_compare_mangled); + i = 0; + for (ki = First(table_list); ki.item; ki = Next(ki)) { + Printf(f_forward, "#define SWIGTYPE%s swig_types[%d]\n", ki.item, i++); + Printf(table, " &_swigt_%s,\n", ki.item); + Printf(cast_init, " _swigc_%s,\n", ki.item); + } + if (i == 0) { + /* empty arrays are not allowed by ISO C */ + Printf(table, " NULL\n"); + Printf(cast_init, " NULL\n"); + } + + Delete(table_list); + + Delete(mangled_list); + + Printf(table, "};\n"); + Printf(cast_init, "};\n"); + Printf(f_table, "%s\n", types); + Printf(f_table, "%s\n", table); + Printf(f_table, "%s\n", cast); + Printf(f_table, "%s\n", cast_init); + Printf(f_table, "\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */\n\n"); + + Printf(f_forward, "static swig_type_info *swig_types[%d];\n", i + 1); + Printf(f_forward, "static swig_module_info swig_module = {swig_types, %d, 0, 0, 0, 0};\n", i); + Printf(f_forward, "#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)\n"); + Printf(f_forward, "#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)\n"); + Printf(f_forward, "\n/* -------- TYPES TABLE (END) -------- */\n\n"); + + Delete(types); + Delete(table); + Delete(cast); + Delete(cast_init); + Delete(imported_types); +} |
