* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at https://www.swig.org/legal.html.
*
* 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.
* ----------------------------------------------------------------------------- */
#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
* For a given key in the typetab table, the value is a fully
* qualified name if not pointing to itself.
* "symtab" - Hash table of symbols defined in a scope
* "inherit" - List of inherited scopes
* "parent" - Parent scope
*
* The contents of these tables can be viewed for debugging using the -debug-typedef
* option which calls SwigType_print_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 in scope '' contains:
* "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)
*
*
* Using declarations are stored in the "typetab" hash table. For example,
*
* namespace NN {
* struct SS {};
* }
* namespace N {
* struct S {};
* using NN::SS;
* }
* using N::S;
*
* typetab in scope '' contains:
* "S" : "N::S"
*
* and typetab in scope 'N' contains:
* "SS" : "NN::SS"
* "S" : "S"
*
*
* For inheritance, SWIG tries to resolve types back to the base class. For instance, if
* you have this:
*
* class Foo {
* public:
* typedef int Integer;
* };
* struct Bar : public Foo {
* void blah(Integer x);
* };
*
* In this case typetab in scope '' contains:
* "Foo" : "Foo"
* "Bar" : "Bar"
* and scope 'Foo' contains:
* "Integer" : "int"
* and scope 'Bar' inherits from 'Foo' but is empty (observe that blah is not a scope or typedef)
*
* The argument type of Bar::blah will be set to Foo::Integer.
*
*
* The scope-inheritance mechanism is used to manage C++ using directives.
*
* namespace XX {
* class CC {};
* }
* namespace X {
* class C {};
* using namespace XX;
* }
* using namespace X;
*
* typetab in scope '' inherits from 'X'
* typetab in scope 'X' inherits from 'XX' and contains:
* "C" : "C"
* typetab in scope 'XX' contains:
* "CC" : "CC"
*
*
* 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 points 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;
static Hash *current_typetab = 0;
static Hash *current_symtab = 0;
static Typetab *global_scope = 0;
static Hash *scopes = 0;
#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, const SwigType *nameprefix);
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(void) {
typedef_resolve_cache = 0;
typedef_all_cache = 0;
typedef_qualified_cache = 0;
}
void SwigType_typesystem_init(void) {
if (global_scope)
Delete(global_scope);
if (scopes)
Delete(scopes);
current_scope = NewHash();
global_scope = current_scope;
Setattr(current_scope, "name", "");
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(const SwigType *type, const_String_or_char_ptr name) {
if (Getattr(current_typetab, name))
return -1;
if (Strcmp(type, name) == 0) {
return 0;
}
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;
if (Getattr(current_typetab, name))
return -1;
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
* ----------------------------------------------------------------------------- */
static 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);
qname = SwigType_scope_name(s);
#if 1
{
String *stripped_qname;
stripped_qname = SwigType_remove_global_scope_prefix(qname);
Setattr(scopes, stripped_qname, s);
Setattr(s, "qname", qname);
Printf(stdout, "SwigType_new_scope stripped %s %s\n", qname, stripped_qname);
*/
Delete(stripped_qname);
}
#else
Printf(stdout, "SwigType_new_scope %s\n", qname);
Setattr(scopes, qname, s);
Setattr(s, "qname", qname);
#endif
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;
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(void) {
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(void) {
Hash *ttab;
Iterator i, j;
Printf(stdout, "SCOPES start =======================================\n");
for (i = First(scopes); i.key; i = Next(i)) {
Printf(stdout, "-------------------------------------------------------------\n");
ttab = Getattr(i.item, "typetab");
Printf(stdout, "Type scope '%s' (%p)\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' (%p)\n", Getattr(j.item, "qname"), j.item);
}
}
}
for (j = First(ttab); j.key; j = Next(j)) {
Printf(stdout, "%40s -> %s\n", j.key, j.item);
}
}
Printf(stdout, "SCOPES finish =======================================\n");
}
static Typetab *SwigType_find_scope(Typetab *s, const SwigType *nameprefix) {
Typetab *ss;
Typetab *s_orig = s;
String *nnameprefix = 0;
static int check_parent = 1;
int is_template = 0;
if (Getmark(s))
return 0;
Setmark(s, 1);
is_template = SwigType_istemplate(nameprefix);
if (is_template) {
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);
if (Strncmp(full, "enum ", 5) == 0) {
Delslice(full, 0, 5);
}
} else {
full = NewString(nameprefix);
}
s = Getattr(scopes, full);
if (!s && is_template) {
SwigType *full_stripped = SwigType_remove_global_scope_prefix(full);
s = Getattr(scopes, full_stripped);
Delete(full_stripped);
}
Delete(full);
if (s) {
if (nnameprefix)
Delete(nnameprefix);
Setmark(s_orig, 0);
return s;
}
if (!s) {
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);
Setmark(s_orig, 0);
return s;
}
}
}
}
if (!check_parent)
break;
ss = Getattr(ss, "parent");
}
if (nnameprefix)
Delete(nnameprefix);
Setmark(s_orig, 0);
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;
static SwigType *_typedef_resolve(Typetab *s, String *base, int look_parent) {
Hash *ttab;
SwigType *type = 0;
List *inherit;
Typetab *parent;
if (!Getmark(s)) {
Setmark(s, 1);
ttab = Getattr(s, "typetab");
type = Getattr(ttab, base);
if (type) {
resolved_scope = s;
Setmark(s, 0);
} else {
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) {
if (look_parent) {
parent = Getattr(s, "parent");
type = parent ? _typedef_resolve(parent, base, 1) : 0;
}
}
Setmark(s, 0);
}
}
return type;
}
* template_parameters_resolve()
*
* For use with templates only. Attempts to resolve one template parameter.
*
* If one of the template parameters can be resolved, the type is returned with
* just the one parameter resolved and the remaining parameters left as is.
* If none of the template parameters can be resolved, zero is returned.
* ----------------------------------------------------------------------------- */
static String *template_parameters_resolve(const String *base) {
List *tparms;
String *suffix;
String *type;
int i, sz;
int rep = 0;
type = SwigType_templateprefix(base);
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, ",");
}
if (rep) {
Append(type, ")>");
Append(type, suffix);
} else {
Delete(type);
type = 0;
}
Delete(suffix);
Delete(tparms);
return type;
}
static SwigType *typedef_resolve(Typetab *s, String *base) {
return _typedef_resolve(s, base, 1);
}
* SwigType_typedef_resolve()
*
* Given a type declaration, this function looks to reduce/resolve the type via a
* typedef (including via C++ using declarations).
*
* If it is able to find a typedef, the resolved type is returned. If no typedef
* is found NULL is returned. The type name is resolved in the current scope.
* The type returned is not always fully qualified for the global scope, it is
* valid for use in the current scope. If the current scope is global scope, a
* fully qualified type should be returned.
*
* Some additional notes are in Doc/Manual/Extending.html.
* ----------------------------------------------------------------------------- */
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, *rnameprefix = 0;
int newtype = 0;
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);
}
type = Getattr(ttab, base);
if (type) {
resolved_scope = s;
}
if (!type) {
if (Swig_scopename_check(base)) {
Swig_scopename_split(base, &nameprefix, &namebase);
#ifdef SWIG_DEBUG
Printf(stdout, "nameprefix = '%s'\n", nameprefix);
#endif
if (nameprefix) {
rnameprefix = SwigType_typedef_resolve(nameprefix);
if(rnameprefix != NULL) {
#ifdef SWIG_DEBUG
Printf(stdout, "nameprefix '%s' is a typedef to '%s'\n", nameprefix, rnameprefix);
#endif
type = Copy(namebase);
Insert(type, 0, "::");
Insert(type, 0, rnameprefix);
if (Strncmp(type, "enum ", 5) == 0) {
Delslice(type, 0, 5);
}
if (Strncmp(type, "::", 2) == 0) {
Delslice(type, 0, 2);
}
newtype = 1;
} else {
String *rnameprefix = template_parameters_resolve(nameprefix);
nameprefix = rnameprefix ? Copy(rnameprefix) : nameprefix;
Delete(rnameprefix);
s = SwigType_find_scope(s, nameprefix);
if (!s) {
Delete(base);
Delete(namebase);
Delete(nameprefix);
r = 0;
goto return_result;
}
#ifdef SWIG_DEBUG
Printf(stdout, "namebase = '%s'\n", namebase);
#endif
type = typedef_resolve(s, namebase);
if (type && resolved_scope) {
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 ((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 {
type = typedef_resolve(s, base);
}
} else {
type = typedef_resolve(s, base);
}
}
if (!type && SwigType_istemplate(base)) {
String *tprefix = SwigType_templateprefix(base);
String *rtprefix = SwigType_typedef_resolve(tprefix);
* in another scope. Using declaration do not have template parameters. */
if (rtprefix && !SwigType_istemplate(rtprefix)) {
String *tsuffix = SwigType_templatesuffix(base);
String *targs = SwigType_templateargs(base);
type = NewString(rtprefix);
newtype = 1;
Append(type, targs);
Append(type, tsuffix);
Delete(targs);
Delete(tsuffix);
Delete(rtprefix);
}
Delete(tprefix);
}
if (type && (Equal(base, type))) {
if (newtype)
Delete(type);
Delete(base);
Delete(namebase);
Delete(nameprefix);
r = 0;
goto return_result;
}
template arguments one by one to see if they can be resolved. */
if (!type && SwigType_istemplate(base)) {
newtype = 1;
type = template_parameters_resolve(base);
}
Delete(namebase);
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);
be added to 'type' after the array qualifier, so that given
a(7).q(volatile).double myarray // typedef volatile double[7] myarray;
the type
q(const).myarray // const myarray
becomes
a(7).q(const volatile).double // const volatile double[7]
and NOT
q(const).a(7).q(volatile).double // non-sensical type
*/
if (r && Len(r) && SwigType_isarray(type)) {
List *r_elem;
String *r_qual;
int r_sz;
r_elem = SwigType_split(r);
r_sz = Len(r_elem);
r_qual = Getitem(r_elem, r_sz-1);
if (SwigType_isqualifier(r_qual)) {
String *new_r;
String *new_type;
List *type_elem;
String *type_qual;
String *r_qual_arg;
int i, type_sz;
type_elem = SwigType_split(type);
type_sz = Len(type_elem);
for (i = 0; i < type_sz; ++i) {
String *e = Getitem(type_elem, i);
if (!SwigType_isarray(e))
break;
}
type_qual = Copy(Getitem(type_elem, i));
r_qual_arg = SwigType_parm(r_qual);
SwigType_add_qualifier(type_qual, r_qual_arg);
Delete(r_qual_arg);
Setitem(type_elem, i, type_qual);
new_r = NewStringEmpty();
for (i = 0; i < r_sz-1; ++i) {
Append(new_r, Getitem(r_elem, i));
}
new_type = NewStringEmpty();
for (i = 0; i < type_sz; ++i) {
Append(new_type, Getitem(type_elem, i));
}
#ifdef SWIG_DEBUG
Printf(stdout, "r+type='%s%s' new_r+new_type='%s%s'\n", r, type, new_r, new_type);
#endif
Delete(r);
r = new_r;
newtype = 1;
type = new_type;
Delete(type_elem);
}
Delete(r_elem);
}
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(const SwigType *t) {
SwigType *n;
SwigType *r;
int count = 0;
if (!typedef_all_cache) {
typedef_all_cache = NewHash();
}
r = Getattr(typedef_all_cache, t);
if (r) {
return Copy(r);
}
#ifdef SWIG_DEBUG
Printf(stdout, "SwigType_typedef_resolve_all start ... %s\n", t);
#endif
r = NewString(t);
while ((n = SwigType_typedef_resolve(r))) {
Delete(r);
r = n;
if (++count >= 512) {
Swig_error(Getfile(t), Getline(t), "Recursive typedef detected resolving '%s' to '%s' to '%s' and so on...\n", SwigType_str(t, 0), SwigType_str(SwigType_typedef_resolve(t), 0), SwigType_str(SwigType_typedef_resolve(SwigType_typedef_resolve(t)), 0));
break;
}
}
{
String *key;
SwigType *rr = Copy(r);
key = NewString(t);
Setattr(typedef_all_cache, key, rr);
Delete(key);
Delete(rr);
}
#ifdef SWIG_DEBUG
Printf(stdout, "SwigType_typedef_resolve_all end === %s => %s\n", t, r);
#endif
return r;
}
* SwigType_typedef_qualified()
*
* Given a type declaration, this function tries to fully qualify it so that the
* resulting type can be used in the global scope. The type name is resolved in
* the current scope.
*
* It provides a fully qualified name, not necessarily a fully expanded name.
* When a using declaration or using directive is found the type may not be fully
* expanded, but it will be resolved and fully qualified for use in the global scope.
*
* This function is for looking up scopes to qualify a type. It does not resolve
* C typedefs, it just qualifies them. See SwigType_typedef_resolve for resolving.
*
* If the unary scope operator (::) is used as a prefix to the type to denote global
* scope, it is left in place.
* ----------------------------------------------------------------------------- */
SwigType *SwigType_typedef_qualified(const SwigType *t) {
List *elements;
String *result;
int i, len;
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) {
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);
} else {
name is part of a namespace. We'll check this by unrolling
out of the current scope */
Typetab *cs = current_scope;
if (cs) {
Typetab *found_scope = SwigType_find_scope(cs, e);
if (found_scope) {
String *qs = SwigType_scope_name(found_scope);
Clear(e);
Append(e, qs);
Delete(qs);
}
}
}
}
if (isenum) {
Insert(e, 0, isenum);
Delete(isenum);
}
} else {
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)) {
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) {
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);
}
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(const 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;
if (!Swig_scopename_check(name))
return -1;
base = Swig_scopename_last(name);
if (Getattr(current_typetab, base)) {
Delete(base);
return -1;
}
Printf(stdout,"tt = %p, name = '%s'\n", tt, name); */
Setattr(current_typetab, base, name);
td = SwigType_typedef_resolve(name);
if (resolved_scope) {
defined_name = Getattr(resolved_scope, "qname");
if (defined_name) {
defined_name = Copy(defined_name);
Append(defined_name, "::");
Append(defined_name, base);
tt = SwigType_find_scope(current_scope, defined_name);
}
}
if (td)
Delete(td);
{
prefix = Swig_scopename_prefix(name);
if (prefix) {
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) {
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(const 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;
}
if (!isclass) {
String *tp = SwigType_istemplate_templateprefix(qtys);
if (tp && 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(const SwigType *t) {
char *c;
c = Char(t);
if (strncmp(c, "p.", 2) == 0) {
if (SwigType_type(c + 2) == T_CHAR)
return T_STRING;
else if (SwigType_type(c + 2) == T_WCHAR)
return T_WSTRING;
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, "z.", 2) == 0)
return T_RVALUE_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);
Printf(stderr, "*** Internal error: Invalid type string '%s'\n", t);
Exit(EXIT_FAILURE);
}
if (strncmp(c, "f(", 2) == 0)
return T_FUNCTION;
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, "wchar_t") == 0)
return T_WCHAR;
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, "auto") == 0)
return T_AUTO;
if (strcmp(c, "v(...)") == 0)
return T_VARARGS;
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 'allocate:default_constructor'
* attribute.
*
* 2.- swig doesn't mark 'type' as non-assignable.
*
* 3.- the user specifies that the value wrapper is not needed by using
* %feature("novaluewrapper") like so:
*
* %feature("novaluewrapper") MyOpaqueClass;
* class MyOpaqueClass;
*
* The user can also force the use of the value wrapper with
* %feature("valuewrapper").
* ----------------------------------------------------------------------------- */
SwigType *SwigType_alttype(const 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) {
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 = 1;
}
}
}
} else {
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) {
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;
static Hash *r_resolved = 0;
static Hash *r_ltype = 0;
static Hash *r_clientdata = 0;
static Hash *r_mangleddata = 0;
static Hash *r_remembered = 0;
static void (*r_tracefunc) (const 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(const 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);
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);
qr = SwigType_typedef_qualified(fr);
Delete(fr);
fr = SwigType_strip_qualifiers(qr);
Delete(qr);
Printf(stdout,"fr= '%s'\n\n", fr); */
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);
}
}
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);
} else if (SwigType_isrvalue_reference(t)) {
SwigType *tt = Copy(t);
SwigType_del_rvalue_reference(tt);
SwigType_add_pointer(tt);
SwigType_remember_clientdata(tt, clientdata);
}
}
void SwigType_remember(const SwigType *ty) {
SwigType_remember_clientdata(ty, 0);
}
void (*SwigType_remember_trace(void (*tf) (const SwigType *, String *, String *))) (const SwigType *, String *, String *) {
void (*o) (const 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).
* ----------------------------------------------------------------------------- */
static 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;
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();
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);
}
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(const SwigType *t1, const 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);
return r;
}
* SwigType_inherit_equiv()
*
* Modify the type table to handle C++ inheritance
* ----------------------------------------------------------------------------- */
static void SwigType_inherit_equiv(File *out) {
String *ckey;
String *prefix, *base;
String *mprefix, *mkey;
Hash *sub;
Hash *rh;
List *rlist;
List *r_resolved_sorted_keys;
Iterator rk, bk, ck;
if (!conversions)
conversions = NewHash();
if (!subclass)
subclass = NewHash();
r_resolved_sorted_keys = SortedKeys(r_resolved, Strcmp);
rk = First(r_resolved_sorted_keys);
while (rk.item) {
List *sub_sorted_keys;
base = SwigType_base(rk.item);
sub = Getattr(subclass, base);
Delete(base);
if (!sub) {
rk = Next(rk);
continue;
}
rh = Getattr(r_resolved, rk.item);
rlist = NewList();
for (ck = First(rh); ck.key; ck = Next(ck)) {
Append(rlist, ck.key);
}
Printf(stdout,"rh = %p '%s'\n", rh,rh); */
sub_sorted_keys = SortedKeys(sub, Strcmp);
bk = First(sub_sorted_keys);
while (bk.item) {
prefix = SwigType_prefix(rk.item);
Append(prefix, bk.item);
mprefix = SwigType_manglestr(prefix);
Setattr(rh, mprefix, prefix);
mkey = SwigType_manglestr(rk.item);
ckey = NewStringf("%s+%s", mprefix, mkey);
if (!Getattr(conversions, ckey)) {
String *convname = NewStringf("%sTo%s", mprefix, mkey);
String *lkey = SwigType_lstr(rk.item, 0);
String *lprefix = SwigType_lstr(prefix, 0);
Hash *subhash = Getattr(sub, bk.item);
String *convcode = Getattr(subhash, "convcode");
if (convcode) {
char *newmemoryused = Strstr(convcode, "newmemory");
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);
{
Hash *r = Getattr(r_resolved, prefix);
if (r) {
Iterator rrk;
rrk = First(r);
while (rrk.key) {
Iterator rlk;
String *rkeymangle;
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);
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);
}
Delete(sub_sorted_keys);
rk = Next(rk);
Delete(rlist);
}
Delete(r_resolved_sorted_keys);
}
* 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);
#ifdef DEBUG
Printf(stdout, "---r_mangled---\n");
Swig_print(r_mangled, 2);
Printf(stdout, "---r_resolved---\n");
Swig_print(r_resolved, 2);
Printf(stdout, "---r_ltype---\n");
Swig_print(r_ltype, 2);
Printf(stdout, "---subclass---\n");
Swig_print(subclass, 2);
Printf(stdout, "---conversions---\n");
Swig_print(conversions, 2);
Printf(stdout, "---r_clientdata---\n");
Swig_print(r_clientdata, 2);
#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 = SortedKeys(r_mangled, Strcmp);
for (ki = First(mangled_list); ki.item; ki = Next(ki)) {
List *el;
Iterator ei;
String *nt;
String *ln;
String *rn;
const String *cd;
Hash *lthash;
Iterator ltiter;
Hash *nthash;
String *cast_temp_conv;
String *resolved_lstr = 0;
List *ntlist;
cast_temp = NewStringEmpty();
cast_temp_conv = 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) {
SwigType *lt = ltiter.key;
SwigType *rt = SwigType_typedef_resolve_all(lt);
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 (!resolved_lstr) {
resolved_lstr = Copy(rn);
} else if (Len(rn) < Len(resolved_lstr)) {
Delete(resolved_lstr);
resolved_lstr = Copy(rn);
}
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);
}
Delete(rt);
Delete(rn);
Delete(ln);
ltiter = Next(ltiter);
}
ntlist = SortedKeys(nthash, Strcmp);
ltiter = First(ntlist);
nt = 0;
while (ltiter.item) {
if (!Equal(resolved_lstr, ltiter.item)) {
if (nt) {
Printf(nt, "|%s", ltiter.item);
} else {
nt = NewString(ltiter.item);
}
}
ltiter = Next(ltiter);
}
* There can be more than one resolved type and the chosen one is simply the
* shortest in length, arguably the most user friendly/readable. */
if (nt) {
Printf(nt, "|%s", resolved_lstr);
} else {
nt = NewString(resolved_lstr);
}
Delete(ntlist);
Delete(nthash);
Delete(resolved_lstr);
Printf(types, "\"%s\", \"%s\", 0, 0, (void*)%s, 0};\n", ki.item, nt, cd);
el = SwigType_equivalent_mangle(ki.item, 0, 0);
SortList(el, Strcmp);
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_conv, " {&_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%s{0, 0, 0, 0}};\n", cast_temp, cast_temp_conv);
Delete(cast_temp_conv);
Delete(cast_temp);
Delete(nt);
}
SortList(table_list, Strcmp);
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) {
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);
}