/* ----------------------------------------------------------------------------- * 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(); int redefined = Swig_need_redefined_warn(n, c, true); if (redefined) { Printf(en, "Identifier '%s' redefined (ignored)", symname); Printf(ec, "previous definition of '%s'", symname); } else { Printf(en, "Redundant redeclaration of '%s'", symname); Printf(ec, "previous declaration of '%s'", symname); } if (Cmp(symname, Getattr(n, "name"))) { Printf(en, " (Renamed from '%s')", SwigType_namestr(Getattr(n, "name"))); } Printf(en, ","); if (Cmp(symname, Getattr(c, "name"))) { Printf(ec, " (Renamed from '%s')", SwigType_namestr(Getattr(c, "name"))); } 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(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); }