mirror of https://github.com/swig/swig
464 lines
13 KiB
C++
464 lines
13 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 https://www.swig.org/legal.html.
|
|
*
|
|
* nested.cxx
|
|
*
|
|
* Nested structs support
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "swigmod.h"
|
|
#include "cparse.h"
|
|
|
|
// Nested classes processing section
|
|
static Hash *classhash = 0;
|
|
|
|
static String *make_name(Node *n, String *name, SwigType *decl) {
|
|
int destructor = name && (*(Char(name)) == '~');
|
|
if (String *yyrename = Getattr(n, "class_rename")) {
|
|
String *s = NewString(yyrename);
|
|
Delattr(n, "class_rename");
|
|
if (destructor && (*(Char(s)) != '~')) {
|
|
Insert(s, 0, "~");
|
|
}
|
|
return s;
|
|
}
|
|
|
|
if (!name)
|
|
return 0;
|
|
return Swig_name_make(n, 0, name, decl, 0);
|
|
}
|
|
|
|
// C version of add_symbols()
|
|
static void add_symbols_c(Node *n) {
|
|
String *decl;
|
|
String *wrn = 0;
|
|
String *symname = 0;
|
|
int iscdecl = Cmp(nodeType(n), "cdecl") == 0;
|
|
Setattr(n, "ismember", "1");
|
|
Setattr(n, "access", "public");
|
|
if (Getattr(n, "sym:name"))
|
|
return;
|
|
decl = Getattr(n, "decl");
|
|
if (!SwigType_isfunction(decl)) {
|
|
String *name = Getattr(n, "name");
|
|
String *makename = Getattr(n, "parser:makename");
|
|
if (iscdecl) {
|
|
String *storage = Getattr(n, "storage");
|
|
if (Cmp(storage, "typedef") == 0) {
|
|
Setattr(n, "kind", "typedef");
|
|
} else {
|
|
SwigType *type = Getattr(n, "type");
|
|
String *value = Getattr(n, "value");
|
|
Setattr(n, "kind", "variable");
|
|
if (value && Len(value)) {
|
|
Setattr(n, "hasvalue", "1");
|
|
}
|
|
if (type) {
|
|
SwigType *ty;
|
|
SwigType *tmp = 0;
|
|
if (decl) {
|
|
ty = tmp = Copy(type);
|
|
SwigType_push(ty, decl);
|
|
} else {
|
|
ty = type;
|
|
}
|
|
if (!SwigType_ismutable(ty)) {
|
|
SetFlag(n, "hasconsttype");
|
|
SetFlag(n, "feature:immutable");
|
|
}
|
|
if (tmp)
|
|
Delete(tmp);
|
|
}
|
|
if (!type) {
|
|
Printf(stderr, "notype name %s\n", name);
|
|
}
|
|
}
|
|
}
|
|
Swig_features_get(Swig_cparse_features(), 0, name, 0, n);
|
|
if (makename) {
|
|
symname = make_name(n, makename, 0);
|
|
Delattr(n, "parser:makename"); /* temporary information, don't leave it hanging around */
|
|
} else {
|
|
makename = name;
|
|
symname = make_name(n, makename, 0);
|
|
}
|
|
|
|
if (!symname) {
|
|
symname = Copy(Getattr(n, "unnamed"));
|
|
}
|
|
if (symname) {
|
|
wrn = Swig_name_warning(n, 0, symname, 0);
|
|
}
|
|
} else {
|
|
String *name = Getattr(n, "name");
|
|
SwigType *fdecl = Copy(decl);
|
|
SwigType *fun = SwigType_pop_function(fdecl);
|
|
if (iscdecl) {
|
|
Setattr(n, "kind", "function");
|
|
}
|
|
|
|
Swig_features_get(Swig_cparse_features(), 0, name, fun, n);
|
|
|
|
symname = make_name(n, name, fun);
|
|
wrn = Swig_name_warning(n, 0, symname, fun);
|
|
|
|
Delete(fdecl);
|
|
Delete(fun);
|
|
|
|
}
|
|
if (!symname)
|
|
return;
|
|
if (GetFlag(n, "feature:ignore")) {
|
|
/* Only add to C symbol table and continue */
|
|
Swig_symbol_add(0, n);
|
|
} else if (strncmp(Char(symname), "$ignore", 7) == 0) {
|
|
char *c = Char(symname) + 7;
|
|
SetFlag(n, "feature:ignore");
|
|
if (strlen(c)) {
|
|
SWIG_WARN_NODE_BEGIN(n);
|
|
Swig_warning(0, Getfile(n), Getline(n), "%s\n", c + 1);
|
|
SWIG_WARN_NODE_END(n);
|
|
}
|
|
Swig_symbol_add(0, n);
|
|
} else {
|
|
Node *c;
|
|
if ((wrn) && (Len(wrn))) {
|
|
String *metaname = symname;
|
|
if (!Getmeta(metaname, "already_warned")) {
|
|
SWIG_WARN_NODE_BEGIN(n);
|
|
Swig_warning(0, Getfile(n), Getline(n), "%s\n", wrn);
|
|
SWIG_WARN_NODE_END(n);
|
|
Setmeta(metaname, "already_warned", "1");
|
|
}
|
|
}
|
|
c = Swig_symbol_add(symname, n);
|
|
|
|
if (c != n) {
|
|
/* symbol conflict attempting to add in the new symbol */
|
|
if (Getattr(n, "sym:weak")) {
|
|
Setattr(n, "sym:name", symname);
|
|
} else {
|
|
String *e = NewStringEmpty();
|
|
String *en = NewStringEmpty();
|
|
String *ec = NewStringEmpty();
|
|
String *symname_stripped = SwigType_templateprefix(symname);
|
|
String *n_name_stripped = SwigType_templateprefix(Getattr(n, "name"));
|
|
String *c_name_stripped = SwigType_templateprefix(Getattr(c, "name"));
|
|
int redefined = Swig_need_redefined_warn(n, c, true);
|
|
String *n_name_decl = Swig_name_decl(n);
|
|
String *c_name_decl = Swig_name_decl(c);
|
|
if (redefined) {
|
|
Printf(en, "Redefinition of identifier '%s' (ignored) as %s", symname_stripped, n_name_decl);
|
|
Printf(ec, "previous definition of '%s' as %s", symname_stripped, c_name_decl);
|
|
} else {
|
|
Printf(en, "Redundant redeclaration of identifier '%s' as %s", symname_stripped, n_name_decl);
|
|
Printf(ec, "previous declaration of '%s' as %s", symname_stripped, c_name_decl);
|
|
}
|
|
if (!Equal(symname_stripped, n_name_stripped)) {
|
|
Printf(en, " (Renamed from '%s')", SwigType_namestr(n_name_stripped));
|
|
}
|
|
Printf(en, ",");
|
|
if (!Equal(symname_stripped, c_name_stripped)) {
|
|
Printf(ec, " (Renamed from '%s')", SwigType_namestr(c_name_stripped));
|
|
}
|
|
Printf(ec, ".");
|
|
SWIG_WARN_NODE_BEGIN(n);
|
|
if (redefined) {
|
|
Swig_warning(WARN_PARSE_REDEFINED, Getfile(n), Getline(n), "%s\n", en);
|
|
Swig_warning(WARN_PARSE_REDEFINED, Getfile(c), Getline(c), "%s\n", ec);
|
|
} else {
|
|
Swig_warning(WARN_PARSE_REDUNDANT, Getfile(n), Getline(n), "%s\n", en);
|
|
Swig_warning(WARN_PARSE_REDUNDANT, Getfile(c), Getline(c), "%s\n", ec);
|
|
}
|
|
SWIG_WARN_NODE_END(n);
|
|
Printf(e, "%s:%d:%s\n%s:%d:%s\n", Getfile(n), Getline(n), en, Getfile(c), Getline(c), ec);
|
|
Setattr(n, "error", e);
|
|
Delete(c_name_decl);
|
|
Delete(n_name_decl);
|
|
Delete(symname_stripped);
|
|
Delete(c_name_stripped);
|
|
Delete(n_name_stripped);
|
|
Delete(e);
|
|
Delete(en);
|
|
Delete(ec);
|
|
}
|
|
}
|
|
}
|
|
Delete(symname);
|
|
}
|
|
|
|
/* Strips C-style and C++-style comments from string in-place. */
|
|
static void strip_comments(char *string) {
|
|
int state = 0;
|
|
/*
|
|
* 0 - not in comment
|
|
* 1 - in c-style comment
|
|
* 2 - in c++-style comment
|
|
* 3 - in string
|
|
* 4 - after reading / not in comments
|
|
* 5 - after reading * in c-style comments
|
|
* 6 - after reading \ in strings
|
|
*/
|
|
char *c = string;
|
|
while (*c) {
|
|
switch (state) {
|
|
case 0:
|
|
if (*c == '\"')
|
|
state = 3;
|
|
else if (*c == '/')
|
|
state = 4;
|
|
break;
|
|
case 1:
|
|
if (*c == '*')
|
|
state = 5;
|
|
*c = ' ';
|
|
break;
|
|
case 2:
|
|
if (*c == '\n')
|
|
state = 0;
|
|
else
|
|
*c = ' ';
|
|
break;
|
|
case 3:
|
|
if (*c == '\"')
|
|
state = 0;
|
|
else if (*c == '\\')
|
|
state = 6;
|
|
break;
|
|
case 4:
|
|
if (*c == '/') {
|
|
*(c - 1) = ' ';
|
|
*c = ' ';
|
|
state = 2;
|
|
} else if (*c == '*') {
|
|
*(c - 1) = ' ';
|
|
*c = ' ';
|
|
state = 1;
|
|
} else
|
|
state = 0;
|
|
break;
|
|
case 5:
|
|
if (*c == '/')
|
|
state = 0;
|
|
else
|
|
state = 1;
|
|
*c = ' ';
|
|
break;
|
|
case 6:
|
|
state = 3;
|
|
break;
|
|
}
|
|
++c;
|
|
}
|
|
}
|
|
|
|
// Create a %insert with a typedef to make a new name visible to C
|
|
static Node *create_insert(Node *n, bool noTypedef = false) {
|
|
// format a typedef
|
|
String *ccode = Getattr(n, "code");
|
|
Push(ccode, " ");
|
|
if (noTypedef) {
|
|
Push(ccode, Getattr(n, "name"));
|
|
Push(ccode, " ");
|
|
Push(ccode, Getattr(n, "kind"));
|
|
} else {
|
|
Push(ccode, Getattr(n, "kind"));
|
|
Push(ccode, "typedef ");
|
|
Append(ccode, " ");
|
|
Append(ccode, Getattr(n, "tdname"));
|
|
}
|
|
Append(ccode, ";");
|
|
|
|
/* Strip comments - further code may break in presence of comments. */
|
|
strip_comments(Char(ccode));
|
|
|
|
/* Make all SWIG created typedef structs/unions/classes unnamed else
|
|
redefinition errors occur - nasty hack alert. */
|
|
if (!noTypedef) {
|
|
const char *types_array[3] = { "struct", "union", "class" };
|
|
for (int i = 0; i < 3; i++) {
|
|
char *code_ptr = Char(ccode);
|
|
while (code_ptr) {
|
|
/* Replace struct name (as in 'struct name {...}' ) with whitespace
|
|
name will be between struct and opening brace */
|
|
|
|
code_ptr = strstr(code_ptr, types_array[i]);
|
|
if (code_ptr) {
|
|
char *open_bracket_pos;
|
|
code_ptr += strlen(types_array[i]);
|
|
open_bracket_pos = strchr(code_ptr, '{');
|
|
if (open_bracket_pos) {
|
|
/* Make sure we don't have something like struct A a; */
|
|
char *semi_colon_pos = strchr(code_ptr, ';');
|
|
if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos)))
|
|
while (code_ptr < open_bracket_pos)
|
|
*code_ptr++ = ' ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{
|
|
/* Remove SWIG directive %constant which may be left in the SWIG created typedefs */
|
|
char *code_ptr = Char(ccode);
|
|
while (code_ptr) {
|
|
code_ptr = strstr(code_ptr, "%constant");
|
|
if (code_ptr) {
|
|
char *directive_end_pos = strchr(code_ptr, ';');
|
|
if (directive_end_pos) {
|
|
while (code_ptr <= directive_end_pos)
|
|
*code_ptr++ = ' ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Node *newnode = NewHash();
|
|
set_nodeType(newnode, "insert");
|
|
Setfile(newnode, Getfile(n));
|
|
Setline(newnode, Getline(n));
|
|
String *code = NewStringEmpty();
|
|
Wrapper_pretty_print(ccode, code);
|
|
Setattr(newnode, "code", code);
|
|
Delete(code);
|
|
Delattr(n, "code");
|
|
return newnode;
|
|
}
|
|
|
|
static void insertNodeAfter(Node *n, Node *c) {
|
|
Node *g = parentNode(n);
|
|
set_parentNode(c, g);
|
|
Node *ns = nextSibling(n);
|
|
if (Node *outer = Getattr(c, "nested:outer")) {
|
|
while (ns && outer == Getattr(ns, "nested:outer")) {
|
|
n = ns;
|
|
ns = nextSibling(n);
|
|
}
|
|
}
|
|
if (!ns) {
|
|
set_lastChild(g, c);
|
|
} else {
|
|
set_nextSibling(c, ns);
|
|
set_previousSibling(ns, c);
|
|
}
|
|
set_nextSibling(n, c);
|
|
set_previousSibling(c, n);
|
|
}
|
|
|
|
void Swig_nested_name_unnamed_c_structs(Node *n) {
|
|
if (!n)
|
|
return;
|
|
if (!classhash)
|
|
classhash = Getattr(n, "classes");
|
|
Node *c = firstChild(n);
|
|
while (c) {
|
|
Node *next = nextSibling(c);
|
|
if (String *declName = Getattr(c, "nested:unnamed")) {
|
|
if (Node *outer = Getattr(c, "nested:outer")) {
|
|
// generate a name
|
|
String *name = NewStringf("%s_%s", Getattr(outer, "name"), declName);
|
|
Delattr(c, "nested:unnamed");
|
|
// set the name to the class and symbol table
|
|
Setattr(c, "tdname", name);
|
|
Setattr(c, "name", name);
|
|
Swig_symbol_setscope(Getattr(c, "symtab"));
|
|
Swig_symbol_setscopename(name);
|
|
// now that we have a name - gather base symbols
|
|
if (List *publicBases = Getattr(c, "baselist")) {
|
|
List *bases = Swig_make_inherit_list(name, publicBases, 0);
|
|
Swig_inherit_base_symbols(bases);
|
|
Delete(bases);
|
|
}
|
|
Setattr(classhash, name, c);
|
|
|
|
// Merge the extension into the symbol table
|
|
if (Node *am = Getattr(Swig_extend_hash(), name)) {
|
|
Swig_extend_merge(c, am);
|
|
Swig_extend_append_previous(c, am);
|
|
Delattr(Swig_extend_hash(), name);
|
|
}
|
|
Swig_symbol_popscope();
|
|
|
|
// process declarations following this type (assign correct new type)
|
|
SwigType *ty = Copy(name);
|
|
Node *decl = nextSibling(c);
|
|
List *declList = NewList();
|
|
while (decl && Getattr(decl, "nested:unnamedtype") == c) {
|
|
Setattr(decl, "type", ty);
|
|
Append(declList, decl);
|
|
Delattr(decl, "nested:unnamedtype");
|
|
SetFlag(decl, "feature:immutable");
|
|
add_symbols_c(decl);
|
|
decl = nextSibling(decl);
|
|
}
|
|
Delete(ty);
|
|
Swig_symbol_setscope(Swig_symbol_global_scope());
|
|
add_symbols_c(c);
|
|
|
|
Node *ins = create_insert(c);
|
|
insertNodeAfter(c, ins);
|
|
removeNode(c);
|
|
insertNodeAfter(n, c);
|
|
Delete(ins);
|
|
Delattr(c, "nested:outer");
|
|
} else {
|
|
// global unnamed struct - ignore it and its instances
|
|
SetFlag(c, "feature:ignore");
|
|
while (next && Getattr(next, "nested:unnamedtype") == c) {
|
|
SetFlag(next, "feature:ignore");
|
|
next = nextSibling(next);
|
|
}
|
|
c = next;
|
|
continue;
|
|
}
|
|
} else if (cparse_cplusplusout) {
|
|
if (Getattr(c, "nested:outer")) {
|
|
Node *ins = create_insert(c, true);
|
|
insertNodeAfter(c, ins);
|
|
Delete(ins);
|
|
Delattr(c, "nested:outer");
|
|
}
|
|
}
|
|
// process children
|
|
Swig_nested_name_unnamed_c_structs(c);
|
|
c = next;
|
|
}
|
|
}
|
|
|
|
static void remove_outer_class_reference(Node *n) {
|
|
for (Node *c = firstChild(n); c; c = nextSibling(c)) {
|
|
if (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None) {
|
|
Delattr(c, "nested:outer");
|
|
remove_outer_class_reference(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Swig_nested_process_classes(Node *n) {
|
|
if (!n)
|
|
return;
|
|
Node *c = firstChild(n);
|
|
while (c) {
|
|
Node *next = nextSibling(c);
|
|
if (!Getattr(c, "templatetype")) {
|
|
if (GetFlag(c, "nested") && (GetFlag(c, "feature:flatnested") || Language::instance()->nestedClassesSupport() == Language::NCS_None)) {
|
|
removeNode(c);
|
|
if (!checkAttribute(c, "access", "public"))
|
|
SetFlag(c, "feature:ignore");
|
|
else if (Strcmp(nodeType(n),"extend") == 0 && Strcmp(nodeType(parentNode(n)),"class") == 0)
|
|
insertNodeAfter(parentNode(n), c);
|
|
else
|
|
insertNodeAfter(n, c);
|
|
}
|
|
Swig_nested_process_classes(c);
|
|
}
|
|
c = next;
|
|
}
|
|
remove_outer_class_reference(n);
|
|
}
|
|
|