aboutsummaryrefslogtreecommitdiff
path: root/Source/Modules/nested.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Modules/nested.cxx')
-rw-r--r--Source/Modules/nested.cxx444
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);
+}
+