swig/Source/Modules/typepass.cxx
Olly Betts 55377bdc08 Add DOH Exit() and SetExitHandler()
Exit() is a wrapper for exit() by default, but SetExitHandler() allows
specifying a function to call instead.

This means that failures within DOH (e.g. Malloc() failing due to lack
of memory) will now perform cleanup such as removing output files.

This commit also cleans up exit statuses so SWIG should now reliably
exit with status 0 if the run was successful and status 1 if there was
an error (or a warning and -Werror was in effect).

Previously in some situations SWIG would try to exit with the status set
to the number of errors encountered, but that's problematic - for
example if there were 256 errors this would result in exit status 0 on
most platforms.  Also some error statuses have special meanings e.g.
those defined by <sysexits.h>.

Also SWIG/Javascript tried to exit with status -1 in a few places (which
typically results in exit status 255).
2022-03-06 12:33:54 +13:00

1308 lines
42 KiB
C++

/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* typepass.cxx
*
* This module builds all of the internal type information by collecting
* typedef declarations as well as registering classes, structures, and unions.
* This information is needed to correctly handle shadow classes and other
* advanced features. This phase of compilation is also used to perform
* type-expansion. All types are fully qualified with namespace prefixes
* and other information needed for compilation.
* ----------------------------------------------------------------------------- */
#include "swigmod.h"
#include "cparse.h"
struct normal_node {
Symtab *symtab;
Hash *typescope;
List *normallist;
normal_node *next;
};
static normal_node *patch_list = 0;
/* Singleton class - all non-static methods in this class are private */
class TypePass:private Dispatcher {
Node *inclass;
Node *module;
int importmode;
String *nsname;
String *nssymname;
Hash *classhash;
List *normalize;
TypePass() :
inclass(0),
module(0),
importmode(0),
nsname(0),
nssymname(0),
classhash(0),
normalize(0) {
}
/* Normalize a type. Replaces type with fully qualified version */
void normalize_type(SwigType *ty) {
SwigType *qty;
if (CPlusPlus) {
Replaceall(ty, "struct ", "");
Replaceall(ty, "union ", "");
Replaceall(ty, "class ", "");
}
qty = SwigType_typedef_qualified(ty);
/* Printf(stdout,"%s --> %s\n", ty, qty); */
Clear(ty);
Append(ty, qty);
Delete(qty);
}
/* Normalize a parameter list */
void normalize_parms(ParmList *p) {
while (p) {
SwigType *ty = Getattr(p, "type");
normalize_type(ty);
/* This is a check for a function type */
{
SwigType *qty = SwigType_typedef_resolve_all(ty);
if (SwigType_isfunction(qty)) {
SwigType_add_pointer(ty);
}
Delete(qty);
}
String *value = Getattr(p, "value");
if (value) {
Node *n = Swig_symbol_clookup(value, 0);
if (n) {
String *q = Swig_symbol_qualified(n);
if (q && Len(q)) {
String *vb = Swig_scopename_last(value);
Clear(value);
Printf(value, "%s::%s", SwigType_namestr(q), vb);
Delete(q);
}
}
}
if (value && SwigType_istemplate(value)) {
String *nv = SwigType_namestr(value);
Setattr(p, "value", nv);
}
p = nextSibling(p);
}
}
void normalize_later(ParmList *p) {
while (p) {
SwigType *ty = Getattr(p, "type");
Append(normalize, ty);
p = nextSibling(p);
}
}
/* Walk through entries in normalize list and patch them up */
void normalize_list() {
Hash *currentsym = Swig_symbol_current();
normal_node *nn = patch_list;
normal_node *np;
while (nn) {
Swig_symbol_setscope(nn->symtab);
SwigType_set_scope(nn->typescope);
Iterator t;
for (t = First(nn->normallist); t.item; t = Next(t)) {
normalize_type(t.item);
}
Delete(nn->normallist);
np = nn->next;
delete(nn);
nn = np;
}
Swig_symbol_setscope(currentsym);
}
/* generate C++ inheritance type-relationships */
void cplus_inherit_types_impl(Node *first, Node *cls, String *clsname, const char *bases, const char *baselist, int ispublic, String *cast = 0) {
if (first == cls)
return; /* The Marcelo check */
if (!cls)
cls = first;
List *alist = 0;
List *ilist = Getattr(cls, bases);
if (!ilist) {
List *nlist = Getattr(cls, baselist);
if (nlist) {
int len = Len(nlist);
int i;
for (i = 0; i < len; i++) {
Node *bcls = 0;
int clsforward = 0;
String *bname = Getitem(nlist, i);
String *sname = bname;
String *tname = 0;
/* Try to locate the base class. We look in the symbol table and we chase
typedef declarations to get to the base class if necessary */
Symtab *st = Getattr(cls, "sym:symtab");
if (SwigType_istemplate(bname)) {
tname = SwigType_typedef_resolve_all(bname);
sname = tname;
}
while (1) {
String *qsname = SwigType_typedef_qualified(sname);
bcls = Swig_symbol_clookup(qsname, st);
Delete(qsname);
if (bcls) {
if (Strcmp(nodeType(bcls), "class") != 0) {
/* Not a class. The symbol could be a typedef. */
if (checkAttribute(bcls, "storage", "typedef")) {
SwigType *decl = Getattr(bcls, "decl");
if (!decl || !(Len(decl))) {
sname = Getattr(bcls, "type");
st = Getattr(bcls, "sym:symtab");
if (SwigType_istemplate(sname)) {
if (tname)
Delete(tname);
tname = SwigType_typedef_resolve_all(sname);
sname = tname;
}
continue;
}
// A case when both outer and nested classes inherit from the same parent. Constructor may be found instead of the class itself.
} else if (GetFlag(cls, "nested") && checkAttribute(bcls, "nodeType", "constructor")) {
bcls = Getattr(bcls, "parentNode");
if (Getattr(bcls, "typepass:visit")) {
if (!Getattr(bcls, "feature:onlychildren")) {
if (!ilist)
ilist = alist = NewList();
Append(ilist, bcls);
} else {
if (!GetFlag(bcls, "feature:ignore")) {
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname));
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname));
}
}
}
break;
}
if (Strcmp(nodeType(bcls), "classforward") != 0) {
Swig_error(Getfile(bname), Getline(bname), "'%s' is not a valid base class.\n", SwigType_namestr(bname));
Swig_error(Getfile(bcls), Getline(bcls), "See definition of '%s'.\n", SwigType_namestr(bname));
} else {
Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bname), Getline(bname), "Base class '%s' is incomplete.\n", SwigType_namestr(bname));
Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname));
clsforward = 1;
}
bcls = 0;
} else {
if (Getattr(bcls, "typepass:visit")) {
if (!Getattr(bcls, "feature:onlychildren")) {
if (!ilist)
ilist = alist = NewList();
Append(ilist, bcls);
} else {
if (!GetFlag(bcls, "feature:ignore")) {
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname));
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname));
}
}
} else {
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' undefined.\n", SwigType_namestr(bname));
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "'%s' must be defined before it is used as a base class.\n", SwigType_namestr(bname));
}
}
}
break;
}
if (tname)
Delete(tname);
if (!bcls) {
if (!clsforward && !GetFlag(cls, "feature:ignore")) {
if (ispublic && !Getmeta(bname, "already_warned")) {
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname));
if (Strchr(bname, '<')) {
Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Maybe you forgot to instantiate '%s' using %%template.\n", SwigType_namestr(bname));
}
Setmeta(bname, "already_warned", "1");
}
}
SwigType_inherit(clsname, bname, cast, 0);
}
}
}
if (ilist) {
Setattr(cls, bases, ilist);
}
}
if (alist)
Delete(alist);
if (!ilist)
return;
int len = Len(ilist);
int i;
for (i = 0; i < len; i++) {
Node *n = Getitem(ilist, i);
String *bname = Getattr(n, "name");
Node *bclass = n; /* Getattr(n,"class"); */
Hash *scopes = Getattr(bclass, "typescope");
SwigType_inherit(clsname, bname, cast, 0);
if (ispublic && !GetFlag(bclass, "feature:ignore")) {
String *smartptr = Getattr(first, "feature:smartptr");
if (smartptr) {
SwigType *smart = Swig_cparse_smartptr(first);
if (smart) {
/* Record a (fake) inheritance relationship between smart pointer
and smart pointer to base class, so that smart pointer upcasts
are automatically generated. */
SwigType *bsmart = Copy(smart);
// TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates
SwigType *rclsname = SwigType_typedef_resolve_all(clsname);
SwigType *rbname = SwigType_typedef_resolve_all(bname);
int replace_count = Replaceall(bsmart, rclsname, rbname);
if (replace_count == 0) {
// If no replacement made, it will be because rclsname is fully resolved, but the
// type in the smartptr feature used a typedef or not fully resolved name.
String *firstname = Getattr(first, "name");
Replaceall(bsmart, firstname, rbname);
}
// The code above currently creates a smartptr of the base class by substitution, replacing Derived
// with Base resulting in something like: 'smartptr< Derived >' from 'smartptr< Base >'. Instead
// the feature:smartptr should be used as it also contains 'smartptr< Base >' as specified by the user.
// A similar fix should also be done in upcastsCode in java.cxx, csharp.cxx and writeClassUpcast in d.cxx.
// Printf(stdout, "smartcomparison %s <=> %s\n", SwigType_namestr(bsmart), Getattr(bclass, "feature:smartptr"));
Delete(rclsname);
Delete(rbname);
String *smartnamestr = SwigType_namestr(smart);
String *bsmartnamestr = SwigType_namestr(bsmart);
/* construct casting code */
String *convcode = NewStringf("\n *newmemory = SWIG_CAST_NEW_MEMORY;\n return (void *) new %s(*(%s *)$from);\n", bsmartnamestr, smartnamestr);
Delete(bsmartnamestr);
Delete(smartnamestr);
/* setup inheritance relationship between smart pointer templates */
SwigType_inherit(smart, bsmart, 0, convcode);
if (!GetFlag(bclass, "feature:smartptr"))
Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Base class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(bclass, "name")), SwigType_namestr(Getattr(first, "name")));
Delete(convcode);
Delete(bsmart);
}
Delete(smart);
} else {
if (GetFlag(bclass, "feature:smartptr"))
Swig_warning(WARN_LANG_SMARTPTR_MISSING, Getfile(first), Getline(first), "Derived class '%s' of '%s' is not similarly marked as a smart pointer.\n", SwigType_namestr(Getattr(first, "name")), SwigType_namestr(Getattr(bclass, "name")));
}
}
if (!importmode) {
String *btype = Copy(bname);
SwigType_add_pointer(btype);
SwigType_remember(btype);
Delete(btype);
}
if (scopes) {
SwigType_inherit_scope(scopes);
}
/* Set up inheritance in the symbol table */
Symtab *st = Getattr(cls, "symtab");
Symtab *bst = Getattr(bclass, "symtab");
if (st == bst) {
Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", SwigType_namestr(Getattr(cls, "name")));
continue;
}
Symtab *s = Swig_symbol_current();
Swig_symbol_setscope(st);
Swig_symbol_inherit(bst);
Swig_symbol_setscope(s);
/* Recursively hit base classes */
String *namestr = SwigType_namestr(Getattr(bclass, "name"));
String *newcast = NewStringf("(%s *)%s", namestr, cast);
Delete(namestr);
cplus_inherit_types_impl(first, bclass, clsname, bases, baselist, ispublic, newcast);
Delete(newcast);
}
}
void append_list(List *lb, List *la) {
if (la && lb) {
for (Iterator bi = First(la); bi.item; bi = Next(bi)) {
Append(lb, bi.item);
}
}
}
void cplus_inherit_types(Node *first, Node *cls, String *clsname, String *cast = 0) {
cplus_inherit_types_impl(first, cls, clsname, "bases", "baselist", 1, cast);
cplus_inherit_types_impl(first, cls, clsname, "protectedbases", "protectedbaselist", 0, cast);
cplus_inherit_types_impl(first, cls, clsname, "privatebases", "privatebaselist", 0, cast);
if (!cls)
cls = first;
List *allbases = NewList();
append_list(allbases, Getattr(cls, "bases"));
append_list(allbases, Getattr(cls, "protectedbases"));
append_list(allbases, Getattr(cls, "privatebases"));
if (Len(allbases)) {
Setattr(cls, "allbases", allbases);
}
Delete(allbases);
}
/* ------------------------------------------------------------
* top()
* ------------------------------------------------------------ */
virtual int top(Node *n) {
importmode = 0;
module = Getattr(n, "module");
inclass = 0;
normalize = 0;
nsname = 0;
nssymname = 0;
classhash = Getattr(n, "classes");
emit_children(n);
normalize_list();
SwigType_set_scope(0);
return SWIG_OK;
}
/* ------------------------------------------------------------
* moduleDirective()
* ------------------------------------------------------------ */
virtual int moduleDirective(Node *n) {
if (!module) {
module = n;
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* importDirective()
* ------------------------------------------------------------ */
virtual int importDirective(Node *n) {
String *oldmodule = module;
int oldimport = importmode;
importmode = 1;
module = 0;
emit_children(n);
importmode = oldimport;
module = oldmodule;
return SWIG_OK;
}
/* ------------------------------------------------------------
* includeDirective()
* externDirective()
* extendDirective()
* ------------------------------------------------------------ */
virtual int includeDirective(Node *n) {
return emit_children(n);
}
virtual int externDeclaration(Node *n) {
return emit_children(n);
}
virtual int extendDirective(Node *n) {
return emit_children(n);
}
/* ------------------------------------------------------------
* classDeclaration()
* ------------------------------------------------------------ */
virtual int classDeclaration(Node *n) {
String *name = Getattr(n, "name");
String *tdname = Getattr(n, "tdname");
String *unnamed = Getattr(n, "unnamed");
String *storage = Getattr(n, "storage");
String *kind = Getattr(n, "kind");
save_value<Node*> oldinclass(inclass);
List *olist = normalize;
Symtab *symtab;
String *nname = 0;
String *fname = 0;
String *scopename = 0;
String *template_default_expanded = 0;
normalize = NewList();
if (name) {
if (SwigType_istemplate(name)) {
// We need to fully resolve the name and expand default template parameters to make templates work correctly */
Node *cn;
SwigType *resolved_name = SwigType_typedef_resolve_all(name);
SwigType *deftype_name = Swig_symbol_template_deftype(resolved_name, 0);
fname = Copy(resolved_name);
if (!Equal(resolved_name, deftype_name))
template_default_expanded = Copy(deftype_name);
if (!Equal(fname, name) && (cn = Swig_symbol_clookup_local(fname, 0))) {
if ((n == cn)
|| (Strcmp(nodeType(cn), "template") == 0)
|| (Getattr(cn, "feature:onlychildren") != 0)
|| (Getattr(n, "feature:onlychildren") != 0)) {
Swig_symbol_cadd(fname, n);
if (template_default_expanded)
Swig_symbol_cadd(template_default_expanded, n);
SwigType_typedef_class(fname);
scopename = Copy(fname);
} else {
Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "Template '%s' was already wrapped,\n", SwigType_namestr(name));
Swig_warning(WARN_TYPE_REDEFINED, Getfile(cn), Getline(cn), "previous wrap of '%s'.\n", SwigType_namestr(Getattr(cn, "name")));
scopename = 0;
}
} else {
Swig_symbol_cadd(fname, n);
SwigType_typedef_class(fname);
scopename = Copy(fname);
}
Delete(deftype_name);
Delete(resolved_name);
} else {
if ((CPlusPlus) || (unnamed)) {
SwigType_typedef_class(name);
} else {
SwigType_typedef_class(NewStringf("%s %s", kind, name));
}
scopename = Copy(name);
}
} else {
scopename = 0;
}
Setattr(n, "typepass:visit", "1");
/* Need to set up a typedef if unnamed */
if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) {
SwigType_typedef(unnamed, tdname);
}
// name of the outer class should already be patched to contain its outer classes names, but not to contain namespaces
// namespace name (if present) is added after processing child nodes
if (Getattr(n, "nested:outer") && name) {
String *outerName = Getattr(Getattr(n, "nested:outer"), "name");
name = NewStringf("%s::%s", outerName, name);
Setattr(n, "name", name);
if (tdname) {
tdname = NewStringf("%s::%s", outerName, tdname);
Setattr(n, "tdname", tdname);
}
}
if (nsname && name) {
nname = NewStringf("%s::%s", nsname, name);
String *tdname = Getattr(n, "tdname");
if (tdname) {
tdname = NewStringf("%s::%s", nsname, tdname);
Setattr(n, "tdname", tdname);
}
}
if (nssymname) {
if (GetFlag(n, "feature:nspace"))
Setattr(n, "sym:nspace", nssymname);
}
SwigType_new_scope(scopename);
SwigType_attach_symtab(Getattr(n, "symtab"));
/* Inherit type definitions into the class */
if (name && !(GetFlag(n, "nested") && !checkAttribute(n, "access", "public") &&
(GetFlag(n, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None))) {
cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name));
}
inclass = n;
symtab = Swig_symbol_setscope(Getattr(n, "symtab"));
emit_children(n);
Swig_symbol_setscope(symtab);
Hash *ts = SwigType_pop_scope();
Setattr(n, "typescope", ts);
Delete(ts);
Setattr(n, "module", module);
// When a fully qualified templated type with default parameters is used in the parsed code,
// the following additional symbols and scopes are needed for successful lookups
if (template_default_expanded) {
Swig_symbol_alias(template_default_expanded, Getattr(n, "symtab"));
SwigType_scope_alias(template_default_expanded, Getattr(n, "typescope"));
}
/* Normalize deferred types */
{
normal_node *nn = new normal_node();
nn->normallist = normalize;
nn->symtab = Getattr(n, "symtab");
nn->next = patch_list;
nn->typescope = Getattr(n, "typescope");
patch_list = nn;
}
normalize = olist;
/* If in a namespace, patch the class name */
if (nname) {
Setattr(n, "name", nname);
Delete(nname);
}
Delete(fname);
return SWIG_OK;
}
/* ------------------------------------------------------------
* templateDeclaration()
* ------------------------------------------------------------ */
virtual int templateDeclaration(Node *n) {
String *name = Getattr(n, "name");
String *ttype = Getattr(n, "templatetype");
if (Strcmp(ttype, "class") == 0) {
String *rname = SwigType_typedef_resolve_all(name);
SwigType_typedef_class(rname);
Delete(rname);
} else if (Strcmp(ttype, "classforward") == 0) {
String *rname = SwigType_typedef_resolve_all(name);
SwigType_typedef_class(rname);
Delete(rname);
/* SwigType_typedef_class(name); */
} else if (Strcmp(ttype, "cdecl") == 0) {
String *rname = SwigType_typedef_resolve_all(name);
SwigType_typedef_class(rname);
Delete(rname);
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* lambdaDeclaration()
* ------------------------------------------------------------ */
virtual int lambdaDeclaration(Node *) {
return SWIG_OK;
}
/* ------------------------------------------------------------
* classforwardDeclaration()
* ------------------------------------------------------------ */
virtual int classforwardDeclaration(Node *n) {
/* Can't do inside a C struct because it breaks C nested structure wrapping */
if ((!inclass) || (CPlusPlus)) {
String *name = Getattr(n, "name");
SwigType_typedef_class(name);
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* namespaceDeclaration()
* ------------------------------------------------------------ */
virtual int namespaceDeclaration(Node *n) {
Symtab *symtab;
String *name = Getattr(n, "name");
String *alias = Getattr(n, "alias");
List *olist = normalize;
normalize = NewList();
if (alias) {
Typetab *ts = Getattr(n, "typescope");
if (!ts) {
/* Create an empty scope for the alias */
Node *ns = Getattr(n, "namespace");
SwigType_scope_alias(name, Getattr(ns, "typescope"));
ts = Getattr(ns, "typescope");
Setattr(n, "typescope", ts);
}
/* Namespace alias */
return SWIG_OK;
} else {
if (name) {
Node *nn = Swig_symbol_clookup(name, n);
Hash *ts = 0;
if (nn)
ts = Getattr(nn, "typescope");
if (!ts) {
SwigType_new_scope(name);
SwigType_attach_symtab(Getattr(n, "symtab"));
} else {
SwigType_set_scope(ts);
}
}
String *oldnsname = nsname;
String *oldnssymname = nssymname;
nsname = Swig_symbol_qualified(Getattr(n, "symtab"));
nssymname = Swig_symbol_qualified_language_scopename(Getattr(n, "symtab"));
symtab = Swig_symbol_setscope(Getattr(n, "symtab"));
emit_children(n);
Swig_symbol_setscope(symtab);
if (name) {
Hash *ts = SwigType_pop_scope();
Setattr(n, "typescope", ts);
Delete(ts);
}
/* Normalize deferred types */
{
normal_node *nn = new normal_node();
nn->normallist = normalize;
nn->symtab = Getattr(n, "symtab");
nn->next = patch_list;
nn->typescope = Getattr(n, "typescope");
patch_list = nn;
}
normalize = olist;
Delete(nssymname);
nssymname = oldnssymname;
Delete(nsname);
nsname = oldnsname;
return SWIG_OK;
}
}
/* ------------------------------------------------------------
* cDeclaration()
* ------------------------------------------------------------ */
virtual int cDeclaration(Node *n) {
if (NoExcept) {
Delattr(n, "throws");
}
/* Normalize types. */
SwigType *ty = Getattr(n, "type");
if (!ty) {
return SWIG_OK;
}
normalize_type(ty);
SwigType *decl = Getattr(n, "decl");
if (decl) {
normalize_type(decl);
}
normalize_parms(Getattr(n, "parms"));
normalize_parms(Getattr(n, "throws"));
if (GetFlag(n, "conversion_operator")) {
/* The call to the operator in the generated wrapper must be fully qualified in order to compile */
SwigType *name = Getattr(n, "name");
SwigType *qualifiedname = Swig_symbol_string_qualify(name, 0);
Clear(name);
Append(name, qualifiedname);
Delete(qualifiedname);
}
if (checkAttribute(n, "storage", "typedef")) {
String *name = Getattr(n, "name");
ty = Getattr(n, "type");
decl = Getattr(n, "decl");
SwigType *t = Copy(ty);
{
/* If the typename is qualified, make sure the scopename is fully qualified when making a typedef */
if (Swig_scopename_check(t) && strncmp(Char(t), "::", 2)) {
String *base, *prefix, *qprefix;
base = Swig_scopename_last(t);
prefix = Swig_scopename_prefix(t);
qprefix = SwigType_typedef_qualified(prefix);
Delete(t);
t = NewStringf("%s::%s", qprefix, base);
Delete(base);
Delete(prefix);
Delete(qprefix);
}
}
SwigType_push(t, decl);
if (CPlusPlus) {
Replaceall(t, "struct ", "");
Replaceall(t, "union ", "");
Replaceall(t, "class ", "");
}
SwigType_typedef(t, name);
}
/* If namespaces are active. We need to patch the name with a namespace prefix */
if (nsname && !inclass) {
String *name = Getattr(n, "name");
if (name) {
String *nname = NewStringf("%s::%s", nsname, name);
Setattr(n, "name", nname);
Delete(nname);
}
}
clean_overloaded(n);
return SWIG_OK;
}
/* ------------------------------------------------------------
* constructorDeclaration()
* ------------------------------------------------------------ */
virtual int constructorDeclaration(Node *n) {
if (NoExcept) {
Delattr(n, "throws");
}
normalize_parms(Getattr(n, "parms"));
normalize_parms(Getattr(n, "throws"));
clean_overloaded(n);
return SWIG_OK;
}
/* ------------------------------------------------------------
* destructorDeclaration()
* ------------------------------------------------------------ */
virtual int destructorDeclaration(Node *) {
return SWIG_OK;
}
/* ------------------------------------------------------------
* constantDirective()
* ------------------------------------------------------------ */
virtual int constantDirective(Node *n) {
SwigType *ty = Getattr(n, "type");
if (ty) {
Setattr(n, "type", SwigType_typedef_qualified(ty));
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* enumDeclaration()
* ------------------------------------------------------------ */
virtual int enumDeclaration(Node *n) {
String *name = Getattr(n, "name");
if (name) {
String *scope = 0;
// Add a typedef to the type table so that we can use 'enum Name' as well as just 'Name'
if (nsname || inclass) {
// But first correct the name and tdname to contain the fully qualified scopename
if (nsname && inclass) {
scope = NewStringf("%s::%s", nsname, Getattr(inclass, "name"));
} else if (nsname) {
scope = NewStringf("%s", nsname);
} else if (inclass) {
scope = NewStringf("%s", Getattr(inclass, "name"));
}
String *nname = NewStringf("%s::%s", scope, name);
Setattr(n, "name", nname);
String *tdname = Getattr(n, "tdname");
if (tdname) {
tdname = NewStringf("%s::%s", scope, tdname);
Setattr(n, "tdname", tdname);
}
SwigType *t = NewStringf("enum %s", nname);
SwigType_typedef(t, name);
} else {
SwigType *t = NewStringf("enum %s", name);
SwigType_typedef(t, name);
}
Delete(scope);
}
String *tdname = Getattr(n, "tdname");
String *unnamed = Getattr(n, "unnamed");
String *storage = Getattr(n, "storage");
// Construct enumtype - for declaring an enum of this type with SwigType_ltype() etc
String *enumtype = 0;
if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) {
enumtype = Copy(Getattr(n, "tdname"));
} else if (name) {
enumtype = NewStringf("%s%s", CPlusPlus ? "" : "enum ", Getattr(n, "name"));
} else {
// anonymous enums
enumtype = Copy(Getattr(n, "type"));
}
Setattr(n, "enumtype", enumtype);
if (nssymname) {
if (GetFlag(n, "feature:nspace"))
Setattr(n, "sym:nspace", nssymname);
}
// This block of code is for dealing with %ignore on an enum item where the target language
// attempts to use the C enum value in the target language itself and expects the previous enum value
// to be one more than the previous value... the previous enum item might not exist if it is ignored!
// - It sets the first non-ignored enum item with the "firstenumitem" attribute.
// - It adds an enumvalue attribute if the previous enum item is ignored
{
Node *c;
int count = 0;
String *previous = 0;
bool previous_ignored = false;
bool firstenumitem = false;
for (c = firstChild(n); c; c = nextSibling(c)) {
assert(strcmp(Char(nodeType(c)), "enumitem") == 0);
bool reset;
String *enumvalue = Getattr(c, "enumvalue");
if (GetFlag(c, "feature:ignore") || !Getattr(c, "sym:name")) {
reset = enumvalue ? true : false;
previous_ignored = true;
} else {
if (!enumvalue && previous_ignored) {
if (previous)
Setattr(c, "enumvalue", NewStringf("(%s) + %d", previous, count+1));
else
Setattr(c, "enumvalue", NewStringf("%d", count));
SetFlag(c, "virtenumvalue"); // identify enumvalue as virtual, ie not from the parsed source
}
if (!firstenumitem) {
SetFlag(c, "firstenumitem");
firstenumitem = true;
}
reset = true;
previous_ignored = false;
}
if (reset) {
previous = enumvalue ? enumvalue : Getattr(c, "name");
count = 0;
} else {
count++;
}
}
}
emit_children(n);
return SWIG_OK;
}
/* ------------------------------------------------------------
* enumvalueDeclaration()
* ------------------------------------------------------------ */
virtual int enumvalueDeclaration(Node *n) {
String *name = Getattr(n, "name");
String *value = Getattr(n, "value");
String *scopedenum = Getattr(parentNode(n), "scopedenum");
if (!value)
value = name;
if (Strcmp(value, name) == 0) {
String *new_value;
if ((nsname || inclass || scopedenum) && cparse_cplusplus) {
new_value = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value);
} else {
new_value = NewString(value);
}
if ((nsname || inclass || scopedenum) && !cparse_cplusplus) {
String *cppvalue = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value);
Setattr(n, "cppvalue", cppvalue); /* for target languages that always generate C++ code even when wrapping C code */
}
Setattr(n, "value", new_value);
Delete(new_value);
}
Node *next = nextSibling(n);
// Make up an enumvalue if one was not specified in the parsed code (not designed to be used on enum items and %ignore - enumvalue will be set instead)
if (!GetFlag(n, "feature:ignore")) {
if (Getattr(n, "_last") && !Getattr(n, "enumvalue")) { // Only the first enum item has _last set (Note: first non-ignored enum item has firstenumitem set)
Setattr(n, "enumvalueex", "0");
}
if (next && !Getattr(next, "enumvalue")) {
Setattr(next, "enumvalueex", NewStringf("%s + 1", Getattr(n, "sym:name")));
}
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* enumforwardDeclaration()
* ------------------------------------------------------------ */
virtual int enumforwardDeclaration(Node *n) {
// Use enumDeclaration() to do all the hard work.
// Note that no children can be emitted in a forward declaration as there aren't any.
int result = enumDeclaration(n);
if (result == SWIG_OK) {
// Detect when the real enum matching the forward enum declaration has not been parsed/declared
SwigType *ty = SwigType_typedef_resolve_all(Getattr(n, "type"));
Replaceall(ty, "enum ", "");
Node *nn = Swig_symbol_clookup(ty, 0);
String *nodetype = nn ? nodeType(nn) : 0;
if (nodetype) {
if (Equal(nodetype, "enumforward")) {
SetFlag(nn, "enumMissing");
} // if a real enum was declared this would be an "enum" node type
}
Delete(ty);
}
return result;
}
#ifdef DEBUG_OVERLOADED
static void show_overloaded(Node *n) {
Node *c = Getattr(n, "sym:overloaded");
Node *checkoverloaded = c;
Printf(stdout, "-------------------- overloaded start %s sym:overloaded():%p -------------------------------\n", Getattr(n, "name"), c);
while (c) {
if (Getattr(c, "error")) {
c = Getattr(c, "sym:nextSibling");
continue;
}
if (Getattr(c, "sym:overloaded") != checkoverloaded) {
Printf(stdout, "sym:overloaded error c:%p checkoverloaded:%p\n", c, checkoverloaded);
Swig_print_node(c);
Exit(EXIT_FAILURE);
}
String *decl = Strcmp(nodeType(c), "using") == 0 ? NewString("------") : Getattr(c, "decl");
Printf(stdout, " show_overloaded %s::%s(%s) [%s] nodeType:%s\n", parentNode(c) ? Getattr(parentNode(c), "name") : "NOPARENT", Getattr(c, "name"), decl, Getattr(c, "sym:overname"), nodeType(c));
if (!Getattr(c, "sym:overloaded")) {
Printf(stdout, "sym:overloaded error.....%p\n", c);
Swig_print_node(c);
Exit(EXIT_FAILURE);
}
c = Getattr(c, "sym:nextSibling");
}
Printf(stdout, "-------------------- overloaded end %s -------------------------------\n", Getattr(n, "name"));
}
#endif
/* ------------------------------------------------------------
* usingDeclaration()
* ------------------------------------------------------------ */
virtual int usingDeclaration(Node *n) {
if (Getattr(n, "namespace")) {
/* using namespace id */
/* For a namespace import. We set up inheritance in the type system */
Node *ns = Getattr(n, "node");
if (ns) {
Typetab *ts = Getattr(ns, "typescope");
if (ts) {
SwigType_using_scope(ts);
}
}
return SWIG_OK;
} else {
Node *ns;
/* using id */
Symtab *stab = Getattr(n, "sym:symtab");
if (stab) {
String *uname = Getattr(n, "uname");
ns = Swig_symbol_clookup(uname, stab);
if (!ns && SwigType_istemplate(uname)) {
String *tmp = Swig_symbol_template_deftype(uname, 0);
if (!Equal(tmp, uname)) {
ns = Swig_symbol_clookup(tmp, stab);
}
Delete(tmp);
}
} else {
ns = 0;
}
if (!ns) {
if (is_public(n)) {
Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname")));
}
} else {
/* Only a single symbol is being used. There are only a few symbols that
we actually care about. These are typedef, class declarations, and enum */
String *ntype = nodeType(ns);
if (Strcmp(ntype, "cdecl") == 0) {
if (checkAttribute(ns, "storage", "typedef")) {
/* A typedef declaration */
String *uname = Getattr(n, "uname");
SwigType_typedef_using(uname);
} else {
/* A normal C declaration. */
if ((inclass) && (!GetFlag(n, "feature:ignore")) && (Getattr(n, "sym:name"))) {
Node *c = ns;
Node *unodes = 0, *last_unodes = 0;
int ccount = 0;
String *symname = Getattr(n, "sym:name");
while (c) {
if (Strcmp(nodeType(c), "cdecl") == 0) {
if (!(Swig_storage_isstatic(c)
|| checkAttribute(c, "storage", "typedef")
|| checkAttribute(c, "storage", "friend")
|| (Getattr(c, "feature:extend") && !Getattr(c, "code"))
|| GetFlag(c, "feature:ignore"))) {
String *csymname = Getattr(c, "sym:name");
if (!csymname || (Strcmp(csymname, symname) == 0)) {
{
String *decl = Getattr(c, "decl");
Node *over = Getattr(n, "sym:overloaded");
int match = 0;
while (over) {
String *odecl = Getattr(over, "decl");
if (Cmp(decl, odecl) == 0) {
match = 1;
break;
}
over = Getattr(over, "sym:nextSibling");
}
if (match) {
/* Don't generate a method if the method is overridden in this class,
* for example don't generate another m(bool) should there be a Base::m(bool) :
* struct Derived : Base {
* void m(bool);
* using Base::m;
* };
*/
c = Getattr(c, "csym:nextSibling");
continue;
}
}
Node *nn = copyNode(c);
Setfile(nn, Getfile(n));
Setline(nn, Getline(n));
Delattr(nn, "access"); // access might be different from the method in the base class
Setattr(nn, "access", Getattr(n, "access"));
if (!Getattr(nn, "sym:name"))
Setattr(nn, "sym:name", symname);
if (!GetFlag(nn, "feature:ignore")) {
ParmList *parms = CopyParmList(Getattr(c, "parms"));
int is_pointer = SwigType_ispointer_return(Getattr(nn, "decl"));
int is_void = checkAttribute(nn, "type", "void") && !is_pointer;
Setattr(nn, "parms", parms);
Delete(parms);
if (Getattr(n, "feature:extend")) {
String *ucode = is_void ? NewStringf("{ self->%s(", Getattr(n, "uname")) : NewStringf("{ return self->%s(", Getattr(n, "uname"));
for (ParmList *p = parms; p;) {
Append(ucode, Getattr(p, "name"));
p = nextSibling(p);
if (p)
Append(ucode, ",");
}
Append(ucode, "); }");
Setattr(nn, "code", ucode);
Delete(ucode);
}
ParmList *throw_parm_list = Getattr(c, "throws");
if (throw_parm_list)
Setattr(nn, "throws", CopyParmList(throw_parm_list));
ccount++;
if (!last_unodes) {
last_unodes = nn;
unodes = nn;
} else {
Setattr(nn, "previousSibling", last_unodes);
Setattr(last_unodes, "nextSibling", nn);
Setattr(nn, "sym:previousSibling", last_unodes);
Setattr(last_unodes, "sym:nextSibling", nn);
Setattr(nn, "sym:overloaded", unodes);
Setattr(unodes, "sym:overloaded", unodes);
last_unodes = nn;
}
} else {
Delete(nn);
}
} else {
Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(n), Getline(n), "Using declaration %s, with name '%s', is not actually using\n", SwigType_namestr(Getattr(n, "uname")), symname);
Swig_warning(WARN_LANG_USING_NAME_DIFFERENT, Getfile(c), Getline(c), "the method from %s, with name '%s', as the names are different.\n", Swig_name_decl(c), csymname);
}
}
}
c = Getattr(c, "csym:nextSibling");
}
if (unodes) {
set_firstChild(n, unodes);
if (ccount > 1) {
if (!Getattr(n, "sym:overloaded")) {
Setattr(n, "sym:overloaded", n);
Setattr(n, "sym:overname", "_SWIG_0");
}
}
}
/* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the
* list of overloaded methods we have just added in as child nodes to the "using" node.
* The node will still exist, it is just the symbol table linked list of overloaded methods
* which is hacked. */
if (Getattr(n, "sym:overloaded")) {
int cnt = 0;
#ifdef DEBUG_OVERLOADED
Node *debugnode = n;
show_overloaded(n);
#endif
if (!firstChild(n)) {
// Remove from overloaded list ('using' node does not actually end up adding in any methods)
Node *ps = Getattr(n, "sym:previousSibling");
Node *ns = Getattr(n, "sym:nextSibling");
if (ps) {
Setattr(ps, "sym:nextSibling", ns);
}
if (ns) {
Setattr(ns, "sym:previousSibling", ps);
}
} else {
// The 'using' node results in methods being added in - slot in the these methods here
Node *ps = Getattr(n, "sym:previousSibling");
Node *ns = Getattr(n, "sym:nextSibling");
Node *fc = firstChild(n);
Node *pp = fc;
Node *firstoverloaded = Getattr(n, "sym:overloaded");
if (firstoverloaded == n) {
// This 'using' node we are cutting out was the first node in the overloaded list.
// Change the first node in the list to its first sibling
Delattr(firstoverloaded, "sym:overloaded");
Node *nnn = Getattr(firstoverloaded, "sym:nextSibling");
firstoverloaded = fc;
while (nnn) {
Setattr(nnn, "sym:overloaded", firstoverloaded);
nnn = Getattr(nnn, "sym:nextSibling");
}
}
while (pp) {
Node *ppn = Getattr(pp, "sym:nextSibling");
Setattr(pp, "sym:overloaded", firstoverloaded);
Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++));
if (ppn)
pp = ppn;
else
break;
}
if (ps) {
Setattr(ps, "sym:nextSibling", fc);
Setattr(fc, "sym:previousSibling", ps);
}
if (ns) {
Setattr(ns, "sym:previousSibling", pp);
Setattr(pp, "sym:nextSibling", ns);
}
#ifdef DEBUG_OVERLOADED
debugnode = firstoverloaded;
#endif
}
Delattr(n, "sym:previousSibling");
Delattr(n, "sym:nextSibling");
Delattr(n, "sym:overloaded");
Delattr(n, "sym:overname");
#ifdef DEBUG_OVERLOADED
show_overloaded(debugnode);
#endif
clean_overloaded(n); // Needed?
}
}
}
} else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) {
/* We install the using class name as kind of a typedef back to the original class */
String *uname = Getattr(n, "uname");
/* Import into current type scope */
SwigType_typedef_using(uname);
} else if (Strcmp(ntype, "enum") == 0) {
SwigType_typedef_using(Getattr(n, "uname"));
} else if (Strcmp(ntype, "template") == 0) {
SwigType_typedef_using(Getattr(n, "uname"));
}
}
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* typemapDirective()
* ------------------------------------------------------------ */
virtual int typemapDirective(Node *n) {
if (inclass || nsname) {
Node *items = firstChild(n);
while (items) {
Parm *pattern = Getattr(items, "pattern");
Parm *parms = Getattr(items, "parms");
normalize_later(pattern);
normalize_later(parms);
items = nextSibling(items);
}
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* typemapcopyDirective()
* ------------------------------------------------------------ */
virtual int typemapcopyDirective(Node *n) {
if (inclass || nsname) {
Node *items = firstChild(n);
ParmList *pattern = Getattr(n, "pattern");
normalize_later(pattern);
while (items) {
ParmList *npattern = Getattr(items, "pattern");
normalize_later(npattern);
items = nextSibling(items);
}
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* applyDirective()
* ------------------------------------------------------------ */
virtual int applyDirective(Node *n) {
if (inclass || nsname) {
ParmList *pattern = Getattr(n, "pattern");
normalize_later(pattern);
Node *items = firstChild(n);
while (items) {
Parm *apattern = Getattr(items, "pattern");
normalize_later(apattern);
items = nextSibling(items);
}
}
return SWIG_OK;
}
/* ------------------------------------------------------------
* clearDirective()
* ------------------------------------------------------------ */
virtual int clearDirective(Node *n) {
if (inclass || nsname) {
Node *p;
for (p = firstChild(n); p; p = nextSibling(p)) {
ParmList *pattern = Getattr(p, "pattern");
normalize_later(pattern);
}
}
return SWIG_OK;
}
public:
static void pass(Node *n) {
TypePass t;
t.top(n);
}
};
void Swig_process_types(Node *n) {
if (!n)
return;
TypePass::pass(n);
}