diff --git a/Source/CParse/cparse.h b/Source/CParse/cparse.h index 6d7342a45..5a0d52d23 100644 --- a/Source/CParse/cparse.h +++ b/Source/CParse/cparse.h @@ -59,7 +59,7 @@ extern "C" { extern void cparse_normalize_void(Node *); extern Parm *Swig_cparse_parm(String *s); extern ParmList *Swig_cparse_parms(String *s, Node *file_line_node); - + extern Node *new_node(const_String_or_char_ptr tag); /* templ.c */ extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope); diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index a1a62cb62..4ce8f0e6d 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -41,7 +41,6 @@ int yyparse(); static Node *top = 0; /* Top of the generated parse tree */ static int unnamed = 0; /* Unnamed datatype counter */ -Hash *extendhash = 0; /* Hash table of added methods */ static Hash *classes = 0; /* Hash table of classes */ static Hash *classes_typedefs = 0; /* Hash table of typedef classes: typedef struct X {...} Y; */ static Symtab *prev_symtab = 0; @@ -71,14 +70,6 @@ static void yyerror (const char *e) { (void)e; } -static Node *new_node(const_String_or_char_ptr tag) { - Node *n = NewHash(); - set_nodeType(n,tag); - Setfile(n,cparse_file); - Setline(n,cparse_line); - return n; -} - /* Copies a node. Does not copy tree links or symbol table data (except for sym:name) */ @@ -650,106 +641,6 @@ static void add_symbols_copy(Node *n) { } } -/* Extension merge. This function is used to handle the %extend directive - when it appears before a class definition. To handle this, the %extend - actually needs to take precedence. Therefore, we will selectively nuke symbols - from the current symbol table, replacing them with the added methods */ - -void merge_extensions(Node *cls, Node *am) { - Node *n; - Node *csym; - - n = firstChild(am); - while (n) { - String *symname; - if (Strcmp(nodeType(n),"constructor") == 0) { - symname = Getattr(n,"sym:name"); - if (symname) { - if (Strcmp(symname,Getattr(n,"name")) == 0) { - /* If the name and the sym:name of a constructor are the same, - then it hasn't been renamed. However---the name of the class - itself might have been renamed so we need to do a consistency - check here */ - if (Getattr(cls,"sym:name")) { - Setattr(n,"sym:name", Getattr(cls,"sym:name")); - } - } - } - } - - symname = Getattr(n,"sym:name"); - DohIncref(symname); - if ((symname) && (!Getattr(n,"error"))) { - /* Remove node from its symbol table */ - Swig_symbol_remove(n); - csym = Swig_symbol_add(symname,n); - if (csym != n) { - /* Conflict with previous definition. Nuke previous definition */ - String *e = NewStringEmpty(); - String *en = NewStringEmpty(); - String *ec = NewStringEmpty(); - Printf(ec,"Identifier '%s' redefined by %%extend (ignored),",symname); - Printf(en,"%%extend definition of '%s'.",symname); - SWIG_WARN_NODE_BEGIN(n); - Swig_warning(WARN_PARSE_REDEFINED,Getfile(csym),Getline(csym),"%s\n",ec); - Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); - SWIG_WARN_NODE_END(n); - Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(csym),Getline(csym),ec, - Getfile(n),Getline(n),en); - Setattr(csym,"error",e); - Delete(e); - Delete(en); - Delete(ec); - Swig_symbol_remove(csym); /* Remove class definition */ - Swig_symbol_add(symname,n); /* Insert extend definition */ - } - } - n = nextSibling(n); - } -} - -void append_previous_extension(Node *cls, Node *am) { - Node *n, *ne; - Node *pe = 0; - Node *ae = 0; - - if (!am) return; - - n = firstChild(am); - while (n) { - ne = nextSibling(n); - set_nextSibling(n,0); - /* typemaps and fragments need to be prepended */ - if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) { - if (!pe) pe = new_node("extend"); - appendChild(pe, n); - } else { - if (!ae) ae = new_node("extend"); - appendChild(ae, n); - } - n = ne; - } - if (pe) prependChild(cls,pe); - if (ae) appendChild(cls,ae); -} - - -/* Check for unused %extend. Special case, don't report unused - extensions for templates */ - -void check_extensions() { - Iterator ki; - - if (!extendhash) return; - for (ki = First(extendhash); ki.key; ki = Next(ki)) { - if (!Strchr(ki.key,'<')) { - SWIG_WARN_NODE_BEGIN(ki.item); - Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", SwigType_namestr(ki.key)); - SWIG_WARN_NODE_END(ki.item); - } - } -} - /* Check a set of declarations to see if any are pure-abstract */ static List *pure_abstracts(Node *n) { @@ -1682,14 +1573,13 @@ extend_directive : EXTEND options idcolon LBRACE { cplus_mode = CPLUS_PUBLIC; if (!classes) classes = NewHash(); if (!classes_typedefs) classes_typedefs = NewHash(); - if (!extendhash) extendhash = NewHash(); clsname = make_class_name($3); cls = Getattr(classes,clsname); if (!cls) { cls = Getattr(classes_typedefs, clsname); if (!cls) { /* No previous definition. Create a new scope */ - Node *am = Getattr(extendhash,clsname); + Node *am = Getattr(Swig_extend_hash(),clsname); if (!am) { Swig_symbol_newscope(); Swig_symbol_setscopename($3); @@ -1735,13 +1625,13 @@ extend_directive : EXTEND options idcolon LBRACE { appendChild(current_class,$$); } else { /* We store the extensions in the extensions hash */ - Node *am = Getattr(extendhash,clsname); + Node *am = Getattr(Swig_extend_hash(),clsname); if (am) { /* Append the members to the previous extend methods */ appendChild(am,$6); } else { appendChild($$,$6); - Setattr(extendhash,clsname,$$); + Setattr(Swig_extend_hash(),clsname,$$); } } current_class = 0; @@ -2824,8 +2714,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va /* !!! This may be broken. We may have to add the %extend methods at the beginning of the class */ - - if (extendhash) { + { String *stmp = 0; String *clsname; Node *am; @@ -2834,32 +2723,32 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va } else { clsname = Getattr(templnode,"name"); } - am = Getattr(extendhash,clsname); + am = Getattr(Swig_extend_hash(),clsname); if (am) { Symtab *st = Swig_symbol_current(); Swig_symbol_setscope(Getattr(templnode,"symtab")); /* Printf(stdout,"%s: %s %p %p\n", Getattr(templnode,"name"), clsname, Swig_symbol_current(), Getattr(templnode,"symtab")); */ - merge_extensions(templnode,am); + Swig_extend_merge(templnode,am); Swig_symbol_setscope(st); - append_previous_extension(templnode,am); - Delattr(extendhash,clsname); + Swig_extend_append_previous(templnode,am); + Delattr(Swig_extend_hash(),clsname); } if (stmp) Delete(stmp); } - /* Add to classes hash */ - if (!classes) classes = NewHash(); - { - if (Namespaceprefix) { - String *temp = NewStringf("%s::%s", Namespaceprefix, Getattr(templnode,"name")); - Setattr(classes,temp,templnode); - Delete(temp); - } else { - String *qs = Swig_symbol_qualifiedscopename(templnode); - Setattr(classes, qs,templnode); - Delete(qs); - } - } + /* Add to classes hash */ + if (!classes) + classes = NewHash(); + + if (Namespaceprefix) { + String *temp = NewStringf("%s::%s", Namespaceprefix, Getattr(templnode,"name")); + Setattr(classes,temp,templnode); + Delete(temp); + } else { + String *qs = Swig_symbol_qualifiedscopename(templnode); + Setattr(classes, qs,templnode); + Delete(qs); + } } } @@ -3571,13 +3460,12 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { Setattr($$,"abstracts", pure_abstracts($7)); /* This bit of code merges in a previously defined %extend directive (if any) */ - - if (extendhash) { + { String *clsname = Swig_symbol_qualifiedscopename(0); - am = Getattr(extendhash, clsname); + am = Getattr(Swig_extend_hash(), clsname); if (am) { - merge_extensions($$, am); - Delattr(extendhash, clsname); + Swig_extend_merge($$, am); + Delattr(Swig_extend_hash(), clsname); } Delete(clsname); } @@ -3588,7 +3476,7 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { appendChild($$, $7); if (am) - append_previous_extension($$, am); + Swig_extend_append_previous($$, am); p = $9; if (p && !nscope_inner) { @@ -3787,15 +3675,16 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { n = nextSibling(n); } n = $8; - /* Check for previous extensions */ - if (extendhash) { + + /* Check for previous extensions */ + { String *clsname = Swig_symbol_qualifiedscopename(0); - Node *am = Getattr(extendhash,clsname); + Node *am = Getattr(Swig_extend_hash(),clsname); if (am) { - /* Merge the extension into the symbol table */ - merge_extensions($$,am); - append_previous_extension($$,am); - Delattr(extendhash,clsname); + /* Merge the extension into the symbol table */ + Swig_extend_merge($$,am); + Swig_extend_append_previous($$,am); + Delattr(Swig_extend_hash(),clsname); } Delete(clsname); } diff --git a/Source/CParse/util.c b/Source/CParse/util.c index 7572dff10..320671d9a 100644 --- a/Source/CParse/util.c +++ b/Source/CParse/util.c @@ -88,3 +88,17 @@ void cparse_normalize_void(Node *n) { } } } + +/* ----------------------------------------------------------------------------- + * new_node() + * + * Create an empty parse node, setting file and line number information + * ----------------------------------------------------------------------------- */ + +Node *new_node(const_String_or_char_ptr tag) { + Node *n = NewHash(); + set_nodeType(n,tag); + Setfile(n,cparse_file); + Setline(n,cparse_line); + return n; +} diff --git a/Source/Makefile.am b/Source/Makefile.am index d5331cba1..da65b2326 100644 --- a/Source/Makefile.am +++ b/Source/Makefile.am @@ -77,6 +77,7 @@ eswig_SOURCES = CParse/cscanner.c \ Swig/cwrap.c \ Swig/deprecate.c \ Swig/error.c \ + Swig/extend.c \ Swig/fragment.c \ Swig/getopt.c \ Swig/include.c \ diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx index d8f20c207..47d0d374b 100644 --- a/Source/Modules/main.cxx +++ b/Source/Modules/main.cxx @@ -198,7 +198,6 @@ static String *external_runtime_name = 0; enum { STAGE1=1, STAGE2=2, STAGE3=4, STAGE4=8, STAGEOVERFLOW=16 }; static List *libfiles = 0; static List *all_output_files = 0; -extern "C" void check_extensions(); /* ----------------------------------------------------------------------------- * check_extension() @@ -1173,7 +1172,7 @@ int SWIG_main(int argc, char *argv[], Language *l) { Printf(stdout, "Processing unnamed structs...\n"); Swig_nested_name_unnamed_c_structs(top); } - check_extensions(); + Swig_extend_unused_check(); if (Verbose) { Printf(stdout, "Processing types...\n"); diff --git a/Source/Modules/nested.cxx b/Source/Modules/nested.cxx index ca1c79a31..9ec52ead1 100644 --- a/Source/Modules/nested.cxx +++ b/Source/Modules/nested.cxx @@ -338,9 +338,7 @@ static void insertNodeAfter(Node *n, Node *c) { set_nextSibling(n, c); set_previousSibling(c, n); } -extern "C" Hash *extendhash; -extern "C" void merge_extensions(Node *cls, Node *am); -extern "C" void append_previous_extension(Node *cls, Node *am); + void Swig_nested_name_unnamed_c_structs(Node *n) { if (!classhash) classhash = Getattr(n, "classes"); @@ -378,13 +376,11 @@ void Swig_nested_name_unnamed_c_structs(Node *n) { decl = nextSibling(decl); } Delete(ty); - 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, name); - } + if (Node *am = Getattr(Swig_extend_hash(), name)) { + // Merge the extension into the symbol table + Swig_extend_merge(c, am); + Swig_extend_append_previous(c, am); + Delattr(Swig_extend_hash(), name); } Swig_symbol_setscope(Swig_symbol_global_scope()); add_symbols_c(c); diff --git a/Source/Swig/extend.c b/Source/Swig/extend.c new file mode 100644 index 000000000..30097b434 --- /dev/null +++ b/Source/Swig/extend.c @@ -0,0 +1,141 @@ +/* ----------------------------------------------------------------------------- + * 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. + * + * extend.c + * + * Extensions support (%extend) + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" + +static Hash *extendhash = 0; /* Hash table of added methods */ + +/* ----------------------------------------------------------------------------- + * Swig_extend_hash() + * + * Access the extend hash + * ----------------------------------------------------------------------------- */ +Hash *Swig_extend_hash(void) { + if (!extendhash) + extendhash = NewHash(); + return extendhash; +} + +/* ----------------------------------------------------------------------------- + * Swig_extend_merge() + * + * Extension merge. This function is used to handle the %extend directive + * when it appears before a class definition. To handle this, the %extend + * actually needs to take precedence. Therefore, we will selectively nuke symbols + * from the current symbol table, replacing them with the added methods. + * ----------------------------------------------------------------------------- */ + +void Swig_extend_merge(Node *cls, Node *am) { + Node *n; + Node *csym; + + n = firstChild(am); + while (n) { + String *symname; + if (Strcmp(nodeType(n),"constructor") == 0) { + symname = Getattr(n,"sym:name"); + if (symname) { + if (Strcmp(symname,Getattr(n,"name")) == 0) { + /* If the name and the sym:name of a constructor are the same, + then it hasn't been renamed. However---the name of the class + itself might have been renamed so we need to do a consistency + check here */ + if (Getattr(cls,"sym:name")) { + Setattr(n,"sym:name", Getattr(cls,"sym:name")); + } + } + } + } + + symname = Getattr(n,"sym:name"); + DohIncref(symname); + if ((symname) && (!Getattr(n,"error"))) { + /* Remove node from its symbol table */ + Swig_symbol_remove(n); + csym = Swig_symbol_add(symname,n); + if (csym != n) { + /* Conflict with previous definition. Nuke previous definition */ + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + Printf(ec,"Identifier '%s' redefined by %%extend (ignored),",symname); + Printf(en,"%%extend definition of '%s'.",symname); + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(csym),Getline(csym),"%s\n",ec); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); + SWIG_WARN_NODE_END(n); + Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(csym),Getline(csym),ec, + Getfile(n),Getline(n),en); + Setattr(csym,"error",e); + Delete(e); + Delete(en); + Delete(ec); + Swig_symbol_remove(csym); /* Remove class definition */ + Swig_symbol_add(symname,n); /* Insert extend definition */ + } + } + n = nextSibling(n); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_extend_append_previous() + * ----------------------------------------------------------------------------- */ + +void Swig_extend_append_previous(Node *cls, Node *am) { + Node *n, *ne; + Node *pe = 0; + Node *ae = 0; + + if (!am) return; + + n = firstChild(am); + while (n) { + ne = nextSibling(n); + set_nextSibling(n,0); + /* typemaps and fragments need to be prepended */ + if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) { + if (!pe) pe = new_node("extend"); + appendChild(pe, n); + } else { + if (!ae) ae = new_node("extend"); + appendChild(ae, n); + } + n = ne; + } + if (pe) prependChild(cls,pe); + if (ae) appendChild(cls,ae); +} + + +/* ----------------------------------------------------------------------------- + * Swig_extend_unused_check() + * + * Check for unused %extend. Special case, don't report unused + * extensions for templates + * ----------------------------------------------------------------------------- */ + +void Swig_extend_unused_check(void) { + Iterator ki; + + if (!extendhash) return; + for (ki = First(extendhash); ki.key; ki = Next(ki)) { + if (!Strchr(ki.key,'<')) { + SWIG_WARN_NODE_BEGIN(ki.item); + Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", SwigType_namestr(ki.key)); + SWIG_WARN_NODE_END(ki.item); + } + } +} + diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h index 5334a29f0..5ee7f8d95 100644 --- a/Source/Swig/swig.h +++ b/Source/Swig/swig.h @@ -420,6 +420,13 @@ extern int ParmList_is_compactdefargs(ParmList *p); extern void Swig_fragment_emit(String *name); extern void Swig_fragment_clear(String *section); +/* --- Extension support --- */ + + extern Hash *Swig_extend_hash(void); + extern void Swig_extend_merge(Node *cls, Node *am); + extern void Swig_extend_append_previous(Node *cls, Node *am); + extern void Swig_extend_unused_check(void); + /* hacks defined in C++ ! */ extern int Swig_director_mode(void); extern int Swig_director_protected_mode(void);