diff options
Diffstat (limited to 'Source/Modules/nested.cxx')
-rw-r--r-- | Source/Modules/nested.cxx | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/Source/Modules/nested.cxx b/Source/Modules/nested.cxx new file mode 100644 index 000000000..a62a9e9da --- /dev/null +++ b/Source/Modules/nested.cxx @@ -0,0 +1,444 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * 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 (!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); + 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); + // Check for extensions +/* // TODO: we can save extensions hash like class hash and move check_extensions() after nesting processing + if (extendhash) { + if (Node *am = Getattr(extendhash, name)) { + // Merge the extension into the symbol table + merge_extensions(c, am); + append_previous_extension(c, am); + Delattr(extendhash, clsname); + } + }*/ + 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 + 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")) { + Delattr(c, "nested:outer"); + remove_outer_class_reference(c); + } + } +} + +void Swig_nested_process_classes(Node *n) { + Node *c = firstChild(n); + while (c) { + Node *next = nextSibling(c); + if (!Getattr(c, "templatetype")) { + if (GetFlag(c, "nested") && GetFlag(c, "feature:flatnested")) { + removeNode(c); + if (!checkAttribute(c, "access", "public")) + SetFlag(c, "feature:ignore"); + else + insertNodeAfter(n, c); + } + Swig_nested_process_classes(c); + } + c = next; + } + remove_outer_class_reference(n); +} + |