git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@6357 626c5289-ae23-0410-ae9c-e8d60b6d4f22
1716 lines
47 KiB
C
1716 lines
47 KiB
C
/* -----------------------------------------------------------------------------
|
|
* 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.
|
|
*
|
|
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
|
|
*
|
|
* Copyright (C) 1999-2000. The University of Chicago
|
|
* See the file LICENSE for information on usage and redistribution.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
char cvsroot_typesys_c[] = "$Header$";
|
|
|
|
#include "swig.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;
|
|
|
|
/* common attribute keys, to avoid calling find_key all the times */
|
|
static String *k_name = 0;
|
|
static String *k_qname = 0;
|
|
static String *k_symtab = 0;
|
|
static String *k_using = 0;
|
|
static String *k_scope = 0;
|
|
static String *k_typetab = 0;
|
|
static String *k_inherit = 0;
|
|
static String *k_parent = 0;
|
|
static String *k_value = 0;
|
|
|
|
|
|
static void flush_cache() {
|
|
typedef_resolve_cache = 0;
|
|
typedef_all_cache = 0;
|
|
typedef_qualified_cache = 0;
|
|
}
|
|
|
|
/* Initialize the scoping system */
|
|
|
|
void SwigType_typesystem_init() {
|
|
k_name = NewString("name");
|
|
k_qname = NewString("qname");
|
|
k_symtab = NewString("symtab");
|
|
k_using = NewString("using");
|
|
k_scope = NewString("scope");
|
|
k_typetab = NewString("typetab");
|
|
k_inherit = NewString("inherit");
|
|
k_parent = NewString("parent");
|
|
k_value = NewString("value");
|
|
|
|
if (global_scope) Delete(global_scope);
|
|
if (scopes) Delete(scopes);
|
|
|
|
current_scope = NewHash();
|
|
global_scope = current_scope;
|
|
|
|
Setattr(current_scope,k_name,""); /* No name for global scope */
|
|
current_typetab = NewHash();
|
|
Setattr(current_scope,k_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, String_or_char *name) {
|
|
Typetab *SwigType_find_scope(Typetab *, String *s);
|
|
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(String_or_char *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,k_name));
|
|
ttab = Getattr(ttab,k_parent);
|
|
while (ttab) {
|
|
String *pname = Getattr(ttab,k_name);
|
|
if (Len(pname)) {
|
|
Insert(qname,0,"::");
|
|
Insert(qname,0,pname);
|
|
}
|
|
ttab = Getattr(ttab,k_parent);
|
|
}
|
|
return qname;
|
|
}
|
|
/* -----------------------------------------------------------------------------
|
|
* SwigType_new_scope()
|
|
*
|
|
* Creates a new scope
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void SwigType_new_scope(const String_or_char *name) {
|
|
Typetab *s;
|
|
Hash *ttab;
|
|
String *qname;
|
|
|
|
if (!name) {
|
|
name = "<unnamed>";
|
|
}
|
|
s = NewHash();
|
|
Setattr(s,k_name, name);
|
|
Setattr(s,k_parent, current_scope);
|
|
ttab = NewHash();
|
|
Setattr(s,k_typetab, ttab);
|
|
|
|
/* Build fully qualified name and */
|
|
qname = SwigType_scope_name(s);
|
|
Setattr(scopes,qname,s);
|
|
Setattr(s,k_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,k_inherit);
|
|
if (!inherits) {
|
|
inherits = NewList();
|
|
Setattr(current_scope,k_inherit, 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,k_using);
|
|
if (!ulist) {
|
|
ulist = NewList();
|
|
Setattr(current_scope,k_using, 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 *s, *s1;
|
|
s = Getattr(current_scope,k_parent);
|
|
if (!s) {
|
|
current_scope = 0;
|
|
current_typetab = 0;
|
|
current_symtab = 0;
|
|
return 0;
|
|
}
|
|
s1 = current_scope;
|
|
current_scope = s;
|
|
current_typetab = Getattr(s,k_typetab);
|
|
current_symtab = Getattr(s,k_symtab);
|
|
flush_cache();
|
|
return s1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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,k_typetab);
|
|
current_symtab = Getattr(t,k_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,k_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,k_typetab);
|
|
|
|
Printf(stdout,"Type scope '%s' (%x)\n", i.key, i.item);
|
|
{
|
|
List *inherit = Getattr(i.item,k_inherit);
|
|
if (inherit) {
|
|
Iterator j;
|
|
for (j = First(inherit); j.item; j = Next(j)) {
|
|
Printf(stdout," Inherits from '%s' (%x)\n", Getattr(j.item,k_qname), j.item);
|
|
}
|
|
}
|
|
}
|
|
Printf(stdout,"-------------------------------------------------------------\n");
|
|
for (j = First(ttab); j.key; j = Next(j)) {
|
|
Printf(stdout,"%40s -> %s\n", j.key, j.item);
|
|
}
|
|
}
|
|
}
|
|
|
|
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,k_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,k_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,k_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) {
|
|
Hash *ttab;
|
|
SwigType *type;
|
|
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)) return 0;
|
|
Setmark(s,1);
|
|
|
|
ttab = Getattr(s,k_typetab);
|
|
type = Getattr(ttab,base);
|
|
if (type) {
|
|
resolved_scope = s;
|
|
Setmark(s,0);
|
|
return type;
|
|
}
|
|
/* Hmmm. Not found in my scope. It could be in an inherited scope */
|
|
inherit = Getattr(s,k_inherit);
|
|
if (inherit) {
|
|
int i,len;
|
|
len = Len(inherit);
|
|
for (i = 0; i < len; i++) {
|
|
type = typedef_resolve(Getitem(inherit,i), base);
|
|
if (type) {
|
|
Setmark(s,0);
|
|
return type;
|
|
}
|
|
}
|
|
}
|
|
parent = Getattr(s,k_parent);
|
|
type = parent ? typedef_resolve(parent, base) : 0;
|
|
Setmark(s,0);
|
|
return type;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* SwigType_typedef_resolve()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
SwigType *SwigType_typedef_resolve(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 = NewString("");
|
|
}
|
|
*/
|
|
|
|
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,k_scope);
|
|
return Copy(r);
|
|
}
|
|
#endif
|
|
|
|
base = SwigType_base(t);
|
|
|
|
/* Printf(stdout,"base = '%s' t='%s'\n", base, t); */
|
|
|
|
if (SwigType_issimple(base)) {
|
|
s = current_scope;
|
|
ttab = current_typetab;
|
|
if (Strncmp(base,"::",2) == 0) {
|
|
s = global_scope;
|
|
ttab = Getattr(s,k_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. */
|
|
nameprefix = Swig_scopename_prefix(base);
|
|
/* Printf(stdout,"nameprefix = '%s'\n", nameprefix); */
|
|
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(nameprefix);
|
|
r = 0;
|
|
goto return_result;
|
|
}
|
|
/* Try to locate the name starting in the scope */
|
|
namebase = Swig_scopename_last(base);
|
|
/* Printf(stdout,"namebase = '%s'\n", namebase); */
|
|
type = typedef_resolve(s,namebase);
|
|
/* Printf(stdout,"%s type = '%s'\n", Getattr(s,"name"), type); */
|
|
if ((type) && (!Swig_scopename_check(type))) {
|
|
Typetab *rtab = resolved_scope;
|
|
String *qname = Getattr(resolved_scope,k_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);
|
|
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 && (Strcmp(base,type) == 0)) {
|
|
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);
|
|
namebase = 0;
|
|
nameprefix = 0;
|
|
} 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)) {
|
|
if ((Strstr(r,"f(") || (Strstr(r,"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,k_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.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
SwigType *SwigType_typedef_qualified(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 = NewString("");
|
|
elements = SwigType_split(t);
|
|
len = Len(elements);
|
|
for (i = 0; i < len; i++) {
|
|
String *e = Getitem(elements,i);
|
|
if (SwigType_issimple(e)) {
|
|
if (!SwigType_istemplate(e)) {
|
|
String *isenum = 0;
|
|
if (SwigType_isenum(e)) {
|
|
isenum = NewString("enum ");
|
|
e = NewString(Char(e)+5);
|
|
}
|
|
resolved_scope = 0;
|
|
if (typedef_resolve(current_scope,e)) {
|
|
/* resolved_scope contains the scope that actually resolved the symbol */
|
|
String *qname = Getattr(resolved_scope,k_qname);
|
|
if (qname) {
|
|
Insert(e,0,"::");
|
|
Insert(e,0,qname);
|
|
}
|
|
} else {
|
|
if (Swig_scopename_check(e)) {
|
|
String *tqname;
|
|
String *qlast;
|
|
String *qname = Swig_scopename_prefix(e);
|
|
if (qname) {
|
|
qlast = Swig_scopename_last(e);
|
|
tqname = SwigType_typedef_qualified(qname);
|
|
Clear(e);
|
|
Printf(e,"%s::%s", tqname, qlast);
|
|
Delete(qname);
|
|
Delete(qlast);
|
|
Delete(tqname);
|
|
}
|
|
/* 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,k_parent);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isenum) {
|
|
Insert(e,0,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 = SwigType_parmlist(e);
|
|
tprefix = SwigType_templateprefix(e);
|
|
tsuffix = SwigType_templatesuffix(e);
|
|
qprefix = SwigType_typedef_qualified(tprefix);
|
|
Printv(qprefix,"<(",NIL);
|
|
pi = First(parms);
|
|
while ((p = pi.item)) {
|
|
String *qt = SwigType_typedef_qualified(p);
|
|
if ((Strcmp(qt,p) == 0)) { /* && (!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) {
|
|
if (Strcmp(nodeType(n),"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,k_name));
|
|
Delete(value);
|
|
value = qn;
|
|
continue;
|
|
} else {
|
|
Delete(qn);
|
|
break;
|
|
}
|
|
} else if ((Strcmp(nodeType(n),"cdecl") == 0) && (Getattr(n,k_value))) {
|
|
Delete(value);
|
|
value = Copy(Getattr(n,k_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(e,"::",2) == 0) {
|
|
Delitem(e,0);
|
|
Delitem(e,0);
|
|
}
|
|
Append(result,e);
|
|
} 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(String_or_char *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,k_qname);
|
|
if (defined_name) {
|
|
defined_name = Copy(defined_name);
|
|
Append(defined_name,"::");
|
|
Append(defined_name,base);
|
|
}
|
|
}
|
|
if (td) Delete(td);
|
|
|
|
/* Printf(stdout,"defined_name = '%s'\n", defined_name);*/
|
|
tt = SwigType_find_scope(current_scope,defined_name);
|
|
|
|
/* 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,k_typetab);
|
|
if (!Getattr(ttab,base) && defined_name) {
|
|
Setattr(ttab,base, defined_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tt) {
|
|
/* Using directive had it's own scope. We need to do 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,"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;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*** * * * 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_remembered = 0; /* Hash of types we remembered already */
|
|
|
|
static void (*r_tracefunc)(SwigType *t, String *mangled, String *clientdata) = 0;
|
|
|
|
void SwigType_remember_clientdata(SwigType *t, const String_or_char *clientdata) {
|
|
String *mt;
|
|
SwigType *lt;
|
|
Hash *h;
|
|
SwigType *fr;
|
|
SwigType *qr;
|
|
String *tkey;
|
|
|
|
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);
|
|
Setattr(r_remembered, tkey, clientdata ? NewString(clientdata) : (void *) "");
|
|
Delete(tkey);
|
|
|
|
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);
|
|
}
|
|
Setattr(r_ltype, mt, 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 (Strstr(t,"<") && !(Strstr(t,"<("))) {
|
|
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 {
|
|
Setattr(r_clientdata, fr, NewString(clientdata));
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
|
|
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.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *subclass = 0;
|
|
static Hash *conversions = 0;
|
|
|
|
void
|
|
SwigType_inherit(String *derived, String *base, String *cast) {
|
|
Hash *h;
|
|
if (!subclass) subclass = NewHash();
|
|
|
|
/* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */
|
|
|
|
if (SwigType_istemplate(derived)) {
|
|
derived = SwigType_typedef_qualified(SwigType_typedef_resolve_all(derived));
|
|
}
|
|
if (SwigType_istemplate(base)) {
|
|
base = SwigType_typedef_qualified(SwigType_typedef_resolve_all(base));
|
|
}
|
|
|
|
/* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast);*/
|
|
|
|
h = Getattr(subclass,base);
|
|
if (!h) {
|
|
h = NewHash();
|
|
Setattr(subclass,base,h);
|
|
}
|
|
if (!Getattr(h,derived)) {
|
|
Setattr(h,derived, cast ? cast : (void *) "");
|
|
}
|
|
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* SwigType_issubtype()
|
|
*
|
|
* Determines if a t1 is a subtype of 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;
|
|
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); */
|
|
Setattr(rh,SwigType_manglestr(prefix),prefix);
|
|
ckey = NewStringf("%s+%s",SwigType_manglestr(prefix), SwigType_manglestr(rk.key));
|
|
if (!Getattr(conversions,ckey)) {
|
|
String *convname = NewStringf("%sTo%s", SwigType_manglestr(prefix), SwigType_manglestr(rk.key));
|
|
Printf(out,"static void *%s(void *x) {\n", convname);
|
|
Printf(out," return (void *)((%s) %s ((%s) x));\n", SwigType_lstr(rk.key,0), Getattr(sub,bk.key), SwigType_lstr(prefix,0));
|
|
Printf(out,"}\n");
|
|
Setattr(conversions,ckey,convname);
|
|
Delete(ckey);
|
|
|
|
/* 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 = SwigType_manglestr(rk.key);
|
|
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);
|
|
bk = Next(bk);
|
|
}
|
|
rk = Next(rk);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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;
|
|
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 = NewString("");
|
|
types = NewString("");
|
|
Printf(table,"static swig_type_info *swig_types_initial[] = {\n");
|
|
|
|
ki = First(r_mangled);
|
|
Printf(f_forward,"\n/* -------- TYPES TABLE (BEGIN) -------- */\n\n");
|
|
while (ki.key) {
|
|
List *el;
|
|
Iterator ei;
|
|
SwigType *lt;
|
|
SwigType *rt;
|
|
String *nt;
|
|
String *ln;
|
|
String *rn;
|
|
const String *cd;
|
|
|
|
Printf(f_forward,"#define SWIGTYPE%s swig_types[%d] \n", ki.key, i);
|
|
Printv(types,"static swig_type_info _swigt_", ki.key, "[] = {", NIL);
|
|
|
|
cd = SwigType_clientdata_collect(ki.key);
|
|
if (!cd) cd = "0";
|
|
lt = Getattr(r_ltype,ki.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 (Strcmp(ln,rn) == 0) {
|
|
nt = NewStringf("%s", ln);
|
|
} else {
|
|
nt = NewStringf("%s|%s", rn, ln);
|
|
}
|
|
Printv(types,"{\"", ki.key, "\", 0, \"",nt,"\", ", cd, ", 0, 0, 0},", NIL);
|
|
el = SwigType_equivalent_mangle(ki.key,0,0);
|
|
for (ei = First(el); ei.item; ei = Next(ei)) {
|
|
String *ckey;
|
|
String *conv;
|
|
ckey = NewStringf("%s+%s", ei.item, ki.key);
|
|
conv = Getattr(conversions,ckey);
|
|
if (conv) {
|
|
Printf(types,"{\"%s\", %s, 0, 0, 0, 0, 0},", ei.item, conv);
|
|
} else {
|
|
Printf(types,"{\"%s\", 0, 0, 0, 0, 0, 0},", ei.item);
|
|
}
|
|
Delete(ckey);
|
|
}
|
|
Delete(el);
|
|
Delete(nt);
|
|
Delete(rt);
|
|
Printf(types,"{0, 0, 0, 0, 0, 0, 0}};\n");
|
|
Printv(table, "_swigt_", ki.key, ", \n", NIL);
|
|
ki = Next(ki);
|
|
i++;
|
|
}
|
|
|
|
Printf(table, "0\n};\n");
|
|
Printf(f_forward,"static swig_type_info *swig_types[%d];\n", i+1);
|
|
Printf(f_forward,"\n/* -------- TYPES TABLE (END) -------- */\n\n");
|
|
Printf(f_table,"%s\n", types);
|
|
Printf(f_table,"%s\n", table);
|
|
Printf(f_table,"\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */\n\n");
|
|
Delete(types);
|
|
Delete(table);
|
|
}
|