blob: 0fcd5ad182031e9dc9afca2fb0f10356c5337073 [file] [log] [blame]
/* -----------------------------------------------------------------------------
* 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 (!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 it's 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);
}