| /* ----------------------------------------------------------------------------- |
| * 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. |
| * |
| * parser.y |
| * |
| * YACC parser for SWIG. The grammar is a somewhat broken subset of C/C++. |
| * This file is a bit of a mess and probably needs to be rewritten at |
| * some point. Beware. |
| * ----------------------------------------------------------------------------- */ |
| |
| /* There are 6 known shift-reduce conflicts in this file, fail compilation if any |
| more are introduced. |
| |
| Please don't increase the number of the conflicts if at all possible. And if |
| you really have no choice but to do it, make sure you clearly document each |
| new conflict in this file. |
| */ |
| %expect 6 |
| |
| %{ |
| #define yylex yylex |
| |
| #include "swig.h" |
| #include "cparse.h" |
| #include "preprocessor.h" |
| #include <ctype.h> |
| |
| /* We do this for portability */ |
| #undef alloca |
| #define alloca malloc |
| |
| /* ----------------------------------------------------------------------------- |
| * Externals |
| * ----------------------------------------------------------------------------- */ |
| |
| int yyparse(); |
| |
| /* NEW Variables */ |
| |
| static Node *top = 0; /* Top of the generated parse tree */ |
| static int unnamed = 0; /* Unnamed datatype counter */ |
| 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; |
| static Node *current_class = 0; |
| String *ModuleName = 0; |
| static Node *module_node = 0; |
| static String *Classprefix = 0; |
| static String *Namespaceprefix = 0; |
| static int inclass = 0; |
| static Node *currentOuterClass = 0; /* for nested classes */ |
| static const char *last_cpptype = 0; |
| static int inherit_list = 0; |
| static Parm *template_parameters = 0; |
| static int parsing_template_declaration = 0; |
| static int extendmode = 0; |
| static int compact_default_args = 0; |
| static int template_reduce = 0; |
| static int cparse_externc = 0; |
| int ignore_nested_classes = 0; |
| int kwargs_supported = 0; |
| /* ----------------------------------------------------------------------------- |
| * Doxygen Comment Globals |
| * ----------------------------------------------------------------------------- */ |
| static String *currentDeclComment = NULL; /* Comment of C/C++ declaration. */ |
| static Node *previousNode = NULL; /* Pointer to the previous node (for post comments) */ |
| static Node *currentNode = NULL; /* Pointer to the current node (for post comments) */ |
| |
| /* ----------------------------------------------------------------------------- |
| * Assist Functions |
| * ----------------------------------------------------------------------------- */ |
| |
| |
| |
| /* Called by the parser (yyparse) when an error is found.*/ |
| static void yyerror (const char *e) { |
| (void)e; |
| } |
| |
| static Node *new_node(const_String_or_char_ptr tag) { |
| Node *n = Swig_cparse_new_node(tag); |
| /* Remember the previous node in case it will need a post-comment */ |
| previousNode = currentNode; |
| currentNode = n; |
| return n; |
| } |
| |
| /* Copies a node. Does not copy tree links or symbol table data (except for |
| sym:name) */ |
| |
| static Node *copy_node(Node *n) { |
| Node *nn; |
| Iterator k; |
| nn = NewHash(); |
| Setfile(nn,Getfile(n)); |
| Setline(nn,Getline(n)); |
| for (k = First(n); k.key; k = Next(k)) { |
| String *ci; |
| String *key = k.key; |
| char *ckey = Char(key); |
| if ((strcmp(ckey,"nextSibling") == 0) || |
| (strcmp(ckey,"previousSibling") == 0) || |
| (strcmp(ckey,"parentNode") == 0) || |
| (strcmp(ckey,"lastChild") == 0)) { |
| continue; |
| } |
| if (Strncmp(key,"csym:",5) == 0) continue; |
| /* We do copy sym:name. For templates */ |
| if ((strcmp(ckey,"sym:name") == 0) || |
| (strcmp(ckey,"sym:weak") == 0) || |
| (strcmp(ckey,"sym:typename") == 0)) { |
| String *ci = Copy(k.item); |
| Setattr(nn,key, ci); |
| Delete(ci); |
| continue; |
| } |
| if (strcmp(ckey,"sym:symtab") == 0) { |
| Setattr(nn,"sym:needs_symtab", "1"); |
| } |
| /* We don't copy any other symbol table attributes */ |
| if (strncmp(ckey,"sym:",4) == 0) { |
| continue; |
| } |
| /* If children. We copy them recursively using this function */ |
| if (strcmp(ckey,"firstChild") == 0) { |
| /* Copy children */ |
| Node *cn = k.item; |
| while (cn) { |
| Node *copy = copy_node(cn); |
| appendChild(nn,copy); |
| Delete(copy); |
| cn = nextSibling(cn); |
| } |
| continue; |
| } |
| /* We don't copy the symbol table. But we drop an attribute |
| requires_symtab so that functions know it needs to be built */ |
| |
| if (strcmp(ckey,"symtab") == 0) { |
| /* Node defined a symbol table. */ |
| Setattr(nn,"requires_symtab","1"); |
| continue; |
| } |
| /* Can't copy nodes */ |
| if (strcmp(ckey,"node") == 0) { |
| continue; |
| } |
| if ((strcmp(ckey,"parms") == 0) || (strcmp(ckey,"pattern") == 0) || (strcmp(ckey,"throws") == 0) |
| || (strcmp(ckey,"kwargs") == 0)) { |
| ParmList *pl = CopyParmList(k.item); |
| Setattr(nn,key,pl); |
| Delete(pl); |
| continue; |
| } |
| if (strcmp(ckey,"nested:outer") == 0) { /* don't copy outer classes links, they will be updated later */ |
| Setattr(nn, key, k.item); |
| continue; |
| } |
| /* defaultargs will be patched back in later in update_defaultargs() */ |
| if (strcmp(ckey,"defaultargs") == 0) { |
| Setattr(nn, "needs_defaultargs", "1"); |
| continue; |
| } |
| /* same for abstracts, which contains pointers to the source node children, and so will need to be patch too */ |
| if (strcmp(ckey,"abstracts") == 0) { |
| SetFlag(nn, "needs_abstracts"); |
| continue; |
| } |
| /* Looks okay. Just copy the data using Copy */ |
| ci = Copy(k.item); |
| Setattr(nn, key, ci); |
| Delete(ci); |
| } |
| return nn; |
| } |
| |
| static void set_comment(Node *n, String *comment) { |
| String *name; |
| Parm *p; |
| if (!n || !comment) |
| return; |
| |
| if (Getattr(n, "doxygen")) |
| Append(Getattr(n, "doxygen"), comment); |
| else { |
| Setattr(n, "doxygen", comment); |
| /* This is the first comment, populate it with @params, if any */ |
| p = Getattr(n, "parms"); |
| while (p) { |
| if (Getattr(p, "doxygen")) |
| Printv(comment, "\n@param ", Getattr(p, "name"), Getattr(p, "doxygen"), NIL); |
| p=nextSibling(p); |
| } |
| } |
| |
| /* Append same comment to every generated overload */ |
| name = Getattr(n, "name"); |
| if (!name) |
| return; |
| n = nextSibling(n); |
| while (n && Getattr(n, "name") && Strcmp(Getattr(n, "name"), name) == 0) { |
| Setattr(n, "doxygen", comment); |
| n = nextSibling(n); |
| } |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * Variables |
| * ----------------------------------------------------------------------------- */ |
| |
| static char *typemap_lang = 0; /* Current language setting */ |
| |
| static int cplus_mode = 0; |
| |
| /* C++ modes */ |
| |
| #define CPLUS_PUBLIC 1 |
| #define CPLUS_PRIVATE 2 |
| #define CPLUS_PROTECTED 3 |
| |
| /* include types */ |
| static int import_mode = 0; |
| |
| void SWIG_typemap_lang(const char *tm_lang) { |
| typemap_lang = Swig_copy_string(tm_lang); |
| } |
| |
| void SWIG_cparse_set_compact_default_args(int defargs) { |
| compact_default_args = defargs; |
| } |
| |
| int SWIG_cparse_template_reduce(int treduce) { |
| template_reduce = treduce; |
| return treduce; |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * Assist functions |
| * ----------------------------------------------------------------------------- */ |
| |
| static int promote_type(int t) { |
| if (t <= T_UCHAR || t == T_CHAR || t == T_WCHAR) return T_INT; |
| return t; |
| } |
| |
| /* Perform type-promotion for binary operators */ |
| static int promote(int t1, int t2) { |
| t1 = promote_type(t1); |
| t2 = promote_type(t2); |
| return t1 > t2 ? t1 : t2; |
| } |
| |
| static String *yyrename = 0; |
| |
| /* Forward renaming operator */ |
| |
| static String *resolve_create_node_scope(String *cname, int is_class_definition); |
| |
| |
| Hash *Swig_cparse_features(void) { |
| static Hash *features_hash = 0; |
| if (!features_hash) features_hash = NewHash(); |
| return features_hash; |
| } |
| |
| /* Fully qualify any template parameters */ |
| static String *feature_identifier_fix(String *s) { |
| String *tp = SwigType_istemplate_templateprefix(s); |
| if (tp) { |
| String *ts, *ta, *tq; |
| ts = SwigType_templatesuffix(s); |
| ta = SwigType_templateargs(s); |
| tq = Swig_symbol_type_qualify(ta,0); |
| Append(tp,tq); |
| Append(tp,ts); |
| Delete(ts); |
| Delete(ta); |
| Delete(tq); |
| return tp; |
| } else { |
| return NewString(s); |
| } |
| } |
| |
| static void set_access_mode(Node *n) { |
| if (cplus_mode == CPLUS_PUBLIC) |
| Setattr(n, "access", "public"); |
| else if (cplus_mode == CPLUS_PROTECTED) |
| Setattr(n, "access", "protected"); |
| else |
| Setattr(n, "access", "private"); |
| } |
| |
| static void restore_access_mode(Node *n) { |
| String *mode = Getattr(n, "access"); |
| if (Strcmp(mode, "private") == 0) |
| cplus_mode = CPLUS_PRIVATE; |
| else if (Strcmp(mode, "protected") == 0) |
| cplus_mode = CPLUS_PROTECTED; |
| else |
| cplus_mode = CPLUS_PUBLIC; |
| } |
| |
| /* Generate the symbol table name for an object */ |
| /* This is a bit of a mess. Need to clean up */ |
| static String *add_oldname = 0; |
| |
| |
| |
| static String *make_name(Node *n, String *name,SwigType *decl) { |
| String *made_name = 0; |
| int destructor = name && (*(Char(name)) == '~'); |
| |
| if (yyrename) { |
| String *s = NewString(yyrename); |
| Delete(yyrename); |
| yyrename = 0; |
| if (destructor && (*(Char(s)) != '~')) { |
| Insert(s,0,"~"); |
| } |
| return s; |
| } |
| |
| if (!name) return 0; |
| |
| if (parsing_template_declaration) |
| SetFlag(n, "parsing_template_declaration"); |
| made_name = Swig_name_make(n, Namespaceprefix, name, decl, add_oldname); |
| Delattr(n, "parsing_template_declaration"); |
| |
| return made_name; |
| } |
| |
| /* Generate an unnamed identifier */ |
| static String *make_unnamed() { |
| unnamed++; |
| return NewStringf("$unnamed%d$",unnamed); |
| } |
| |
| /* Return if the node is a friend declaration */ |
| static int is_friend(Node *n) { |
| return Cmp(Getattr(n,"storage"),"friend") == 0; |
| } |
| |
| static int is_operator(String *name) { |
| return Strncmp(name,"operator ", 9) == 0; |
| } |
| |
| |
| /* Add declaration list to symbol table */ |
| static int add_only_one = 0; |
| |
| static void add_symbols(Node *n) { |
| String *decl; |
| String *wrn = 0; |
| |
| if (inclass && n) { |
| cparse_normalize_void(n); |
| } |
| while (n) { |
| String *symname = 0; |
| /* for friends, we need to pop the scope once */ |
| String *old_prefix = 0; |
| Symtab *old_scope = 0; |
| int isfriend = inclass && is_friend(n); |
| int iscdecl = Cmp(nodeType(n),"cdecl") == 0; |
| int only_csymbol = 0; |
| |
| if (inclass) { |
| String *name = Getattr(n, "name"); |
| if (isfriend) { |
| /* for friends, we need to add the scopename if needed */ |
| String *prefix = name ? Swig_scopename_prefix(name) : 0; |
| old_prefix = Namespaceprefix; |
| old_scope = Swig_symbol_popscope(); |
| Namespaceprefix = Swig_symbol_qualifiedscopename(0); |
| if (!prefix) { |
| if (name && !is_operator(name) && Namespaceprefix) { |
| String *nname = NewStringf("%s::%s", Namespaceprefix, name); |
| Setattr(n,"name",nname); |
| Delete(nname); |
| } |
| } else { |
| Symtab *st = Swig_symbol_getscope(prefix); |
| String *ns = st ? Getattr(st,"name") : prefix; |
| String *base = Swig_scopename_last(name); |
| String *nname = NewStringf("%s::%s", ns, base); |
| Setattr(n,"name",nname); |
| Delete(nname); |
| Delete(base); |
| Delete(prefix); |
| } |
| Namespaceprefix = 0; |
| } else { |
| /* for member functions, we need to remove the redundant |
| class scope if provided, as in |
| |
| struct Foo { |
| int Foo::method(int a); |
| }; |
| |
| */ |
| String *prefix = name ? Swig_scopename_prefix(name) : 0; |
| if (prefix) { |
| if (Classprefix && (Equal(prefix,Classprefix))) { |
| String *base = Swig_scopename_last(name); |
| Setattr(n,"name",base); |
| Delete(base); |
| } |
| Delete(prefix); |
| } |
| } |
| } |
| |
| if (!isfriend && (inclass || extendmode)) { |
| Setattr(n,"ismember","1"); |
| } |
| |
| if (extendmode) { |
| if (!Getattr(n, "template")) |
| SetFlag(n,"isextendmember"); |
| } |
| |
| if (!isfriend && inclass) { |
| if ((cplus_mode != CPLUS_PUBLIC)) { |
| only_csymbol = 1; |
| if (cplus_mode == CPLUS_PROTECTED) { |
| Setattr(n,"access", "protected"); |
| only_csymbol = !Swig_need_protected(n); |
| } else { |
| Setattr(n,"access", "private"); |
| /* private are needed only when they are pure virtuals - why? */ |
| if ((Cmp(Getattr(n,"storage"),"virtual") == 0) && (Cmp(Getattr(n,"value"),"0") == 0)) { |
| only_csymbol = 0; |
| } |
| if (Cmp(nodeType(n),"destructor") == 0) { |
| /* Needed for "unref" feature */ |
| only_csymbol = 0; |
| } |
| } |
| } else { |
| Setattr(n,"access", "public"); |
| } |
| } |
| if (Getattr(n,"sym:name")) { |
| n = nextSibling(n); |
| continue; |
| } |
| 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) || (storage && Strstr(storage, "constexpr"))) { |
| 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(), Namespaceprefix, 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) { |
| if (parsing_template_declaration) |
| SetFlag(n, "parsing_template_declaration"); |
| wrn = Swig_name_warning(n, Namespaceprefix, symname,0); |
| Delattr(n, "parsing_template_declaration"); |
| } |
| } 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(),Namespaceprefix,name,fun,n); |
| |
| symname = make_name(n, name,fun); |
| if (parsing_template_declaration) |
| SetFlag(n, "parsing_template_declaration"); |
| wrn = Swig_name_warning(n, Namespaceprefix,symname,fun); |
| Delattr(n, "parsing_template_declaration"); |
| |
| Delete(fdecl); |
| Delete(fun); |
| |
| } |
| if (!symname) { |
| n = nextSibling(n); |
| continue; |
| } |
| if (cparse_cplusplus) { |
| String *value = Getattr(n, "value"); |
| if (value && Strcmp(value, "delete") == 0) { |
| /* C++11 deleted definition / deleted function */ |
| SetFlag(n,"deleted"); |
| SetFlag(n,"feature:ignore"); |
| } |
| if (SwigType_isrvalue_reference(Getattr(n, "refqualifier"))) { |
| /* Ignore rvalue ref-qualifiers by default |
| * Use Getattr instead of GetFlag to handle explicit ignore and explicit not ignore */ |
| if (!(Getattr(n, "feature:ignore") || Strncmp(symname, "$ignore", 7) == 0)) { |
| SWIG_WARN_NODE_BEGIN(n); |
| Swig_warning(WARN_TYPE_RVALUE_REF_QUALIFIER_IGNORED, Getfile(n), Getline(n), |
| "Method with rvalue ref-qualifier %s ignored.\n", Swig_name_decl(n)); |
| SWIG_WARN_NODE_END(n); |
| SetFlag(n, "feature:ignore"); |
| } |
| } |
| } |
| if (only_csymbol || GetFlag(n, "feature:ignore") || Strncmp(symname, "$ignore", 7) == 0) { |
| /* Only add to C symbol table and continue */ |
| Swig_symbol_add(0, n); |
| if (!only_csymbol && !GetFlag(n, "feature:ignore")) { |
| /* Print the warning attached to $ignore name, if any */ |
| char *c = Char(symname) + 7; |
| if (strlen(c)) { |
| SWIG_WARN_NODE_BEGIN(n); |
| Swig_warning(0,Getfile(n), Getline(n), "%s\n",c+1); |
| SWIG_WARN_NODE_END(n); |
| } |
| /* If the symbol was ignored via "rename" and is visible, set also feature:ignore*/ |
| SetFlag(n, "feature:ignore"); |
| } |
| if (!GetFlag(n, "feature:ignore") && Strcmp(symname,"$ignore") == 0) { |
| /* Add feature:ignore if the symbol was explicitly ignored, regardless of visibility */ |
| SetFlag(n, "feature:ignore"); |
| } |
| } 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,inclass); |
| 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 if (!is_friend(n) && !is_friend(c)) { |
| 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); |
| } |
| } |
| } |
| /* restore the class scope if needed */ |
| if (isfriend) { |
| Swig_symbol_setscope(old_scope); |
| if (old_prefix) { |
| Delete(Namespaceprefix); |
| Namespaceprefix = old_prefix; |
| } |
| } |
| Delete(symname); |
| |
| if (add_only_one) return; |
| n = nextSibling(n); |
| } |
| } |
| |
| |
| /* add symbols a parse tree node copy */ |
| |
| static void add_symbols_copy(Node *n) { |
| String *name; |
| int emode = 0; |
| while (n) { |
| char *cnodeType = Char(nodeType(n)); |
| |
| if (strcmp(cnodeType,"access") == 0) { |
| String *kind = Getattr(n,"kind"); |
| if (Strcmp(kind,"public") == 0) { |
| cplus_mode = CPLUS_PUBLIC; |
| } else if (Strcmp(kind,"private") == 0) { |
| cplus_mode = CPLUS_PRIVATE; |
| } else if (Strcmp(kind,"protected") == 0) { |
| cplus_mode = CPLUS_PROTECTED; |
| } |
| n = nextSibling(n); |
| continue; |
| } |
| |
| add_oldname = Getattr(n,"sym:name"); |
| if ((add_oldname) || (Getattr(n,"sym:needs_symtab"))) { |
| int old_inclass = -1; |
| Node *old_current_class = 0; |
| if (add_oldname) { |
| DohIncref(add_oldname); |
| /* Disable this, it prevents %rename to work with templates */ |
| /* If already renamed, we used that name */ |
| /* |
| if (Strcmp(add_oldname, Getattr(n,"name")) != 0) { |
| Delete(yyrename); |
| yyrename = Copy(add_oldname); |
| } |
| */ |
| } |
| Delattr(n,"sym:needs_symtab"); |
| Delattr(n,"sym:name"); |
| |
| add_only_one = 1; |
| add_symbols(n); |
| |
| if (Getattr(n,"partialargs")) { |
| Swig_symbol_cadd(Getattr(n,"partialargs"),n); |
| } |
| add_only_one = 0; |
| name = Getattr(n,"name"); |
| if (Getattr(n,"requires_symtab")) { |
| Swig_symbol_newscope(); |
| Swig_symbol_setscopename(name); |
| Delete(Namespaceprefix); |
| Namespaceprefix = Swig_symbol_qualifiedscopename(0); |
| } |
| if (strcmp(cnodeType,"class") == 0) { |
| old_inclass = inclass; |
| inclass = 1; |
| old_current_class = current_class; |
| current_class = n; |
| if (Strcmp(Getattr(n,"kind"),"class") == 0) { |
| cplus_mode = CPLUS_PRIVATE; |
| } else { |
| cplus_mode = CPLUS_PUBLIC; |
| } |
| } |
| if (strcmp(cnodeType,"extend") == 0) { |
| emode = cplus_mode; |
| cplus_mode = CPLUS_PUBLIC; |
| } |
| add_symbols_copy(firstChild(n)); |
| if (strcmp(cnodeType,"extend") == 0) { |
| cplus_mode = emode; |
| } |
| if (Getattr(n,"requires_symtab")) { |
| Setattr(n,"symtab", Swig_symbol_popscope()); |
| Delattr(n,"requires_symtab"); |
| Delete(Namespaceprefix); |
| Namespaceprefix = Swig_symbol_qualifiedscopename(0); |
| } |
| if (add_oldname) { |
| Delete(add_oldname); |
| add_oldname = 0; |
| } |
| if (strcmp(cnodeType,"class") == 0) { |
| inclass = old_inclass; |
| current_class = old_current_class; |
| } |
| } else { |
| if (strcmp(cnodeType,"extend") == 0) { |
| emode = cplus_mode; |
| cplus_mode = CPLUS_PUBLIC; |
| } |
| add_symbols_copy(firstChild(n)); |
| if (strcmp(cnodeType,"extend") == 0) { |
| cplus_mode = emode; |
| } |
| } |
| n = nextSibling(n); |
| } |
| } |
| |
| /* Add in the "defaultargs" attribute for functions in instantiated templates. |
| * n should be any instantiated template (class or start of linked list of functions). */ |
| static void update_defaultargs(Node *n) { |
| if (n) { |
| Node *firstdefaultargs = n; |
| update_defaultargs(firstChild(n)); |
| n = nextSibling(n); |
| /* recursively loop through nodes of all types, but all we really need are the overloaded functions */ |
| while (n) { |
| update_defaultargs(firstChild(n)); |
| if (!Getattr(n, "defaultargs")) { |
| if (Getattr(n, "needs_defaultargs")) { |
| Setattr(n, "defaultargs", firstdefaultargs); |
| Delattr(n, "needs_defaultargs"); |
| } else { |
| firstdefaultargs = n; |
| } |
| } else { |
| /* Functions added in with %extend (for specialized template classes) will already have default args patched up */ |
| assert(Getattr(n, "defaultargs") == firstdefaultargs); |
| } |
| n = nextSibling(n); |
| } |
| } |
| } |
| |
| /* Check a set of declarations to see if any are pure-abstract */ |
| |
| static List *pure_abstracts(Node *n) { |
| List *abstracts = 0; |
| while (n) { |
| if (Cmp(nodeType(n),"cdecl") == 0) { |
| String *decl = Getattr(n,"decl"); |
| if (SwigType_isfunction(decl)) { |
| String *init = Getattr(n,"value"); |
| if (Cmp(init,"0") == 0) { |
| if (!abstracts) { |
| abstracts = NewList(); |
| } |
| Append(abstracts,n); |
| SetFlag(n,"abstract"); |
| } |
| } |
| } else if (Cmp(nodeType(n),"destructor") == 0) { |
| if (Cmp(Getattr(n,"value"),"0") == 0) { |
| if (!abstracts) { |
| abstracts = NewList(); |
| } |
| Append(abstracts,n); |
| SetFlag(n,"abstract"); |
| } |
| } |
| n = nextSibling(n); |
| } |
| return abstracts; |
| } |
| |
| /* Recompute the "abstracts" attribute for the classes in instantiated templates, similarly to update_defaultargs() above. */ |
| static void update_abstracts(Node *n) { |
| for (; n; n = nextSibling(n)) { |
| Node* const child = firstChild(n); |
| if (!child) |
| continue; |
| |
| update_abstracts(child); |
| |
| if (Getattr(n, "needs_abstracts")) { |
| Setattr(n, "abstracts", pure_abstracts(child)); |
| Delattr(n, "needs_abstracts"); |
| } |
| } |
| } |
| |
| /* Make a classname */ |
| |
| static String *make_class_name(String *name) { |
| String *nname = 0; |
| String *prefix; |
| if (Namespaceprefix) { |
| nname= NewStringf("%s::%s", Namespaceprefix, name); |
| } else { |
| nname = NewString(name); |
| } |
| prefix = SwigType_istemplate_templateprefix(nname); |
| if (prefix) { |
| String *args, *qargs; |
| args = SwigType_templateargs(nname); |
| qargs = Swig_symbol_type_qualify(args,0); |
| Append(prefix,qargs); |
| Delete(nname); |
| Delete(args); |
| Delete(qargs); |
| nname = prefix; |
| } |
| return nname; |
| } |
| |
| /* Use typedef name as class name */ |
| |
| static void add_typedef_name(Node *n, Node *declnode, String *oldName, Symtab *cscope, String *scpname) { |
| String *class_rename = 0; |
| SwigType *decl = Getattr(declnode, "decl"); |
| if (!decl || !Len(decl)) { |
| String *cname; |
| String *tdscopename; |
| String *class_scope = Swig_symbol_qualifiedscopename(cscope); |
| String *name = Getattr(declnode, "name"); |
| cname = Copy(name); |
| Setattr(n, "tdname", cname); |
| tdscopename = class_scope ? NewStringf("%s::%s", class_scope, name) : Copy(name); |
| class_rename = Getattr(n, "class_rename"); |
| if (class_rename && (Strcmp(class_rename, oldName) == 0)) |
| Setattr(n, "class_rename", NewString(name)); |
| if (!classes_typedefs) classes_typedefs = NewHash(); |
| if (!Equal(scpname, tdscopename) && !Getattr(classes_typedefs, tdscopename)) { |
| Setattr(classes_typedefs, tdscopename, n); |
| } |
| Setattr(n, "decl", decl); |
| Delete(class_scope); |
| Delete(cname); |
| Delete(tdscopename); |
| } |
| } |
| |
| /* If the class name is qualified. We need to create or lookup namespace entries */ |
| |
| static Symtab *set_scope_to_global() { |
| Symtab *symtab = Swig_symbol_global_scope(); |
| Swig_symbol_setscope(symtab); |
| return symtab; |
| } |
| |
| /* Remove the block braces, { and }, if the 'noblock' attribute is set. |
| * Node *kw can be either a Hash or Parmlist. */ |
| static String *remove_block(Node *kw, const String *inputcode) { |
| String *modified_code = 0; |
| while (kw) { |
| String *name = Getattr(kw,"name"); |
| if (name && (Cmp(name,"noblock") == 0)) { |
| char *cstr = Char(inputcode); |
| int len = Len(inputcode); |
| if (len && cstr[0] == '{') { |
| --len; ++cstr; |
| if (len && cstr[len - 1] == '}') { --len; } |
| /* we now remove the extra spaces */ |
| while (len && isspace((int)cstr[0])) { --len; ++cstr; } |
| while (len && isspace((int)cstr[len - 1])) { --len; } |
| modified_code = NewStringWithSize(cstr, len); |
| break; |
| } |
| } |
| kw = nextSibling(kw); |
| } |
| return modified_code; |
| } |
| |
| /* |
| #define RESOLVE_DEBUG 1 |
| */ |
| static Node *nscope = 0; |
| static Node *nscope_inner = 0; |
| |
| /* Remove the scope prefix from cname and return the base name without the prefix. |
| * The scopes required for the symbol name are resolved and/or created, if required. |
| * For example AA::BB::CC as input returns CC and creates the namespace AA then inner |
| * namespace BB in the current scope. */ |
| static String *resolve_create_node_scope(String *cname, int is_class_definition) { |
| Symtab *gscope = 0; |
| Node *cname_node = 0; |
| String *last = Swig_scopename_last(cname); |
| nscope = 0; |
| nscope_inner = 0; |
| |
| if (Strncmp(cname,"::" ,2) != 0) { |
| if (is_class_definition) { |
| /* Only lookup symbols which are in scope via a using declaration but not via a using directive. |
| For example find y via 'using x::y' but not y via a 'using namespace x'. */ |
| cname_node = Swig_symbol_clookup_no_inherit(cname, 0); |
| if (!cname_node) { |
| Node *full_lookup_node = Swig_symbol_clookup(cname, 0); |
| if (full_lookup_node) { |
| /* This finds a symbol brought into scope via both a using directive and a using declaration. */ |
| Node *last_node = Swig_symbol_clookup_no_inherit(last, 0); |
| if (last_node == full_lookup_node) |
| cname_node = last_node; |
| } |
| } |
| } else { |
| /* For %template, the template needs to be in scope via any means. */ |
| cname_node = Swig_symbol_clookup(cname, 0); |
| } |
| } |
| #if RESOLVE_DEBUG |
| if (!cname_node) |
| Printf(stdout, "symbol does not yet exist (%d): [%s]\n", is_class_definition, cname); |
| else |
| Printf(stdout, "symbol does exist (%d): [%s]\n", is_class_definition, cname); |
| #endif |
| |
| if (cname_node) { |
| /* The symbol has been defined already or is in another scope. |
| If it is a weak symbol, it needs replacing and if it was brought into the current scope, |
| the scope needs adjusting appropriately for the new symbol. |
| Similarly for defined templates. */ |
| Symtab *symtab = Getattr(cname_node, "sym:symtab"); |
| Node *sym_weak = Getattr(cname_node, "sym:weak"); |
| if ((symtab && sym_weak) || Equal(nodeType(cname_node), "template")) { |
| /* Check if the scope is the current scope */ |
| String *current_scopename = Swig_symbol_qualifiedscopename(0); |
| String *found_scopename = Swig_symbol_qualifiedscopename(symtab); |
| if (!current_scopename) |
| current_scopename = NewString(""); |
| if (!found_scopename) |
| found_scopename = NewString(""); |
| |
| { |
| int fail = 1; |
| List *current_scopes = Swig_scopename_tolist(current_scopename); |
| List *found_scopes = Swig_scopename_tolist(found_scopename); |
| Iterator cit = First(current_scopes); |
| Iterator fit = First(found_scopes); |
| #if RESOLVE_DEBUG |
| Printf(stdout, "comparing current: [%s] found: [%s]\n", current_scopename, found_scopename); |
| #endif |
| for (; fit.item && cit.item; fit = Next(fit), cit = Next(cit)) { |
| String *current = cit.item; |
| String *found = fit.item; |
| #if RESOLVE_DEBUG |
| Printf(stdout, " looping %s %s\n", current, found); |
| #endif |
| if (Strcmp(current, found) != 0) |
| break; |
| } |
| |
| if (!cit.item) { |
| String *subscope = NewString(""); |
| for (; fit.item; fit = Next(fit)) { |
| if (Len(subscope) > 0) |
| Append(subscope, "::"); |
| Append(subscope, fit.item); |
| } |
| if (Len(subscope) > 0) |
| cname = NewStringf("%s::%s", subscope, last); |
| else |
| cname = Copy(last); |
| #if RESOLVE_DEBUG |
| Printf(stdout, "subscope to create: [%s] cname: [%s]\n", subscope, cname); |
| #endif |
| fail = 0; |
| Delete(subscope); |
| } else { |
| if (is_class_definition) { |
| if (!fit.item) { |
| /* It is valid to define a new class with the same name as one forward declared in a parent scope */ |
| fail = 0; |
| } else if (Swig_scopename_check(cname)) { |
| /* Classes defined with scope qualifiers must have a matching forward declaration in matching scope */ |
| fail = 1; |
| } else { |
| /* This may let through some invalid cases */ |
| fail = 0; |
| } |
| #if RESOLVE_DEBUG |
| Printf(stdout, "scope for class definition, fail: %d\n", fail); |
| #endif |
| } else { |
| #if RESOLVE_DEBUG |
| Printf(stdout, "no matching base scope for template\n"); |
| #endif |
| fail = 1; |
| } |
| } |
| |
| Delete(found_scopes); |
| Delete(current_scopes); |
| |
| if (fail) { |
| String *cname_resolved = NewStringf("%s::%s", found_scopename, last); |
| Swig_error(cparse_file, cparse_line, "'%s' resolves to '%s' and was incorrectly instantiated in scope '%s' instead of within scope '%s'.\n", cname, cname_resolved, current_scopename, found_scopename); |
| cname = Copy(last); |
| Delete(cname_resolved); |
| } |
| } |
| |
| Delete(current_scopename); |
| Delete(found_scopename); |
| } |
| } else if (!is_class_definition) { |
| /* A template instantiation requires a template to be found in scope... fail here too? |
| Swig_error(cparse_file, cparse_line, "No template found to instantiate '%s' with %%template.\n", cname); |
| */ |
| } |
| |
| if (Swig_scopename_check(cname)) { |
| Node *ns; |
| String *prefix = Swig_scopename_prefix(cname); |
| if (prefix && (Strncmp(prefix,"::",2) == 0)) { |
| /* I don't think we can use :: global scope to declare classes and hence neither %template. - consider reporting error instead - wsfulton. */ |
| /* Use the global scope */ |
| String *nprefix = NewString(Char(prefix)+2); |
| Delete(prefix); |
| prefix= nprefix; |
| gscope = set_scope_to_global(); |
| } |
| if (Len(prefix) == 0) { |
| String *base = Copy(last); |
| /* Use the global scope, but we need to add a 'global' namespace. */ |
| if (!gscope) gscope = set_scope_to_global(); |
| /* note that this namespace is not the "unnamed" one, |
| and we don't use Setattr(nscope,"name", ""), |
| because the unnamed namespace is private */ |
| nscope = new_node("namespace"); |
| Setattr(nscope,"symtab", gscope);; |
| nscope_inner = nscope; |
| Delete(last); |
| return base; |
| } |
| /* Try to locate the scope */ |
| ns = Swig_symbol_clookup(prefix,0); |
| if (!ns) { |
| Swig_error(cparse_file,cparse_line,"Undefined scope '%s'\n", prefix); |
| } else { |
| Symtab *nstab = Getattr(ns,"symtab"); |
| if (!nstab) { |
| Swig_error(cparse_file,cparse_line, "'%s' is not defined as a valid scope.\n", prefix); |
| ns = 0; |
| } else { |
| /* Check if the node scope is the current scope */ |
| String *tname = Swig_symbol_qualifiedscopename(0); |
| String *nname = Swig_symbol_qualifiedscopename(nstab); |
| if (tname && (Strcmp(tname,nname) == 0)) { |
| ns = 0; |
| cname = Copy(last); |
| } |
| Delete(tname); |
| Delete(nname); |
| } |
| if (ns) { |
| /* we will try to create a new node using the namespaces we |
| can find in the scope name */ |
| List *scopes = Swig_scopename_tolist(prefix); |
| String *sname; |
| Iterator si; |
| |
| for (si = First(scopes); si.item; si = Next(si)) { |
| Node *ns1,*ns2; |
| sname = si.item; |
| ns1 = Swig_symbol_clookup(sname,0); |
| assert(ns1); |
| if (Strcmp(nodeType(ns1),"namespace") == 0) { |
| if (Getattr(ns1,"alias")) { |
| ns1 = Getattr(ns1,"namespace"); |
| } |
| } else { |
| /* now this last part is a class */ |
| si = Next(si); |
| /* or a nested class tree, which is unrolled here */ |
| for (; si.item; si = Next(si)) { |
| if (si.item) { |
| Printf(sname,"::%s",si.item); |
| } |
| } |
| /* we get the 'inner' class */ |
| nscope_inner = Swig_symbol_clookup(sname,0); |
| /* set the scope to the inner class */ |
| Swig_symbol_setscope(Getattr(nscope_inner,"symtab")); |
| /* save the last namespace prefix */ |
| Delete(Namespaceprefix); |
| Namespaceprefix = Swig_symbol_qualifiedscopename(0); |
| /* and return the node name, including the inner class prefix */ |
| break; |
| } |
| /* here we just populate the namespace tree as usual */ |
| ns2 = new_node("namespace"); |
| Setattr(ns2,"name",sname); |
| Setattr(ns2,"symtab", Getattr(ns1,"symtab")); |
| add_symbols(ns2); |
| Swig_symbol_setscope(Getattr(ns1,"symtab")); |
| Delete(Namespaceprefix); |
| Namespaceprefix = Swig_symbol_qualifiedscopename(0); |
| if (nscope_inner) { |
| if (Getattr(nscope_inner,"symtab") != Getattr(ns2,"symtab")) { |
| appendChild(nscope_inner,ns2); |
| Delete(ns2); |
| } |
| } |
| nscope_inner = ns2; |
| if (!nscope) nscope = ns2; |
| } |
| cname = Copy(last); |
| Delete(scopes); |
| } |
| } |
| Delete(prefix); |
| } |
| Delete(last); |
| |
| return cname; |
| } |
| |
| /* look for simple typedef name in typedef list */ |
| static String *try_to_find_a_name_for_unnamed_structure(const char *storage, Node *decls) { |
| String *name = 0; |
| Node *n = decls; |
| if (storage && (strcmp(storage, "typedef") == 0)) { |
| for (; n; n = nextSibling(n)) { |
| if (!Len(Getattr(n, "decl"))) { |
| name = Copy(Getattr(n, "name")); |
| break; |
| } |
| } |
| } |
| return name; |
| } |
| |
| /* traverse copied tree segment, and update outer class links*/ |
| static void update_nested_classes(Node *n) |
| { |
| Node *c = firstChild(n); |
| while (c) { |
| if (Getattr(c, "nested:outer")) |
| Setattr(c, "nested:outer", n); |
| update_nested_classes(c); |
| c = nextSibling(c); |
| } |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * nested_forward_declaration() |
| * |
| * Nested struct handling for C++ code if the nested classes are disabled. |
| * Create the nested class/struct/union as a forward declaration. |
| * ----------------------------------------------------------------------------- */ |
| |
| static Node *nested_forward_declaration(const char *storage, const char *kind, String *sname, String *name, Node *cpp_opt_declarators) { |
| Node *nn = 0; |
| |
| if (sname) { |
| /* Add forward declaration of the nested type */ |
| Node *n = new_node("classforward"); |
| Setattr(n, "kind", kind); |
| Setattr(n, "name", sname); |
| Setattr(n, "storage", storage); |
| Setattr(n, "sym:weak", "1"); |
| add_symbols(n); |
| nn = n; |
| } |
| |
| /* Add any variable instances. Also add in any further typedefs of the nested type. |
| Note that anonymous typedefs (eg typedef struct {...} a, b;) are treated as class forward declarations */ |
| if (cpp_opt_declarators) { |
| int storage_typedef = (storage && (strcmp(storage, "typedef") == 0)); |
| int variable_of_anonymous_type = !sname && !storage_typedef; |
| if (!variable_of_anonymous_type) { |
| int anonymous_typedef = !sname && (storage && (strcmp(storage, "typedef") == 0)); |
| Node *n = cpp_opt_declarators; |
| SwigType *type = name; |
| while (n) { |
| Setattr(n, "type", type); |
| Setattr(n, "storage", storage); |
| if (anonymous_typedef) { |
| Setattr(n, "nodeType", "classforward"); |
| Setattr(n, "sym:weak", "1"); |
| } |
| n = nextSibling(n); |
| } |
| add_symbols(cpp_opt_declarators); |
| |
| if (nn) { |
| set_nextSibling(nn, cpp_opt_declarators); |
| } else { |
| nn = cpp_opt_declarators; |
| } |
| } |
| } |
| |
| if (!currentOuterClass || !GetFlag(currentOuterClass, "nested")) { |
| if (nn && Equal(nodeType(nn), "classforward")) { |
| Node *n = nn; |
| if (!GetFlag(n, "feature:ignore")) { |
| SWIG_WARN_NODE_BEGIN(n); |
| Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line,"Nested %s not currently supported (%s ignored)\n", kind, sname ? sname : name); |
| SWIG_WARN_NODE_END(n); |
| } |
| } else { |
| Swig_warning(WARN_PARSE_UNNAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", kind); |
| } |
| } |
| |
| return nn; |
| } |
| |
| |
| Node *Swig_cparse(File *f) { |
| scanner_file(f); |
| top = 0; |
| yyparse(); |
| return top; |
| } |
| |
| static void single_new_feature(const char *featurename, String *val, Hash *featureattribs, char *declaratorid, SwigType *type, ParmList *declaratorparms, String *qualifier) { |
| String *fname; |
| String *name; |
| String *fixname; |
| SwigType *t = Copy(type); |
| |
| /* Printf(stdout, "single_new_feature: [%s] [%s] [%s] [%s] [%s] [%s]\n", featurename, val, declaratorid, t, ParmList_str_defaultargs(declaratorparms), qualifier); */ |
| |
| /* Warn about deprecated features */ |
| if (strcmp(featurename, "nestedworkaround") == 0) |
| Swig_warning(WARN_DEPRECATED_NESTED_WORKAROUND, cparse_file, cparse_line, "The 'nestedworkaround' feature is deprecated.\n"); |
| |
| fname = NewStringf("feature:%s",featurename); |
| if (declaratorid) { |
| fixname = feature_identifier_fix(declaratorid); |
| } else { |
| fixname = NewStringEmpty(); |
| } |
| if (Namespaceprefix) { |
| name = NewStringf("%s::%s",Namespaceprefix, fixname); |
| } else { |
| name = fixname; |
| } |
| |
| if (declaratorparms) Setmeta(val,"parms",declaratorparms); |
| if (!Len(t)) t = 0; |
| if (t) { |
| if (qualifier) SwigType_push(t,qualifier); |
| if (SwigType_isfunction(t)) { |
| SwigType *decl = SwigType_pop_function(t); |
| if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",name); |
| Swig_feature_set(Swig_cparse_features(), nname, decl, fname, val, featureattribs); |
| Delete(nname); |
| } else { |
| Swig_feature_set(Swig_cparse_features(), name, decl, fname, val, featureattribs); |
| } |
| Delete(decl); |
| } else if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",name); |
| Swig_feature_set(Swig_cparse_features(),nname,0,fname,val, featureattribs); |
| Delete(nname); |
| } |
| } else { |
| /* Global feature, that is, feature not associated with any particular symbol */ |
| Swig_feature_set(Swig_cparse_features(),name,0,fname,val, featureattribs); |
| } |
| Delete(fname); |
| Delete(name); |
| } |
| |
| /* Add a new feature to the Hash. Additional features are added if the feature has a parameter list (declaratorparms) |
| * and one or more of the parameters have a default argument. An extra feature is added for each defaulted parameter, |
| * simulating the equivalent overloaded method. */ |
| static void new_feature(const char *featurename, String *val, Hash *featureattribs, char *declaratorid, SwigType *type, ParmList *declaratorparms, String *qualifier) { |
| |
| ParmList *declparms = declaratorparms; |
| |
| /* remove the { and } braces if the noblock attribute is set */ |
| String *newval = remove_block(featureattribs, val); |
| val = newval ? newval : val; |
| |
| /* Add the feature */ |
| single_new_feature(featurename, val, featureattribs, declaratorid, type, declaratorparms, qualifier); |
| |
| /* Add extra features if there are default parameters in the parameter list */ |
| if (type) { |
| while (declparms) { |
| if (ParmList_has_defaultargs(declparms)) { |
| |
| /* Create a parameter list for the new feature by copying all |
| but the last (defaulted) parameter */ |
| ParmList* newparms = CopyParmListMax(declparms, ParmList_len(declparms)-1); |
| |
| /* Create new declaration - with the last parameter removed */ |
| SwigType *newtype = Copy(type); |
| Delete(SwigType_pop_function(newtype)); /* remove the old parameter list from newtype */ |
| SwigType_add_function(newtype,newparms); |
| |
| single_new_feature(featurename, Copy(val), featureattribs, declaratorid, newtype, newparms, qualifier); |
| declparms = newparms; |
| } else { |
| declparms = 0; |
| } |
| } |
| } |
| } |
| |
| /* check if a function declaration is a plain C object */ |
| static int is_cfunction(Node *n) { |
| if (!cparse_cplusplus || cparse_externc) |
| return 1; |
| if (Swig_storage_isexternc(n)) { |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* If the Node is a function with parameters, check to see if any of the parameters |
| * have default arguments. If so create a new function for each defaulted argument. |
| * The additional functions form a linked list of nodes with the head being the original Node n. */ |
| static void default_arguments(Node *n) { |
| Node *function = n; |
| |
| if (function) { |
| ParmList *varargs = Getattr(function,"feature:varargs"); |
| if (varargs) { |
| /* Handles the %varargs directive by looking for "feature:varargs" and |
| * substituting ... with an alternative set of arguments. */ |
| Parm *p = Getattr(function,"parms"); |
| Parm *pp = 0; |
| while (p) { |
| SwigType *t = Getattr(p,"type"); |
| if (Strcmp(t,"v(...)") == 0) { |
| if (pp) { |
| ParmList *cv = Copy(varargs); |
| set_nextSibling(pp,cv); |
| Delete(cv); |
| } else { |
| ParmList *cv = Copy(varargs); |
| Setattr(function,"parms", cv); |
| Delete(cv); |
| } |
| break; |
| } |
| pp = p; |
| p = nextSibling(p); |
| } |
| } |
| |
| /* Do not add in functions if kwargs is being used or if user wants old default argument wrapping |
| (one wrapped method per function irrespective of number of default arguments) */ |
| if (compact_default_args |
| || is_cfunction(function) |
| || GetFlag(function,"feature:compactdefaultargs") |
| || (GetFlag(function,"feature:kwargs") && kwargs_supported)) { |
| ParmList *p = Getattr(function,"parms"); |
| if (p) |
| Setattr(p,"compactdefargs", "1"); /* mark parameters for special handling */ |
| function = 0; /* don't add in extra methods */ |
| } |
| } |
| |
| while (function) { |
| ParmList *parms = Getattr(function,"parms"); |
| if (ParmList_has_defaultargs(parms)) { |
| |
| /* Create a parameter list for the new function by copying all |
| but the last (defaulted) parameter */ |
| ParmList* newparms = CopyParmListMax(parms,ParmList_len(parms)-1); |
| |
| /* Create new function and add to symbol table */ |
| { |
| SwigType *ntype = Copy(nodeType(function)); |
| char *cntype = Char(ntype); |
| Node *new_function = new_node(ntype); |
| SwigType *decl = Copy(Getattr(function,"decl")); |
| int constqualifier = SwigType_isconst(decl); |
| String *ccode = Copy(Getattr(function,"code")); |
| String *cstorage = Copy(Getattr(function,"storage")); |
| String *cvalue = Copy(Getattr(function,"value")); |
| SwigType *ctype = Copy(Getattr(function,"type")); |
| String *cthrow = Copy(Getattr(function,"throw")); |
| |
| Delete(SwigType_pop_function(decl)); /* remove the old parameter list from decl */ |
| SwigType_add_function(decl,newparms); |
| if (constqualifier) |
| SwigType_add_qualifier(decl,"const"); |
| |
| Setattr(new_function,"name", Getattr(function,"name")); |
| Setattr(new_function,"code", ccode); |
| Setattr(new_function,"decl", decl); |
| Setattr(new_function,"parms", newparms); |
| Setattr(new_function,"storage", cstorage); |
| Setattr(new_function,"value", cvalue); |
| Setattr(new_function,"type", ctype); |
| Setattr(new_function,"throw", cthrow); |
| |
| Delete(ccode); |
| Delete(cstorage); |
| Delete(cvalue); |
| Delete(ctype); |
| Delete(cthrow); |
| Delete(decl); |
| |
| { |
| Node *throws = Getattr(function,"throws"); |
| ParmList *pl = CopyParmList(throws); |
| if (throws) Setattr(new_function,"throws",pl); |
| Delete(pl); |
| } |
| |
| /* copy specific attributes for global (or in a namespace) template functions - these are not templated class methods */ |
| if (strcmp(cntype,"template") == 0) { |
| Node *templatetype = Getattr(function,"templatetype"); |
| Node *symtypename = Getattr(function,"sym:typename"); |
| Parm *templateparms = Getattr(function,"templateparms"); |
| if (templatetype) { |
| Node *tmp = Copy(templatetype); |
| Setattr(new_function,"templatetype",tmp); |
| Delete(tmp); |
| } |
| if (symtypename) { |
| Node *tmp = Copy(symtypename); |
| Setattr(new_function,"sym:typename",tmp); |
| Delete(tmp); |
| } |
| if (templateparms) { |
| Parm *tmp = CopyParmList(templateparms); |
| Setattr(new_function,"templateparms",tmp); |
| Delete(tmp); |
| } |
| } else if (strcmp(cntype,"constructor") == 0) { |
| /* only copied for constructors as this is not a user defined feature - it is hard coded in the parser */ |
| if (GetFlag(function,"feature:new")) SetFlag(new_function,"feature:new"); |
| } |
| |
| add_symbols(new_function); |
| /* mark added functions as ones with overloaded parameters and point to the parsed method */ |
| Setattr(new_function,"defaultargs", n); |
| |
| /* Point to the new function, extending the linked list */ |
| set_nextSibling(function, new_function); |
| Delete(new_function); |
| function = new_function; |
| |
| Delete(ntype); |
| } |
| } else { |
| function = 0; |
| } |
| } |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * mark_nodes_as_extend() |
| * |
| * Used by the %extend to mark subtypes with "feature:extend". |
| * template instances declared within %extend are skipped |
| * ----------------------------------------------------------------------------- */ |
| |
| static void mark_nodes_as_extend(Node *n) { |
| for (; n; n = nextSibling(n)) { |
| if (Getattr(n, "template") && Strcmp(nodeType(n), "class") == 0) |
| continue; |
| /* Fix me: extend is not a feature. Replace with isextendmember? */ |
| Setattr(n, "feature:extend", "1"); |
| mark_nodes_as_extend(firstChild(n)); |
| } |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * add_qualifier_to_declarator() |
| * |
| * Normally the qualifier is pushed on to the front of the type. |
| * Adding a qualifier to a pointer to member function is a special case. |
| * For example : typedef double (Cls::*pmf)(void) const; |
| * The qualifier is : q(const). |
| * The declarator is : m(Cls).f(void). |
| * We need : m(Cls).q(const).f(void). |
| * ----------------------------------------------------------------------------- */ |
| |
| static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) { |
| int is_pointer_to_member_function = 0; |
| String *decl = Copy(type); |
| String *poppedtype = NewString(""); |
| assert(qualifier); |
| |
| while (decl) { |
| if (SwigType_ismemberpointer(decl)) { |
| String *memberptr = SwigType_pop(decl); |
| if (SwigType_isfunction(decl)) { |
| is_pointer_to_member_function = 1; |
| SwigType_push(decl, qualifier); |
| SwigType_push(decl, memberptr); |
| Insert(decl, 0, poppedtype); |
| Delete(memberptr); |
| break; |
| } else { |
| Append(poppedtype, memberptr); |
| } |
| Delete(memberptr); |
| } else { |
| String *popped = SwigType_pop(decl); |
| if (!popped) |
| break; |
| Append(poppedtype, popped); |
| Delete(popped); |
| } |
| } |
| |
| if (!is_pointer_to_member_function) { |
| Delete(decl); |
| decl = Copy(type); |
| SwigType_push(decl, qualifier); |
| } |
| |
| Delete(poppedtype); |
| return decl; |
| } |
| |
| %} |
| |
| %union { |
| const char *id; |
| List *bases; |
| struct Define { |
| String *val; |
| String *rawval; |
| int type; |
| String *qualifier; |
| String *refqualifier; |
| String *bitfield; |
| Parm *throws; |
| String *throwf; |
| String *nexcept; |
| String *final; |
| } dtype; |
| struct { |
| const char *type; |
| String *filename; |
| int line; |
| } loc; |
| struct { |
| char *id; |
| SwigType *type; |
| String *defarg; |
| ParmList *parms; |
| short have_parms; |
| ParmList *throws; |
| String *throwf; |
| String *nexcept; |
| String *final; |
| } decl; |
| Parm *tparms; |
| struct { |
| String *method; |
| Hash *kwargs; |
| } tmap; |
| struct { |
| String *type; |
| String *us; |
| } ptype; |
| SwigType *type; |
| String *str; |
| Parm *p; |
| ParmList *pl; |
| int intvalue; |
| Node *node; |
| }; |
| |
| %token <id> ID |
| %token <str> HBLOCK |
| %token <id> POUND |
| %token <id> STRING WSTRING |
| %token <loc> INCLUDE IMPORT INSERT |
| %token <str> CHARCONST WCHARCONST |
| %token <dtype> NUM_INT NUM_FLOAT NUM_UNSIGNED NUM_LONG NUM_ULONG NUM_LONGLONG NUM_ULONGLONG NUM_BOOL |
| %token <intvalue> TYPEDEF |
| %token <type> TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_TYPEDEF TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64 |
| %token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE PERIOD |
| %token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET |
| %token BEGINFILE ENDOFFILE |
| %token ILLEGAL CONSTANT |
| %token NAME RENAME NAMEWARN EXTEND PRAGMA FEATURE VARARGS |
| %token ENUM |
| %token CLASS TYPENAME PRIVATE PUBLIC PROTECTED COLON STATIC VIRTUAL FRIEND THROW CATCH EXPLICIT |
| %token STATIC_ASSERT CONSTEXPR THREAD_LOCAL DECLTYPE AUTO NOEXCEPT /* C++11 keywords */ |
| %token OVERRIDE FINAL /* C++11 identifiers with special meaning */ |
| %token USING |
| %token <node> NAMESPACE |
| %token NATIVE INLINE |
| %token TYPEMAP EXCEPT ECHO APPLY CLEAR SWIGTEMPLATE FRAGMENT |
| %token WARN |
| %token LESSTHAN GREATERTHAN DELETE_KW DEFAULT |
| %token LESSTHANOREQUALTO GREATERTHANOREQUALTO EQUALTO NOTEQUALTO |
| %token ARROW |
| %token QUESTIONMARK |
| %token TYPES PARMS |
| %token NONID DSTAR DCNOT |
| %token <intvalue> TEMPLATE |
| %token <str> OPERATOR |
| %token <str> CONVERSIONOPERATOR |
| %token PARSETYPE PARSEPARM PARSEPARMS |
| |
| %token <str> DOXYGENSTRING |
| %token <str> DOXYGENPOSTSTRING |
| |
| %left CAST |
| %left QUESTIONMARK |
| %left LOR |
| %left LAND |
| %left OR |
| %left XOR |
| %left AND |
| %left EQUALTO NOTEQUALTO |
| %left GREATERTHAN LESSTHAN GREATERTHANOREQUALTO LESSTHANOREQUALTO |
| %left LSHIFT RSHIFT |
| %left PLUS MINUS |
| %left STAR SLASH MODULO |
| %left UMINUS NOT LNOT |
| %left DCOLON |
| |
| %type <node> program interface declaration swig_directive ; |
| |
| /* SWIG directives */ |
| %type <node> extend_directive apply_directive clear_directive constant_directive ; |
| %type <node> echo_directive except_directive fragment_directive include_directive inline_directive ; |
| %type <node> insert_directive module_directive name_directive native_directive ; |
| %type <node> pragma_directive rename_directive feature_directive varargs_directive typemap_directive ; |
| %type <node> types_directive template_directive warn_directive ; |
| |
| /* C declarations */ |
| %type <node> c_declaration c_decl c_decl_tail c_enum_key c_enum_inherit c_enum_decl c_enum_forward_decl c_constructor_decl; |
| %type <node> enumlist enumlist_item edecl_with_dox edecl; |
| |
| /* C++ declarations */ |
| %type <node> cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl cpp_alternate_rettype; |
| %type <node> cpp_members cpp_member cpp_member_no_dox; |
| %type <node> cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator cpp_static_assert; |
| %type <node> cpp_swig_directive cpp_template_possible cpp_opt_declarators ; |
| %type <node> cpp_using_decl cpp_namespace_decl cpp_catch_decl cpp_lambda_decl; |
| %type <node> kwargs options; |
| |
| /* Misc */ |
| %type <id> identifier; |
| %type <dtype> initializer cpp_const exception_specification cv_ref_qualifier qualifiers_exception_specification; |
| %type <id> storage_class extern_string; |
| %type <pl> parms ptail rawparms varargs_parms ; |
| %type <pl> templateparameters templateparameterstail; |
| %type <p> parm_no_dox parm valparm rawvalparms valparms valptail ; |
| %type <p> typemap_parm tm_list tm_tail ; |
| %type <p> templateparameter ; |
| %type <id> templcpptype cpptype classkey classkeyopt access_specifier; |
| %type <node> base_specifier; |
| %type <str> ellipsis variadic; |
| %type <type> type rawtype type_right anon_bitfield_type decltype ; |
| %type <bases> base_list inherit raw_inherit; |
| %type <dtype> definetype def_args etype default_delete deleted_definition explicit_default; |
| %type <dtype> expr exprnum exprcompound valexpr exprmem; |
| %type <id> ename ; |
| %type <id> less_valparms_greater; |
| %type <str> type_qualifier; |
| %type <str> ref_qualifier; |
| %type <id> type_qualifier_raw; |
| %type <id> idstring idstringopt; |
| %type <id> pragma_lang; |
| %type <str> pragma_arg; |
| %type <loc> includetype; |
| %type <type> pointer primitive_type; |
| %type <decl> declarator direct_declarator notso_direct_declarator parameter_declarator plain_declarator; |
| %type <decl> abstract_declarator direct_abstract_declarator ctor_end; |
| %type <tmap> typemap_type; |
| %type <str> idcolon idcolontail idcolonnt idcolontailnt idtemplate idtemplatetemplate stringbrace stringbracesemi; |
| %type <str> string stringnum wstring; |
| %type <tparms> template_parms; |
| %type <dtype> cpp_end cpp_vend; |
| %type <intvalue> rename_namewarn; |
| %type <ptype> type_specifier primitive_type_list ; |
| %type <node> fname stringtype; |
| %type <node> featattr; |
| %type <node> lambda_introducer lambda_body; |
| %type <pl> lambda_tail; |
| %type <str> virt_specifier_seq virt_specifier_seq_opt; |
| |
| %% |
| |
| /* ====================================================================== |
| * High-level Interface file |
| * |
| * An interface is just a sequence of declarations which may be SWIG directives |
| * or normal C declarations. |
| * ====================================================================== */ |
| |
| program : interface { |
| if (!classes) classes = NewHash(); |
| Setattr($1,"classes",classes); |
| Setattr($1,"name",ModuleName); |
| |
| if ((!module_node) && ModuleName) { |
| module_node = new_node("module"); |
| Setattr(module_node,"name",ModuleName); |
| } |
| Setattr($1,"module",module_node); |
| top = $1; |
| } |
| | PARSETYPE parm SEMI { |
| top = Copy(Getattr($2,"type")); |
| Delete($2); |
| } |
| | PARSETYPE error { |
| top = 0; |
| } |
| | PARSEPARM parm SEMI { |
| top = $2; |
| } |
| | PARSEPARM error { |
| top = 0; |
| } |
| | PARSEPARMS LPAREN parms RPAREN SEMI { |
| top = $3; |
| } |
| | PARSEPARMS error SEMI { |
| top = 0; |
| } |
| ; |
| |
| interface : interface declaration { |
| /* add declaration to end of linked list (the declaration isn't always a single declaration, sometimes it is a linked list itself) */ |
| if (currentDeclComment != NULL) { |
| set_comment($2, currentDeclComment); |
| currentDeclComment = NULL; |
| } |
| appendChild($1,$2); |
| $$ = $1; |
| } |
| | interface DOXYGENSTRING { |
| currentDeclComment = $2; |
| $$ = $1; |
| } |
| | interface DOXYGENPOSTSTRING { |
| Node *node = lastChild($1); |
| if (node) { |
| set_comment(node, $2); |
| } |
| $$ = $1; |
| } |
| | empty { |
| $$ = new_node("top"); |
| } |
| ; |
| |
| declaration : swig_directive { $$ = $1; } |
| | c_declaration { $$ = $1; } |
| | cpp_declaration { $$ = $1; } |
| | SEMI { $$ = 0; } |
| | error { |
| $$ = 0; |
| if (cparse_unknown_directive) { |
| Swig_error(cparse_file, cparse_line, "Unknown directive '%s'.\n", cparse_unknown_directive); |
| } else { |
| Swig_error(cparse_file, cparse_line, "Syntax error in input(1).\n"); |
| } |
| SWIG_exit(EXIT_FAILURE); |
| } |
| /* Out of class constructor/destructor declarations */ |
| | c_constructor_decl { |
| if ($$) { |
| add_symbols($$); |
| } |
| $$ = $1; |
| } |
| |
| /* Out of class conversion operator. For example: |
| inline A::operator char *() const { ... }. |
| |
| This is nearly impossible to parse normally. We just let the |
| first part generate a syntax error and then resynchronize on the |
| CONVERSIONOPERATOR token---discarding the rest of the definition. Ugh. |
| |
| */ |
| |
| | error CONVERSIONOPERATOR { |
| $$ = 0; |
| skip_decl(); |
| } |
| ; |
| |
| /* ====================================================================== |
| * SWIG DIRECTIVES |
| * ====================================================================== */ |
| |
| swig_directive : extend_directive { $$ = $1; } |
| | apply_directive { $$ = $1; } |
| | clear_directive { $$ = $1; } |
| | constant_directive { $$ = $1; } |
| | echo_directive { $$ = $1; } |
| | except_directive { $$ = $1; } |
| | fragment_directive { $$ = $1; } |
| | include_directive { $$ = $1; } |
| | inline_directive { $$ = $1; } |
| | insert_directive { $$ = $1; } |
| | module_directive { $$ = $1; } |
| | name_directive { $$ = $1; } |
| | native_directive { $$ = $1; } |
| | pragma_directive { $$ = $1; } |
| | rename_directive { $$ = $1; } |
| | feature_directive { $$ = $1; } |
| | varargs_directive { $$ = $1; } |
| | typemap_directive { $$ = $1; } |
| | types_directive { $$ = $1; } |
| | template_directive { $$ = $1; } |
| | warn_directive { $$ = $1; } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %extend classname { ... } |
| ------------------------------------------------------------ */ |
| |
| extend_directive : EXTEND options classkeyopt idcolon LBRACE { |
| Node *cls; |
| String *clsname; |
| extendmode = 1; |
| cplus_mode = CPLUS_PUBLIC; |
| if (!classes) classes = NewHash(); |
| if (!classes_typedefs) classes_typedefs = NewHash(); |
| clsname = make_class_name($4); |
| cls = Getattr(classes,clsname); |
| if (!cls) { |
| cls = Getattr(classes_typedefs, clsname); |
| if (!cls) { |
| /* No previous definition. Create a new scope */ |
| Node *am = Getattr(Swig_extend_hash(),clsname); |
| if (!am) { |
| Swig_symbol_newscope(); |
| Swig_symbol_setscopename($4); |
| prev_symtab = 0; |
| } else { |
| prev_symtab = Swig_symbol_setscope(Getattr(am,"symtab")); |
| } |
| current_class = 0; |
| } else { |
| /* Previous typedef class definition. Use its symbol table. |
| Deprecated, just the real name should be used. |
| Note that %extend before the class typedef never worked, only %extend after the class typdef. */ |
| prev_symtab = Swig_symbol_setscope(Getattr(cls, "symtab")); |
| current_class = cls; |
| SWIG_WARN_NODE_BEGIN(cls); |
| Swig_warning(WARN_PARSE_EXTEND_NAME, cparse_file, cparse_line, "Deprecated %%extend name used - the %s name '%s' should be used instead of the typedef name '%s'.\n", Getattr(cls, "kind"), SwigType_namestr(Getattr(cls, "name")), $4); |
| SWIG_WARN_NODE_END(cls); |
| } |
| } else { |
| /* Previous class definition. Use its symbol table */ |
| prev_symtab = Swig_symbol_setscope(Getattr(cls,"symtab")); |
| current_class = cls; |
| } |
| Classprefix = NewString($4); |
| Namespaceprefix= Swig_symbol_qualifiedscopename(0); |
| Delete(clsname); |
| } cpp_members RBRACE { |
| String *clsname; |
| extendmode = 0; |
| $$ = new_node("extend"); |
| Setattr($$,"symtab",Swig_symbol_popscope()); |
| if (prev_symtab) { |
| Swig_symbol_setscope(prev_symtab); |
| } |
| Namespaceprefix = Swig_symbol_qualifiedscopename(0); |
| clsname = make_class_name($4); |
| Setattr($$,"name",clsname); |
| |
| mark_nodes_as_extend($7); |
| if (current_class) { |
| /* We add the extension to the previously defined class */ |
| appendChild($$, $7); |
| appendChild(current_class,$$); |
| } else { |
| /* We store the extensions in the extensions hash */ |
| Node *am = Getattr(Swig_extend_hash(),clsname); |
| if (am) { |
| /* Append the members to the previous extend methods */ |
| appendChild(am, $7); |
| } else { |
| appendChild($$, $7); |
| Setattr(Swig_extend_hash(),clsname,$$); |
| } |
| } |
| current_class = 0; |
| Delete(Classprefix); |
| Delete(clsname); |
| Classprefix = 0; |
| prev_symtab = 0; |
| $$ = 0; |
| |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %apply |
| ------------------------------------------------------------ */ |
| |
| apply_directive : APPLY typemap_parm LBRACE tm_list RBRACE { |
| $$ = new_node("apply"); |
| Setattr($$,"pattern",Getattr($2,"pattern")); |
| appendChild($$,$4); |
| }; |
| |
| /* ------------------------------------------------------------ |
| %clear |
| ------------------------------------------------------------ */ |
| |
| clear_directive : CLEAR tm_list SEMI { |
| $$ = new_node("clear"); |
| appendChild($$,$2); |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %constant name = value; |
| %constant type name = value; |
| ------------------------------------------------------------ */ |
| |
| constant_directive : CONSTANT identifier EQUAL definetype SEMI { |
| if (($4.type != T_ERROR) && ($4.type != T_SYMBOL)) { |
| SwigType *type = NewSwigType($4.type); |
| $$ = new_node("constant"); |
| Setattr($$,"name",$2); |
| Setattr($$,"type",type); |
| Setattr($$,"value",$4.val); |
| if ($4.rawval) Setattr($$,"rawval", $4.rawval); |
| Setattr($$,"storage","%constant"); |
| SetFlag($$,"feature:immutable"); |
| add_symbols($$); |
| Delete(type); |
| } else { |
| if ($4.type == T_ERROR) { |
| Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line,"Unsupported constant value (ignored)\n"); |
| } |
| $$ = 0; |
| } |
| |
| } |
| | CONSTANT type declarator def_args SEMI { |
| if (($4.type != T_ERROR) && ($4.type != T_SYMBOL)) { |
| SwigType_push($2,$3.type); |
| /* Sneaky callback function trick */ |
| if (SwigType_isfunction($2)) { |
| SwigType_add_pointer($2); |
| } |
| $$ = new_node("constant"); |
| Setattr($$,"name",$3.id); |
| Setattr($$,"type",$2); |
| Setattr($$,"value",$4.val); |
| if ($4.rawval) Setattr($$,"rawval", $4.rawval); |
| Setattr($$,"storage","%constant"); |
| SetFlag($$,"feature:immutable"); |
| add_symbols($$); |
| } else { |
| if ($4.type == T_ERROR) { |
| Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line, "Unsupported constant value\n"); |
| } |
| $$ = 0; |
| } |
| } |
| /* Member function pointers with qualifiers. eg. |
| %constant short (Funcs::*pmf)(bool) const = &Funcs::F; */ |
| | CONSTANT type direct_declarator LPAREN parms RPAREN cv_ref_qualifier def_args SEMI { |
| if (($8.type != T_ERROR) && ($8.type != T_SYMBOL)) { |
| SwigType_add_function($2, $5); |
| SwigType_push($2, $7.qualifier); |
| SwigType_push($2, $3.type); |
| /* Sneaky callback function trick */ |
| if (SwigType_isfunction($2)) { |
| SwigType_add_pointer($2); |
| } |
| $$ = new_node("constant"); |
| Setattr($$, "name", $3.id); |
| Setattr($$, "type", $2); |
| Setattr($$, "value", $8.val); |
| if ($8.rawval) Setattr($$, "rawval", $8.rawval); |
| Setattr($$, "storage", "%constant"); |
| SetFlag($$, "feature:immutable"); |
| add_symbols($$); |
| } else { |
| if ($8.type == T_ERROR) { |
| Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line, "Unsupported constant value\n"); |
| } |
| $$ = 0; |
| } |
| } |
| | CONSTANT error SEMI { |
| Swig_warning(WARN_PARSE_BAD_VALUE,cparse_file,cparse_line,"Bad constant value (ignored).\n"); |
| $$ = 0; |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %echo "text" |
| %echo %{ ... %} |
| ------------------------------------------------------------ */ |
| |
| echo_directive : ECHO HBLOCK { |
| char temp[64]; |
| Replace($2,"$file",cparse_file, DOH_REPLACE_ANY); |
| sprintf(temp,"%d", cparse_line); |
| Replace($2,"$line",temp,DOH_REPLACE_ANY); |
| Printf(stderr,"%s\n", $2); |
| Delete($2); |
| $$ = 0; |
| } |
| | ECHO string { |
| char temp[64]; |
| String *s = $2; |
| Replace(s,"$file",cparse_file, DOH_REPLACE_ANY); |
| sprintf(temp,"%d", cparse_line); |
| Replace(s,"$line",temp,DOH_REPLACE_ANY); |
| Printf(stderr,"%s\n", s); |
| Delete(s); |
| $$ = 0; |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %except(lang) { ... } |
| %except { ... } |
| %except(lang); |
| %except; |
| ------------------------------------------------------------ */ |
| |
| except_directive : EXCEPT LPAREN identifier RPAREN LBRACE { |
| skip_balanced('{','}'); |
| $$ = 0; |
| Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); |
| } |
| |
| | EXCEPT LBRACE { |
| skip_balanced('{','}'); |
| $$ = 0; |
| Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); |
| } |
| |
| | EXCEPT LPAREN identifier RPAREN SEMI { |
| $$ = 0; |
| Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); |
| } |
| |
| | EXCEPT SEMI { |
| $$ = 0; |
| Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); |
| } |
| ; |
| |
| /* fragment keyword arguments */ |
| stringtype : string LBRACE parm RBRACE { |
| $$ = NewHash(); |
| Setattr($$,"value",$1); |
| Setattr($$,"type",Getattr($3,"type")); |
| } |
| ; |
| |
| fname : string { |
| $$ = NewHash(); |
| Setattr($$,"value",$1); |
| } |
| | stringtype { |
| $$ = $1; |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %fragment(name, section) %{ ... %} |
| %fragment("name" {type}, "section") %{ ... %} |
| %fragment("name", "section", fragment="fragment1", fragment="fragment2") %{ ... %} |
| Also as above but using { ... } |
| %fragment("name"); |
| ------------------------------------------------------------ */ |
| |
| fragment_directive: FRAGMENT LPAREN fname COMMA kwargs RPAREN HBLOCK { |
| Hash *p = $5; |
| $$ = new_node("fragment"); |
| Setattr($$,"value",Getattr($3,"value")); |
| Setattr($$,"type",Getattr($3,"type")); |
| Setattr($$,"section",Getattr(p,"name")); |
| Setattr($$,"kwargs",nextSibling(p)); |
| Setattr($$,"code",$7); |
| } |
| | FRAGMENT LPAREN fname COMMA kwargs RPAREN LBRACE { |
| Hash *p = $5; |
| String *code; |
| skip_balanced('{','}'); |
| $$ = new_node("fragment"); |
| Setattr($$,"value",Getattr($3,"value")); |
| Setattr($$,"type",Getattr($3,"type")); |
| Setattr($$,"section",Getattr(p,"name")); |
| Setattr($$,"kwargs",nextSibling(p)); |
| Delitem(scanner_ccode,0); |
| Delitem(scanner_ccode,DOH_END); |
| code = Copy(scanner_ccode); |
| Setattr($$,"code",code); |
| Delete(code); |
| } |
| | FRAGMENT LPAREN fname RPAREN SEMI { |
| $$ = new_node("fragment"); |
| Setattr($$,"value",Getattr($3,"value")); |
| Setattr($$,"type",Getattr($3,"type")); |
| Setattr($$,"emitonly","1"); |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %includefile(option1="xyz", ...) "filename" [ declarations ] |
| %importfile(option1="xyz", ...) "filename" [ declarations ] |
| ------------------------------------------------------------ */ |
| |
| include_directive: includetype options string BEGINFILE { |
| $1.filename = Copy(cparse_file); |
| $1.line = cparse_line; |
| scanner_set_location($3,1); |
| if ($2) { |
| String *maininput = Getattr($2, "maininput"); |
| if (maininput) |
| scanner_set_main_input_file(NewString(maininput)); |
| } |
| } interface ENDOFFILE { |
| String *mname = 0; |
| $$ = $6; |
| scanner_set_location($1.filename,$1.line+1); |
| if (strcmp($1.type,"include") == 0) set_nodeType($$,"include"); |
| if (strcmp($1.type,"import") == 0) { |
| mname = $2 ? Getattr($2,"module") : 0; |
| set_nodeType($$,"import"); |
| if (import_mode) --import_mode; |
| } |
| |
| Setattr($$,"name",$3); |
| /* Search for the module (if any) */ |
| { |
| Node *n = firstChild($$); |
| while (n) { |
| if (Strcmp(nodeType(n),"module") == 0) { |
| if (mname) { |
| Setattr(n,"name", mname); |
| mname = 0; |
| } |
| Setattr($$,"module",Getattr(n,"name")); |
| break; |
| } |
| n = nextSibling(n); |
| } |
| if (mname) { |
| /* There is no module node in the import |
| node, ie, you imported a .h file |
| directly. We are forced then to create |
| a new import node with a module node. |
| */ |
| Node *nint = new_node("import"); |
| Node *mnode = new_node("module"); |
| Setattr(mnode,"name", mname); |
| Setattr(mnode,"options",$2); |
| appendChild(nint,mnode); |
| Delete(mnode); |
| appendChild(nint,firstChild($$)); |
| $$ = nint; |
| Setattr($$,"module",mname); |
| } |
| } |
| Setattr($$,"options",$2); |
| } |
| ; |
| |
| includetype : INCLUDE { $$.type = "include"; } |
| | IMPORT { $$.type = "import"; ++import_mode;} |
| ; |
| |
| /* ------------------------------------------------------------ |
| %inline %{ ... %} |
| ------------------------------------------------------------ */ |
| |
| inline_directive : INLINE HBLOCK { |
| String *cpps; |
| if (Namespaceprefix) { |
| Swig_error(cparse_file, cparse_start_line, "%%inline directive inside a namespace is disallowed.\n"); |
| $$ = 0; |
| } else { |
| $$ = new_node("insert"); |
| Setattr($$,"code",$2); |
| /* Need to run through the preprocessor */ |
| Seek($2,0,SEEK_SET); |
| Setline($2,cparse_start_line); |
| Setfile($2,cparse_file); |
| cpps = Preprocessor_parse($2); |
| start_inline(Char(cpps), cparse_start_line); |
| Delete($2); |
| Delete(cpps); |
| } |
| |
| } |
| | INLINE LBRACE { |
| String *cpps; |
| int start_line = cparse_line; |
| skip_balanced('{','}'); |
| if (Namespaceprefix) { |
| Swig_error(cparse_file, cparse_start_line, "%%inline directive inside a namespace is disallowed.\n"); |
| |
| $$ = 0; |
| } else { |
| String *code; |
| $$ = new_node("insert"); |
| Delitem(scanner_ccode,0); |
| Delitem(scanner_ccode,DOH_END); |
| code = Copy(scanner_ccode); |
| Setattr($$,"code", code); |
| Delete(code); |
| cpps=Copy(scanner_ccode); |
| start_inline(Char(cpps), start_line); |
| Delete(cpps); |
| } |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %{ ... %} |
| %insert(section) "filename" |
| %insert("section") "filename" |
| %insert(section) %{ ... %} |
| %insert("section") %{ ... %} |
| ------------------------------------------------------------ */ |
| |
| insert_directive : HBLOCK { |
| $$ = new_node("insert"); |
| Setattr($$,"code",$1); |
| } |
| | INSERT LPAREN idstring RPAREN string { |
| String *code = NewStringEmpty(); |
| $$ = new_node("insert"); |
| Setattr($$,"section",$3); |
| Setattr($$,"code",code); |
| if (Swig_insert_file($5,code) < 0) { |
| Swig_error(cparse_file, cparse_line, "Couldn't find '%s'.\n", $5); |
| $$ = 0; |
| } |
| } |
| | INSERT LPAREN idstring RPAREN HBLOCK { |
| $$ = new_node("insert"); |
| Setattr($$,"section",$3); |
| Setattr($$,"code",$5); |
| } |
| | INSERT LPAREN idstring RPAREN LBRACE { |
| String *code; |
| skip_balanced('{','}'); |
| $$ = new_node("insert"); |
| Setattr($$,"section",$3); |
| Delitem(scanner_ccode,0); |
| Delitem(scanner_ccode,DOH_END); |
| code = Copy(scanner_ccode); |
| Setattr($$,"code", code); |
| Delete(code); |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %module modname |
| %module "modname" |
| ------------------------------------------------------------ */ |
| |
| module_directive: MODULE options idstring { |
| $$ = new_node("module"); |
| if ($2) { |
| Setattr($$,"options",$2); |
| if (Getattr($2,"directors")) { |
| Wrapper_director_mode_set(1); |
| if (!cparse_cplusplus) { |
| Swig_error(cparse_file, cparse_line, "Directors are not supported for C code and require the -c++ option\n"); |
| } |
| } |
| if (Getattr($2,"dirprot")) { |
| Wrapper_director_protected_mode_set(1); |
| } |
| if (Getattr($2,"allprotected")) { |
| Wrapper_all_protected_mode_set(1); |
| } |
| if (Getattr($2,"templatereduce")) { |
| template_reduce = 1; |
| } |
| if (Getattr($2,"notemplatereduce")) { |
| template_reduce = 0; |
| } |
| } |
| if (!ModuleName) ModuleName = NewString($3); |
| if (!import_mode) { |
| /* first module included, we apply global |
| ModuleName, which can be modify by -module */ |
| String *mname = Copy(ModuleName); |
| Setattr($$,"name",mname); |
| Delete(mname); |
| } else { |
| /* import mode, we just pass the idstring */ |
| Setattr($$,"name",$3); |
| } |
| if (!module_node) module_node = $$; |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %name(newname) declaration |
| %name("newname") declaration |
| ------------------------------------------------------------ */ |
| |
| name_directive : NAME LPAREN idstring RPAREN { |
| Swig_warning(WARN_DEPRECATED_NAME,cparse_file,cparse_line, "%%name is deprecated. Use %%rename instead.\n"); |
| Delete(yyrename); |
| yyrename = NewString($3); |
| $$ = 0; |
| } |
| | NAME LPAREN RPAREN { |
| Swig_warning(WARN_DEPRECATED_NAME,cparse_file,cparse_line, "%%name is deprecated. Use %%rename instead.\n"); |
| $$ = 0; |
| Swig_error(cparse_file,cparse_line,"Missing argument to %%name directive.\n"); |
| } |
| ; |
| |
| |
| /* ------------------------------------------------------------ |
| %native(scriptname) name; |
| %native(scriptname) type name (parms); |
| ------------------------------------------------------------ */ |
| |
| native_directive : NATIVE LPAREN identifier RPAREN storage_class identifier SEMI { |
| $$ = new_node("native"); |
| Setattr($$,"name",$3); |
| Setattr($$,"wrap:name",$6); |
| add_symbols($$); |
| } |
| | NATIVE LPAREN identifier RPAREN storage_class type declarator SEMI { |
| if (!SwigType_isfunction($7.type)) { |
| Swig_error(cparse_file,cparse_line,"%%native declaration '%s' is not a function.\n", $7.id); |
| $$ = 0; |
| } else { |
| Delete(SwigType_pop_function($7.type)); |
| /* Need check for function here */ |
| SwigType_push($6,$7.type); |
| $$ = new_node("native"); |
| Setattr($$,"name",$3); |
| Setattr($$,"wrap:name",$7.id); |
| Setattr($$,"type",$6); |
| Setattr($$,"parms",$7.parms); |
| Setattr($$,"decl",$7.type); |
| } |
| add_symbols($$); |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %pragma(lang) name=value |
| %pragma(lang) name |
| %pragma name = value |
| %pragma name |
| ------------------------------------------------------------ */ |
| |
| pragma_directive : PRAGMA pragma_lang identifier EQUAL pragma_arg { |
| $$ = new_node("pragma"); |
| Setattr($$,"lang",$2); |
| Setattr($$,"name",$3); |
| Setattr($$,"value",$5); |
| } |
| | PRAGMA pragma_lang identifier { |
| $$ = new_node("pragma"); |
| Setattr($$,"lang",$2); |
| Setattr($$,"name",$3); |
| } |
| ; |
| |
| pragma_arg : string { $$ = $1; } |
| | HBLOCK { $$ = $1; } |
| ; |
| |
| pragma_lang : LPAREN identifier RPAREN { $$ = $2; } |
| | empty { $$ = (char *) "swig"; } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %rename(newname) identifier; |
| ------------------------------------------------------------ */ |
| |
| rename_directive : rename_namewarn declarator idstring SEMI { |
| SwigType *t = $2.type; |
| Hash *kws = NewHash(); |
| String *fixname; |
| fixname = feature_identifier_fix($2.id); |
| Setattr(kws,"name",$3); |
| if (!Len(t)) t = 0; |
| /* Special declarator check */ |
| if (t) { |
| if (SwigType_isfunction(t)) { |
| SwigType *decl = SwigType_pop_function(t); |
| if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",fixname); |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix, nname,decl,kws,$2.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,nname,decl,kws); |
| } |
| Delete(nname); |
| } else { |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,(fixname),decl,kws,$2.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,(fixname),decl,kws); |
| } |
| } |
| Delete(decl); |
| } else if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",fixname); |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,(nname),0,kws,$2.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,(nname),0,kws); |
| } |
| Delete(nname); |
| } |
| } else { |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,(fixname),0,kws,$2.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,(fixname),0,kws); |
| } |
| } |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | rename_namewarn LPAREN kwargs RPAREN declarator cpp_const SEMI { |
| String *fixname; |
| Hash *kws = $3; |
| SwigType *t = $5.type; |
| fixname = feature_identifier_fix($5.id); |
| if (!Len(t)) t = 0; |
| /* Special declarator check */ |
| if (t) { |
| if ($6.qualifier) SwigType_push(t,$6.qualifier); |
| if (SwigType_isfunction(t)) { |
| SwigType *decl = SwigType_pop_function(t); |
| if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",fixname); |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix, nname,decl,kws,$5.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,nname,decl,kws); |
| } |
| Delete(nname); |
| } else { |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,(fixname),decl,kws,$5.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,(fixname),decl,kws); |
| } |
| } |
| Delete(decl); |
| } else if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",fixname); |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,(nname),0,kws,$5.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,(nname),0,kws); |
| } |
| Delete(nname); |
| } |
| } else { |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,(fixname),0,kws,$5.parms); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,(fixname),0,kws); |
| } |
| } |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | rename_namewarn LPAREN kwargs RPAREN string SEMI { |
| if ($1) { |
| Swig_name_rename_add(Namespaceprefix,$5,0,$3,0); |
| } else { |
| Swig_name_namewarn_add(Namespaceprefix,$5,0,$3); |
| } |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| ; |
| |
| rename_namewarn : RENAME { |
| $$ = 1; |
| } |
| | NAMEWARN { |
| $$ = 0; |
| }; |
| |
| |
| /* ------------------------------------------------------------ |
| Feature targeting a symbol name (non-global feature): |
| |
| %feature(featurename) name "val"; |
| %feature(featurename, val) name; |
| |
| where "val" could instead be the other bracket types, that is, |
| { val } or %{ val %} or indeed omitted whereupon it defaults to "1". |
| Or, the global feature which does not target a symbol name: |
| |
| %feature(featurename) "val"; |
| %feature(featurename, val); |
| |
| An empty val (empty string) clears the feature. |
| Any number of feature attributes can optionally be added, for example |
| a non-global feature with 2 attributes: |
| |
| %feature(featurename, attrib1="attribval1", attrib2="attribval2") name "val"; |
| %feature(featurename, val, attrib1="attribval1", attrib2="attribval2") name; |
| ------------------------------------------------------------ */ |
| |
| /* Non-global feature */ |
| feature_directive : FEATURE LPAREN idstring RPAREN declarator cpp_const stringbracesemi { |
| String *val = $7 ? NewString($7) : NewString("1"); |
| new_feature($3, val, 0, $5.id, $5.type, $5.parms, $6.qualifier); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | FEATURE LPAREN idstring COMMA stringnum RPAREN declarator cpp_const SEMI { |
| String *val = Len($5) ? $5 : 0; |
| new_feature($3, val, 0, $7.id, $7.type, $7.parms, $8.qualifier); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | FEATURE LPAREN idstring featattr RPAREN declarator cpp_const stringbracesemi { |
| String *val = $8 ? NewString($8) : NewString("1"); |
| new_feature($3, val, $4, $6.id, $6.type, $6.parms, $7.qualifier); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | FEATURE LPAREN idstring COMMA stringnum featattr RPAREN declarator cpp_const SEMI { |
| String *val = Len($5) ? $5 : 0; |
| new_feature($3, val, $6, $8.id, $8.type, $8.parms, $9.qualifier); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| |
| /* Global feature */ |
| | FEATURE LPAREN idstring RPAREN stringbracesemi { |
| String *val = $5 ? NewString($5) : NewString("1"); |
| new_feature($3, val, 0, 0, 0, 0, 0); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | FEATURE LPAREN idstring COMMA stringnum RPAREN SEMI { |
| String *val = Len($5) ? $5 : 0; |
| new_feature($3, val, 0, 0, 0, 0, 0); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | FEATURE LPAREN idstring featattr RPAREN stringbracesemi { |
| String *val = $6 ? NewString($6) : NewString("1"); |
| new_feature($3, val, $4, 0, 0, 0, 0); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| | FEATURE LPAREN idstring COMMA stringnum featattr RPAREN SEMI { |
| String *val = Len($5) ? $5 : 0; |
| new_feature($3, val, $6, 0, 0, 0, 0); |
| $$ = 0; |
| scanner_clear_rename(); |
| } |
| ; |
| |
| stringbracesemi : stringbrace { $$ = $1; } |
| | SEMI { $$ = 0; } |
| | PARMS LPAREN parms RPAREN SEMI { $$ = $3; } |
| ; |
| |
| featattr : COMMA idstring EQUAL stringnum { |
| $$ = NewHash(); |
| Setattr($$,"name",$2); |
| Setattr($$,"value",$4); |
| } |
| | COMMA idstring EQUAL stringnum featattr { |
| $$ = NewHash(); |
| Setattr($$,"name",$2); |
| Setattr($$,"value",$4); |
| set_nextSibling($$,$5); |
| } |
| ; |
| |
| /* %varargs() directive. */ |
| |
| varargs_directive : VARARGS LPAREN varargs_parms RPAREN declarator cpp_const SEMI { |
| Parm *val; |
| String *name; |
| SwigType *t; |
| if (Namespaceprefix) name = NewStringf("%s::%s", Namespaceprefix, $5.id); |
| else name = NewString($5.id); |
| val = $3; |
| if ($5.parms) { |
| Setmeta(val,"parms",$5.parms); |
| } |
| t = $5.type; |
| if (!Len(t)) t = 0; |
| if (t) { |
| if ($6.qualifier) SwigType_push(t,$6.qualifier); |
| if (SwigType_isfunction(t)) { |
| SwigType *decl = SwigType_pop_function(t); |
| if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",name); |
| Swig_feature_set(Swig_cparse_features(), nname, decl, "feature:varargs", val, 0); |
| Delete(nname); |
| } else { |
| Swig_feature_set(Swig_cparse_features(), name, decl, "feature:varargs", val, 0); |
| } |
| Delete(decl); |
| } else if (SwigType_ispointer(t)) { |
| String *nname = NewStringf("*%s",name); |
| Swig_feature_set(Swig_cparse_features(),nname,0,"feature:varargs",val, 0); |
| Delete(nname); |
| } |
| } else { |
| Swig_feature_set(Swig_cparse_features(),name,0,"feature:varargs",val, 0); |
| } |
| Delete(name); |
| $$ = 0; |
| }; |
| |
| varargs_parms : parms { $$ = $1; } |
| | NUM_INT COMMA parm { |
| int i; |
| int n; |
| Parm *p; |
| n = atoi(Char($1.val)); |
| if (n <= 0) { |
| Swig_error(cparse_file, cparse_line,"Argument count in %%varargs must be positive.\n"); |
| $$ = 0; |
| } else { |
| String *name = Getattr($3, "name"); |
| $$ = Copy($3); |
| if (name) |
| Setattr($$, "name", NewStringf("%s%d", name, n)); |
| for (i = 1; i < n; i++) { |
| p = Copy($3); |
| name = Getattr(p, "name"); |
| if (name) |
| Setattr(p, "name", NewStringf("%s%d", name, n-i)); |
| set_nextSibling(p,$$); |
| Delete($$); |
| $$ = p; |
| } |
| } |
| } |
| ; |
| |
| |
| /* ------------------------------------------------------------ |
| %typemap(method) type { ... } |
| %typemap(method) type "..." |
| %typemap(method) type; - typemap deletion |
| %typemap(method) type1,type2,... = type; - typemap copy |
| %typemap type1,type2,... = type; - typemap copy |
| ------------------------------------------------------------ */ |
| |
| typemap_directive : TYPEMAP LPAREN typemap_type RPAREN tm_list stringbrace { |
| $$ = 0; |
| if ($3.method) { |
| String *code = 0; |
| $$ = new_node("typemap"); |
| Setattr($$,"method",$3.method); |
| if ($3.kwargs) { |
| ParmList *kw = $3.kwargs; |
| code = remove_block(kw, $6); |
| Setattr($$,"kwargs", $3.kwargs); |
| } |
| code = code ? code : NewString($6); |
| Setattr($$,"code", code); |
| Delete(code); |
| appendChild($$,$5); |
| } |
| } |
| | TYPEMAP LPAREN typemap_type RPAREN tm_list SEMI { |
| $$ = 0; |
| if ($3.method) { |
| $$ = new_node("typemap"); |
| Setattr($$,"method",$3.method); |
| appendChild($$,$5); |
| } |
| } |
| | TYPEMAP LPAREN typemap_type RPAREN tm_list EQUAL typemap_parm SEMI { |
| $$ = 0; |
| if ($3.method) { |
| $$ = new_node("typemapcopy"); |
| Setattr($$,"method",$3.method); |
| Setattr($$,"pattern", Getattr($7,"pattern")); |
| appendChild($$,$5); |
| } |
| } |
| ; |
| |
| /* typemap method type (lang,method) or (method) */ |
| |
| typemap_type : kwargs { |
| Hash *p; |
| String *name; |
| p = nextSibling($1); |
| if (p && (!Getattr(p,"value"))) { |
| /* this is the deprecated two argument typemap form */ |
| Swig_warning(WARN_DEPRECATED_TYPEMAP_LANG,cparse_file, cparse_line, |
| "Specifying the language name in %%typemap is deprecated - use #ifdef SWIG<LANG> instead.\n"); |
| /* two argument typemap form */ |
| name = Getattr($1,"name"); |
| if (!name || (Strcmp(name,typemap_lang))) { |
| $$.method = 0; |
| $$.kwargs = 0; |
| } else { |
| $$.method = Getattr(p,"name"); |
| $$.kwargs = nextSibling(p); |
| } |
| } else { |
| /* one-argument typemap-form */ |
| $$.method = Getattr($1,"name"); |
| $$.kwargs = p; |
| } |
| } |
| ; |
| |
| tm_list : typemap_parm tm_tail { |
| $$ = $1; |
| set_nextSibling($$,$2); |
| } |
| ; |
| |
| tm_tail : COMMA typemap_parm tm_tail { |
| $$ = $2; |
| set_nextSibling($$,$3); |
| } |
| | empty { $$ = 0;} |
| ; |
| |
| typemap_parm : type plain_declarator { |
| Parm *parm; |
| SwigType_push($1,$2.type); |
| $$ = new_node("typemapitem"); |
| parm = NewParmWithoutFileLineInfo($1,$2.id); |
| Setattr($$,"pattern",parm); |
| Setattr($$,"parms", $2.parms); |
| Delete(parm); |
| /* $$ = NewParmWithoutFileLineInfo($1,$2.id); |
| Setattr($$,"parms",$2.parms); */ |
| } |
| | LPAREN parms RPAREN { |
| $$ = new_node("typemapitem"); |
| Setattr($$,"pattern",$2); |
| /* Setattr($$,"multitype",$2); */ |
| } |
| | LPAREN parms RPAREN LPAREN parms RPAREN { |
| $$ = new_node("typemapitem"); |
| Setattr($$,"pattern", $2); |
| /* Setattr($$,"multitype",$2); */ |
| Setattr($$,"parms",$5); |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %types(parmlist); |
| %types(parmlist) %{ ... %} |
| ------------------------------------------------------------ */ |
| |
| types_directive : TYPES LPAREN parms RPAREN stringbracesemi { |
| $$ = new_node("types"); |
| Setattr($$,"parms",$3); |
| if ($5) |
| Setattr($$,"convcode",NewString($5)); |
| } |
| ; |
| |
| /* ------------------------------------------------------------ |
| %template(name) tname<args>; |
| ------------------------------------------------------------ */ |
| |
| template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN valparms GREATERTHAN SEMI { |
| Parm *p, *tp; |
| Node *n; |
| Node *outer_class = currentOuterClass; |
| Symtab *tscope = 0; |
| int specialized = 0; |
| int variadic = 0; |
| |
| $$ = 0; |
| |
| tscope = Swig_symbol_current(); /* Get the current scope */ |
|