diff options
author | vitalyisaev <vitalyisaev@ydb.tech> | 2023-11-30 13:26:22 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@ydb.tech> | 2023-11-30 15:44:45 +0300 |
commit | 0a98fece5a9b54f16afeb3a94b3eb3105e9c3962 (patch) | |
tree | 291d72dbd7e9865399f668c84d11ed86fb190bbf /contrib/tools/swig/Source/CParse | |
parent | cb2c8d75065e5b3c47094067cb4aa407d4813298 (diff) | |
download | ydb-0a98fece5a9b54f16afeb3a94b3eb3105e9c3962.tar.gz |
YQ Connector:Use docker-compose in integrational tests
Diffstat (limited to 'contrib/tools/swig/Source/CParse')
-rw-r--r-- | contrib/tools/swig/Source/CParse/cparse.h | 85 | ||||
-rw-r--r-- | contrib/tools/swig/Source/CParse/cscanner.c | 1088 | ||||
-rw-r--r-- | contrib/tools/swig/Source/CParse/parser.y | 7499 | ||||
-rw-r--r-- | contrib/tools/swig/Source/CParse/templ.c | 976 | ||||
-rw-r--r-- | contrib/tools/swig/Source/CParse/util.c | 126 |
5 files changed, 9774 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/CParse/cparse.h b/contrib/tools/swig/Source/CParse/cparse.h new file mode 100644 index 0000000000..2b63f034d0 --- /dev/null +++ b/contrib/tools/swig/Source/CParse/cparse.h @@ -0,0 +1,85 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * cparse.h + * + * SWIG parser module. + * ----------------------------------------------------------------------------- */ + +#ifndef SWIG_CPARSE_H +#define SWIG_CPARSE_H + +#include "swig.h" +#include "swigwarn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* cscanner.c */ + extern String *cparse_file; + extern int cparse_line; + extern int cparse_cplusplus; + extern int cparse_cplusplusout; + extern int cparse_start_line; + extern String *cparse_unknown_directive; + extern int scan_doxygen_comments; + + extern void Swig_cparse_cplusplus(int); + extern void Swig_cparse_cplusplusout(int); + extern void scanner_file(File *); + extern void scanner_next_token(int); + extern void skip_balanced(int startchar, int endchar); + extern String *get_raw_text_balanced(int startchar, int endchar); + extern void skip_decl(void); + extern void scanner_check_typedef(void); + extern void scanner_ignore_typedef(void); + extern void scanner_last_id(int); + extern void scanner_clear_rename(void); + extern void scanner_set_location(String *file, int line); + extern void scanner_set_main_input_file(String *file); + extern String *scanner_get_main_input_file(void); + extern void Swig_cparse_follow_locators(int); + extern void start_inline(char *, int); + extern String *scanner_ccode; + extern int yylex(void); + +/* parser.y */ + extern SwigType *Swig_cparse_type(String *); + extern Node *Swig_cparse(File *); + extern Hash *Swig_cparse_features(void); + extern void SWIG_cparse_set_compact_default_args(int defargs); + extern int SWIG_cparse_template_reduce(int treduce); + +/* util.c */ + extern void Swig_cparse_replace_descriptor(String *s); + extern SwigType *Swig_cparse_smartptr(Node *n); + 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 *Swig_cparse_new_node(const_String_or_char_ptr tag); + +/* templ.c */ + extern int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope); + extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, Symtab *tscope); + extern void Swig_cparse_debug_templates(int); + +#ifdef __cplusplus +} +#endif +#define SWIG_WARN_NODE_BEGIN(Node) \ + { \ + String *wrnfilter = Node ? Getattr(Node,"feature:warnfilter") : 0; \ + if (wrnfilter) Swig_warnfilter(wrnfilter,1) +#define SWIG_WARN_NODE_END(Node) \ + if (wrnfilter) Swig_warnfilter(wrnfilter,0); \ + } + +#define COMPOUND_EXPR_VAL(dtype) \ + ((dtype).type == T_CHAR || (dtype).type == T_WCHAR ? (dtype).rawval : (dtype).val) +#endif diff --git a/contrib/tools/swig/Source/CParse/cscanner.c b/contrib/tools/swig/Source/CParse/cscanner.c new file mode 100644 index 0000000000..2eb3f97749 --- /dev/null +++ b/contrib/tools/swig/Source/CParse/cscanner.c @@ -0,0 +1,1088 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * scanner.c + * + * SWIG tokenizer. This file is a wrapper around the generic C scanner + * found in Swig/scanner.c. Extra logic is added both to accommodate the + * bison-based grammar and certain peculiarities of C++ parsing (e.g., + * operator overloading, typedef resolution, etc.). This code also splits + * C identifiers up into keywords and SWIG directives. + * ----------------------------------------------------------------------------- */ + +#include "cparse.h" +#include "parser.h" +#include <string.h> +#include <ctype.h> + +/* Scanner object */ +static Scanner *scan = 0; + +/* Global string containing C code. Used by the parser to grab code blocks */ +String *scanner_ccode = 0; + +/* The main file being parsed */ +static String *main_input_file = 0; + +/* Error reporting/location information */ +int cparse_line = 1; +String *cparse_file = 0; +int cparse_start_line = 0; + +/* C++ mode */ +int cparse_cplusplus = 0; + +/* Generate C++ compatible code when wrapping C code */ +int cparse_cplusplusout = 0; + +/* To allow better error reporting */ +String *cparse_unknown_directive = 0; + +/* Private vars */ +static int scan_init = 0; +static int num_brace = 0; +static int last_brace = 0; +static int last_id = 0; +static int rename_active = 0; + +/* Doxygen comments scanning */ +int scan_doxygen_comments = 0; + +int isStructuralDoxygen(String *s) { + static const char* const structuralTags[] = { + "addtogroup", + "callgraph", + "callergraph", + "category", + "def", + "defgroup", + "dir", + "example", + "file", + "headerfile", + "internal", + "mainpage", + "name", + "nosubgrouping", + "overload", + "package", + "page", + "protocol", + "relates", + "relatesalso", + "showinitializer", + "weakgroup", + }; + + unsigned n; + char *slashPointer = Strchr(s, '\\'); + char *atPointer = Strchr(s,'@'); + if (slashPointer == NULL && atPointer == NULL) + return 0; + else if(slashPointer == NULL) + slashPointer = atPointer; + + slashPointer++; /* skip backslash or at sign */ + + for (n = 0; n < sizeof(structuralTags)/sizeof(structuralTags[0]); n++) { + const size_t len = strlen(structuralTags[n]); + if (strncmp(slashPointer, structuralTags[n], len) == 0) { + /* Take care to avoid false positives with prefixes of other tags. */ + if (slashPointer[len] == '\0' || isspace((int)slashPointer[len])) + return 1; + } + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_cparse_cplusplus() + * ----------------------------------------------------------------------------- */ + +void Swig_cparse_cplusplus(int v) { + cparse_cplusplus = v; +} + +/* ----------------------------------------------------------------------------- + * Swig_cparse_cplusplusout() + * ----------------------------------------------------------------------------- */ + +void Swig_cparse_cplusplusout(int v) { + cparse_cplusplusout = v; +} + +/* ---------------------------------------------------------------------------- + * scanner_init() + * + * Initialize buffers + * ------------------------------------------------------------------------- */ + +void scanner_init(void) { + scan = NewScanner(); + Scanner_idstart(scan,"%"); + scan_init = 1; + scanner_ccode = NewStringEmpty(); +} + +/* ---------------------------------------------------------------------------- + * scanner_file(DOHFile *f) + * + * Start reading from new file + * ------------------------------------------------------------------------- */ +void scanner_file(DOHFile * f) { + if (!scan_init) scanner_init(); + Scanner_clear(scan); + Scanner_push(scan,f); +} + +/* ---------------------------------------------------------------------------- + * start_inline(char *text, int line) + * + * Take a chunk of text and recursively feed it back into the scanner. Used + * by the %inline directive. + * ------------------------------------------------------------------------- */ + +void start_inline(char *text, int line) { + String *stext = NewString(text); + + Seek(stext,0,SEEK_SET); + Setfile(stext,cparse_file); + Setline(stext,line); + Scanner_push(scan,stext); + Delete(stext); +} + +/* ----------------------------------------------------------------------------- + * skip_balanced() + * + * Skips a piece of code enclosed in begin/end symbols such as '{...}' or + * (...). Ignores symbols inside comments or strings. + * ----------------------------------------------------------------------------- */ + +void skip_balanced(int startchar, int endchar) { + int start_line = Scanner_line(scan); + Clear(scanner_ccode); + + if (Scanner_skip_balanced(scan,startchar,endchar) < 0) { + Swig_error(cparse_file, start_line, "Missing '%c'. Reached end of input.\n", endchar); + return; + } + + cparse_line = Scanner_line(scan); + cparse_file = Scanner_file(scan); + + Append(scanner_ccode, Scanner_text(scan)); + if (endchar == '}') + num_brace--; + return; +} + +/* ----------------------------------------------------------------------------- + * get_raw_text_balanced() + * + * Returns raw text between 2 braces + * ----------------------------------------------------------------------------- */ + +String *get_raw_text_balanced(int startchar, int endchar) { + return Scanner_get_raw_text_balanced(scan, startchar, endchar); +} + +/* ---------------------------------------------------------------------------- + * void skip_decl(void) + * + * This tries to skip over an entire declaration. For example + * + * friend ostream& operator<<(ostream&, const char *s); + * + * or + * friend ostream& operator<<(ostream&, const char *s) { } + * + * ------------------------------------------------------------------------- */ + +void skip_decl(void) { + int tok; + int done = 0; + int start_line = Scanner_line(scan); + + while (!done) { + tok = Scanner_token(scan); + if (tok == 0) { + if (!Swig_error_count()) { + Swig_error(cparse_file, start_line, "Missing semicolon (';'). Reached end of input.\n"); + } + return; + } + if (tok == SWIG_TOKEN_LBRACE) { + if (Scanner_skip_balanced(scan,'{','}') < 0) { + Swig_error(cparse_file, start_line, "Missing closing brace ('}'). Reached end of input.\n"); + } + break; + } + if (tok == SWIG_TOKEN_SEMI) { + done = 1; + } + } + cparse_file = Scanner_file(scan); + cparse_line = Scanner_line(scan); +} + +/* ---------------------------------------------------------------------------- + * int yylook() + * + * Lexical scanner. + * ------------------------------------------------------------------------- */ + +static int yylook(void) { + + int tok = 0; + + while (1) { + if ((tok = Scanner_token(scan)) == 0) + return 0; + if (tok == SWIG_TOKEN_ERROR) + return 0; + cparse_start_line = Scanner_start_line(scan); + cparse_line = Scanner_line(scan); + cparse_file = Scanner_file(scan); + + switch(tok) { + case SWIG_TOKEN_ID: + return ID; + case SWIG_TOKEN_LPAREN: + return LPAREN; + case SWIG_TOKEN_RPAREN: + return RPAREN; + case SWIG_TOKEN_SEMI: + return SEMI; + case SWIG_TOKEN_COMMA: + return COMMA; + case SWIG_TOKEN_STAR: + return STAR; + case SWIG_TOKEN_RBRACE: + num_brace--; + if (num_brace < 0) { + Swig_error(cparse_file, cparse_line, "Syntax error. Extraneous closing brace ('}')\n"); + num_brace = 0; + } else { + return RBRACE; + } + break; + case SWIG_TOKEN_LBRACE: + last_brace = num_brace; + num_brace++; + return LBRACE; + case SWIG_TOKEN_EQUAL: + return EQUAL; + case SWIG_TOKEN_EQUALTO: + return EQUALTO; + case SWIG_TOKEN_PLUS: + return PLUS; + case SWIG_TOKEN_MINUS: + return MINUS; + case SWIG_TOKEN_SLASH: + return SLASH; + case SWIG_TOKEN_AND: + return AND; + case SWIG_TOKEN_LAND: + return LAND; + case SWIG_TOKEN_OR: + return OR; + case SWIG_TOKEN_LOR: + return LOR; + case SWIG_TOKEN_XOR: + return XOR; + case SWIG_TOKEN_NOT: + return NOT; + case SWIG_TOKEN_LNOT: + return LNOT; + case SWIG_TOKEN_NOTEQUAL: + return NOTEQUALTO; + case SWIG_TOKEN_LBRACKET: + return LBRACKET; + case SWIG_TOKEN_RBRACKET: + return RBRACKET; + case SWIG_TOKEN_QUESTION: + return QUESTIONMARK; + case SWIG_TOKEN_LESSTHAN: + return LESSTHAN; + case SWIG_TOKEN_LTEQUAL: + return LESSTHANOREQUALTO; + case SWIG_TOKEN_LSHIFT: + return LSHIFT; + case SWIG_TOKEN_GREATERTHAN: + return GREATERTHAN; + case SWIG_TOKEN_GTEQUAL: + return GREATERTHANOREQUALTO; + case SWIG_TOKEN_RSHIFT: + return RSHIFT; + case SWIG_TOKEN_ARROW: + return ARROW; + case SWIG_TOKEN_PERIOD: + return PERIOD; + case SWIG_TOKEN_MODULO: + return MODULO; + case SWIG_TOKEN_COLON: + return COLON; + case SWIG_TOKEN_DCOLONSTAR: + return DSTAR; + case SWIG_TOKEN_LTEQUALGT: + return LESSEQUALGREATER; + + case SWIG_TOKEN_DCOLON: + { + int nexttok = Scanner_token(scan); + if (nexttok == SWIG_TOKEN_STAR) { + return DSTAR; + } else if (nexttok == SWIG_TOKEN_NOT) { + return DCNOT; + } else { + Scanner_pushtoken(scan,nexttok,Scanner_text(scan)); + if (!last_id) { + scanner_next_token(DCOLON); + return NONID; + } else { + return DCOLON; + } + } + } + break; + + case SWIG_TOKEN_ELLIPSIS: + return ELLIPSIS; + + case SWIG_TOKEN_LLBRACKET: + do { + tok = Scanner_token(scan); + } while ((tok != SWIG_TOKEN_RRBRACKET) && (tok > 0)); + if (tok <= 0) { + Swig_error(cparse_file, cparse_line, "Unbalanced double brackets, missing closing (']]'). Reached end of input.\n"); + } + break; + + case SWIG_TOKEN_RRBRACKET: + /* Turn an unmatched ]] back into two ] - e.g. `a[a[0]]` */ + scanner_next_token(RBRACKET); + return RBRACKET; + + /* Look for multi-character sequences */ + + case SWIG_TOKEN_RSTRING: + yylval.type = NewString(Scanner_text(scan)); + return TYPE_RAW; + + case SWIG_TOKEN_STRING: + yylval.id = Swig_copy_string(Char(Scanner_text(scan))); + return STRING; + + case SWIG_TOKEN_WSTRING: + yylval.id = Swig_copy_string(Char(Scanner_text(scan))); + return WSTRING; + + case SWIG_TOKEN_CHAR: + yylval.str = NewString(Scanner_text(scan)); + if (Len(yylval.str) == 0) { + Swig_error(cparse_file, cparse_line, "Empty character constant\n"); + } + return CHARCONST; + + case SWIG_TOKEN_WCHAR: + yylval.str = NewString(Scanner_text(scan)); + if (Len(yylval.str) == 0) { + Swig_error(cparse_file, cparse_line, "Empty character constant\n"); + } + return WCHARCONST; + + /* Numbers */ + + case SWIG_TOKEN_INT: + return NUM_INT; + + case SWIG_TOKEN_UINT: + return NUM_UNSIGNED; + + case SWIG_TOKEN_LONG: + return NUM_LONG; + + case SWIG_TOKEN_ULONG: + return NUM_ULONG; + + case SWIG_TOKEN_LONGLONG: + return NUM_LONGLONG; + + case SWIG_TOKEN_ULONGLONG: + return NUM_ULONGLONG; + + case SWIG_TOKEN_DOUBLE: + case SWIG_TOKEN_FLOAT: + return NUM_FLOAT; + + case SWIG_TOKEN_BOOL: + return NUM_BOOL; + + case SWIG_TOKEN_POUND: + Scanner_skip_line(scan); + yylval.id = Swig_copy_string(Char(Scanner_text(scan))); + return POUND; + break; + + case SWIG_TOKEN_CODEBLOCK: + yylval.str = NewString(Scanner_text(scan)); + return HBLOCK; + + case SWIG_TOKEN_COMMENT: + { + typedef enum { + DOX_COMMENT_PRE = -1, + DOX_COMMENT_NONE, + DOX_COMMENT_POST + } comment_kind_t; + comment_kind_t existing_comment = DOX_COMMENT_NONE; + + /* Concatenate or skip all consecutive comments at once. */ + do { + String *cmt = Scanner_text(scan); + String *cmt_modified = 0; + char *loc = Char(cmt); + if ((strncmp(loc, "/*@SWIG", 7) == 0) && (loc[Len(cmt)-3] == '@')) { + Scanner_locator(scan, cmt); + } + if (scan_doxygen_comments) { /* else just skip this node, to avoid crashes in parser module*/ + + int slashStyle = 0; /* Flag for "///" style doxygen comments */ + if (strncmp(loc, "///", 3) == 0) { + slashStyle = 1; + if (Len(cmt) == 3) { + /* Modify to make length=4 to ensure that the empty comment does + get processed to preserve the newlines in the original comments. */ + cmt_modified = NewStringf("%s ", cmt); + cmt = cmt_modified; + loc = Char(cmt); + } + } + + /* Check for all possible Doxygen comment start markers while ignoring + comments starting with a row of asterisks or slashes just as + Doxygen itself does. Also skip empty comment (slash-star-star-slash), + which causes a crash due to begin > end. */ + if (Len(cmt) > 3 && loc[0] == '/' && + ((loc[1] == '/' && ((loc[2] == '/' && loc[3] != '/') || loc[2] == '!')) || + (loc[1] == '*' && ((loc[2] == '*' && loc[3] != '*' && loc[3] != '/') || loc[2] == '!')))) { + comment_kind_t this_comment = loc[3] == '<' ? DOX_COMMENT_POST : DOX_COMMENT_PRE; + if (existing_comment != DOX_COMMENT_NONE && this_comment != existing_comment) { + /* We can't concatenate together Doxygen pre- and post-comments. */ + break; + } + + if (this_comment == DOX_COMMENT_POST || !isStructuralDoxygen(loc)) { + String *str; + + int begin = this_comment == DOX_COMMENT_POST ? 4 : 3; + int end = Len(cmt); + if (loc[end - 1] == '/' && loc[end - 2] == '*') { + end -= 2; + } + + str = NewStringWithSize(loc + begin, end - begin); + + if (existing_comment == DOX_COMMENT_NONE) { + yylval.str = str; + Setline(yylval.str, Scanner_start_line(scan)); + Setfile(yylval.str, Scanner_file(scan)); + } else { + if (slashStyle) { + /* Add a newline to the end of each doxygen "///" comment, + since they are processed individually, unlike the + slash-star style, which gets processed as a block with + newlines included. */ + Append(yylval.str, "\n"); + } + Append(yylval.str, str); + } + + existing_comment = this_comment; + } + } + } + do { + tok = Scanner_token(scan); + } while (tok == SWIG_TOKEN_ENDLINE); + Delete(cmt_modified); + } while (tok == SWIG_TOKEN_COMMENT); + + Scanner_pushtoken(scan, tok, Scanner_text(scan)); + + switch (existing_comment) { + case DOX_COMMENT_PRE: + return DOXYGENSTRING; + case DOX_COMMENT_NONE: + break; + case DOX_COMMENT_POST: + return DOXYGENPOSTSTRING; + } + } + break; + case SWIG_TOKEN_ENDLINE: + break; + case SWIG_TOKEN_BACKSLASH: + break; + default: + Swig_error(cparse_file, cparse_line, "Illegal token '%s'.\n", Scanner_text(scan)); + return (ILLEGAL); + } + } +} + +static int check_typedef = 0; + +void scanner_set_location(String *file, int line) { + Scanner_set_location(scan,file,line-1); +} + +void scanner_check_typedef(void) { + check_typedef = 1; +} + +void scanner_ignore_typedef(void) { + check_typedef = 0; +} + +void scanner_last_id(int x) { + last_id = x; +} + +void scanner_clear_rename(void) { + rename_active = 0; +} + +/* Used to push a fictitious token into the scanner */ +static int next_token = 0; +void scanner_next_token(int tok) { + next_token = tok; +} + +void scanner_set_main_input_file(String *file) { + main_input_file = file; +} + +String *scanner_get_main_input_file(void) { + return main_input_file; +} + +/* ---------------------------------------------------------------------------- + * int yylex() + * + * Gets the lexene and returns tokens. + * ------------------------------------------------------------------------- */ + +int yylex(void) { + + int l; + char *yytext; + + if (!scan_init) { + scanner_init(); + } + + Delete(cparse_unknown_directive); + cparse_unknown_directive = NULL; + + if (next_token) { + l = next_token; + next_token = 0; + return l; + } + + l = yylook(); + + /* Swig_diagnostic(cparse_file, cparse_line, ":::%d: '%s'\n", l, Scanner_text(scan)); */ + + if (l == NONID) { + last_id = 1; + } else { + last_id = 0; + } + + /* We got some sort of non-white space object. We set the start_line + variable unless it has already been set */ + + if (!cparse_start_line) { + cparse_start_line = cparse_line; + } + + /* Copy the lexene */ + + switch (l) { + + case NUM_INT: + case NUM_FLOAT: + case NUM_ULONG: + case NUM_LONG: + case NUM_UNSIGNED: + case NUM_LONGLONG: + case NUM_ULONGLONG: + case NUM_BOOL: + if (l == NUM_INT) + yylval.dtype.type = T_INT; + if (l == NUM_FLOAT) + yylval.dtype.type = T_DOUBLE; + if (l == NUM_ULONG) + yylval.dtype.type = T_ULONG; + if (l == NUM_LONG) + yylval.dtype.type = T_LONG; + if (l == NUM_UNSIGNED) + yylval.dtype.type = T_UINT; + if (l == NUM_LONGLONG) + yylval.dtype.type = T_LONGLONG; + if (l == NUM_ULONGLONG) + yylval.dtype.type = T_ULONGLONG; + if (l == NUM_BOOL) + yylval.dtype.type = T_BOOL; + yylval.dtype.val = NewString(Scanner_text(scan)); + yylval.dtype.bitfield = 0; + yylval.dtype.throws = 0; + return (l); + + case ID: + yytext = Char(Scanner_text(scan)); + if (yytext[0] != '%') { + /* Look for keywords now */ + + if (strcmp(yytext, "int") == 0) { + yylval.type = NewSwigType(T_INT); + return (TYPE_INT); + } + if (strcmp(yytext, "double") == 0) { + yylval.type = NewSwigType(T_DOUBLE); + return (TYPE_DOUBLE); + } + if (strcmp(yytext, "void") == 0) { + yylval.type = NewSwigType(T_VOID); + return (TYPE_VOID); + } + if (strcmp(yytext, "char") == 0) { + yylval.type = NewSwigType(T_CHAR); + return (TYPE_CHAR); + } + if (strcmp(yytext, "wchar_t") == 0) { + yylval.type = NewSwigType(T_WCHAR); + return (TYPE_WCHAR); + } + if (strcmp(yytext, "short") == 0) { + yylval.type = NewSwigType(T_SHORT); + return (TYPE_SHORT); + } + if (strcmp(yytext, "long") == 0) { + yylval.type = NewSwigType(T_LONG); + return (TYPE_LONG); + } + if (strcmp(yytext, "float") == 0) { + yylval.type = NewSwigType(T_FLOAT); + return (TYPE_FLOAT); + } + if (strcmp(yytext, "signed") == 0) { + yylval.type = NewSwigType(T_INT); + return (TYPE_SIGNED); + } + if (strcmp(yytext, "unsigned") == 0) { + yylval.type = NewSwigType(T_UINT); + return (TYPE_UNSIGNED); + } + if (strcmp(yytext, "bool") == 0) { + yylval.type = NewSwigType(T_BOOL); + return (TYPE_BOOL); + } + + /* Non ISO (Windows) C extensions */ + if (strcmp(yytext, "__int8") == 0) { + yylval.type = NewString(yytext); + return (TYPE_NON_ISO_INT8); + } + if (strcmp(yytext, "__int16") == 0) { + yylval.type = NewString(yytext); + return (TYPE_NON_ISO_INT16); + } + if (strcmp(yytext, "__int32") == 0) { + yylval.type = NewString(yytext); + return (TYPE_NON_ISO_INT32); + } + if (strcmp(yytext, "__int64") == 0) { + yylval.type = NewString(yytext); + return (TYPE_NON_ISO_INT64); + } + + /* C++ keywords */ + if (cparse_cplusplus) { + if (strcmp(yytext, "and") == 0) + return (LAND); + if (strcmp(yytext, "or") == 0) + return (LOR); + if (strcmp(yytext, "not") == 0) + return (LNOT); + if (strcmp(yytext, "class") == 0) + return (CLASS); + if (strcmp(yytext, "private") == 0) + return (PRIVATE); + if (strcmp(yytext, "public") == 0) + return (PUBLIC); + if (strcmp(yytext, "protected") == 0) + return (PROTECTED); + if (strcmp(yytext, "friend") == 0) + return (FRIEND); + if (strcmp(yytext, "constexpr") == 0) + return (CONSTEXPR); + if (strcmp(yytext, "thread_local") == 0) + return (THREAD_LOCAL); + if (strcmp(yytext, "decltype") == 0) + return (DECLTYPE); + if (strcmp(yytext, "virtual") == 0) + return (VIRTUAL); + if (strcmp(yytext, "static_assert") == 0) + return (STATIC_ASSERT); + if (strcmp(yytext, "operator") == 0) { + int nexttok; + String *s = NewString("operator "); + + /* If we have an operator, we have to collect the operator symbol and attach it to + the operator identifier. To do this, we need to scan ahead by several tokens. + Cases include: + + (1) If the next token is an operator as determined by Scanner_isoperator(), + it means that the operator applies to one of the standard C++ mathematical, + assignment, or logical operator symbols (e.g., '+','<=','==','&', etc.) + In this case, we merely append the symbol text to the operator string above. + + (2) If the next token is (, we look for ). This is operator (). + (3) If the next token is [, we look for ]. This is operator []. + (4) If the next token is an identifier. The operator is possibly a conversion operator. + (a) Must check for special case new[] and delete[] + + Error handling is somewhat tricky here. We'll try to back out gracefully if we can. + + */ + + do { + nexttok = Scanner_token(scan); + } while (nexttok == SWIG_TOKEN_ENDLINE || nexttok == SWIG_TOKEN_COMMENT); + + if (Scanner_isoperator(nexttok)) { + /* One of the standard C/C++ symbolic operators */ + Append(s,Scanner_text(scan)); + yylval.str = s; + return OPERATOR; + } else if (nexttok == SWIG_TOKEN_LPAREN) { + /* Function call operator. The next token MUST be a RPAREN */ + nexttok = Scanner_token(scan); + if (nexttok != SWIG_TOKEN_RPAREN) { + Swig_error(Scanner_file(scan),Scanner_line(scan),"Syntax error. Bad operator name.\n"); + } else { + Append(s,"()"); + yylval.str = s; + return OPERATOR; + } + } else if (nexttok == SWIG_TOKEN_LBRACKET) { + /* Array access operator. The next token MUST be a RBRACKET */ + nexttok = Scanner_token(scan); + if (nexttok != SWIG_TOKEN_RBRACKET) { + Swig_error(Scanner_file(scan),Scanner_line(scan),"Syntax error. Bad operator name.\n"); + } else { + Append(s,"[]"); + yylval.str = s; + return OPERATOR; + } + } else if (nexttok == SWIG_TOKEN_STRING) { + /* Operator "" or user-defined string literal ""_suffix */ + Append(s,"\"\""); + yylval.str = s; + return OPERATOR; + } else if (nexttok == SWIG_TOKEN_ID) { + /* We have an identifier. This could be any number of things. It could be a named version of + an operator (e.g., 'and_eq') or it could be a conversion operator. To deal with this, we're + going to read tokens until we encounter a ( or ;. Some care is needed for formatting. */ + int needspace = 1; + int termtoken = 0; + const char *termvalue = 0; + + Append(s,Scanner_text(scan)); + while (1) { + + nexttok = Scanner_token(scan); + if (nexttok <= 0) { + Swig_error(Scanner_file(scan),Scanner_line(scan),"Syntax error. Bad operator name.\n"); + } + if (nexttok == SWIG_TOKEN_LPAREN) { + termtoken = SWIG_TOKEN_LPAREN; + termvalue = "("; + break; + } else if (nexttok == SWIG_TOKEN_CODEBLOCK) { + termtoken = SWIG_TOKEN_CODEBLOCK; + termvalue = Char(Scanner_text(scan)); + break; + } else if (nexttok == SWIG_TOKEN_LBRACE) { + termtoken = SWIG_TOKEN_LBRACE; + termvalue = "{"; + break; + } else if (nexttok == SWIG_TOKEN_SEMI) { + termtoken = SWIG_TOKEN_SEMI; + termvalue = ";"; + break; + } else if (nexttok == SWIG_TOKEN_STRING) { + termtoken = SWIG_TOKEN_STRING; + termvalue = Swig_copy_string(Char(Scanner_text(scan))); + break; + } else if (nexttok == SWIG_TOKEN_ID) { + if (needspace) { + Append(s," "); + } + Append(s,Scanner_text(scan)); + } else if (nexttok == SWIG_TOKEN_ENDLINE) { + } else if (nexttok == SWIG_TOKEN_COMMENT) { + } else { + Append(s,Scanner_text(scan)); + needspace = 0; + } + } + yylval.str = s; + if (!rename_active) { + String *cs; + char *t = Char(s) + 9; + if (!((strcmp(t, "new") == 0) + || (strcmp(t, "delete") == 0) + || (strcmp(t, "new[]") == 0) + || (strcmp(t, "delete[]") == 0) + || (strcmp(t, "and") == 0) + || (strcmp(t, "and_eq") == 0) + || (strcmp(t, "bitand") == 0) + || (strcmp(t, "bitor") == 0) + || (strcmp(t, "compl") == 0) + || (strcmp(t, "not") == 0) + || (strcmp(t, "not_eq") == 0) + || (strcmp(t, "or") == 0) + || (strcmp(t, "or_eq") == 0) + || (strcmp(t, "xor") == 0) + || (strcmp(t, "xor_eq") == 0) + )) { + /* retract(strlen(t)); */ + + /* The operator is a conversion operator. In order to deal with this, we need to feed the + type information back into the parser. For now this is a hack. Needs to be cleaned up later. */ + cs = NewString(t); + if (termtoken) Append(cs,termvalue); + Seek(cs,0,SEEK_SET); + Setline(cs,cparse_line); + Setfile(cs,cparse_file); + Scanner_push(scan,cs); + Delete(cs); + return CONVERSIONOPERATOR; + } + } + if (termtoken) + Scanner_pushtoken(scan, termtoken, termvalue); + return (OPERATOR); + } + } + if (strcmp(yytext, "throw") == 0) + return (THROW); + if (strcmp(yytext, "noexcept") == 0) + return (NOEXCEPT); + if (strcmp(yytext, "try") == 0) + return (yylex()); + if (strcmp(yytext, "catch") == 0) + return (CATCH); + if (strcmp(yytext, "inline") == 0) + return (yylex()); + if (strcmp(yytext, "mutable") == 0) + return (yylex()); + if (strcmp(yytext, "explicit") == 0) + return (EXPLICIT); + if (strcmp(yytext, "auto") == 0) + return (AUTO); + if (strcmp(yytext, "export") == 0) + return (yylex()); + if (strcmp(yytext, "typename") == 0) + return (TYPENAME); + if (strcmp(yytext, "template") == 0) { + yylval.intvalue = cparse_line; + return (TEMPLATE); + } + if (strcmp(yytext, "delete") == 0) + return (DELETE_KW); + if (strcmp(yytext, "default") == 0) + return (DEFAULT); + if (strcmp(yytext, "using") == 0) + return (USING); + if (strcmp(yytext, "namespace") == 0) + return (NAMESPACE); + if (strcmp(yytext, "override") == 0) { + last_id = 1; + return (OVERRIDE); + } + if (strcmp(yytext, "final") == 0) { + last_id = 1; + return (FINAL); + } + } else { + if (strcmp(yytext, "class") == 0) { + Swig_warning(WARN_PARSE_CLASS_KEYWORD, cparse_file, cparse_line, "class keyword used, but not in C++ mode.\n"); + } + if (strcmp(yytext, "_Complex") == 0) { + yylval.type = NewSwigType(T_COMPLEX); + return (TYPE_COMPLEX); + } + if (strcmp(yytext, "restrict") == 0) + return (yylex()); + } + + /* Misc keywords */ + + if (strcmp(yytext, "extern") == 0) + return (EXTERN); + if (strcmp(yytext, "const") == 0) + return (CONST_QUAL); + if (strcmp(yytext, "static") == 0) + return (STATIC); + if (strcmp(yytext, "struct") == 0) + return (STRUCT); + if (strcmp(yytext, "union") == 0) + return (UNION); + if (strcmp(yytext, "enum") == 0) + return (ENUM); + if (strcmp(yytext, "sizeof") == 0) + return (SIZEOF); + + if (strcmp(yytext, "typedef") == 0) { + yylval.intvalue = 0; + return (TYPEDEF); + } + + /* Ignored keywords */ + + if (strcmp(yytext, "volatile") == 0) + return (VOLATILE); + if (strcmp(yytext, "register") == 0) + return (REGISTER); + if (strcmp(yytext, "inline") == 0) + return (yylex()); + + } else { + /* SWIG directives */ + String *stext = 0; + if (strcmp(yytext, "%module") == 0) + return (MODULE); + if (strcmp(yytext, "%insert") == 0) + return (INSERT); + if (strcmp(yytext, "%name") == 0) + return (NAME); + if (strcmp(yytext, "%rename") == 0) { + rename_active = 1; + return (RENAME); + } + if (strcmp(yytext, "%namewarn") == 0) { + rename_active = 1; + return (NAMEWARN); + } + if (strcmp(yytext, "%includefile") == 0) + return (INCLUDE); + if (strcmp(yytext, "%beginfile") == 0) + return (BEGINFILE); + if (strcmp(yytext, "%endoffile") == 0) + return (ENDOFFILE); + if (strcmp(yytext, "%val") == 0) { + Swig_warning(WARN_DEPRECATED_VAL, cparse_file, cparse_line, "%%val directive deprecated (ignored).\n"); + return (yylex()); + } + if (strcmp(yytext, "%out") == 0) { + Swig_warning(WARN_DEPRECATED_OUT, cparse_file, cparse_line, "%%out directive deprecated (ignored).\n"); + return (yylex()); + } + if (strcmp(yytext, "%constant") == 0) + return (CONSTANT); + if (strcmp(yytext, "%typedef") == 0) { + yylval.intvalue = 1; + return (TYPEDEF); + } + if (strcmp(yytext, "%native") == 0) + return (NATIVE); + if (strcmp(yytext, "%pragma") == 0) + return (PRAGMA); + if (strcmp(yytext, "%extend") == 0) + return (EXTEND); + if (strcmp(yytext, "%fragment") == 0) + return (FRAGMENT); + if (strcmp(yytext, "%inline") == 0) + return (INLINE); + if (strcmp(yytext, "%typemap") == 0) + return (TYPEMAP); + if (strcmp(yytext, "%feature") == 0) { + /* The rename_active indicates we don't need the information of the + * following function's return type. This applied for %rename, so do + * %feature. + */ + rename_active = 1; + return (FEATURE); + } + if (strcmp(yytext, "%except") == 0) + return (EXCEPT); + if (strcmp(yytext, "%importfile") == 0) + return (IMPORT); + if (strcmp(yytext, "%echo") == 0) + return (ECHO); + if (strcmp(yytext, "%apply") == 0) + return (APPLY); + if (strcmp(yytext, "%clear") == 0) + return (CLEAR); + if (strcmp(yytext, "%types") == 0) + return (TYPES); + if (strcmp(yytext, "%parms") == 0) + return (PARMS); + if (strcmp(yytext, "%varargs") == 0) + return (VARARGS); + if (strcmp(yytext, "%template") == 0) { + return (SWIGTEMPLATE); + } + if (strcmp(yytext, "%warn") == 0) + return (WARN); + + /* Note down the apparently unknown directive for error reporting - if + * we end up reporting a generic syntax error we'll instead report an + * error for his as an unknown directive. Then we treat it as MODULO + * (`%`) followed by an identifier and if that parses OK then + * `cparse_unknown_directive` doesn't get used. + * + * This allows `a%b` to be handled in expressions without a space after + * the operator. + */ + cparse_unknown_directive = NewString(yytext); + stext = NewString(yytext + 1); + Seek(stext,0,SEEK_SET); + Setfile(stext,cparse_file); + Setline(stext,cparse_line); + Scanner_push(scan,stext); + Delete(stext); + return (MODULO); + } + /* Have an unknown identifier, as a last step, we'll do a typedef lookup on it. */ + + /* Need to fix this */ + if (check_typedef) { + if (SwigType_istypedef(yytext)) { + yylval.type = NewString(yytext); + return (TYPE_TYPEDEF); + } + } + yylval.id = Swig_copy_string(yytext); + last_id = 1; + return (ID); + case POUND: + return yylex(); + case SWIG_TOKEN_COMMENT: + return yylex(); + default: + return (l); + } +} diff --git a/contrib/tools/swig/Source/CParse/parser.y b/contrib/tools/swig/Source/CParse/parser.y new file mode 100644 index 0000000000..97b467b5c4 --- /dev/null +++ b/contrib/tools/swig/Source/CParse/parser.y @@ -0,0 +1,7499 @@ +/* ----------------------------------------------------------------------------- + * 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 https://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 a small number of 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 7 + +%{ +#define yylex yylex + +/* doh.h uses #pragma GCC poison with GCC to prevent direct calls to certain + * standard C library functions being introduced, but those cause errors due + * to checks like `#if defined YYMALLOC || defined malloc` in the bison + * template code. We can't easily arrange to include headers after that + * template code, so instead we disable the problematic poisoning for this + * file. + */ +#define DOH_NO_POISON_MALLOC_FREE + +#include "swig.h" +#include "cparse.h" +#include "preprocessor.h" +#include <ctype.h> + +/* We do this for portability */ +#undef alloca +#define alloca Malloc + +#define YYMALLOC Malloc +#define YYFREE Free + +/* ----------------------------------------------------------------------------- + * Externals + * ----------------------------------------------------------------------------- */ + +int yyparse(void); + +/* 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(void) { + 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(void) { + 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; +}; + +// Define special token END for end of input. +%token END 0 + +%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 ELLIPSIS +%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 LESSEQUALGREATER +%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 LESSEQUALGREATER +%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> 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 exprsimple exprcompound valexpr exprmem callparms callptail; +%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 lambda_template; +%type <pl> lambda_tail; +%type <str> virt_specifier_seq virt_specifier_seq_opt; +%type <str> class_virt_specifier_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"); + } + 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 typedef. */ + 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; + + Note: Source/Preprocessor/cpp.c injects `%constant X = Y;` for + each `#define X Y` so that's handled here too. + ------------------------------------------------------------ */ + +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; + } + | CONSTANT error END { + Swig_error(cparse_file,cparse_line,"Missing semicolon (';') after %%constant.\n"); + Exit(EXIT_FAILURE); + } + ; + +/* ------------------------------------------------------------ + %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 { + String *name = Getattr($1, "name"); + Hash *p = nextSibling($1); + $$.method = name; + $$.kwargs = p; + if (Getattr($1, "value")) { + Swig_error(cparse_file, cparse_line, + "%%typemap method shouldn't have a value specified.\n"); + } + while (p) { + if (!Getattr(p, "value")) { + Swig_error(cparse_file, cparse_line, + "%%typemap attribute '%s' is missing its value. If this is specifying the target language, that's no longer supported: use #ifdef SWIG<LANG> instead.\n", + Getattr(p, "name")); + /* Set to empty value to avoid segfaults later. */ + Setattr(p, "value", NewStringEmpty()); + } + p = nextSibling(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 */ + + /* If the class name is qualified, we need to create or lookup namespace entries */ + $5 = resolve_create_node_scope($5, 0); + + if (nscope_inner && Strcmp(nodeType(nscope_inner), "class") == 0) { + outer_class = nscope_inner; + } + + /* + We use the new namespace entry 'nscope' only to + emit the template node. The template parameters are + resolved in the current 'tscope'. + + This is closer to the C++ (typedef) behavior. + */ + n = Swig_cparse_template_locate($5,$7,tscope); + + /* Patch the argument types to respect namespaces */ + p = $7; + while (p) { + SwigType *value = Getattr(p,"value"); + if (!value) { + SwigType *ty = Getattr(p,"type"); + if (ty) { + SwigType *rty = 0; + int reduce = template_reduce; + if (reduce || !SwigType_ispointer(ty)) { + rty = Swig_symbol_typedef_reduce(ty,tscope); + if (!reduce) reduce = SwigType_ispointer(rty); + } + ty = reduce ? Swig_symbol_type_qualify(rty,tscope) : Swig_symbol_type_qualify(ty,tscope); + Setattr(p,"type",ty); + Delete(ty); + Delete(rty); + } + } else { + value = Swig_symbol_type_qualify(value,tscope); + Setattr(p,"value",value); + Delete(value); + } + + p = nextSibling(p); + } + + /* Look for the template */ + { + Node *nn = n; + Node *linklistend = 0; + Node *linkliststart = 0; + while (nn) { + Node *templnode = 0; + if (Strcmp(nodeType(nn),"template") == 0) { + int nnisclass = (Strcmp(Getattr(nn,"templatetype"),"class") == 0); /* if not a templated class it is a templated function */ + Parm *tparms = Getattr(nn,"templateparms"); + if (!tparms) { + specialized = 1; + } else if (Getattr(tparms,"variadic") && strncmp(Char(Getattr(tparms,"variadic")), "1", 1)==0) { + variadic = 1; + } + if (nnisclass && !variadic && !specialized && (ParmList_len($7) > ParmList_len(tparms))) { + Swig_error(cparse_file, cparse_line, "Too many template parameters. Maximum of %d.\n", ParmList_len(tparms)); + } else if (nnisclass && !specialized && ((ParmList_len($7) < (ParmList_numrequired(tparms) - (variadic?1:0))))) { /* Variadic parameter is optional */ + Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. %d required.\n", (ParmList_numrequired(tparms)-(variadic?1:0)) ); + } else if (!nnisclass && ((ParmList_len($7) != ParmList_len(tparms)))) { + /* must be an overloaded templated method - ignore it as it is overloaded with a different number of template parameters */ + nn = Getattr(nn,"sym:nextSibling"); /* repeat for overloaded templated functions */ + continue; + } else { + String *tname = Copy($5); + int def_supplied = 0; + /* Expand the template */ + Node *templ = Swig_symbol_clookup($5,0); + Parm *targs = templ ? Getattr(templ,"templateparms") : 0; + + ParmList *temparms; + if (specialized) temparms = CopyParmList($7); + else temparms = CopyParmList(tparms); + + /* Create typedef's and arguments */ + p = $7; + tp = temparms; + if (!p && ParmList_len(p) != ParmList_len(temparms)) { + /* we have no template parameters supplied in %template for a template that has default args*/ + p = tp; + def_supplied = 1; + } + + while (p) { + String *value = Getattr(p,"value"); + if (def_supplied) { + Setattr(p,"default","1"); + } + if (value) { + Setattr(tp,"value",value); + } else { + SwigType *ty = Getattr(p,"type"); + if (ty) { + Setattr(tp,"type",ty); + } + Delattr(tp,"value"); + } + /* fix default arg values */ + if (targs) { + Parm *pi = temparms; + Parm *ti = targs; + String *tv = Getattr(tp,"value"); + if (!tv) tv = Getattr(tp,"type"); + while(pi != tp && ti && pi) { + String *name = Getattr(ti,"name"); + String *value = Getattr(pi,"value"); + if (!value) value = Getattr(pi,"type"); + Replaceid(tv, name, value); + pi = nextSibling(pi); + ti = nextSibling(ti); + } + } + p = nextSibling(p); + tp = nextSibling(tp); + if (!p && tp) { + p = tp; + def_supplied = 1; + } else if (p && !tp) { /* Variadic template - tp < p */ + SWIG_WARN_NODE_BEGIN(nn); + Swig_warning(WARN_CPP11_VARIADIC_TEMPLATE,cparse_file, cparse_line,"Only the first variadic template argument is currently supported.\n"); + SWIG_WARN_NODE_END(nn); + break; + } + } + + templnode = copy_node(nn); + update_nested_classes(templnode); /* update classes nested within template */ + /* We need to set the node name based on name used to instantiate */ + Setattr(templnode,"name",tname); + Delete(tname); + if (!specialized) { + Delattr(templnode,"sym:typename"); + } else { + Setattr(templnode,"sym:typename","1"); + } + /* for now, nested %template is allowed only in the same scope as the template declaration */ + if ($3 && !(nnisclass && ((outer_class && (outer_class != Getattr(nn, "nested:outer"))) + ||(extendmode && current_class && (current_class != Getattr(nn, "nested:outer")))))) { + /* + Comment this out for 1.3.28. We need to + re-enable it later but first we need to + move %ignore from using %rename to use + %feature(ignore). + + String *symname = Swig_name_make(templnode,0,$3,0,0); + */ + String *symname = NewString($3); + Swig_cparse_template_expand(templnode,symname,temparms,tscope); + Setattr(templnode,"sym:name",symname); + } else { + static int cnt = 0; + String *nname = NewStringf("__dummy_%d__", cnt++); + Swig_cparse_template_expand(templnode,nname,temparms,tscope); + Setattr(templnode,"sym:name",nname); + SetFlag(templnode,"hidden"); + Delete(nname); + Setattr(templnode,"feature:onlychildren", "typemap,typemapitem,typemapcopy,typedef,types,fragment,apply"); + if ($3) { + Swig_warning(WARN_PARSE_NESTED_TEMPLATE, cparse_file, cparse_line, "Named nested template instantiations not supported. Processing as if no name was given to %%template().\n"); + } + } + Delattr(templnode,"templatetype"); + Setattr(templnode,"template",nn); + Setfile(templnode,cparse_file); + Setline(templnode,cparse_line); + Delete(temparms); + if (outer_class && nnisclass) { + SetFlag(templnode, "nested"); + Setattr(templnode, "nested:outer", outer_class); + } + add_symbols_copy(templnode); + + if (Strcmp(nodeType(templnode),"class") == 0) { + + /* Identify pure abstract methods */ + Setattr(templnode,"abstracts", pure_abstracts(firstChild(templnode))); + + /* Set up inheritance in symbol table */ + { + Symtab *csyms; + List *baselist = Getattr(templnode,"baselist"); + csyms = Swig_symbol_current(); + Swig_symbol_setscope(Getattr(templnode,"symtab")); + if (baselist) { + List *bases = Swig_make_inherit_list(Getattr(templnode,"name"),baselist, Namespaceprefix); + if (bases) { + Iterator s; + for (s = First(bases); s.item; s = Next(s)) { + Symtab *st = Getattr(s.item,"symtab"); + if (st) { + Setfile(st,Getfile(s.item)); + Setline(st,Getline(s.item)); + Swig_symbol_inherit(st); + } + } + Delete(bases); + } + } + Swig_symbol_setscope(csyms); + } + + /* Merge in %extend methods for this class. + This only merges methods within %extend for a template specialized class such as + template<typename T> class K {}; %extend K<int> { ... } + The copy_node() call above has already added in the generic %extend methods such as + template<typename T> class K {}; %extend K { ... } */ + + /* !!! This may be broken. We may have to add the + %extend methods at the beginning of the class */ + { + String *stmp = 0; + String *clsname; + Node *am; + if (Namespaceprefix) { + clsname = stmp = NewStringf("%s::%s", Namespaceprefix, Getattr(templnode,"name")); + } else { + clsname = Getattr(templnode,"name"); + } + 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")); */ + Swig_extend_merge(templnode,am); + Swig_symbol_setscope(st); + 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); + } + } + } + + /* all the overloaded templated functions are added into a linked list */ + if (!linkliststart) + linkliststart = templnode; + if (nscope_inner) { + /* non-global namespace */ + if (templnode) { + appendChild(nscope_inner,templnode); + Delete(templnode); + if (nscope) $$ = nscope; + } + } else { + /* global namespace */ + if (!linklistend) { + $$ = templnode; + } else { + set_nextSibling(linklistend,templnode); + Delete(templnode); + } + linklistend = templnode; + } + } + nn = Getattr(nn,"sym:nextSibling"); /* repeat for overloaded templated functions. If a templated class there will never be a sibling. */ + } + update_defaultargs(linkliststart); + update_abstracts(linkliststart); + } + Swig_symbol_setscope(tscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + ; + +/* ------------------------------------------------------------ + %warn "text" + %warn(no) + ------------------------------------------------------------ */ + +warn_directive : WARN string { + Swig_warning(0,cparse_file, cparse_line,"%s\n", $2); + $$ = 0; + } + ; + +/* ====================================================================== + * C Parsing + * ====================================================================== */ + +c_declaration : c_decl { + $$ = $1; + if ($$) { + add_symbols($$); + default_arguments($$); + } + } + | c_enum_decl { $$ = $1; } + | c_enum_forward_decl { $$ = $1; } + +/* An extern C type declaration, disable cparse_cplusplus if needed. */ + + | EXTERN string LBRACE { + if (Strcmp($2,"C") == 0) { + cparse_externc = 1; + } + } interface RBRACE { + cparse_externc = 0; + if (Strcmp($2,"C") == 0) { + Node *n = firstChild($5); + $$ = new_node("extern"); + Setattr($$,"name",$2); + appendChild($$,n); + while (n) { + String *s = Getattr(n, "storage"); + if (s) { + if (Strstr(s, "thread_local")) { + Insert(s,0,"externc "); + } else if (!Equal(s, "typedef")) { + Setattr(n,"storage","externc"); + } + } else { + Setattr(n,"storage","externc"); + } + n = nextSibling(n); + } + } else { + if (!Equal($2,"C++")) { + Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", $2); + } + $$ = new_node("extern"); + Setattr($$,"name",$2); + appendChild($$,firstChild($5)); + } + } + | cpp_lambda_decl { + $$ = $1; + SWIG_WARN_NODE_BEGIN($$); + Swig_warning(WARN_CPP11_LAMBDA, cparse_file, cparse_line, "Lambda expressions and closures are not fully supported yet.\n"); + SWIG_WARN_NODE_END($$); + } + | USING idcolon EQUAL type plain_declarator SEMI { + /* Convert using statement to a typedef statement */ + $$ = new_node("cdecl"); + Setattr($$,"type",$4); + Setattr($$,"storage","typedef"); + Setattr($$,"name",$2); + Setattr($$,"decl",$5.type); + SetFlag($$,"typealias"); + add_symbols($$); + } + | TEMPLATE LESSTHAN template_parms GREATERTHAN USING idcolon EQUAL type plain_declarator SEMI { + /* Convert alias template to a "template" typedef statement */ + $$ = new_node("template"); + Setattr($$,"type",$8); + Setattr($$,"storage","typedef"); + Setattr($$,"name",$6); + Setattr($$,"decl",$9.type); + Setattr($$,"templateparms",$3); + Setattr($$,"templatetype","cdecl"); + SetFlag($$,"aliastemplate"); + add_symbols($$); + } + | cpp_static_assert { + $$ = $1; + } + ; + +/* ------------------------------------------------------------ + A C global declaration of some kind (may be variable, function, typedef, etc.) + ------------------------------------------------------------ */ + +c_decl : storage_class type declarator cpp_const initializer c_decl_tail { + String *decl = $3.type; + $$ = new_node("cdecl"); + if ($4.qualifier) + decl = add_qualifier_to_declarator($3.type, $4.qualifier); + Setattr($$,"refqualifier",$4.refqualifier); + Setattr($$,"type",$2); + Setattr($$,"storage",$1); + Setattr($$,"name",$3.id); + Setattr($$,"decl",decl); + Setattr($$,"parms",$3.parms); + Setattr($$,"value",$5.val); + Setattr($$,"throws",$4.throws); + Setattr($$,"throw",$4.throwf); + Setattr($$,"noexcept",$4.nexcept); + Setattr($$,"final",$4.final); + if ($5.val && $5.type) { + /* store initializer type as it might be different to the declared type */ + SwigType *valuetype = NewSwigType($5.type); + if (Len(valuetype) > 0) + Setattr($$,"valuetype",valuetype); + else + Delete(valuetype); + } + if (!$6) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + } else { + Node *n = $6; + /* Inherit attributes */ + while (n) { + String *type = Copy($2); + Setattr(n,"type",type); + Setattr(n,"storage",$1); + n = nextSibling(n); + Delete(type); + } + } + if ($5.bitfield) { + Setattr($$,"bitfield", $5.bitfield); + } + + if ($3.id) { + /* Look for "::" declarations (ignored) */ + if (Strstr($3.id, "::")) { + /* This is a special case. If the scope name of the declaration exactly + matches that of the declaration, then we will allow it. Otherwise, delete. */ + String *p = Swig_scopename_prefix($3.id); + if (p) { + if ((Namespaceprefix && Strcmp(p, Namespaceprefix) == 0) || + (Classprefix && Strcmp(p, Classprefix) == 0)) { + String *lstr = Swig_scopename_last($3.id); + Setattr($$, "name", lstr); + Delete(lstr); + set_nextSibling($$, $6); + } else { + Delete($$); + $$ = $6; + } + Delete(p); + } else { + Delete($$); + $$ = $6; + } + } else { + set_nextSibling($$, $6); + } + } else { + Swig_error(cparse_file, cparse_line, "Missing symbol name for global declaration\n"); + $$ = 0; + } + + if ($4.qualifier && $1 && Strstr($1, "static")) + Swig_error(cparse_file, cparse_line, "Static function %s cannot have a qualifier.\n", Swig_name_decl($$)); + } + /* Alternate function syntax introduced in C++11: + auto funcName(int x, int y) -> int; */ + | storage_class AUTO declarator cpp_const ARROW cpp_alternate_rettype virt_specifier_seq_opt initializer c_decl_tail { + $$ = new_node("cdecl"); + if ($4.qualifier) SwigType_push($3.type, $4.qualifier); + Setattr($$,"refqualifier",$4.refqualifier); + Setattr($$,"type",$6); + Setattr($$,"storage",$1); + Setattr($$,"name",$3.id); + Setattr($$,"decl",$3.type); + Setattr($$,"parms",$3.parms); + Setattr($$,"value",$4.val); + Setattr($$,"throws",$4.throws); + Setattr($$,"throw",$4.throwf); + Setattr($$,"noexcept",$4.nexcept); + Setattr($$,"final",$4.final); + if (!$9) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + } else { + Node *n = $9; + while (n) { + String *type = Copy($6); + Setattr(n,"type",type); + Setattr(n,"storage",$1); + n = nextSibling(n); + Delete(type); + } + } + if ($4.bitfield) { + Setattr($$,"bitfield", $4.bitfield); + } + + if (Strstr($3.id,"::")) { + String *p = Swig_scopename_prefix($3.id); + if (p) { + if ((Namespaceprefix && Strcmp(p, Namespaceprefix) == 0) || + (Classprefix && Strcmp(p, Classprefix) == 0)) { + String *lstr = Swig_scopename_last($3.id); + Setattr($$,"name",lstr); + Delete(lstr); + set_nextSibling($$, $9); + } else { + Delete($$); + $$ = $9; + } + Delete(p); + } else { + Delete($$); + $$ = $9; + } + } else { + set_nextSibling($$, $9); + } + + if ($4.qualifier && $1 && Strstr($1, "static")) + Swig_error(cparse_file, cparse_line, "Static function %s cannot have a qualifier.\n", Swig_name_decl($$)); + } + ; + +/* Allow lists of variables and functions to be built up */ + +c_decl_tail : SEMI { + $$ = 0; + Clear(scanner_ccode); + } + | COMMA declarator cpp_const initializer c_decl_tail { + $$ = new_node("cdecl"); + if ($3.qualifier) SwigType_push($2.type,$3.qualifier); + Setattr($$,"refqualifier",$3.refqualifier); + Setattr($$,"name",$2.id); + Setattr($$,"decl",$2.type); + Setattr($$,"parms",$2.parms); + Setattr($$,"value",$4.val); + Setattr($$,"throws",$3.throws); + Setattr($$,"throw",$3.throwf); + Setattr($$,"noexcept",$3.nexcept); + Setattr($$,"final",$3.final); + if ($4.bitfield) { + Setattr($$,"bitfield", $4.bitfield); + } + if (!$5) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + } else { + set_nextSibling($$, $5); + } + } + | LBRACE { + skip_balanced('{','}'); + $$ = 0; + } + | error { + $$ = 0; + if (yychar == RPAREN) { + Swig_error(cparse_file, cparse_line, "Unexpected closing parenthesis (')').\n"); + } else { + Swig_error(cparse_file, cparse_line, "Syntax error - possibly a missing semicolon (';').\n"); + } + Exit(EXIT_FAILURE); + } + ; + +initializer : def_args { + $$ = $1; + } + ; + +cpp_alternate_rettype : primitive_type { $$ = $1; } + | TYPE_BOOL { $$ = $1; } + | TYPE_VOID { $$ = $1; } +/* + | TYPE_TYPEDEF template_decl { $$ = NewStringf("%s%s",$1,$2); } +*/ + | TYPE_RAW { $$ = $1; } + | idcolon { $$ = $1; } + | idcolon AND { + $$ = $1; + SwigType_add_reference($$); + } + | decltype { $$ = $1; } + ; + +/* ------------------------------------------------------------ + Lambda functions and expressions, such as: + auto myFunc = [] { return something; }; + auto myFunc = [](int x, int y) { return x+y; }; + auto myFunc = [](int x, int y) -> int { return x+y; }; + auto myFunc = [](int x, int y) throw() -> int { return x+y; }; + auto six = [](int x, int y) { return x+y; }(4, 2); + ------------------------------------------------------------ */ +cpp_lambda_decl : storage_class AUTO idcolon EQUAL lambda_introducer lambda_template LPAREN parms RPAREN cpp_const lambda_body lambda_tail { + $$ = new_node("lambda"); + Setattr($$,"name",$3); + add_symbols($$); + } + | storage_class AUTO idcolon EQUAL lambda_introducer lambda_template LPAREN parms RPAREN cpp_const ARROW type lambda_body lambda_tail { + $$ = new_node("lambda"); + Setattr($$,"name",$3); + add_symbols($$); + } + | storage_class AUTO idcolon EQUAL lambda_introducer lambda_template lambda_body lambda_tail { + $$ = new_node("lambda"); + Setattr($$,"name",$3); + add_symbols($$); + } + ; + +lambda_introducer : LBRACKET { + skip_balanced('[',']'); + $$ = 0; + } + ; + +lambda_template : LESSTHAN { + skip_balanced('<','>'); + $$ = 0; + } + | empty { $$ = 0; } + ; + +lambda_body : LBRACE { + skip_balanced('{','}'); + $$ = 0; + } + +lambda_tail : SEMI { + $$ = 0; + } + | LPAREN { + skip_balanced('(',')'); + } SEMI { + $$ = 0; + } + ; + +/* ------------------------------------------------------------ + enum + or + enum class + ------------------------------------------------------------ */ + +c_enum_key : ENUM { + $$ = (char *)"enum"; + } + | ENUM CLASS { + $$ = (char *)"enum class"; + } + | ENUM STRUCT { + $$ = (char *)"enum struct"; + } + ; + +/* ------------------------------------------------------------ + base enum type (eg. unsigned short) + ------------------------------------------------------------ */ + +c_enum_inherit : COLON type_right { + $$ = $2; + } + | empty { $$ = 0; } + ; +/* ------------------------------------------------------------ + enum [class] Name; + enum [class] Name [: base_type]; + ------------------------------------------------------------ */ + +c_enum_forward_decl : storage_class c_enum_key ename c_enum_inherit SEMI { + SwigType *ty = 0; + int scopedenum = $3 && !Equal($2, "enum"); + $$ = new_node("enumforward"); + ty = NewStringf("enum %s", $3); + Setattr($$,"enumkey",$2); + if (scopedenum) + SetFlag($$, "scopedenum"); + Setattr($$,"name",$3); + Setattr($$,"inherit",$4); + Setattr($$,"type",ty); + Setattr($$,"sym:weak", "1"); + add_symbols($$); + } + ; + +/* ------------------------------------------------------------ + enum [class] Name [: base_type] { ... }; + or + enum [class] Name [: base_type] { ... } MyEnum [= ...]; + * ------------------------------------------------------------ */ + +c_enum_decl : storage_class c_enum_key ename c_enum_inherit LBRACE enumlist RBRACE SEMI { + SwigType *ty = 0; + int scopedenum = $3 && !Equal($2, "enum"); + $$ = new_node("enum"); + ty = NewStringf("enum %s", $3); + Setattr($$,"enumkey",$2); + if (scopedenum) + SetFlag($$, "scopedenum"); + Setattr($$,"name",$3); + Setattr($$,"inherit",$4); + Setattr($$,"type",ty); + appendChild($$,$6); + add_symbols($$); /* Add to tag space */ + + if (scopedenum) { + Swig_symbol_newscope(); + Swig_symbol_setscopename($3); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + + add_symbols($6); /* Add enum values to appropriate enum or enum class scope */ + + if (scopedenum) { + Setattr($$,"symtab", Swig_symbol_popscope()); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + } + | storage_class c_enum_key ename c_enum_inherit LBRACE enumlist RBRACE declarator cpp_const initializer c_decl_tail { + Node *n; + SwigType *ty = 0; + String *unnamed = 0; + int unnamedinstance = 0; + int scopedenum = $3 && !Equal($2, "enum"); + + $$ = new_node("enum"); + Setattr($$,"enumkey",$2); + if (scopedenum) + SetFlag($$, "scopedenum"); + Setattr($$,"inherit",$4); + if ($3) { + Setattr($$,"name",$3); + ty = NewStringf("enum %s", $3); + } else if ($8.id) { + unnamed = make_unnamed(); + ty = NewStringf("enum %s", unnamed); + Setattr($$,"unnamed",unnamed); + /* name is not set for unnamed enum instances, e.g. enum { foo } Instance; */ + if ($1 && Cmp($1,"typedef") == 0) { + Setattr($$,"name",$8.id); + } else { + unnamedinstance = 1; + } + Setattr($$,"storage",$1); + } + if ($8.id && Cmp($1,"typedef") == 0) { + Setattr($$,"tdname",$8.id); + Setattr($$,"allows_typedef","1"); + } + appendChild($$,$6); + n = new_node("cdecl"); + Setattr(n,"type",ty); + Setattr(n,"name",$8.id); + Setattr(n,"storage",$1); + Setattr(n,"decl",$8.type); + Setattr(n,"parms",$8.parms); + Setattr(n,"unnamed",unnamed); + + if (unnamedinstance) { + SwigType *cty = NewString("enum "); + Setattr($$,"type",cty); + SetFlag($$,"unnamedinstance"); + SetFlag(n,"unnamedinstance"); + Delete(cty); + } + if ($11) { + Node *p = $11; + set_nextSibling(n,p); + while (p) { + SwigType *cty = Copy(ty); + Setattr(p,"type",cty); + Setattr(p,"unnamed",unnamed); + Setattr(p,"storage",$1); + Delete(cty); + p = nextSibling(p); + } + } else { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr(n,"code",code); + Delete(code); + } + } + + /* Ensure that typedef enum ABC {foo} XYZ; uses XYZ for sym:name, like structs. + * Note that class_rename/yyrename are bit of a mess so used this simple approach to change the name. */ + if ($8.id && $3 && Cmp($1,"typedef") == 0) { + String *name = NewString($8.id); + Setattr($$, "parser:makename", name); + Delete(name); + } + + add_symbols($$); /* Add enum to tag space */ + set_nextSibling($$,n); + Delete(n); + + if (scopedenum) { + Swig_symbol_newscope(); + Swig_symbol_setscopename($3); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + + add_symbols($6); /* Add enum values to appropriate enum or enum class scope */ + + if (scopedenum) { + Setattr($$,"symtab", Swig_symbol_popscope()); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + + add_symbols(n); + Delete(unnamed); + } + ; + +c_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end { + /* This is a sick hack. If the ctor_end has parameters, + and the parms parameter only has 1 parameter, this + could be a declaration of the form: + + type (id)(parms) + + Otherwise it's an error. */ + int err = 0; + $$ = 0; + + if ((ParmList_len($4) == 1) && (!Swig_scopename_check($2))) { + SwigType *ty = Getattr($4,"type"); + String *name = Getattr($4,"name"); + err = 1; + if (!name) { + $$ = new_node("cdecl"); + Setattr($$,"type",$2); + Setattr($$,"storage",$1); + Setattr($$,"name",ty); + + if ($6.have_parms) { + SwigType *decl = NewStringEmpty(); + SwigType_add_function(decl,$6.parms); + Setattr($$,"decl",decl); + Setattr($$,"parms",$6.parms); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + } + if ($6.defarg) { + Setattr($$,"value",$6.defarg); + } + Setattr($$,"throws",$6.throws); + Setattr($$,"throw",$6.throwf); + Setattr($$,"noexcept",$6.nexcept); + Setattr($$,"final",$6.final); + err = 0; + } + } + if (err) { + Swig_error(cparse_file,cparse_line,"Syntax error in input(2).\n"); + Exit(EXIT_FAILURE); + } + } + ; + +/* ====================================================================== + * C++ Support + * ====================================================================== */ + +cpp_declaration : cpp_class_decl { $$ = $1; } + | cpp_forward_class_decl { $$ = $1; } + | cpp_template_decl { $$ = $1; } + | cpp_using_decl { $$ = $1; } + | cpp_namespace_decl { $$ = $1; } + | cpp_catch_decl { $$ = 0; } + ; + + +/* A simple class/struct/union definition */ + +/* Note that class_virt_specifier_opt for supporting final classes introduces one shift-reduce conflict + with C style variable declarations, such as: struct X final; */ + +cpp_class_decl: storage_class cpptype idcolon class_virt_specifier_opt inherit LBRACE { + String *prefix; + List *bases = 0; + Node *scope = 0; + String *code; + $<node>$ = new_node("class"); + Setline($<node>$,cparse_start_line); + Setattr($<node>$,"kind",$2); + if ($5) { + Setattr($<node>$,"baselist", Getattr($5,"public")); + Setattr($<node>$,"protectedbaselist", Getattr($5,"protected")); + Setattr($<node>$,"privatebaselist", Getattr($5,"private")); + } + Setattr($<node>$,"allows_typedef","1"); + + /* preserve the current scope */ + Setattr($<node>$,"prev_symtab",Swig_symbol_current()); + + /* If the class name is qualified. We need to create or lookup namespace/scope entries */ + scope = resolve_create_node_scope($3, 1); + /* save nscope_inner to the class - it may be overwritten in nested classes*/ + Setattr($<node>$, "nested:innerscope", nscope_inner); + Setattr($<node>$, "nested:nscope", nscope); + Setfile(scope,cparse_file); + Setline(scope,cparse_line); + $3 = scope; + Setattr($<node>$,"name",$3); + + if (currentOuterClass) { + SetFlag($<node>$, "nested"); + Setattr($<node>$, "nested:outer", currentOuterClass); + set_access_mode($<node>$); + } + Swig_features_get(Swig_cparse_features(), Namespaceprefix, Getattr($<node>$, "name"), 0, $<node>$); + /* save yyrename to the class attribute, to be used later in add_symbols()*/ + Setattr($<node>$, "class_rename", make_name($<node>$, $3, 0)); + Setattr($<node>$, "Classprefix", $3); + Classprefix = NewString($3); + /* Deal with inheritance */ + if ($5) + bases = Swig_make_inherit_list($3,Getattr($5,"public"),Namespaceprefix); + prefix = SwigType_istemplate_templateprefix($3); + if (prefix) { + String *fbase, *tbase; + if (Namespaceprefix) { + fbase = NewStringf("%s::%s", Namespaceprefix,$3); + tbase = NewStringf("%s::%s", Namespaceprefix, prefix); + } else { + fbase = Copy($3); + tbase = Copy(prefix); + } + Swig_name_inherit(tbase,fbase); + Delete(fbase); + Delete(tbase); + } + if (strcmp($2,"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + if (!cparse_cplusplus) { + set_scope_to_global(); + } + Swig_symbol_newscope(); + Swig_symbol_setscopename($3); + Swig_inherit_base_symbols(bases); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + cparse_start_line = cparse_line; + + /* If there are active template parameters, we need to make sure they are + placed in the class symbol table so we can catch shadows */ + + if (template_parameters) { + Parm *tp = template_parameters; + while(tp) { + String *tpname = Copy(Getattr(tp,"name")); + Node *tn = new_node("templateparm"); + Setattr(tn,"name",tpname); + Swig_symbol_cadd(tpname,tn); + tp = nextSibling(tp); + Delete(tpname); + } + } + Delete(prefix); + inclass = 1; + currentOuterClass = $<node>$; + if (cparse_cplusplusout) { + /* save the structure declaration to declare it in global scope for C++ to see */ + code = get_raw_text_balanced('{', '}'); + Setattr($<node>$, "code", code); + Delete(code); + } + } cpp_members RBRACE cpp_opt_declarators { + Node *p; + SwigType *ty; + Symtab *cscope; + Node *am = 0; + String *scpname = 0; + (void) $<node>6; + $$ = currentOuterClass; + currentOuterClass = Getattr($$, "nested:outer"); + nscope_inner = Getattr($<node>$, "nested:innerscope"); + nscope = Getattr($<node>$, "nested:nscope"); + Delattr($<node>$, "nested:innerscope"); + Delattr($<node>$, "nested:nscope"); + if (nscope_inner && Strcmp(nodeType(nscope_inner), "class") == 0) { /* actual parent class for this class */ + Node* forward_declaration = Swig_symbol_clookup_no_inherit(Getattr($<node>$,"name"), Getattr(nscope_inner, "symtab")); + if (forward_declaration) { + Setattr($<node>$, "access", Getattr(forward_declaration, "access")); + } + Setattr($<node>$, "nested:outer", nscope_inner); + SetFlag($<node>$, "nested"); + } + if (!currentOuterClass) + inclass = 0; + cscope = Getattr($$, "prev_symtab"); + Delattr($$, "prev_symtab"); + + /* Check for pure-abstract class */ + Setattr($$,"abstracts", pure_abstracts($8)); + + /* This bit of code merges in a previously defined %extend directive (if any) */ + { + String *clsname = Swig_symbol_qualifiedscopename(0); + am = Getattr(Swig_extend_hash(), clsname); + if (am) { + Swig_extend_merge($$, am); + Delattr(Swig_extend_hash(), clsname); + } + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes, scpname, $$); + + appendChild($$, $8); + + if (am) + Swig_extend_append_previous($$, am); + + p = $10; + if (p && !nscope_inner) { + if (!cparse_cplusplus && currentOuterClass) + appendChild(currentOuterClass, p); + else + appendSibling($$, p); + } + + if (nscope_inner) { + ty = NewString(scpname); /* if the class is declared out of scope, let the declarator use fully qualified type*/ + } else if (cparse_cplusplus && !cparse_externc) { + ty = NewString($3); + } else { + ty = NewStringf("%s %s", $2, $3); + } + while (p) { + Setattr(p, "storage", $1); + Setattr(p, "type" ,ty); + if (!cparse_cplusplus && currentOuterClass && (!Getattr(currentOuterClass, "name"))) { + SetFlag(p, "hasconsttype"); + SetFlag(p, "feature:immutable"); + } + p = nextSibling(p); + } + if ($10 && Cmp($1,"typedef") == 0) + add_typedef_name($$, $10, $3, cscope, scpname); + Delete(scpname); + + if (cplus_mode != CPLUS_PUBLIC) { + /* we 'open' the class at the end, to allow %template + to add new members */ + Node *pa = new_node("access"); + Setattr(pa, "kind", "public"); + cplus_mode = CPLUS_PUBLIC; + appendChild($$, pa); + Delete(pa); + } + if (currentOuterClass) + restore_access_mode($$); + Setattr($$, "symtab", Swig_symbol_popscope()); + Classprefix = Getattr($<node>$, "Classprefix"); + Delattr($<node>$, "Classprefix"); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + if (cplus_mode == CPLUS_PRIVATE) { + $$ = 0; /* skip private nested classes */ + } else if (cparse_cplusplus && currentOuterClass && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) { + $$ = nested_forward_declaration($1, $2, $3, Copy($3), $10); + } else if (nscope_inner) { + /* this is tricky */ + /* we add the declaration in the original namespace */ + if (Strcmp(nodeType(nscope_inner), "class") == 0 && cparse_cplusplus && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) + $$ = nested_forward_declaration($1, $2, $3, Copy($3), $10); + appendChild(nscope_inner, $$); + Swig_symbol_setscope(Getattr(nscope_inner, "symtab")); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + yyrename = Copy(Getattr($<node>$, "class_rename")); + add_symbols($$); + Delattr($$, "class_rename"); + /* but the variable definition in the current scope */ + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($10); + if (nscope) { + $$ = nscope; /* here we return recreated namespace tower instead of the class itself */ + if ($10) { + appendSibling($$, $10); + } + } else if (!SwigType_istemplate(ty) && template_parameters == 0) { /* for template we need the class itself */ + $$ = $10; + } + } else { + Delete(yyrename); + yyrename = 0; + if (!cparse_cplusplus && currentOuterClass) { /* nested C structs go into global scope*/ + Node *outer = currentOuterClass; + while (Getattr(outer, "nested:outer")) + outer = Getattr(outer, "nested:outer"); + appendSibling(outer, $$); + Swig_symbol_setscope(cscope); /* declaration goes in the parent scope */ + add_symbols($10); + set_scope_to_global(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + yyrename = Copy(Getattr($<node>$, "class_rename")); + add_symbols($$); + if (!cparse_cplusplusout) + Delattr($$, "nested:outer"); + Delattr($$, "class_rename"); + $$ = 0; + } else { + yyrename = Copy(Getattr($<node>$, "class_rename")); + add_symbols($$); + add_symbols($10); + Delattr($$, "class_rename"); + } + } + Delete(ty); + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + Classprefix = currentOuterClass ? Getattr(currentOuterClass, "Classprefix") : 0; + } + +/* An unnamed struct, possibly with a typedef */ + + | storage_class cpptype inherit LBRACE { + String *unnamed; + String *code; + unnamed = make_unnamed(); + $<node>$ = new_node("class"); + Setline($<node>$,cparse_start_line); + Setattr($<node>$,"kind",$2); + if ($3) { + Setattr($<node>$,"baselist", Getattr($3,"public")); + Setattr($<node>$,"protectedbaselist", Getattr($3,"protected")); + Setattr($<node>$,"privatebaselist", Getattr($3,"private")); + } + Setattr($<node>$,"storage",$1); + Setattr($<node>$,"unnamed",unnamed); + Setattr($<node>$,"allows_typedef","1"); + if (currentOuterClass) { + SetFlag($<node>$, "nested"); + Setattr($<node>$, "nested:outer", currentOuterClass); + set_access_mode($<node>$); + } + Swig_features_get(Swig_cparse_features(), Namespaceprefix, 0, 0, $<node>$); + /* save yyrename to the class attribute, to be used later in add_symbols()*/ + Setattr($<node>$, "class_rename", make_name($<node>$,0,0)); + if (strcmp($2,"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + Swig_symbol_newscope(); + cparse_start_line = cparse_line; + currentOuterClass = $<node>$; + inclass = 1; + Classprefix = 0; + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + /* save the structure declaration to make a typedef for it later*/ + code = get_raw_text_balanced('{', '}'); + Setattr($<node>$, "code", code); + Delete(code); + } cpp_members RBRACE cpp_opt_declarators { + String *unnamed; + List *bases = 0; + String *name = 0; + Node *n; + Classprefix = 0; + (void)$<node>5; + $$ = currentOuterClass; + currentOuterClass = Getattr($$, "nested:outer"); + if (!currentOuterClass) + inclass = 0; + else + restore_access_mode($$); + unnamed = Getattr($$,"unnamed"); + /* Check for pure-abstract class */ + Setattr($$,"abstracts", pure_abstracts($6)); + n = $8; + if (cparse_cplusplus && currentOuterClass && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) { + String *name = n ? Copy(Getattr(n, "name")) : 0; + $$ = nested_forward_declaration($1, $2, 0, name, n); + Swig_symbol_popscope(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } else if (n) { + appendSibling($$,n); + /* If a proper typedef name was given, we'll use it to set the scope name */ + name = try_to_find_a_name_for_unnamed_structure($1, n); + if (name) { + String *scpname = 0; + SwigType *ty; + Setattr($$,"tdname",name); + Setattr($$,"name",name); + Swig_symbol_setscopename(name); + if ($3) + bases = Swig_make_inherit_list(name,Getattr($3,"public"),Namespaceprefix); + Swig_inherit_base_symbols(bases); + + /* If a proper name was given, we use that as the typedef, not unnamed */ + Clear(unnamed); + Append(unnamed, name); + if (cparse_cplusplus && !cparse_externc) { + ty = NewString(name); + } else { + ty = NewStringf("%s %s", $2,name); + } + while (n) { + Setattr(n,"storage",$1); + Setattr(n, "type", ty); + if (!cparse_cplusplus && currentOuterClass && (!Getattr(currentOuterClass, "name"))) { + SetFlag(n,"hasconsttype"); + SetFlag(n,"feature:immutable"); + } + n = nextSibling(n); + } + n = $8; + + /* Check for previous extensions */ + { + String *clsname = Swig_symbol_qualifiedscopename(0); + Node *am = Getattr(Swig_extend_hash(),clsname); + if (am) { + /* Merge the extension into the symbol table */ + Swig_extend_merge($$,am); + Swig_extend_append_previous($$,am); + Delattr(Swig_extend_hash(),clsname); + } + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes,scpname,$$); + Delete(scpname); + } else { /* no suitable name was found for a struct */ + Setattr($$, "nested:unnamed", Getattr(n, "name")); /* save the name of the first declarator for later use in name generation*/ + while (n) { /* attach unnamed struct to the declarators, so that they would receive proper type later*/ + Setattr(n, "nested:unnamedtype", $$); + Setattr(n, "storage", $1); + n = nextSibling(n); + } + n = $8; + Swig_symbol_setscopename("<unnamed>"); + } + appendChild($$,$6); + /* Pop the scope */ + Setattr($$,"symtab",Swig_symbol_popscope()); + if (name) { + Delete(yyrename); + yyrename = Copy(Getattr($<node>$, "class_rename")); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($$); + add_symbols(n); + Delattr($$, "class_rename"); + }else if (cparse_cplusplus) + $$ = 0; /* ignore unnamed structs for C++ */ + Delete(unnamed); + } else { /* unnamed struct w/o declarator*/ + Swig_symbol_popscope(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($6); + Delete($$); + $$ = $6; /* pass member list to outer class/namespace (instead of self)*/ + } + Classprefix = currentOuterClass ? Getattr(currentOuterClass, "Classprefix") : 0; + } + ; + +cpp_opt_declarators : SEMI { $$ = 0; } + | declarator cpp_const initializer c_decl_tail { + $$ = new_node("cdecl"); + Setattr($$,"name",$1.id); + Setattr($$,"decl",$1.type); + Setattr($$,"parms",$1.parms); + set_nextSibling($$, $4); + } + ; +/* ------------------------------------------------------------ + class Name; + ------------------------------------------------------------ */ + +cpp_forward_class_decl : storage_class cpptype idcolon SEMI { + if ($1 && (Strcmp($1,"friend") == 0)) { + /* Ignore */ + $$ = 0; + } else { + $$ = new_node("classforward"); + Setattr($$,"kind",$2); + Setattr($$,"name",$3); + Setattr($$,"sym:weak", "1"); + add_symbols($$); + } + } + ; + +/* ------------------------------------------------------------ + template<...> decl + ------------------------------------------------------------ */ + +cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { + if (currentOuterClass) + Setattr(currentOuterClass, "template_parameters", template_parameters); + template_parameters = $3; + parsing_template_declaration = 1; + } cpp_template_possible { + String *tname = 0; + int error = 0; + + /* check if we get a namespace node with a class declaration, and retrieve the class */ + Symtab *cscope = Swig_symbol_current(); + Symtab *sti = 0; + Node *ntop = $6; + Node *ni = ntop; + SwigType *ntype = ni ? nodeType(ni) : 0; + while (ni && Strcmp(ntype,"namespace") == 0) { + sti = Getattr(ni,"symtab"); + ni = firstChild(ni); + ntype = nodeType(ni); + } + if (sti) { + Swig_symbol_setscope(sti); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + $6 = ni; + } + + $$ = $6; + if ($$) tname = Getattr($$,"name"); + + /* Check if the class is a template specialization */ + if (($$) && (Strchr(tname,'<')) && (!is_operator(tname))) { + /* If a specialization. Check if defined. */ + Node *tempn = 0; + { + String *tbase = SwigType_templateprefix(tname); + tempn = Swig_symbol_clookup_local(tbase,0); + if (!tempn || (Strcmp(nodeType(tempn),"template") != 0)) { + SWIG_WARN_NODE_BEGIN(tempn); + Swig_warning(WARN_PARSE_TEMPLATE_SP_UNDEF, Getfile($$),Getline($$),"Specialization of non-template '%s'.\n", tbase); + SWIG_WARN_NODE_END(tempn); + tempn = 0; + error = 1; + } + Delete(tbase); + } + Setattr($$,"specialization","1"); + Setattr($$,"templatetype",nodeType($$)); + set_nodeType($$,"template"); + /* Template partial specialization */ + if (tempn && ($3) && ($6)) { + List *tlist; + String *targs = SwigType_templateargs(tname); + tlist = SwigType_parmlist(targs); + /* Printf(stdout,"targs = '%s' %s\n", targs, tlist); */ + if (!Getattr($$,"sym:weak")) { + Setattr($$,"sym:typename","1"); + } + + if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) { + Swig_error(Getfile($$),Getline($$),"Inconsistent argument count in template partial specialization. %d %d\n", Len(tlist), ParmList_len(Getattr(tempn,"templateparms"))); + + } else { + + /* This code builds the argument list for the partial template + specialization. This is a little hairy, but the idea is as + follows: + + $3 contains a list of arguments supplied for the template. + For example template<class T>. + + tlist is a list of the specialization arguments--which may be + different. For example class<int,T>. + + tp is a copy of the arguments in the original template definition. + + The patching algorithm walks through the list of supplied + arguments ($3), finds the position in the specialization arguments + (tlist), and then patches the name in the argument list of the + original template. + */ + + { + String *pn; + Parm *p, *p1; + int i, nargs; + Parm *tp = CopyParmList(Getattr(tempn,"templateparms")); + nargs = Len(tlist); + p = $3; + while (p) { + for (i = 0; i < nargs; i++){ + pn = Getattr(p,"name"); + if (Strcmp(pn,SwigType_base(Getitem(tlist,i))) == 0) { + int j; + Parm *p1 = tp; + for (j = 0; j < i; j++) { + p1 = nextSibling(p1); + } + Setattr(p1,"name",pn); + Setattr(p1,"partialarg","1"); + } + } + p = nextSibling(p); + } + p1 = tp; + i = 0; + while (p1) { + if (!Getattr(p1,"partialarg")) { + Delattr(p1,"name"); + Setattr(p1,"type", Getitem(tlist,i)); + } + i++; + p1 = nextSibling(p1); + } + Setattr($$,"templateparms",tp); + Delete(tp); + } + #if 0 + /* Patch the parameter list */ + if (tempn) { + Parm *p,*p1; + ParmList *tp = CopyParmList(Getattr(tempn,"templateparms")); + p = $3; + p1 = tp; + while (p && p1) { + String *pn = Getattr(p,"name"); + Printf(stdout,"pn = '%s'\n", pn); + if (pn) Setattr(p1,"name",pn); + else Delattr(p1,"name"); + pn = Getattr(p,"type"); + if (pn) Setattr(p1,"type",pn); + p = nextSibling(p); + p1 = nextSibling(p1); + } + Setattr($$,"templateparms",tp); + Delete(tp); + } else { + Setattr($$,"templateparms",$3); + } + #endif + Delattr($$,"specialization"); + Setattr($$,"partialspecialization","1"); + /* Create a specialized name for matching */ + { + Parm *p = $3; + String *fname = NewString(Getattr($$,"name")); + String *ffname = 0; + ParmList *partialparms = 0; + + char tmp[32]; + int i, ilen; + while (p) { + String *n = Getattr(p,"name"); + if (!n) { + p = nextSibling(p); + continue; + } + ilen = Len(tlist); + for (i = 0; i < ilen; i++) { + if (Strstr(Getitem(tlist,i),n)) { + sprintf(tmp,"$%d",i+1); + Replaceid(fname,n,tmp); + } + } + p = nextSibling(p); + } + /* Patch argument names with typedef */ + { + Iterator tt; + Parm *parm_current = 0; + List *tparms = SwigType_parmlist(fname); + ffname = SwigType_templateprefix(fname); + Append(ffname,"<("); + for (tt = First(tparms); tt.item; ) { + SwigType *rtt = Swig_symbol_typedef_reduce(tt.item,0); + SwigType *ttr = Swig_symbol_type_qualify(rtt,0); + + Parm *newp = NewParmWithoutFileLineInfo(ttr, 0); + if (partialparms) + set_nextSibling(parm_current, newp); + else + partialparms = newp; + parm_current = newp; + + Append(ffname,ttr); + tt = Next(tt); + if (tt.item) Putc(',',ffname); + Delete(rtt); + Delete(ttr); + } + Delete(tparms); + Append(ffname,")>"); + } + { + Node *new_partial = NewHash(); + String *partials = Getattr(tempn,"partials"); + if (!partials) { + partials = NewList(); + Setattr(tempn,"partials",partials); + Delete(partials); + } + /* Printf(stdout,"partial: fname = '%s', '%s'\n", fname, Swig_symbol_typedef_reduce(fname,0)); */ + Setattr(new_partial, "partialparms", partialparms); + Setattr(new_partial, "templcsymname", ffname); + Append(partials, new_partial); + } + Setattr($$,"partialargs",ffname); + Swig_symbol_cadd(ffname,$$); + } + } + Delete(tlist); + Delete(targs); + } else { + /* An explicit template specialization */ + /* add default args from primary (unspecialized) template */ + String *ty = Swig_symbol_template_deftype(tname,0); + String *fname = Swig_symbol_type_qualify(ty,0); + Swig_symbol_cadd(fname,$$); + Delete(ty); + Delete(fname); + } + } else if ($$) { + Setattr($$,"templatetype",nodeType($6)); + set_nodeType($$,"template"); + Setattr($$,"templateparms", $3); + if (!Getattr($$,"sym:weak")) { + Setattr($$,"sym:typename","1"); + } + add_symbols($$); + default_arguments($$); + /* We also place a fully parameterized version in the symbol table */ + { + Parm *p; + String *fname = NewStringf("%s<(", Getattr($$,"name")); + p = $3; + while (p) { + String *n = Getattr(p,"name"); + if (!n) n = Getattr(p,"type"); + Append(fname,n); + p = nextSibling(p); + if (p) Putc(',',fname); + } + Append(fname,")>"); + Swig_symbol_cadd(fname,$$); + } + } + $$ = ntop; + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + if (error || (nscope_inner && Strcmp(nodeType(nscope_inner), "class") == 0)) { + $$ = 0; + } + if (currentOuterClass) + template_parameters = Getattr(currentOuterClass, "template_parameters"); + else + template_parameters = 0; + parsing_template_declaration = 0; + } + + /* Class template explicit instantiation definition */ + | TEMPLATE cpptype idcolon { + Swig_warning(WARN_PARSE_EXPLICIT_TEMPLATE, cparse_file, cparse_line, "Explicit template instantiation ignored.\n"); + $$ = 0; + } + + /* Function template explicit instantiation definition */ + | TEMPLATE cpp_alternate_rettype idcolon LPAREN parms RPAREN { + Swig_warning(WARN_PARSE_EXPLICIT_TEMPLATE, cparse_file, cparse_line, "Explicit template instantiation ignored.\n"); + $$ = 0; + } + + /* Class template explicit instantiation declaration (extern template) */ + | EXTERN TEMPLATE cpptype idcolon { + Swig_warning(WARN_PARSE_EXTERN_TEMPLATE, cparse_file, cparse_line, "Extern template ignored.\n"); + $$ = 0; + } + + /* Function template explicit instantiation declaration (extern template) */ + | EXTERN TEMPLATE cpp_alternate_rettype idcolon LPAREN parms RPAREN { + Swig_warning(WARN_PARSE_EXTERN_TEMPLATE, cparse_file, cparse_line, "Extern template ignored.\n"); + $$ = 0; + } + ; + +cpp_template_possible: c_decl { + $$ = $1; + } + | cpp_class_decl { + $$ = $1; + } + | cpp_constructor_decl { + $$ = $1; + } + | cpp_template_decl { + $$ = 0; + } + | cpp_forward_class_decl { + $$ = $1; + } + | cpp_conversion_operator { + $$ = $1; + } + ; + +template_parms : templateparameters { + /* Rip out the parameter names */ + Parm *p = $1; + $$ = $1; + + while (p) { + String *name = Getattr(p,"name"); + if (!name) { + /* Hmmm. Maybe it's a 'class T' parameter */ + char *type = Char(Getattr(p,"type")); + /* Template template parameter */ + if (strncmp(type,"template<class> ",16) == 0) { + type += 16; + } + if ((strncmp(type,"class ",6) == 0) || (strncmp(type,"typename ", 9) == 0)) { + char *t = strchr(type,' '); + Setattr(p,"name", t+1); + } else + /* Variadic template args */ + if ((strncmp(type,"class... ",9) == 0) || (strncmp(type,"typename... ", 12) == 0)) { + char *t = strchr(type,' '); + Setattr(p,"name", t+1); + Setattr(p,"variadic", "1"); + } else { + /* + Swig_error(cparse_file, cparse_line, "Missing template parameter name\n"); + $$.rparms = 0; + $$.parms = 0; + break; */ + } + } + p = nextSibling(p); + } + } + ; + +templateparameters : templateparameter templateparameterstail { + set_nextSibling($1,$2); + $$ = $1; + } + | empty { $$ = 0; } + ; + +templateparameter : templcpptype def_args { + $$ = NewParmWithoutFileLineInfo(NewString($1), 0); + Setattr($$, "value", $2.rawval ? $2.rawval : $2.val); + } + | parm { + $$ = $1; + } + ; + +templateparameterstail : COMMA templateparameter templateparameterstail { + set_nextSibling($2,$3); + $$ = $2; + } + | empty { $$ = 0; } + ; + +/* Namespace support */ + +cpp_using_decl : USING idcolon SEMI { + String *uname = Swig_symbol_type_qualify($2,0); + String *name = Swig_scopename_last($2); + $$ = new_node("using"); + Setattr($$,"uname",uname); + Setattr($$,"name", name); + Delete(uname); + Delete(name); + add_symbols($$); + } + | USING NAMESPACE idcolon SEMI { + Node *n = Swig_symbol_clookup($3,0); + if (!n) { + Swig_error(cparse_file, cparse_line, "Nothing known about namespace '%s'\n", $3); + $$ = 0; + } else { + + while (Strcmp(nodeType(n),"using") == 0) { + n = Getattr(n,"node"); + } + if (n) { + if (Strcmp(nodeType(n),"namespace") == 0) { + Symtab *current = Swig_symbol_current(); + Symtab *symtab = Getattr(n,"symtab"); + $$ = new_node("using"); + Setattr($$,"node",n); + Setattr($$,"namespace", $3); + if (current != symtab) { + Swig_symbol_inherit(symtab); + } + } else { + Swig_error(cparse_file, cparse_line, "'%s' is not a namespace.\n", $3); + $$ = 0; + } + } else { + $$ = 0; + } + } + } + ; + +cpp_namespace_decl : NAMESPACE idcolon LBRACE { + Hash *h; + Node *parent_ns = 0; + List *scopes = Swig_scopename_tolist($2); + int ilen = Len(scopes); + int i; + +/* +Printf(stdout, "==== Namespace %s creation...\n", $2); +*/ + $<node>$ = 0; + for (i = 0; i < ilen; i++) { + Node *ns = new_node("namespace"); + Symtab *current_symtab = Swig_symbol_current(); + String *scopename = Getitem(scopes, i); + Setattr(ns, "name", scopename); + $<node>$ = ns; + if (parent_ns) + appendChild(parent_ns, ns); + parent_ns = ns; + h = Swig_symbol_clookup(scopename, 0); + if (h && (current_symtab == Getattr(h, "sym:symtab")) && (Strcmp(nodeType(h), "namespace") == 0)) { +/* +Printf(stdout, " Scope %s [found C++17 style]\n", scopename); +*/ + if (Getattr(h, "alias")) { + h = Getattr(h, "namespace"); + Swig_warning(WARN_PARSE_NAMESPACE_ALIAS, cparse_file, cparse_line, "Namespace alias '%s' not allowed here. Assuming '%s'\n", + scopename, Getattr(h, "name")); + scopename = Getattr(h, "name"); + } + Swig_symbol_setscope(Getattr(h, "symtab")); + } else { +/* +Printf(stdout, " Scope %s [creating single scope C++17 style]\n", scopename); +*/ + h = Swig_symbol_newscope(); + Swig_symbol_setscopename(scopename); + } + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + Delete(scopes); + } interface RBRACE { + Node *n = $<node>4; + Node *top_ns = 0; + do { + Setattr(n, "symtab", Swig_symbol_popscope()); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols(n); + top_ns = n; + n = parentNode(n); + } while(n); + appendChild($<node>4, firstChild($5)); + Delete($5); + $$ = top_ns; + } + | NAMESPACE LBRACE { + Hash *h; + $1 = Swig_symbol_current(); + h = Swig_symbol_clookup(" ",0); + if (h && (Strcmp(nodeType(h),"namespace") == 0)) { + Swig_symbol_setscope(Getattr(h,"symtab")); + } else { + Swig_symbol_newscope(); + /* we don't use "__unnamed__", but a long 'empty' name */ + Swig_symbol_setscopename(" "); + } + Namespaceprefix = 0; + } interface RBRACE { + $$ = $4; + set_nodeType($$,"namespace"); + Setattr($$,"unnamed","1"); + Setattr($$,"symtab", Swig_symbol_popscope()); + Swig_symbol_setscope($1); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($$); + } + | NAMESPACE identifier EQUAL idcolon SEMI { + /* Namespace alias */ + Node *n; + $$ = new_node("namespace"); + Setattr($$,"name",$2); + Setattr($$,"alias",$4); + n = Swig_symbol_clookup($4,0); + if (!n) { + Swig_error(cparse_file, cparse_line, "Unknown namespace '%s'\n", $4); + $$ = 0; + } else { + if (Strcmp(nodeType(n),"namespace") != 0) { + Swig_error(cparse_file, cparse_line, "'%s' is not a namespace\n",$4); + $$ = 0; + } else { + while (Getattr(n,"alias")) { + n = Getattr(n,"namespace"); + } + Setattr($$,"namespace",n); + add_symbols($$); + /* Set up a scope alias */ + Swig_symbol_alias($2,Getattr(n,"symtab")); + } + } + } + ; + +cpp_members : cpp_member cpp_members { + $$ = $1; + /* Insert cpp_member (including any siblings) to the front of the cpp_members linked list */ + if ($$) { + Node *p = $$; + Node *pp =0; + while (p) { + pp = p; + p = nextSibling(p); + } + set_nextSibling(pp,$2); + if ($2) + set_previousSibling($2, pp); + } else { + $$ = $2; + } + } + | EXTEND LBRACE { + extendmode = 1; + if (cplus_mode != CPLUS_PUBLIC) { + Swig_error(cparse_file,cparse_line,"%%extend can only be used in a public section\n"); + } + } cpp_members RBRACE { + extendmode = 0; + } cpp_members { + $$ = new_node("extend"); + mark_nodes_as_extend($4); + appendChild($$,$4); + set_nextSibling($$,$7); + } + | include_directive { $$ = $1; } + | empty { $$ = 0;} + | error { + Swig_error(cparse_file,cparse_line,"Syntax error in input(3).\n"); + Exit(EXIT_FAILURE); + } cpp_members { + $$ = $3; + } + ; + +/* ====================================================================== + * C++ Class members + * ====================================================================== */ + +/* A class member. May be data or a function. Static or virtual as well */ + +cpp_member_no_dox : c_declaration { $$ = $1; } + | cpp_constructor_decl { + $$ = $1; + if (extendmode && current_class) { + String *symname; + symname= make_name($$,Getattr($$,"name"), Getattr($$,"decl")); + if (Strcmp(symname,Getattr($$,"name")) == 0) { + /* No renaming operation. Set name to class name */ + Delete(yyrename); + yyrename = NewString(Getattr(current_class,"sym:name")); + } else { + Delete(yyrename); + yyrename = symname; + } + } + add_symbols($$); + default_arguments($$); + } + | cpp_destructor_decl { $$ = $1; } + | cpp_protection_decl { $$ = $1; } + | cpp_swig_directive { $$ = $1; } + | cpp_conversion_operator { $$ = $1; } + | cpp_forward_class_decl { $$ = $1; } + | cpp_class_decl { $$ = $1; } + | storage_class idcolon SEMI { $$ = 0; } + | cpp_using_decl { $$ = $1; } + | cpp_template_decl { $$ = $1; } + | cpp_catch_decl { $$ = 0; } + | template_directive { $$ = $1; } + | warn_directive { $$ = $1; } + | anonymous_bitfield { $$ = 0; } + | fragment_directive {$$ = $1; } + | types_directive {$$ = $1; } + | SEMI { $$ = 0; } + +cpp_member : cpp_member_no_dox { + $$ = $1; + } + | DOXYGENSTRING cpp_member_no_dox { + $$ = $2; + set_comment($2, $1); + } + | cpp_member_no_dox DOXYGENPOSTSTRING { + $$ = $1; + set_comment($1, $2); + } + ; + +/* Possibly a constructor */ +/* Note: the use of 'type' is here to resolve a shift-reduce conflict. For example: + typedef Foo (); + typedef Foo (*ptr)(); +*/ + +cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end { + if (inclass || extendmode) { + SwigType *decl = NewStringEmpty(); + $$ = new_node("constructor"); + Setattr($$,"storage",$1); + Setattr($$,"name",$2); + Setattr($$,"parms",$4); + SwigType_add_function(decl,$4); + Setattr($$,"decl",decl); + Setattr($$,"throws",$6.throws); + Setattr($$,"throw",$6.throwf); + Setattr($$,"noexcept",$6.nexcept); + Setattr($$,"final",$6.final); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + SetFlag($$,"feature:new"); + if ($6.defarg) + Setattr($$,"value",$6.defarg); + } else { + $$ = 0; + } + } + ; + +/* A destructor (hopefully) */ + +cpp_destructor_decl : NOT idtemplate LPAREN parms RPAREN cpp_end { + String *name = NewStringf("%s",$2); + if (*(Char(name)) != '~') Insert(name,0,"~"); + $$ = new_node("destructor"); + Setattr($$,"name",name); + Delete(name); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + { + String *decl = NewStringEmpty(); + SwigType_add_function(decl,$4); + Setattr($$,"decl",decl); + Delete(decl); + } + Setattr($$,"throws",$6.throws); + Setattr($$,"throw",$6.throwf); + Setattr($$,"noexcept",$6.nexcept); + Setattr($$,"final",$6.final); + if ($6.val) + Setattr($$,"value",$6.val); + if ($6.qualifier) + Swig_error(cparse_file, cparse_line, "Destructor %s %s cannot have a qualifier.\n", Swig_name_decl($$), SwigType_str($6.qualifier, 0)); + add_symbols($$); + } + +/* A virtual destructor */ + + | VIRTUAL NOT idtemplate LPAREN parms RPAREN cpp_vend { + String *name; + $$ = new_node("destructor"); + Setattr($$,"storage","virtual"); + name = NewStringf("%s",$3); + if (*(Char(name)) != '~') Insert(name,0,"~"); + Setattr($$,"name",name); + Delete(name); + Setattr($$,"throws",$7.throws); + Setattr($$,"throw",$7.throwf); + Setattr($$,"noexcept",$7.nexcept); + Setattr($$,"final",$7.final); + if ($7.val) + Setattr($$,"value",$7.val); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + { + String *decl = NewStringEmpty(); + SwigType_add_function(decl,$5); + Setattr($$,"decl",decl); + Delete(decl); + } + if ($7.qualifier) + Swig_error(cparse_file, cparse_line, "Destructor %s %s cannot have a qualifier.\n", Swig_name_decl($$), SwigType_str($7.qualifier, 0)); + add_symbols($$); + } + ; + + +/* C++ type conversion operator */ +cpp_conversion_operator : storage_class CONVERSIONOPERATOR type pointer LPAREN parms RPAREN cpp_vend { + $$ = new_node("cdecl"); + Setattr($$,"type",$3); + Setattr($$,"name",$2); + Setattr($$,"storage",$1); + + SwigType_add_function($4,$6); + if ($8.qualifier) { + SwigType_push($4,$8.qualifier); + } + if ($8.val) { + Setattr($$,"value",$8.val); + } + Setattr($$,"refqualifier",$8.refqualifier); + Setattr($$,"decl",$4); + Setattr($$,"parms",$6); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + | storage_class CONVERSIONOPERATOR type AND LPAREN parms RPAREN cpp_vend { + SwigType *decl; + $$ = new_node("cdecl"); + Setattr($$,"type",$3); + Setattr($$,"name",$2); + Setattr($$,"storage",$1); + decl = NewStringEmpty(); + SwigType_add_reference(decl); + SwigType_add_function(decl,$6); + if ($8.qualifier) { + SwigType_push(decl,$8.qualifier); + } + if ($8.val) { + Setattr($$,"value",$8.val); + } + Setattr($$,"refqualifier",$8.refqualifier); + Setattr($$,"decl",decl); + Setattr($$,"parms",$6); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + | storage_class CONVERSIONOPERATOR type LAND LPAREN parms RPAREN cpp_vend { + SwigType *decl; + $$ = new_node("cdecl"); + Setattr($$,"type",$3); + Setattr($$,"name",$2); + Setattr($$,"storage",$1); + decl = NewStringEmpty(); + SwigType_add_rvalue_reference(decl); + SwigType_add_function(decl,$6); + if ($8.qualifier) { + SwigType_push(decl,$8.qualifier); + } + if ($8.val) { + Setattr($$,"value",$8.val); + } + Setattr($$,"refqualifier",$8.refqualifier); + Setattr($$,"decl",decl); + Setattr($$,"parms",$6); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + + | storage_class CONVERSIONOPERATOR type pointer AND LPAREN parms RPAREN cpp_vend { + SwigType *decl; + $$ = new_node("cdecl"); + Setattr($$,"type",$3); + Setattr($$,"name",$2); + Setattr($$,"storage",$1); + decl = NewStringEmpty(); + SwigType_add_pointer(decl); + SwigType_add_reference(decl); + SwigType_add_function(decl,$7); + if ($9.qualifier) { + SwigType_push(decl,$9.qualifier); + } + if ($9.val) { + Setattr($$,"value",$9.val); + } + Setattr($$,"refqualifier",$9.refqualifier); + Setattr($$,"decl",decl); + Setattr($$,"parms",$7); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + + | storage_class CONVERSIONOPERATOR type LPAREN parms RPAREN cpp_vend { + String *t = NewStringEmpty(); + $$ = new_node("cdecl"); + Setattr($$,"type",$3); + Setattr($$,"name",$2); + Setattr($$,"storage",$1); + SwigType_add_function(t,$5); + if ($7.qualifier) { + SwigType_push(t,$7.qualifier); + } + if ($7.val) { + Setattr($$,"value",$7.val); + } + Setattr($$,"refqualifier",$7.refqualifier); + Setattr($$,"decl",t); + Setattr($$,"parms",$5); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + ; + +/* isolated catch clause. */ + +cpp_catch_decl : CATCH LPAREN parms RPAREN LBRACE { + skip_balanced('{','}'); + $$ = 0; + } + ; + +/* static_assert(bool, const char*); (C++11) + * static_assert(bool); (C++17) */ +cpp_static_assert : STATIC_ASSERT LPAREN { + skip_balanced('(',')'); + $$ = 0; + } + ; + +/* public: */ +cpp_protection_decl : PUBLIC COLON { + $$ = new_node("access"); + Setattr($$,"kind","public"); + cplus_mode = CPLUS_PUBLIC; + } + +/* private: */ + | PRIVATE COLON { + $$ = new_node("access"); + Setattr($$,"kind","private"); + cplus_mode = CPLUS_PRIVATE; + } + +/* protected: */ + + | PROTECTED COLON { + $$ = new_node("access"); + Setattr($$,"kind","protected"); + cplus_mode = CPLUS_PROTECTED; + } + ; +/* These directives can be included inside a class definition */ + +cpp_swig_directive: pragma_directive { $$ = $1; } + +/* A constant (includes #defines) inside a class */ + | constant_directive { $$ = $1; } + +/* This is the new style rename */ + + | name_directive { $$ = $1; } + +/* rename directive */ + | rename_directive { $$ = $1; } + | feature_directive { $$ = $1; } + | varargs_directive { $$ = $1; } + | insert_directive { $$ = $1; } + | typemap_directive { $$ = $1; } + | apply_directive { $$ = $1; } + | clear_directive { $$ = $1; } + | echo_directive { $$ = $1; } + ; + +cpp_end : cpp_const SEMI { + Clear(scanner_ccode); + $$.val = 0; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + } + | cpp_const EQUAL default_delete SEMI { + Clear(scanner_ccode); + $$.val = $3.val; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + } + | cpp_const LBRACE { + skip_balanced('{','}'); + $$.val = 0; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + } + ; + +cpp_vend : cpp_const SEMI { + Clear(scanner_ccode); + $$.val = 0; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + } + | cpp_const EQUAL definetype SEMI { + Clear(scanner_ccode); + $$.val = $3.val; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + } + | cpp_const LBRACE { + skip_balanced('{','}'); + $$.val = 0; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + } + ; + + +anonymous_bitfield : storage_class anon_bitfield_type COLON expr SEMI { }; + +/* Equals type_right without the ENUM keyword and cpptype (templates etc.): */ +anon_bitfield_type : primitive_type { $$ = $1; + /* Printf(stdout,"primitive = '%s'\n", $$);*/ + } + | TYPE_BOOL { $$ = $1; } + | TYPE_VOID { $$ = $1; } +/* + | TYPE_TYPEDEF template_decl { $$ = NewStringf("%s%s",$1,$2); } +*/ + | TYPE_RAW { $$ = $1; } + + | idcolon { + $$ = $1; + } + ; + +/* ====================================================================== + * PRIMITIVES + * ====================================================================== */ +extern_string : EXTERN string { + if (Strcmp($2,"C") == 0) { + $$ = "externc"; + } else if (Strcmp($2,"C++") == 0) { + $$ = "extern"; + } else { + Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", $2); + $$ = 0; + } + } + ; + +storage_class : EXTERN { $$ = "extern"; } + | extern_string { $$ = $1; } + | extern_string THREAD_LOCAL { + if (Equal($1, "extern")) { + $$ = "extern thread_local"; + } else { + $$ = "externc thread_local"; + } + } + | extern_string TYPEDEF { $$ = "typedef"; } + | STATIC { $$ = "static"; } + | TYPEDEF { $$ = "typedef"; } + | VIRTUAL { $$ = "virtual"; } + | FRIEND { $$ = "friend"; } + | EXPLICIT { $$ = "explicit"; } + | CONSTEXPR { $$ = "constexpr"; } + | EXPLICIT CONSTEXPR { $$ = "explicit constexpr"; } + | CONSTEXPR EXPLICIT { $$ = "explicit constexpr"; } + | STATIC CONSTEXPR { $$ = "static constexpr"; } + | CONSTEXPR STATIC { $$ = "static constexpr"; } + | THREAD_LOCAL { $$ = "thread_local"; } + | THREAD_LOCAL STATIC { $$ = "static thread_local"; } + | STATIC THREAD_LOCAL { $$ = "static thread_local"; } + | EXTERN THREAD_LOCAL { $$ = "extern thread_local"; } + | THREAD_LOCAL EXTERN { $$ = "extern thread_local"; } + | empty { $$ = 0; } + ; + +/* ------------------------------------------------------------------------------ + Function parameter lists + ------------------------------------------------------------------------------ */ + +parms : rawparms { + Parm *p; + $$ = $1; + p = $1; + while (p) { + Replace(Getattr(p,"type"),"typename ", "", DOH_REPLACE_ANY); + p = nextSibling(p); + } + } + ; + +rawparms : parm ptail { + set_nextSibling($1,$2); + $$ = $1; + } + | empty { + $$ = 0; + previousNode = currentNode; + currentNode=0; + } + ; + +ptail : COMMA parm ptail { + set_nextSibling($2,$3); + $$ = $2; + } + | COMMA DOXYGENPOSTSTRING parm ptail { + set_comment(previousNode, $2); + set_nextSibling($3, $4); + $$ = $3; + } + | empty { $$ = 0; } + ; + + +parm_no_dox : rawtype parameter_declarator { + SwigType_push($1,$2.type); + $$ = NewParmWithoutFileLineInfo($1,$2.id); + previousNode = currentNode; + currentNode = $$; + Setfile($$,cparse_file); + Setline($$,cparse_line); + if ($2.defarg) { + Setattr($$,"value",$2.defarg); + } + } + + | TEMPLATE LESSTHAN cpptype GREATERTHAN cpptype idcolon def_args { + $$ = NewParmWithoutFileLineInfo(NewStringf("template<class> %s %s", $5,$6), 0); + previousNode = currentNode; + currentNode = $$; + Setfile($$,cparse_file); + Setline($$,cparse_line); + if ($7.val) { + Setattr($$,"value",$7.val); + } + } + | ELLIPSIS { + SwigType *t = NewString("v(...)"); + $$ = NewParmWithoutFileLineInfo(t, 0); + previousNode = currentNode; + currentNode = $$; + Setfile($$,cparse_file); + Setline($$,cparse_line); + } + ; + +parm : parm_no_dox { + $$ = $1; + } + | DOXYGENSTRING parm_no_dox { + $$ = $2; + set_comment($2, $1); + } + | parm_no_dox DOXYGENPOSTSTRING { + $$ = $1; + set_comment($1, $2); + } + ; + +valparms : rawvalparms { + Parm *p; + $$ = $1; + p = $1; + while (p) { + if (Getattr(p,"type")) { + Replace(Getattr(p,"type"),"typename ", "", DOH_REPLACE_ANY); + } + p = nextSibling(p); + } + } + ; + +rawvalparms : valparm valptail { + set_nextSibling($1,$2); + $$ = $1; + } + | empty { $$ = 0; } + ; + +valptail : COMMA valparm valptail { + set_nextSibling($2,$3); + $$ = $2; + } + | empty { $$ = 0; } + ; + + +valparm : parm { + $$ = $1; + { + /* We need to make a possible adjustment for integer parameters. */ + SwigType *type; + Node *n = 0; + + while (!n) { + type = Getattr($1,"type"); + n = Swig_symbol_clookup(type,0); /* See if we can find a node that matches the typename */ + if ((n) && (Strcmp(nodeType(n),"cdecl") == 0)) { + SwigType *decl = Getattr(n,"decl"); + if (!SwigType_isfunction(decl)) { + String *value = Getattr(n,"value"); + if (value) { + String *v = Copy(value); + Setattr($1,"type",v); + Delete(v); + n = 0; + } + } + } else { + break; + } + } + } + + } + | valexpr { + $$ = NewParmWithoutFileLineInfo(0,0); + Setfile($$,cparse_file); + Setline($$,cparse_line); + Setattr($$,"value",$1.val); + } + ; + +callparms : valexpr callptail { + $$ = $1; + Printf($$.val, "%s", $2.val); + } + | empty { $$.val = NewStringEmpty(); } + ; + +callptail : COMMA valexpr callptail { + $$.val = NewStringf(",%s%s", $2.val, $3.val); + $$.type = 0; + } + | empty { $$.val = NewStringEmpty(); } + ; + +def_args : EQUAL definetype { + $$ = $2; + if ($2.type == T_ERROR) { + Swig_warning(WARN_PARSE_BAD_DEFAULT,cparse_file, cparse_line, "Can't set default argument (ignored)\n"); + $$.val = 0; + $$.rawval = 0; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + } + | EQUAL definetype LBRACKET expr RBRACKET { + $$ = $2; + if ($2.type == T_ERROR) { + Swig_warning(WARN_PARSE_BAD_DEFAULT,cparse_file, cparse_line, "Can't set default argument (ignored)\n"); + $$ = $2; + $$.val = 0; + $$.rawval = 0; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } else { + $$.val = NewStringf("%s[%s]",$2.val,$4.val); + } + } + | EQUAL LBRACE { + skip_balanced('{','}'); + $$.val = NewString(scanner_ccode); + $$.rawval = 0; + $$.type = T_INT; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + | COLON expr { + $$.val = 0; + $$.rawval = 0; + $$.type = 0; + $$.bitfield = $2.val; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + | empty { + $$.val = 0; + $$.rawval = 0; + $$.type = T_INT; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + ; + +parameter_declarator : declarator def_args { + $$ = $1; + $$.defarg = $2.rawval ? $2.rawval : $2.val; + } + | abstract_declarator def_args { + $$ = $1; + $$.defarg = $2.rawval ? $2.rawval : $2.val; + } + | def_args { + $$.type = 0; + $$.id = 0; + $$.defarg = $1.rawval ? $1.rawval : $1.val; + } + /* Member function pointers with qualifiers. eg. + int f(short (Funcs::*parm)(bool) const); */ + | direct_declarator LPAREN parms RPAREN cv_ref_qualifier { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_function(t,$3); + if ($5.qualifier) + SwigType_push(t, $5.qualifier); + if (!$$.have_parms) { + $$.parms = $3; + $$.have_parms = 1; + } + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t, $$.type); + Delete($$.type); + $$.type = t; + } + $$.defarg = 0; + } + ; + +plain_declarator : declarator { + $$ = $1; + if (SwigType_isfunction($1.type)) { + Delete(SwigType_pop_function($1.type)); + } else if (SwigType_isarray($1.type)) { + SwigType *ta = SwigType_pop_arrays($1.type); + if (SwigType_isfunction($1.type)) { + Delete(SwigType_pop_function($1.type)); + } else { + $$.parms = 0; + } + SwigType_push($1.type,ta); + Delete(ta); + } else { + $$.parms = 0; + } + } + | abstract_declarator { + $$ = $1; + if (SwigType_isfunction($1.type)) { + Delete(SwigType_pop_function($1.type)); + } else if (SwigType_isarray($1.type)) { + SwigType *ta = SwigType_pop_arrays($1.type); + if (SwigType_isfunction($1.type)) { + Delete(SwigType_pop_function($1.type)); + } else { + $$.parms = 0; + } + SwigType_push($1.type,ta); + Delete(ta); + } else { + $$.parms = 0; + } + } + /* Member function pointers with qualifiers. eg. + int f(short (Funcs::*parm)(bool) const) */ + | direct_declarator LPAREN parms RPAREN cv_ref_qualifier { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_function(t, $3); + if ($5.qualifier) + SwigType_push(t, $5.qualifier); + if (!$$.have_parms) { + $$.parms = $3; + $$.have_parms = 1; + } + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t, $$.type); + Delete($$.type); + $$.type = t; + } + } + | empty { + $$.type = 0; + $$.id = 0; + $$.parms = 0; + } + ; + +declarator : pointer notso_direct_declarator { + $$ = $2; + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | pointer AND notso_direct_declarator { + $$ = $3; + SwigType_add_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | pointer LAND notso_direct_declarator { + $$ = $3; + SwigType_add_rvalue_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | direct_declarator { + $$ = $1; + if (!$$.type) $$.type = NewStringEmpty(); + } + | AND notso_direct_declarator { + $$ = $2; + $$.type = NewStringEmpty(); + SwigType_add_reference($$.type); + if ($2.type) { + SwigType_push($$.type,$2.type); + Delete($2.type); + } + } + | LAND notso_direct_declarator { + /* Introduced in C++11, move operator && */ + /* Adds one S/R conflict */ + $$ = $2; + $$.type = NewStringEmpty(); + SwigType_add_rvalue_reference($$.type); + if ($2.type) { + SwigType_push($$.type,$2.type); + Delete($2.type); + } + } + | idcolon DSTAR notso_direct_declarator { + SwigType *t = NewStringEmpty(); + + $$ = $3; + SwigType_add_memberpointer(t,$1); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | pointer idcolon DSTAR notso_direct_declarator { + SwigType *t = NewStringEmpty(); + $$ = $4; + SwigType_add_memberpointer(t,$2); + SwigType_push($1,t); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + Delete(t); + } + | pointer idcolon DSTAR AND notso_direct_declarator { + $$ = $5; + SwigType_add_memberpointer($1,$2); + SwigType_add_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | idcolon DSTAR AND notso_direct_declarator { + SwigType *t = NewStringEmpty(); + $$ = $4; + SwigType_add_memberpointer(t,$1); + SwigType_add_reference(t); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + + /* Variadic versions eg. MyClasses&... myIds */ + + | pointer ELLIPSIS notso_direct_declarator { + $$ = $3; + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | pointer AND ELLIPSIS notso_direct_declarator { + $$ = $4; + SwigType_add_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | pointer LAND ELLIPSIS notso_direct_declarator { + $$ = $4; + SwigType_add_rvalue_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | ELLIPSIS direct_declarator { + $$ = $2; + if (!$$.type) $$.type = NewStringEmpty(); + } + | AND ELLIPSIS notso_direct_declarator { + $$ = $3; + $$.type = NewStringEmpty(); + SwigType_add_reference($$.type); + if ($3.type) { + SwigType_push($$.type,$3.type); + Delete($3.type); + } + } + | LAND ELLIPSIS notso_direct_declarator { + /* Introduced in C++11, move operator && */ + /* Adds one S/R conflict */ + $$ = $3; + $$.type = NewStringEmpty(); + SwigType_add_rvalue_reference($$.type); + if ($3.type) { + SwigType_push($$.type,$3.type); + Delete($3.type); + } + } + | idcolon DSTAR ELLIPSIS notso_direct_declarator { + SwigType *t = NewStringEmpty(); + + $$ = $4; + SwigType_add_memberpointer(t,$1); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | pointer idcolon DSTAR ELLIPSIS notso_direct_declarator { + SwigType *t = NewStringEmpty(); + $$ = $5; + SwigType_add_memberpointer(t,$2); + SwigType_push($1,t); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + Delete(t); + } + | pointer idcolon DSTAR AND ELLIPSIS notso_direct_declarator { + $$ = $6; + SwigType_add_memberpointer($1,$2); + SwigType_add_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | pointer idcolon DSTAR LAND ELLIPSIS notso_direct_declarator { + $$ = $6; + SwigType_add_memberpointer($1,$2); + SwigType_add_rvalue_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | idcolon DSTAR AND ELLIPSIS notso_direct_declarator { + SwigType *t = NewStringEmpty(); + $$ = $5; + SwigType_add_memberpointer(t,$1); + SwigType_add_reference(t); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | idcolon DSTAR LAND ELLIPSIS notso_direct_declarator { + SwigType *t = NewStringEmpty(); + $$ = $5; + SwigType_add_memberpointer(t,$1); + SwigType_add_rvalue_reference(t); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + ; + +notso_direct_declarator : idcolon { + /* Note: This is non-standard C. Template declarator is allowed to follow an identifier */ + $$.id = Char($1); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } + | NOT idcolon { + $$.id = Char(NewStringf("~%s",$2)); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } + +/* This generates a shift-reduce conflict with constructors */ + | LPAREN idcolon RPAREN { + $$.id = Char($2); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } + +/* + | LPAREN AND idcolon RPAREN { + $$.id = Char($3); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } +*/ +/* Technically, this should be LPAREN declarator RPAREN, but we get reduce/reduce conflicts */ + | LPAREN pointer notso_direct_declarator RPAREN { + $$ = $3; + if ($$.type) { + SwigType_push($2,$$.type); + Delete($$.type); + } + $$.type = $2; + } + | LPAREN idcolon DSTAR notso_direct_declarator RPAREN { + SwigType *t; + $$ = $4; + t = NewStringEmpty(); + SwigType_add_memberpointer(t,$2); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | notso_direct_declarator LBRACKET RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,""); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | notso_direct_declarator LBRACKET expr RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,$3.val); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | notso_direct_declarator LPAREN parms RPAREN { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_function(t,$3); + if (!$$.have_parms) { + $$.parms = $3; + $$.have_parms = 1; + } + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t, $$.type); + Delete($$.type); + $$.type = t; + } + } + ; + +direct_declarator : idcolon { + /* Note: This is non-standard C. Template declarator is allowed to follow an identifier */ + $$.id = Char($1); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } + + | NOT idcolon { + $$.id = Char(NewStringf("~%s",$2)); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } + +/* This generate a shift-reduce conflict with constructors */ +/* + | LPAREN idcolon RPAREN { + $$.id = Char($2); + $$.type = 0; + $$.parms = 0; + $$.have_parms = 0; + } +*/ +/* Technically, this should be LPAREN declarator RPAREN, but we get reduce/reduce conflicts */ + | LPAREN pointer direct_declarator RPAREN { + $$ = $3; + if ($$.type) { + SwigType_push($2,$$.type); + Delete($$.type); + } + $$.type = $2; + } + | LPAREN AND direct_declarator RPAREN { + $$ = $3; + if (!$$.type) { + $$.type = NewStringEmpty(); + } + SwigType_add_reference($$.type); + } + | LPAREN LAND direct_declarator RPAREN { + $$ = $3; + if (!$$.type) { + $$.type = NewStringEmpty(); + } + SwigType_add_rvalue_reference($$.type); + } + | LPAREN idcolon DSTAR declarator RPAREN { + SwigType *t; + $$ = $4; + t = NewStringEmpty(); + SwigType_add_memberpointer(t,$2); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | LPAREN idcolon DSTAR type_qualifier declarator RPAREN { + SwigType *t; + $$ = $5; + t = NewStringEmpty(); + SwigType_add_memberpointer(t, $2); + SwigType_push(t, $4); + if ($$.type) { + SwigType_push(t, $$.type); + Delete($$.type); + } + $$.type = t; + } + | LPAREN idcolon DSTAR abstract_declarator RPAREN { + SwigType *t; + $$ = $4; + t = NewStringEmpty(); + SwigType_add_memberpointer(t, $2); + if ($$.type) { + SwigType_push(t, $$.type); + Delete($$.type); + } + $$.type = t; + } + | LPAREN idcolon DSTAR type_qualifier abstract_declarator RPAREN { + SwigType *t; + $$ = $5; + t = NewStringEmpty(); + SwigType_add_memberpointer(t, $2); + SwigType_push(t, $4); + if ($$.type) { + SwigType_push(t, $$.type); + Delete($$.type); + } + $$.type = t; + } + | direct_declarator LBRACKET RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,""); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | direct_declarator LBRACKET expr RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,$3.val); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | direct_declarator LPAREN parms RPAREN { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_function(t,$3); + if (!$$.have_parms) { + $$.parms = $3; + $$.have_parms = 1; + } + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t, $$.type); + Delete($$.type); + $$.type = t; + } + } + /* User-defined string literals. eg. + int operator"" _mySuffix(const char* val, int length) {...} */ + /* This produces one S/R conflict. */ + | OPERATOR ID LPAREN parms RPAREN { + SwigType *t; + Append($1, " "); /* intervening space is mandatory */ + Append($1, Char($2)); + $$.id = Char($1); + t = NewStringEmpty(); + SwigType_add_function(t,$4); + if (!$$.have_parms) { + $$.parms = $4; + $$.have_parms = 1; + } + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t, $$.type); + Delete($$.type); + $$.type = t; + } + } + ; + +abstract_declarator : pointer { + $$.type = $1; + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + } + | pointer direct_abstract_declarator { + $$ = $2; + SwigType_push($1,$2.type); + $$.type = $1; + Delete($2.type); + } + | pointer AND { + $$.type = $1; + SwigType_add_reference($$.type); + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + } + | pointer LAND { + $$.type = $1; + SwigType_add_rvalue_reference($$.type); + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + } + | pointer AND direct_abstract_declarator { + $$ = $3; + SwigType_add_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | pointer LAND direct_abstract_declarator { + $$ = $3; + SwigType_add_rvalue_reference($1); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + | direct_abstract_declarator { + $$ = $1; + } + | AND direct_abstract_declarator { + $$ = $2; + $$.type = NewStringEmpty(); + SwigType_add_reference($$.type); + if ($2.type) { + SwigType_push($$.type,$2.type); + Delete($2.type); + } + } + | LAND direct_abstract_declarator { + $$ = $2; + $$.type = NewStringEmpty(); + SwigType_add_rvalue_reference($$.type); + if ($2.type) { + SwigType_push($$.type,$2.type); + Delete($2.type); + } + } + | AND { + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + $$.type = NewStringEmpty(); + SwigType_add_reference($$.type); + } + | LAND { + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + $$.type = NewStringEmpty(); + SwigType_add_rvalue_reference($$.type); + } + | idcolon DSTAR { + $$.type = NewStringEmpty(); + SwigType_add_memberpointer($$.type,$1); + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + } + | idcolon DSTAR type_qualifier { + $$.type = NewStringEmpty(); + SwigType_add_memberpointer($$.type, $1); + SwigType_push($$.type, $3); + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + } + | pointer idcolon DSTAR { + SwigType *t = NewStringEmpty(); + $$.type = $1; + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + SwigType_add_memberpointer(t,$2); + SwigType_push($$.type,t); + Delete(t); + } + | pointer idcolon DSTAR direct_abstract_declarator { + $$ = $4; + SwigType_add_memberpointer($1,$2); + if ($$.type) { + SwigType_push($1,$$.type); + Delete($$.type); + } + $$.type = $1; + } + ; + +direct_abstract_declarator : direct_abstract_declarator LBRACKET RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,""); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | direct_abstract_declarator LBRACKET expr RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,$3.val); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | LBRACKET RBRACKET { + $$.type = NewStringEmpty(); + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + SwigType_add_array($$.type,""); + } + | LBRACKET expr RBRACKET { + $$.type = NewStringEmpty(); + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + SwigType_add_array($$.type,$2.val); + } + | LPAREN abstract_declarator RPAREN { + $$ = $2; + } + | direct_abstract_declarator LPAREN parms RPAREN { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_function(t,$3); + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t,$$.type); + Delete($$.type); + $$.type = t; + } + if (!$$.have_parms) { + $$.parms = $3; + $$.have_parms = 1; + } + } + | direct_abstract_declarator LPAREN parms RPAREN cv_ref_qualifier { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_function(t,$3); + SwigType_push(t, $5.qualifier); + if (!$$.type) { + $$.type = t; + } else { + SwigType_push(t,$$.type); + Delete($$.type); + $$.type = t; + } + if (!$$.have_parms) { + $$.parms = $3; + $$.have_parms = 1; + } + } + | LPAREN parms RPAREN { + $$.type = NewStringEmpty(); + SwigType_add_function($$.type,$2); + $$.parms = $2; + $$.have_parms = 1; + $$.id = 0; + } + ; + + +pointer : STAR type_qualifier pointer { + $$ = NewStringEmpty(); + SwigType_add_pointer($$); + SwigType_push($$,$2); + SwigType_push($$,$3); + Delete($3); + } + | STAR pointer { + $$ = NewStringEmpty(); + SwigType_add_pointer($$); + SwigType_push($$,$2); + Delete($2); + } + | STAR type_qualifier { + $$ = NewStringEmpty(); + SwigType_add_pointer($$); + SwigType_push($$,$2); + } + | STAR { + $$ = NewStringEmpty(); + SwigType_add_pointer($$); + } + ; + +/* cv-qualifier plus C++11 ref-qualifier for non-static member functions */ +cv_ref_qualifier : type_qualifier { + $$.qualifier = $1; + $$.refqualifier = 0; + } + | type_qualifier ref_qualifier { + $$.qualifier = $1; + $$.refqualifier = $2; + SwigType_push($$.qualifier, $2); + } + | ref_qualifier { + $$.qualifier = NewStringEmpty(); + $$.refqualifier = $1; + SwigType_push($$.qualifier, $1); + } + ; + +ref_qualifier : AND { + $$ = NewStringEmpty(); + SwigType_add_reference($$); + } + | LAND { + $$ = NewStringEmpty(); + SwigType_add_rvalue_reference($$); + } + ; + +type_qualifier : type_qualifier_raw { + $$ = NewStringEmpty(); + if ($1) SwigType_add_qualifier($$,$1); + } + | type_qualifier_raw type_qualifier { + $$ = $2; + if ($1) SwigType_add_qualifier($$,$1); + } + ; + +type_qualifier_raw : CONST_QUAL { $$ = "const"; } + | VOLATILE { $$ = "volatile"; } + | REGISTER { $$ = 0; } + ; + +/* Data type must be a built in type or an identifier for user-defined types + This type can be preceded by a modifier. */ + +type : rawtype { + $$ = $1; + Replace($$,"typename ","", DOH_REPLACE_ANY); + } + ; + +rawtype : type_qualifier type_right { + $$ = $2; + SwigType_push($$,$1); + } + | type_right { $$ = $1; } + | type_right type_qualifier { + $$ = $1; + SwigType_push($$,$2); + } + | type_qualifier type_right type_qualifier { + $$ = $2; + SwigType_push($$,$3); + SwigType_push($$,$1); + } + ; + +type_right : primitive_type { $$ = $1; + /* Printf(stdout,"primitive = '%s'\n", $$);*/ + } + | TYPE_BOOL { $$ = $1; } + | TYPE_VOID { $$ = $1; } +/* + | TYPE_TYPEDEF template_decl { $$ = NewStringf("%s%s",$1,$2); } +*/ + | c_enum_key idcolon { $$ = NewStringf("enum %s", $2); } + | TYPE_RAW { $$ = $1; } + + | idcolon { + $$ = $1; + } + | cpptype idcolon { + $$ = NewStringf("%s %s", $1, $2); + } + | decltype { + $$ = $1; + } + ; + +decltype : DECLTYPE LPAREN idcolon RPAREN { + Node *n = Swig_symbol_clookup($3,0); + if (!n) { + Swig_error(cparse_file, cparse_line, "Identifier %s not defined.\n", $3); + $$ = $3; + } else { + $$ = Getattr(n, "type"); + } + } + ; + +primitive_type : primitive_type_list { + if (!$1.type) $1.type = NewString("int"); + if ($1.us) { + $$ = NewStringf("%s %s", $1.us, $1.type); + Delete($1.us); + Delete($1.type); + } else { + $$ = $1.type; + } + if (Cmp($$,"signed int") == 0) { + Delete($$); + $$ = NewString("int"); + } else if (Cmp($$,"signed long") == 0) { + Delete($$); + $$ = NewString("long"); + } else if (Cmp($$,"signed short") == 0) { + Delete($$); + $$ = NewString("short"); + } else if (Cmp($$,"signed long long") == 0) { + Delete($$); + $$ = NewString("long long"); + } + } + ; + +primitive_type_list : type_specifier { + $$ = $1; + } + | type_specifier primitive_type_list { + if ($1.us && $2.us) { + Swig_error(cparse_file, cparse_line, "Extra %s specifier.\n", $2.us); + } + $$ = $2; + if ($1.us) $$.us = $1.us; + if ($1.type) { + if (!$2.type) $$.type = $1.type; + else { + int err = 0; + if ((Cmp($1.type,"long") == 0)) { + if ((Cmp($2.type,"long") == 0) || (Strncmp($2.type,"double",6) == 0)) { + $$.type = NewStringf("long %s", $2.type); + } else if (Cmp($2.type,"int") == 0) { + $$.type = $1.type; + } else { + err = 1; + } + } else if ((Cmp($1.type,"short")) == 0) { + if (Cmp($2.type,"int") == 0) { + $$.type = $1.type; + } else { + err = 1; + } + } else if (Cmp($1.type,"int") == 0) { + $$.type = $2.type; + } else if (Cmp($1.type,"double") == 0) { + if (Cmp($2.type,"long") == 0) { + $$.type = NewString("long double"); + } else if (Cmp($2.type,"_Complex") == 0) { + $$.type = NewString("double _Complex"); + } else { + err = 1; + } + } else if (Cmp($1.type,"float") == 0) { + if (Cmp($2.type,"_Complex") == 0) { + $$.type = NewString("float _Complex"); + } else { + err = 1; + } + } else if (Cmp($1.type,"_Complex") == 0) { + $$.type = NewStringf("%s _Complex", $2.type); + } else { + err = 1; + } + if (err) { + Swig_error(cparse_file, cparse_line, "Extra %s specifier.\n", $1.type); + } + } + } + } + ; + + +type_specifier : TYPE_INT { + $$.type = NewString("int"); + $$.us = 0; + } + | TYPE_SHORT { + $$.type = NewString("short"); + $$.us = 0; + } + | TYPE_LONG { + $$.type = NewString("long"); + $$.us = 0; + } + | TYPE_CHAR { + $$.type = NewString("char"); + $$.us = 0; + } + | TYPE_WCHAR { + $$.type = NewString("wchar_t"); + $$.us = 0; + } + | TYPE_FLOAT { + $$.type = NewString("float"); + $$.us = 0; + } + | TYPE_DOUBLE { + $$.type = NewString("double"); + $$.us = 0; + } + | TYPE_SIGNED { + $$.us = NewString("signed"); + $$.type = 0; + } + | TYPE_UNSIGNED { + $$.us = NewString("unsigned"); + $$.type = 0; + } + | TYPE_COMPLEX { + $$.type = NewString("_Complex"); + $$.us = 0; + } + | TYPE_NON_ISO_INT8 { + $$.type = NewString("__int8"); + $$.us = 0; + } + | TYPE_NON_ISO_INT16 { + $$.type = NewString("__int16"); + $$.us = 0; + } + | TYPE_NON_ISO_INT32 { + $$.type = NewString("__int32"); + $$.us = 0; + } + | TYPE_NON_ISO_INT64 { + $$.type = NewString("__int64"); + $$.us = 0; + } + ; + +definetype : { /* scanner_check_typedef(); */ } expr { + $$ = $2; + if ($$.type == T_STRING) { + $$.rawval = NewStringf("\"%(escape)s\"",$$.val); + } else if ($$.type != T_CHAR && $$.type != T_WSTRING && $$.type != T_WCHAR) { + $$.rawval = NewStringf("%s", $$.val); + } + $$.qualifier = 0; + $$.refqualifier = 0; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + scanner_ignore_typedef(); + } + | default_delete { + $$ = $1; + } + ; + +default_delete : deleted_definition { + $$ = $1; + } + | explicit_default { + $$ = $1; + } + ; + +/* For C++ deleted definition '= delete' */ +deleted_definition : DELETE_KW { + $$.val = NewString("delete"); + $$.rawval = 0; + $$.type = T_STRING; + $$.qualifier = 0; + $$.refqualifier = 0; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + ; + +/* For C++ explicitly defaulted functions '= default' */ +explicit_default : DEFAULT { + $$.val = NewString("default"); + $$.rawval = 0; + $$.type = T_STRING; + $$.qualifier = 0; + $$.refqualifier = 0; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + ; + +/* Some stuff for handling enums */ + +ename : identifier { $$ = $1; } + | empty { $$ = (char *) 0;} + ; + +constant_directives : constant_directive + | constant_directive constant_directives + ; + +optional_ignored_defines + : constant_directives + | empty + ; + +/* Enum lists - any #define macros (constant directives) within the enum list are ignored. Trailing commas accepted. */ + +/* + Note that "_last" attribute is not supposed to be set on the last enum element, as might be expected from its name, but on the _first_ one, and _only_ on it, + so we propagate it back to the first item while parsing and reset it on all the subsequent ones. + */ + +enumlist : enumlist_item { + Setattr($1,"_last",$1); + $$ = $1; + } + | enumlist_item DOXYGENPOSTSTRING { + Setattr($1,"_last",$1); + set_comment($1, $2); + $$ = $1; + } + | enumlist_item COMMA enumlist { + if ($3) { + set_nextSibling($1, $3); + Setattr($1,"_last",Getattr($3,"_last")); + Setattr($3,"_last",NULL); + } else { + Setattr($1,"_last",$1); + } + $$ = $1; + } + | enumlist_item COMMA DOXYGENPOSTSTRING enumlist { + if ($4) { + set_nextSibling($1, $4); + Setattr($1,"_last",Getattr($4,"_last")); + Setattr($4,"_last",NULL); + } else { + Setattr($1,"_last",$1); + } + set_comment($1, $3); + $$ = $1; + } + | optional_ignored_defines { + $$ = 0; + } + ; + +enumlist_item : optional_ignored_defines edecl_with_dox optional_ignored_defines { + $$ = $2; + } + ; + +edecl_with_dox : edecl { + $$ = $1; + } + | DOXYGENSTRING edecl { + $$ = $2; + set_comment($2, $1); + } + ; + +edecl : identifier { + SwigType *type = NewSwigType(T_INT); + $$ = new_node("enumitem"); + Setattr($$,"name",$1); + Setattr($$,"type",type); + SetFlag($$,"feature:immutable"); + Delete(type); + } + | identifier EQUAL etype { + SwigType *type = NewSwigType($3.type == T_BOOL ? T_BOOL : ($3.type == T_CHAR ? T_CHAR : T_INT)); + $$ = new_node("enumitem"); + Setattr($$,"name",$1); + Setattr($$,"type",type); + SetFlag($$,"feature:immutable"); + Setattr($$,"enumvalue", $3.val); + Setattr($$,"value",$1); + Delete(type); + } + ; + +etype : expr { + $$ = $1; + if (($$.type != T_INT) && ($$.type != T_UINT) && + ($$.type != T_LONG) && ($$.type != T_ULONG) && + ($$.type != T_LONGLONG) && ($$.type != T_ULONGLONG) && + ($$.type != T_SHORT) && ($$.type != T_USHORT) && + ($$.type != T_SCHAR) && ($$.type != T_UCHAR) && + ($$.type != T_CHAR) && ($$.type != T_BOOL)) { + Swig_error(cparse_file,cparse_line,"Type error. Expecting an integral type\n"); + } + } + ; + +/* Arithmetic expressions. Used for constants, C++ templates, and other cool stuff. */ + +expr : valexpr { $$ = $1; } + | type { + Node *n; + $$.val = $1; + $$.type = T_INT; + /* Check if value is in scope */ + n = Swig_symbol_clookup($1,0); + if (n) { + /* A band-aid for enum values used in expressions. */ + if (Strcmp(nodeType(n),"enumitem") == 0) { + String *q = Swig_symbol_qualified(n); + if (q) { + $$.val = NewStringf("%s::%s", q, Getattr(n,"name")); + Delete(q); + } + } + } + } + ; + +/* simple member access expressions */ +exprmem : ID ARROW ID { + $$.val = NewStringf("%s->%s", $1, $3); + $$.type = 0; + } + | ID ARROW ID LPAREN callparms RPAREN { + $$.val = NewStringf("%s->%s(%s)", $1, $3, $5.val); + $$.type = 0; + } + | exprmem ARROW ID { + $$ = $1; + Printf($$.val, "->%s", $3); + } + | exprmem ARROW ID LPAREN callparms RPAREN { + $$ = $1; + Printf($$.val, "->%s(%s)", $3, $5.val); + } + | ID PERIOD ID { + $$.val = NewStringf("%s.%s", $1, $3); + $$.type = 0; + } + | ID PERIOD ID LPAREN callparms RPAREN { + $$.val = NewStringf("%s.%s(%s)", $1, $3, $5.val); + $$.type = 0; + } + | exprmem PERIOD ID { + $$ = $1; + Printf($$.val, ".%s", $3); + } + | exprmem PERIOD ID LPAREN callparms RPAREN { + $$ = $1; + Printf($$.val, ".%s(%s)", $3, $5.val); + } + ; + +/* Non-compound expression */ +exprsimple : exprnum { + $$ = $1; + } + | exprmem { + $$ = $1; + } + | string { + $$.val = $1; + $$.type = T_STRING; + } + | SIZEOF LPAREN type parameter_declarator RPAREN { + SwigType_push($3,$4.type); + $$.val = NewStringf("sizeof(%s)",SwigType_str($3,0)); + $$.type = T_ULONG; + } + | SIZEOF ELLIPSIS LPAREN type parameter_declarator RPAREN { + SwigType_push($4,$5.type); + $$.val = NewStringf("sizeof...(%s)",SwigType_str($4,0)); + $$.type = T_ULONG; + } + /* We don't support all valid expressions here currently - e.g. + * sizeof(<unaryop> x) doesn't work - but those are unlikely to + * be seen in real code. + * + * Note: sizeof(x) is not handled here, but instead by the rule + * for sizeof(<type>) because it matches that syntactically. + */ + | SIZEOF LPAREN exprsimple RPAREN { + $$.val = NewStringf("sizeof(%s)", $3.val); + $$.type = T_ULONG; + } + /* `sizeof expr` without parentheses is valid for an expression, + * but not for a type. This doesn't support `sizeof x` in + * addition to the case not supported above. + */ + | SIZEOF exprsimple { + $$.val = NewStringf("sizeof(%s)", $2.val); + $$.type = T_ULONG; + } + | wstring { + $$.val = $1; + $$.rawval = NewStringf("L\"%s\"", $$.val); + $$.type = T_WSTRING; + } + | CHARCONST { + $$.val = NewString($1); + if (Len($$.val)) { + $$.rawval = NewStringf("'%(escape)s'", $$.val); + } else { + $$.rawval = NewString("'\\0'"); + } + $$.type = T_CHAR; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + | WCHARCONST { + $$.val = NewString($1); + if (Len($$.val)) { + $$.rawval = NewStringf("L\'%s\'", $$.val); + } else { + $$.rawval = NewString("L'\\0'"); + } + $$.type = T_WCHAR; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + + ; + +valexpr : exprsimple { $$ = $1; } + | exprcompound { $$ = $1; } + +/* grouping */ + | LPAREN expr RPAREN %prec CAST { + $$.val = NewStringf("(%s)",$2.val); + if ($2.rawval) { + $$.rawval = NewStringf("(%s)",$2.rawval); + } + $$.type = $2.type; + } + +/* A few common casting operations */ + + | LPAREN expr RPAREN expr %prec CAST { + $$ = $4; + if ($4.type != T_STRING) { + switch ($2.type) { + case T_FLOAT: + case T_DOUBLE: + case T_LONGDOUBLE: + case T_FLTCPLX: + case T_DBLCPLX: + $$.val = NewStringf("(%s)%s", $2.val, $4.val); /* SwigType_str and decimal points don't mix! */ + break; + default: + $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $4.val); + break; + } + } + $$.type = promote($2.type, $4.type); + } + | LPAREN expr pointer RPAREN expr %prec CAST { + $$ = $5; + if ($5.type != T_STRING) { + SwigType_push($2.val,$3); + $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val); + } + } + | LPAREN expr AND RPAREN expr %prec CAST { + $$ = $5; + if ($5.type != T_STRING) { + SwigType_add_reference($2.val); + $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val); + } + } + | LPAREN expr LAND RPAREN expr %prec CAST { + $$ = $5; + if ($5.type != T_STRING) { + SwigType_add_rvalue_reference($2.val); + $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $5.val); + } + } + | LPAREN expr pointer AND RPAREN expr %prec CAST { + $$ = $6; + if ($6.type != T_STRING) { + SwigType_push($2.val,$3); + SwigType_add_reference($2.val); + $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $6.val); + } + } + | LPAREN expr pointer LAND RPAREN expr %prec CAST { + $$ = $6; + if ($6.type != T_STRING) { + SwigType_push($2.val,$3); + SwigType_add_rvalue_reference($2.val); + $$.val = NewStringf("(%s) %s", SwigType_str($2.val,0), $6.val); + } + } + | AND expr { + $$ = $2; + $$.val = NewStringf("&%s",$2.val); + } + | STAR expr { + $$ = $2; + $$.val = NewStringf("*%s",$2.val); + } + ; + +exprnum : NUM_INT { $$ = $1; } + | NUM_FLOAT { $$ = $1; } + | NUM_UNSIGNED { $$ = $1; } + | NUM_LONG { $$ = $1; } + | NUM_ULONG { $$ = $1; } + | NUM_LONGLONG { $$ = $1; } + | NUM_ULONGLONG { $$ = $1; } + | NUM_BOOL { $$ = $1; } + ; + +exprcompound : expr PLUS expr { + $$.val = NewStringf("%s+%s", COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr MINUS expr { + $$.val = NewStringf("%s-%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr STAR expr { + $$.val = NewStringf("%s*%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr SLASH expr { + $$.val = NewStringf("%s/%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr MODULO expr { + $$.val = NewStringf("%s%%%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr AND expr { + $$.val = NewStringf("%s&%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr OR expr { + $$.val = NewStringf("%s|%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr XOR expr { + $$.val = NewStringf("%s^%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote($1.type,$3.type); + } + | expr LSHIFT expr { + $$.val = NewStringf("%s << %s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote_type($1.type); + } + | expr RSHIFT expr { + $$.val = NewStringf("%s >> %s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = promote_type($1.type); + } + | expr LAND expr { + $$.val = NewStringf("%s&&%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + | expr LOR expr { + $$.val = NewStringf("%s||%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + | expr EQUALTO expr { + $$.val = NewStringf("%s==%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + | expr NOTEQUALTO expr { + $$.val = NewStringf("%s!=%s",COMPOUND_EXPR_VAL($1),COMPOUND_EXPR_VAL($3)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + /* Trying to parse `>` in the general case results in conflicts + * in the parser, but all user-reported cases are actually inside + * parentheses and we can handle that case. + */ + | LPAREN expr GREATERTHAN expr RPAREN { + $$.val = NewStringf("%s > %s", COMPOUND_EXPR_VAL($2), COMPOUND_EXPR_VAL($4)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + + /* Similarly for `<` except trying to handle exprcompound on the + * left side gives a shift/reduce conflict, so also restrict + * handling to non-compound subexpressions there. Again this + * covers all user-reported cases. + */ + | LPAREN exprsimple LESSTHAN expr RPAREN { + $$.val = NewStringf("%s < %s", COMPOUND_EXPR_VAL($2), COMPOUND_EXPR_VAL($4)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + | expr GREATERTHANOREQUALTO expr { + $$.val = NewStringf("%s >= %s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + | expr LESSTHANOREQUALTO expr { + $$.val = NewStringf("%s <= %s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3)); + $$.type = cparse_cplusplus ? T_BOOL : T_INT; + } + | expr LESSEQUALGREATER expr { + $$.val = NewStringf("%s <=> %s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3)); + /* Really `<=>` returns one of `std::strong_ordering`, + * `std::partial_ordering` or `std::weak_ordering`, but we + * fake it by treating the return value as `int`. The main + * thing to do with the return value in this context is to + * compare it with 0, for which `int` does the job. */ + $$.type = T_INT; + } + | expr QUESTIONMARK expr COLON expr %prec QUESTIONMARK { + $$.val = NewStringf("%s?%s:%s", COMPOUND_EXPR_VAL($1), COMPOUND_EXPR_VAL($3), COMPOUND_EXPR_VAL($5)); + /* This may not be exactly right, but is probably good enough + * for the purposes of parsing constant expressions. */ + $$.type = promote($3.type, $5.type); + } + | MINUS expr %prec UMINUS { + $$.val = NewStringf("-%s",$2.val); + $$.type = $2.type; + } + | PLUS expr %prec UMINUS { + $$.val = NewStringf("+%s",$2.val); + $$.type = $2.type; + } + | NOT expr { + $$.val = NewStringf("~%s",$2.val); + $$.type = $2.type; + } + | LNOT expr { + $$.val = NewStringf("!%s",COMPOUND_EXPR_VAL($2)); + $$.type = T_INT; + } + | type LPAREN { + String *qty; + skip_balanced('(',')'); + qty = Swig_symbol_type_qualify($1,0); + if (SwigType_istemplate(qty)) { + String *nstr = SwigType_namestr(qty); + Delete(qty); + qty = nstr; + } + $$.val = NewStringf("%s%s",qty,scanner_ccode); + Clear(scanner_ccode); + $$.type = T_INT; + Delete(qty); + } + ; + +variadic : ELLIPSIS { + $$ = NewString("..."); + } + | empty { + $$ = 0; + } + ; + +inherit : raw_inherit { + $$ = $1; + } + ; + +raw_inherit : COLON { inherit_list = 1; } base_list { $$ = $3; inherit_list = 0; } + | empty { $$ = 0; } + ; + +base_list : base_specifier { + Hash *list = NewHash(); + Node *base = $1; + Node *name = Getattr(base,"name"); + List *lpublic = NewList(); + List *lprotected = NewList(); + List *lprivate = NewList(); + Setattr(list,"public",lpublic); + Setattr(list,"protected",lprotected); + Setattr(list,"private",lprivate); + Delete(lpublic); + Delete(lprotected); + Delete(lprivate); + Append(Getattr(list,Getattr(base,"access")),name); + $$ = list; + } + + | base_list COMMA base_specifier { + Hash *list = $1; + Node *base = $3; + Node *name = Getattr(base,"name"); + Append(Getattr(list,Getattr(base,"access")),name); + $$ = list; + } + ; + +base_specifier : opt_virtual { + $<intvalue>$ = cparse_line; + } idcolon variadic { + $$ = NewHash(); + Setfile($$,cparse_file); + Setline($$,$<intvalue>2); + Setattr($$,"name",$3); + Setfile($3,cparse_file); + Setline($3,$<intvalue>2); + if (last_cpptype && (Strcmp(last_cpptype,"struct") != 0)) { + Setattr($$,"access","private"); + Swig_warning(WARN_PARSE_NO_ACCESS, Getfile($$), Getline($$), "No access specifier given for base class '%s' (ignored).\n", SwigType_namestr($3)); + } else { + Setattr($$,"access","public"); + } + if ($4) + SetFlag($$, "variadic"); + } + | opt_virtual access_specifier { + $<intvalue>$ = cparse_line; + } opt_virtual idcolon variadic { + $$ = NewHash(); + Setfile($$,cparse_file); + Setline($$,$<intvalue>3); + Setattr($$,"name",$5); + Setfile($5,cparse_file); + Setline($5,$<intvalue>3); + Setattr($$,"access",$2); + if (Strcmp($2,"public") != 0) { + Swig_warning(WARN_PARSE_PRIVATE_INHERIT, Getfile($$), Getline($$), "%s inheritance from base '%s' (ignored).\n", $2, SwigType_namestr($5)); + } + if ($6) + SetFlag($$, "variadic"); + } + ; + +access_specifier : PUBLIC { $$ = (char*)"public"; } + | PRIVATE { $$ = (char*)"private"; } + | PROTECTED { $$ = (char*)"protected"; } + ; + +templcpptype : CLASS { + $$ = (char*)"class"; + if (!inherit_list) last_cpptype = $$; + } + | TYPENAME { + $$ = (char *)"typename"; + if (!inherit_list) last_cpptype = $$; + } + | CLASS ELLIPSIS { + $$ = (char *)"class..."; + if (!inherit_list) last_cpptype = $$; + } + | TYPENAME ELLIPSIS { + $$ = (char *)"typename..."; + if (!inherit_list) last_cpptype = $$; + } + ; + +cpptype : templcpptype { + $$ = $1; + } + | STRUCT { + $$ = (char*)"struct"; + if (!inherit_list) last_cpptype = $$; + } + | UNION { + $$ = (char*)"union"; + if (!inherit_list) last_cpptype = $$; + } + ; + +classkey : CLASS { + $$ = (char*)"class"; + if (!inherit_list) last_cpptype = $$; + } + | STRUCT { + $$ = (char*)"struct"; + if (!inherit_list) last_cpptype = $$; + } + | UNION { + $$ = (char*)"union"; + if (!inherit_list) last_cpptype = $$; + } + ; + +classkeyopt : classkey { + $$ = $1; + } + | empty { + $$ = 0; + } + ; + +opt_virtual : VIRTUAL + | empty + ; + +virt_specifier_seq : OVERRIDE { + $$ = 0; + } + | FINAL { + $$ = NewString("1"); + } + | FINAL OVERRIDE { + $$ = NewString("1"); + } + | OVERRIDE FINAL { + $$ = NewString("1"); + } + ; + +virt_specifier_seq_opt : virt_specifier_seq { + $$ = $1; + } + | empty { + $$ = 0; + } + ; + +class_virt_specifier_opt : FINAL { + $$ = NewString("1"); + } + | empty { + $$ = 0; + } + ; + +exception_specification : THROW LPAREN parms RPAREN { + $$.throws = $3; + $$.throwf = NewString("1"); + $$.nexcept = 0; + $$.final = 0; + } + | NOEXCEPT { + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = NewString("true"); + $$.final = 0; + } + | virt_specifier_seq { + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = $1; + } + | THROW LPAREN parms RPAREN virt_specifier_seq { + $$.throws = $3; + $$.throwf = NewString("1"); + $$.nexcept = 0; + $$.final = $5; + } + | NOEXCEPT virt_specifier_seq { + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = NewString("true"); + $$.final = $2; + } + | NOEXCEPT LPAREN expr RPAREN { + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = $3.val; + $$.final = 0; + } + ; + +qualifiers_exception_specification : cv_ref_qualifier { + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + } + | exception_specification { + $$ = $1; + $$.qualifier = 0; + $$.refqualifier = 0; + } + | cv_ref_qualifier exception_specification { + $$ = $2; + $$.qualifier = $1.qualifier; + $$.refqualifier = $1.refqualifier; + } + ; + +cpp_const : qualifiers_exception_specification { + $$ = $1; + } + | empty { + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + $$.qualifier = 0; + $$.refqualifier = 0; + } + ; + +ctor_end : cpp_const ctor_initializer SEMI { + Clear(scanner_ccode); + $$.have_parms = 0; + $$.defarg = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + if ($1.qualifier) + Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n"); + } + | cpp_const ctor_initializer LBRACE { + skip_balanced('{','}'); + $$.have_parms = 0; + $$.defarg = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + if ($1.qualifier) + Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n"); + } + | LPAREN parms RPAREN SEMI { + Clear(scanner_ccode); + $$.parms = $2; + $$.have_parms = 1; + $$.defarg = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + | LPAREN parms RPAREN LBRACE { + skip_balanced('{','}'); + $$.parms = $2; + $$.have_parms = 1; + $$.defarg = 0; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + | EQUAL definetype SEMI { + $$.have_parms = 0; + $$.defarg = $2.val; + $$.throws = 0; + $$.throwf = 0; + $$.nexcept = 0; + $$.final = 0; + } + | exception_specification EQUAL default_delete SEMI { + $$.have_parms = 0; + $$.defarg = $3.val; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + $$.nexcept = $1.nexcept; + $$.final = $1.final; + if ($1.qualifier) + Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n"); + } + ; + +ctor_initializer : COLON mem_initializer_list + | empty + ; + +mem_initializer_list : mem_initializer + | mem_initializer_list COMMA mem_initializer + | mem_initializer ELLIPSIS + | mem_initializer_list COMMA mem_initializer ELLIPSIS + ; + +mem_initializer : idcolon LPAREN { + skip_balanced('(',')'); + Clear(scanner_ccode); + } + /* Uniform initialization in C++11. + Example: + struct MyStruct { + MyStruct(int x, double y) : x_{x}, y_{y} {} + int x_; + double y_; + }; + */ + | idcolon LBRACE { + skip_balanced('{','}'); + Clear(scanner_ccode); + } + ; + +less_valparms_greater : LESSTHAN valparms GREATERTHAN { + String *s = NewStringEmpty(); + SwigType_add_template(s,$2); + $$ = Char(s); + scanner_last_id(1); + } + ; + +/* Identifiers including the C++11 identifiers with special meaning */ +identifier : ID { $$ = $1; } + | OVERRIDE { $$ = Swig_copy_string("override"); } + | FINAL { $$ = Swig_copy_string("final"); } + ; + +idstring : identifier { $$ = $1; } + | default_delete { $$ = Char($1.val); } + | string { $$ = Char($1); } + ; + +idstringopt : idstring { $$ = $1; } + | empty { $$ = 0; } + ; + +idcolon : idtemplate idcolontail { + $$ = 0; + if (!$$) $$ = NewStringf("%s%s", $1,$2); + Delete($2); + } + | NONID DCOLON idtemplatetemplate idcolontail { + $$ = NewStringf("::%s%s",$3,$4); + Delete($4); + } + | idtemplate { + $$ = NewString($1); + } + | NONID DCOLON idtemplatetemplate { + $$ = NewStringf("::%s",$3); + } + | OPERATOR { + $$ = NewStringf("%s", $1); + } + | OPERATOR less_valparms_greater { + $$ = NewStringf("%s%s", $1, $2); + } + | NONID DCOLON OPERATOR { + $$ = NewStringf("::%s",$3); + } + ; + +idcolontail : DCOLON idtemplatetemplate idcolontail { + $$ = NewStringf("::%s%s",$2,$3); + Delete($3); + } + | DCOLON idtemplatetemplate { + $$ = NewStringf("::%s",$2); + } + | DCOLON OPERATOR { + $$ = NewStringf("::%s",$2); + } +/* | DCOLON CONVERSIONOPERATOR { + $$ = NewString($2); + } */ + + | DCNOT idtemplate { + $$ = NewStringf("::~%s",$2); + } + ; + + +idtemplate : identifier { + $$ = NewStringf("%s", $1); + } + | identifier less_valparms_greater { + $$ = NewStringf("%s%s", $1, $2); + } + ; + +idtemplatetemplate : idtemplate { + $$ = $1; + } + | TEMPLATE identifier less_valparms_greater { + $$ = NewStringf("%s%s", $2, $3); + } + ; + +/* Identifier, but no templates */ +idcolonnt : identifier idcolontailnt { + $$ = 0; + if (!$$) $$ = NewStringf("%s%s", $1,$2); + Delete($2); + } + | NONID DCOLON identifier idcolontailnt { + $$ = NewStringf("::%s%s",$3,$4); + Delete($4); + } + | identifier { + $$ = NewString($1); + } + | NONID DCOLON identifier { + $$ = NewStringf("::%s",$3); + } + | OPERATOR { + $$ = NewString($1); + } + | NONID DCOLON OPERATOR { + $$ = NewStringf("::%s",$3); + } + ; + +idcolontailnt : DCOLON identifier idcolontailnt { + $$ = NewStringf("::%s%s",$2,$3); + Delete($3); + } + | DCOLON identifier { + $$ = NewStringf("::%s",$2); + } + | DCOLON OPERATOR { + $$ = NewStringf("::%s",$2); + } + | DCNOT identifier { + $$ = NewStringf("::~%s",$2); + } + ; + +/* Concatenated strings */ +string : string STRING { + $$ = NewStringf("%s%s", $1, $2); + } + | STRING { $$ = NewString($1);} + ; +/* Concatenated wide strings: L"str1" L"str2" */ +wstring : wstring WSTRING { + $$ = NewStringf("%s%s", $1, $2); + } +/* Concatenated wide string and normal string literal: L"str1" "str2" */ +/*not all the compilers support this concatenation mode, so perhaps better to postpone it*/ + /*| wstring STRING { here $2 comes unescaped, we have to escape it back first via NewStringf("%(escape)s)" + $$ = NewStringf("%s%s", $1, $2); + }*/ + | WSTRING { $$ = NewString($1);} + ; + +stringbrace : string { + $$ = $1; + } + | LBRACE { + skip_balanced('{','}'); + $$ = NewString(scanner_ccode); + } + | HBLOCK { + $$ = $1; + } + ; + +options : LPAREN kwargs RPAREN { + Hash *n; + $$ = NewHash(); + n = $2; + while(n) { + String *name, *value; + name = Getattr(n,"name"); + value = Getattr(n,"value"); + if (!value) value = (String *) "1"; + Setattr($$,name, value); + n = nextSibling(n); + } + } + | empty { $$ = 0; }; + + +/* Keyword arguments */ +kwargs : idstring EQUAL stringnum { + $$ = NewHash(); + Setattr($$,"name",$1); + Setattr($$,"value",$3); + } + | idstring EQUAL stringnum COMMA kwargs { + $$ = NewHash(); + Setattr($$,"name",$1); + Setattr($$,"value",$3); + set_nextSibling($$,$5); + } + | idstring { + $$ = NewHash(); + Setattr($$,"name",$1); + } + | idstring COMMA kwargs { + $$ = NewHash(); + Setattr($$,"name",$1); + set_nextSibling($$,$3); + } + | idstring EQUAL stringtype { + $$ = $3; + Setattr($$,"name",$1); + } + | idstring EQUAL stringtype COMMA kwargs { + $$ = $3; + Setattr($$,"name",$1); + set_nextSibling($$,$5); + } + ; + +stringnum : string { + $$ = $1; + } + | exprnum { + $$ = Char($1.val); + } + ; + +empty : ; + +%% + +SwigType *Swig_cparse_type(String *s) { + String *ns; + ns = NewStringf("%s;",s); + Seek(ns,0,SEEK_SET); + scanner_file(ns); + top = 0; + scanner_next_token(PARSETYPE); + yyparse(); + /* Printf(stdout,"typeparse: '%s' ---> '%s'\n", s, top); */ + return top; +} + + +Parm *Swig_cparse_parm(String *s) { + String *ns; + ns = NewStringf("%s;",s); + Seek(ns,0,SEEK_SET); + scanner_file(ns); + top = 0; + scanner_next_token(PARSEPARM); + yyparse(); + /* Printf(stdout,"typeparse: '%s' ---> '%s'\n", s, top); */ + Delete(ns); + return top; +} + + +ParmList *Swig_cparse_parms(String *s, Node *file_line_node) { + String *ns; + char *cs = Char(s); + if (cs && cs[0] != '(') { + ns = NewStringf("(%s);",s); + } else { + ns = NewStringf("%s;",s); + } + Setfile(ns, Getfile(file_line_node)); + Setline(ns, Getline(file_line_node)); + Seek(ns,0,SEEK_SET); + scanner_file(ns); + top = 0; + scanner_next_token(PARSEPARMS); + yyparse(); + /* Printf(stdout,"typeparse: '%s' ---> '%s'\n", s, top); */ + return top; +} + diff --git a/contrib/tools/swig/Source/CParse/templ.c b/contrib/tools/swig/Source/CParse/templ.c new file mode 100644 index 0000000000..0dec215869 --- /dev/null +++ b/contrib/tools/swig/Source/CParse/templ.c @@ -0,0 +1,976 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * templ.c + * + * Expands a template into a specialized version. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" + +static int template_debug = 0; + + +const char *baselists[3]; + +void SwigType_template_init(void) { + baselists[0] = "baselist"; + baselists[1] = "protectedbaselist"; + baselists[2] = "privatebaselist"; +} + + +static void add_parms(ParmList *p, List *patchlist, List *typelist, int is_pattern) { + while (p) { + SwigType *ty = Getattr(p, "type"); + SwigType *val = Getattr(p, "value"); + Append(typelist, ty); + Append(typelist, val); + if (is_pattern) { + /* Typemap patterns are not simple parameter lists. + * Output style ("out", "ret" etc) typemap names can be + * qualified names and so may need template expansion */ + SwigType *name = Getattr(p, "name"); + Append(typelist, name); + } + Append(patchlist, val); + p = nextSibling(p); + } +} + +void Swig_cparse_debug_templates(int x) { + template_debug = x; +} + +/* ----------------------------------------------------------------------------- + * cparse_template_expand() + * + * Expands a template node into a specialized version. This is done by + * patching typenames and other aspects of the node according to a list of + * template parameters + * ----------------------------------------------------------------------------- */ + +static void cparse_template_expand(Node *templnode, Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist) { + static int expanded = 0; + String *nodeType; + if (!n) + return; + nodeType = nodeType(n); + if (Getattr(n, "error")) + return; + + if (Equal(nodeType, "template")) { + /* Change the node type back to normal */ + if (!expanded) { + expanded = 1; + set_nodeType(n, Getattr(n, "templatetype")); + cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist); + expanded = 0; + return; + } else { + /* Called when template appears inside another template */ + /* Member templates */ + + set_nodeType(n, Getattr(n, "templatetype")); + cparse_template_expand(templnode, n, tname, rname, templateargs, patchlist, typelist, cpatchlist); + set_nodeType(n, "template"); + return; + } + } else if (Equal(nodeType, "cdecl")) { + /* A simple C declaration */ + SwigType *t, *v, *d; + String *code; + t = Getattr(n, "type"); + v = Getattr(n, "value"); + d = Getattr(n, "decl"); + + code = Getattr(n, "code"); + + Append(typelist, t); + Append(typelist, d); + Append(patchlist, v); + Append(cpatchlist, code); + + if (Getattr(n, "conversion_operator")) { + Append(cpatchlist, Getattr(n, "name")); + if (Getattr(n, "sym:name")) { + Append(cpatchlist, Getattr(n, "sym:name")); + } + } + if (checkAttribute(n, "storage", "friend")) { + String *symname = Getattr(n, "sym:name"); + if (symname) { + String *stripped_name = SwigType_templateprefix(symname); + Setattr(n, "sym:name", stripped_name); + Delete(stripped_name); + } + Append(typelist, Getattr(n, "name")); + } + + add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0); + add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0); + + } else if (Equal(nodeType, "class")) { + /* Patch base classes */ + { + int b = 0; + for (b = 0; b < 3; ++b) { + List *bases = Getattr(n, baselists[b]); + if (bases) { + int i; + int ilen = Len(bases); + for (i = 0; i < ilen; i++) { + String *name = Copy(Getitem(bases, i)); + Setitem(bases, i, name); + Append(typelist, name); + } + } + } + } + /* Patch children */ + { + Node *cn = firstChild(n); + while (cn) { + cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); + cn = nextSibling(cn); + } + } + } else if (Equal(nodeType, "constructor")) { + String *name = Getattr(n, "name"); + if (!(Getattr(n, "templatetype"))) { + String *symname; + String *stripped_name = SwigType_templateprefix(name); + if (Strstr(tname, stripped_name)) { + Replaceid(name, stripped_name, tname); + } + Delete(stripped_name); + symname = Getattr(n, "sym:name"); + if (symname) { + stripped_name = SwigType_templateprefix(symname); + if (Strstr(tname, stripped_name)) { + Replaceid(symname, stripped_name, tname); + } + Delete(stripped_name); + } + if (strchr(Char(name), '<')) { + Append(patchlist, Getattr(n, "name")); + } else { + Append(name, templateargs); + } + name = Getattr(n, "sym:name"); + if (name) { + if (strchr(Char(name), '<')) { + Clear(name); + Append(name, rname); + } else { + String *tmp = Copy(name); + Replace(tmp, tname, rname, DOH_REPLACE_ANY); + Clear(name); + Append(name, tmp); + Delete(tmp); + } + } + /* Setattr(n,"sym:name",name); */ + } + Append(cpatchlist, Getattr(n, "code")); + Append(typelist, Getattr(n, "decl")); + add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0); + add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0); + } else if (Equal(nodeType, "destructor")) { + /* We only need to patch the dtor of the template itself, not the destructors of any nested classes, so check that the parent of this node is the root + * template node, with the special exception for %extend which adds its methods under an intermediate node. */ + Node* parent = parentNode(n); + if (parent == templnode || (parentNode(parent) == templnode && Equal(nodeType(parent), "extend"))) { + String *name = Getattr(n, "name"); + if (name) { + if (strchr(Char(name), '<')) + Append(patchlist, Getattr(n, "name")); + else + Append(name, templateargs); + } + name = Getattr(n, "sym:name"); + if (name) { + if (strchr(Char(name), '<')) { + String *sn = Copy(tname); + Setattr(n, "sym:name", sn); + Delete(sn); + } else { + Replace(name, tname, rname, DOH_REPLACE_ANY); + } + } + /* Setattr(n,"sym:name",name); */ + Append(cpatchlist, Getattr(n, "code")); + } + } else if (Equal(nodeType, "using")) { + String *uname = Getattr(n, "uname"); + if (uname && strchr(Char(uname), '<')) { + Append(patchlist, uname); + } + if (Getattr(n, "namespace")) { + /* Namespace link. This is nasty. Is other namespace defined? */ + + } + } else { + /* Look for obvious parameters */ + Node *cn; + Append(cpatchlist, Getattr(n, "code")); + Append(typelist, Getattr(n, "type")); + Append(typelist, Getattr(n, "decl")); + add_parms(Getattr(n, "parms"), cpatchlist, typelist, 0); + add_parms(Getattr(n, "kwargs"), cpatchlist, typelist, 0); + add_parms(Getattr(n, "pattern"), cpatchlist, typelist, 1); + add_parms(Getattr(n, "throws"), cpatchlist, typelist, 0); + cn = firstChild(n); + while (cn) { + cparse_template_expand(templnode, cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); + cn = nextSibling(cn); + } + } +} + +/* ----------------------------------------------------------------------------- + * cparse_fix_function_decl() + * + * Move the prefix of the "type" attribute (excluding any trailing qualifier) + * to the end of the "decl" attribute. + * Examples: + * decl="f().", type="p.q(const).char" => decl="f().p.", type="q(const).char" + * decl="f().p.", type="p.SomeClass" => decl="f().p.p.", type="SomeClass" + * decl="f().", type="r.q(const).p.int" => decl="f().r.q(const).p.", type="int" + * ----------------------------------------------------------------------------- */ + +static void cparse_fix_function_decl(String *name, SwigType *decl, SwigType *type) { + String *prefix; + int prefixLen; + SwigType *last; + + /* The type's prefix is what potentially has to be moved to the end of 'decl' */ + prefix = SwigType_prefix(type); + + /* First some parts (qualifier and array) have to be removed from prefix + in order to remain in the 'type' attribute. */ + last = SwigType_last(prefix); + while (last) { + if (SwigType_isqualifier(last) || SwigType_isarray(last)) { + /* Keep this part in the 'type' */ + Delslice(prefix, Len(prefix) - Len(last), DOH_END); + Delete(last); + last = SwigType_last(prefix); + } else { + /* Done with processing prefix */ + Delete(last); + last = 0; + } + } + + /* Transfer prefix from the 'type' to the 'decl' attribute */ + prefixLen = Len(prefix); + if (prefixLen > 0) { + Append(decl, prefix); + Delslice(type, 0, prefixLen); + if (template_debug) { + Printf(stdout, " change function '%s' to type='%s', decl='%s'\n", name, type, decl); + } + } + + Delete(prefix); +} + +/* ----------------------------------------------------------------------------- + * cparse_postprocess_expanded_template() + * + * This function postprocesses the given node after template expansion. + * Currently the only task to perform is fixing function decl and type attributes. + * ----------------------------------------------------------------------------- */ + +static void cparse_postprocess_expanded_template(Node *n) { + String *nodeType; + if (!n) + return; + nodeType = nodeType(n); + if (Getattr(n, "error")) + return; + + if (Equal(nodeType, "cdecl")) { + /* A simple C declaration */ + SwigType *d = Getattr(n, "decl"); + if (d && SwigType_isfunction(d)) { + /* A function node */ + SwigType *t = Getattr(n, "type"); + if (t) { + String *name = Getattr(n, "name"); + cparse_fix_function_decl(name, d, t); + } + } + } else { + /* Look for any children */ + Node *cn = firstChild(n); + while (cn) { + cparse_postprocess_expanded_template(cn); + cn = nextSibling(cn); + } + } +} + +/* ----------------------------------------------------------------------------- + * partial_arg() + * ----------------------------------------------------------------------------- */ + +static +String *partial_arg(String *s, String *p) { + char *c; + char *cp = Char(p); + String *prefix; + String *newarg; + + /* Find the prefix on the partial argument */ + + c = strchr(cp, '$'); + if (!c) { + return Copy(s); + } + prefix = NewStringWithSize(cp, (int)(c - cp)); + newarg = Copy(s); + Replace(newarg, prefix, "", DOH_REPLACE_FIRST); + Delete(prefix); + return newarg; +} + +/* ----------------------------------------------------------------------------- + * Swig_cparse_template_expand() + * ----------------------------------------------------------------------------- */ + +int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab *tscope) { + List *patchlist, *cpatchlist, *typelist; + String *templateargs; + String *tname; + String *iname; + String *tbase; + patchlist = NewList(); + cpatchlist = NewList(); + typelist = NewList(); + + { + String *tmp = NewStringEmpty(); + if (tparms) { + SwigType_add_template(tmp, tparms); + } + templateargs = Copy(tmp); + Delete(tmp); + } + + tname = Copy(Getattr(n, "name")); + tbase = Swig_scopename_last(tname); + + /* Look for partial specialization matching */ + if (Getattr(n, "partialargs")) { + Parm *p, *tp; + ParmList *ptargs = SwigType_function_parms(Getattr(n, "partialargs"), n); + p = ptargs; + tp = tparms; + while (p && tp) { + SwigType *ptype; + SwigType *tptype; + SwigType *partial_type; + ptype = Getattr(p, "type"); + tptype = Getattr(tp, "type"); + if (ptype && tptype) { + partial_type = partial_arg(tptype, ptype); + /* Printf(stdout,"partial '%s' '%s' ---> '%s'\n", tptype, ptype, partial_type); */ + Setattr(tp, "type", partial_type); + Delete(partial_type); + } + p = nextSibling(p); + tp = nextSibling(tp); + } + assert(ParmList_len(ptargs) == ParmList_len(tparms)); + Delete(ptargs); + } + + /* + Parm *p = tparms; + while (p) { + Printf(stdout, "tparm: '%s' '%s' '%s'\n", Getattr(p, "name"), Getattr(p, "type"), Getattr(p, "value")); + p = nextSibling(p); + } + */ + + /* Printf(stdout,"targs = '%s'\n", templateargs); + Printf(stdout,"rname = '%s'\n", rname); + Printf(stdout,"tname = '%s'\n", tname); */ + cparse_template_expand(n, n, tname, rname, templateargs, patchlist, typelist, cpatchlist); + + /* Set the name */ + { + String *name = Getattr(n, "name"); + if (name) { + Append(name, templateargs); + } + iname = name; + } + + /* Patch all of the types */ + { + Parm *tp = Getattr(n, "templateparms"); + Parm *p = tparms; + /* Printf(stdout,"%s\n", ParmList_str_defaultargs(tp)); */ + + if (tp) { + Symtab *tsdecl = Getattr(n, "sym:symtab"); + String *tsname = Getattr(n, "sym:name"); + while (p && tp) { + String *name, *value, *valuestr, *tmp, *tmpr; + int sz, i; + String *dvalue = 0; + String *qvalue = 0; + + name = Getattr(tp, "name"); + value = Getattr(p, "value"); + + if (name) { + if (!value) + value = Getattr(p, "type"); + qvalue = Swig_symbol_typedef_reduce(value, tsdecl); + dvalue = Swig_symbol_type_qualify(qvalue, tsdecl); + if (SwigType_istemplate(dvalue)) { + String *ty = Swig_symbol_template_deftype(dvalue, tscope); + Delete(dvalue); + dvalue = ty; + } + + assert(dvalue); + valuestr = SwigType_str(dvalue, 0); + /* Need to patch default arguments */ + { + Parm *rp = nextSibling(p); + while (rp) { + String *rvalue = Getattr(rp, "value"); + if (rvalue) { + Replace(rvalue, name, dvalue, DOH_REPLACE_ID); + } + rp = nextSibling(rp); + } + } + sz = Len(patchlist); + for (i = 0; i < sz; i++) { + String *s = Getitem(patchlist, i); + Replace(s, name, dvalue, DOH_REPLACE_ID); + } + sz = Len(typelist); + for (i = 0; i < sz; i++) { + String *s = Getitem(typelist, i); + /* + The approach of 'trivially' replacing template arguments is kind of fragile. + In particular if types with similar name in different namespaces appear. + We will not replace template args if a type/class exists with the same + name which is not a template. + */ + Node * tynode = Swig_symbol_clookup(s, 0); + String *tyname = tynode ? Getattr(tynode, "sym:name") : 0; + if (!tyname || !tsname || !Equal(tyname, tsname) || Getattr(tynode, "templatetype")) { + SwigType_typename_replace(s, name, dvalue); + SwigType_typename_replace(s, tbase, iname); + } + } + + tmp = NewStringf("#%s", name); + tmpr = NewStringf("\"%s\"", valuestr); + + sz = Len(cpatchlist); + for (i = 0; i < sz; i++) { + String *s = Getitem(cpatchlist, i); + Replace(s, tmp, tmpr, DOH_REPLACE_ID); + Replace(s, name, valuestr, DOH_REPLACE_ID); + } + Delete(tmp); + Delete(tmpr); + Delete(valuestr); + Delete(dvalue); + Delete(qvalue); + } + p = nextSibling(p); + tp = nextSibling(tp); + if (!p) + p = tp; + } + } else { + /* No template parameters at all. This could be a specialization */ + int i, sz; + sz = Len(typelist); + for (i = 0; i < sz; i++) { + String *s = Getitem(typelist, i); + SwigType_typename_replace(s, tbase, iname); + } + } + } + cparse_postprocess_expanded_template(n); + + /* Patch bases */ + { + List *bases = Getattr(n, "baselist"); + if (bases) { + Iterator b; + for (b = First(bases); b.item; b = Next(b)) { + String *qn = Swig_symbol_type_qualify(b.item, tscope); + Clear(b.item); + Append(b.item, qn); + Delete(qn); + } + } + } + Delete(patchlist); + Delete(cpatchlist); + Delete(typelist); + Delete(tbase); + Delete(tname); + Delete(templateargs); + + /* set_nodeType(n,"template"); */ + return 0; +} + +typedef enum { ExactNoMatch = -2, PartiallySpecializedNoMatch = -1, PartiallySpecializedMatch = 1, ExactMatch = 2 } EMatch; + +/* ----------------------------------------------------------------------------- + * does_parm_match() + * + * Template argument deduction - check if a template type matches a partially specialized + * template parameter type. Typedef reduce 'partial_parm_type' to see if it matches 'type'. + * + * type - template parameter type to match against + * partial_parm_type - partially specialized template type - a possible match + * partial_parm_type_base - base type of partial_parm_type + * tscope - template scope + * specialization_priority - (output) contains a value indicating how good the match is + * (higher is better) only set if return is set to PartiallySpecializedMatch or ExactMatch. + * ----------------------------------------------------------------------------- */ + +static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const char *partial_parm_type_base, Symtab *tscope, int *specialization_priority) { + static const int EXACT_MATCH_PRIORITY = 99999; /* a number bigger than the length of any conceivable type */ + int matches; + int substitutions; + EMatch match; + SwigType *ty = Swig_symbol_typedef_reduce(type, tscope); + String *base = SwigType_base(ty); + SwigType *t = Copy(partial_parm_type); + substitutions = Replaceid(t, partial_parm_type_base, base); /* eg: Replaceid("p.$1", "$1", "int") returns t="p.int" */ + matches = Equal(ty, t); + *specialization_priority = -1; + if (substitutions == 1) { + /* we have a non-explicit specialized parameter (in partial_parm_type) because a substitution for $1, $2... etc has taken place */ + SwigType *tt = Copy(partial_parm_type); + int len; + /* + check for match to partial specialization type, for example, all of the following could match the type in the %template: + template <typename T> struct XX {}; + template <typename T> struct XX<T &> {}; // r.$1 + template <typename T> struct XX<T const&> {}; // r.q(const).$1 + template <typename T> struct XX<T *const&> {}; // r.q(const).p.$1 + %template(XXX) XX<int *const&>; // r.q(const).p.int + + where type="r.q(const).p.int" will match either of tt="r.", tt="r.q(const)" tt="r.q(const).p" + */ + Replaceid(tt, partial_parm_type_base, ""); /* remove the $1, $2 etc, eg tt="p.$1" => "p." */ + len = Len(tt); + if (Strncmp(tt, ty, len) == 0) { + match = PartiallySpecializedMatch; + *specialization_priority = len; + } else { + match = PartiallySpecializedNoMatch; + } + Delete(tt); + } else { + match = matches ? ExactMatch : ExactNoMatch; + if (matches) + *specialization_priority = EXACT_MATCH_PRIORITY; /* exact matches always take precedence */ + } + /* + Printf(stdout, " does_parm_match %2d %5d [%s] [%s]\n", match, *specialization_priority, type, partial_parm_type); + */ + Delete(t); + Delete(base); + Delete(ty); + return match; +} + +/* ----------------------------------------------------------------------------- + * template_locate() + * + * Search for a template that matches name with given parameters. + * ----------------------------------------------------------------------------- */ + +static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { + Node *n = 0; + String *tname = 0; + Node *templ; + Symtab *primary_scope = 0; + List *possiblepartials = 0; + Parm *p; + Parm *parms = 0; + Parm *targs; + ParmList *expandedparms; + int *priorities_matrix = 0; + int max_possible_partials = 0; + int posslen = 0; + + /* Search for primary (unspecialized) template */ + templ = Swig_symbol_clookup(name, 0); + + if (template_debug) { + tname = Copy(name); + SwigType_add_template(tname, tparms); + Printf(stdout, "\n"); + Swig_diagnostic(cparse_file, cparse_line, "template_debug: Searching for match to: '%s'\n", tname); + Delete(tname); + tname = 0; + } + + if (templ) { + tname = Copy(name); + parms = CopyParmList(tparms); + + /* All template specializations must be in the primary template's scope, store the symbol table for this scope for specialization lookups */ + primary_scope = Getattr(templ, "sym:symtab"); + + /* Add default values from primary template */ + targs = Getattr(templ, "templateparms"); + expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, primary_scope); + + /* reduce the typedef */ + p = expandedparms; + while (p) { + SwigType *ty = Getattr(p, "type"); + if (ty) { + SwigType *nt = Swig_symbol_type_qualify(ty, tscope); + Setattr(p, "type", nt); + Delete(nt); + } + p = nextSibling(p); + } + SwigType_add_template(tname, expandedparms); + + /* Search for an explicit (exact) specialization. Example: template<> class name<int> { ... } */ + { + if (template_debug) { + Printf(stdout, " searching for : '%s' (explicit specialization)\n", tname); + } + n = Swig_symbol_clookup_local(tname, primary_scope); + if (!n) { + SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope); + if (!Equal(rname, tname)) { + if (template_debug) { + Printf(stdout, " searching for : '%s' (explicit specialization with typedef reduction)\n", rname); + } + n = Swig_symbol_clookup_local(rname, primary_scope); + } + Delete(rname); + } + if (n) { + Node *tn; + String *nodeType = nodeType(n); + if (Equal(nodeType, "template")) { + if (template_debug) { + Printf(stdout, " explicit specialization found: '%s'\n", Getattr(n, "name")); + } + goto success; + } + tn = Getattr(n, "template"); + if (tn) { + if (template_debug) { + Printf(stdout, " previous instantiation found: '%s'\n", Getattr(n, "name")); + } + n = tn; + goto success; /* Previously wrapped by a template instantiation */ + } + Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n)); + Delete(tname); + Delete(parms); + return 0; /* Found a match, but it's not a template of any kind. */ + } + } + + /* Search for partial specializations. + * Example: template<typename T> class name<T *> { ... } + + * There are 3 types of template arguments: + * (1) Template type arguments + * (2) Template non type arguments + * (3) Template template arguments + * only (1) is really supported for partial specializations + */ + + /* Rank each template parameter against the desired template parameters then build a matrix of best matches */ + possiblepartials = NewList(); + { + char tmp[32]; + List *partials; + + partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */ + if (partials) { + Iterator pi; + int parms_len = ParmList_len(parms); + int *priorities_row; + max_possible_partials = Len(partials); + priorities_matrix = (int *)Malloc(sizeof(int) * max_possible_partials * parms_len); /* slightly wasteful allocation for max possible matches */ + priorities_row = priorities_matrix; + for (pi = First(partials); pi.item; pi = Next(pi)) { + Parm *p = parms; + int all_parameters_match = 1; + int i = 1; + Parm *partialparms = Getattr(pi.item, "partialparms"); + Parm *pp = partialparms; + String *templcsymname = Getattr(pi.item, "templcsymname"); + if (template_debug) { + Printf(stdout, " checking match: '%s' (partial specialization)\n", templcsymname); + } + if (ParmList_len(partialparms) == parms_len) { + while (p && pp) { + SwigType *t; + sprintf(tmp, "$%d", i); + t = Getattr(p, "type"); + if (!t) + t = Getattr(p, "value"); + if (t) { + EMatch match = does_parm_match(t, Getattr(pp, "type"), tmp, tscope, priorities_row + i - 1); + if (match < (int)PartiallySpecializedMatch) { + all_parameters_match = 0; + break; + } + } + i++; + p = nextSibling(p); + pp = nextSibling(pp); + } + if (all_parameters_match) { + Append(possiblepartials, pi.item); + priorities_row += parms_len; + } + } + } + } + } + + posslen = Len(possiblepartials); + if (template_debug) { + int i; + if (posslen == 0) + Printf(stdout, " matched partials: NONE\n"); + else if (posslen == 1) + Printf(stdout, " chosen partial: '%s'\n", Getattr(Getitem(possiblepartials, 0), "templcsymname")); + else { + Printf(stdout, " possibly matched partials:\n"); + for (i = 0; i < posslen; i++) { + Printf(stdout, " '%s'\n", Getattr(Getitem(possiblepartials, i), "templcsymname")); + } + } + } + + if (posslen > 1) { + /* Now go through all the possibly matched partial specialization templates and look for a non-ambiguous match. + * Exact matches rank the highest and deduced parameters are ranked by how specialized they are, eg looking for + * a match to const int *, the following rank (highest to lowest): + * const int * (exact match) + * const T * + * T * + * T + * + * An ambiguous example when attempting to match as either specialization could match: %template() X<int *, double *>; + * template<typename T1, typename T2> X class {}; // primary template + * template<typename T1> X<T1, double *> class {}; // specialization (1) + * template<typename T2> X<int *, T2> class {}; // specialization (2) + */ + if (template_debug) { + int row, col; + int parms_len = ParmList_len(parms); + Printf(stdout, " parameter priorities matrix (%d parms):\n", parms_len); + for (row = 0; row < posslen; row++) { + int *priorities_row = priorities_matrix + row*parms_len; + Printf(stdout, " "); + for (col = 0; col < parms_len; col++) { + Printf(stdout, "%5d ", priorities_row[col]); + } + Printf(stdout, "\n"); + } + } + { + int row, col; + int parms_len = ParmList_len(parms); + /* Printf(stdout, " parameter priorities inverse matrix (%d parms):\n", parms_len); */ + for (col = 0; col < parms_len; col++) { + int *priorities_col = priorities_matrix + col; + int maxpriority = -1; + /* + Printf(stdout, "max_possible_partials: %d col:%d\n", max_possible_partials, col); + Printf(stdout, " "); + */ + /* determine the highest rank for this nth parameter */ + for (row = 0; row < posslen; row++) { + int *element_ptr = priorities_col + row*parms_len; + int priority = *element_ptr; + if (priority > maxpriority) + maxpriority = priority; + /* Printf(stdout, "%5d ", priority); */ + } + /* Printf(stdout, "\n"); */ + /* flag all the parameters which equal the highest rank */ + for (row = 0; row < posslen; row++) { + int *element_ptr = priorities_col + row*parms_len; + int priority = *element_ptr; + *element_ptr = (priority >= maxpriority) ? 1 : 0; + } + } + } + { + int row, col; + int parms_len = ParmList_len(parms); + Iterator pi = First(possiblepartials); + Node *chosenpartials = NewList(); + if (template_debug) + Printf(stdout, " priority flags matrix:\n"); + for (row = 0; row < posslen; row++) { + int *priorities_row = priorities_matrix + row*parms_len; + int highest_count = 0; /* count of highest priority parameters */ + for (col = 0; col < parms_len; col++) { + highest_count += priorities_row[col]; + } + if (template_debug) { + Printf(stdout, " "); + for (col = 0; col < parms_len; col++) { + Printf(stdout, "%5d ", priorities_row[col]); + } + Printf(stdout, "\n"); + } + if (highest_count == parms_len) { + Append(chosenpartials, pi.item); + } + pi = Next(pi); + } + if (Len(chosenpartials) > 0) { + /* one or more best match found */ + Delete(possiblepartials); + possiblepartials = chosenpartials; + posslen = Len(possiblepartials); + } else { + /* no best match found */ + Delete(chosenpartials); + } + } + } + + if (posslen > 0) { + String *s = Getattr(Getitem(possiblepartials, 0), "templcsymname"); + n = Swig_symbol_clookup_local(s, primary_scope); + if (posslen > 1) { + int i; + if (n) { + Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname)); + Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), " instantiation '%s' used,\n", SwigType_namestr(Getattr(n, "name"))); + } + for (i = 1; i < posslen; i++) { + String *templcsymname = Getattr(Getitem(possiblepartials, i), "templcsymname"); + Node *ignored_node = Swig_symbol_clookup_local(templcsymname, primary_scope); + assert(ignored_node); + Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(ignored_node), Getline(ignored_node), " instantiation '%s' ignored.\n", SwigType_namestr(Getattr(ignored_node, "name"))); + } + } + } + + if (!n) { + if (template_debug) { + Printf(stdout, " chosen primary template: '%s'\n", Getattr(templ, "name")); + } + n = templ; + } + } else { + if (template_debug) { + Printf(stdout, " primary template not found\n"); + } + /* Give up if primary (unspecialized) template not found as specializations will only exist if there is a primary template */ + n = 0; + } + + if (!n) { + Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name); + } else if (n) { + String *nodeType = nodeType(n); + if (!Equal(nodeType, "template")) { + Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType); + n = 0; + } + } +success: + Delete(tname); + Delete(possiblepartials); + if ((template_debug) && (n)) { + /* + Printf(stdout, "Node: %p\n", n); + Swig_print_node(n); + */ + Printf(stdout, " chosen template:'%s'\n", Getattr(n, "name")); + } + Delete(parms); + Free(priorities_matrix); + return n; +} + + +/* ----------------------------------------------------------------------------- + * Swig_cparse_template_locate() + * + * Search for a template that matches name with given parameters. + * For templated classes finds the specialized template should there be one. + * For templated functions finds the unspecialized template even if a specialized + * template exists. + * ----------------------------------------------------------------------------- */ + +Node *Swig_cparse_template_locate(String *name, Parm *tparms, Symtab *tscope) { + Node *n = template_locate(name, tparms, tscope); /* this function does what we want for templated classes */ + + if (n) { + String *nodeType = nodeType(n); + int isclass = 0; + assert(Equal(nodeType, "template")); + (void)nodeType; + isclass = (Equal(Getattr(n, "templatetype"), "class")); + if (!isclass) { + /* If not a templated class we must have a templated function. + The template found is not necessarily the one we want when dealing with templated + functions. We don't want any specialized templated functions as they won't have + the default parameters. Let's look for the unspecialized template. Also make sure + the number of template parameters is correct as it is possible to overload a + templated function with different numbers of template parameters. */ + + if (template_debug) { + Printf(stdout, " Not a templated class, seeking most appropriate templated function\n"); + } + + n = Swig_symbol_clookup_local(name, 0); + while (n) { + Parm *tparmsfound = Getattr(n, "templateparms"); + if (ParmList_len(tparms) == ParmList_len(tparmsfound)) { + /* successful match */ + break; + } + /* repeat until we find a match with correct number of templated parameters */ + n = Getattr(n, "sym:nextSibling"); + } + + if (!n) { + Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name); + } + + if ((template_debug) && (n)) { + Printf(stdout, "Templated function found: %p\n", n); + Swig_print_node(n); + } + } + } + + return n; +} diff --git a/contrib/tools/swig/Source/CParse/util.c b/contrib/tools/swig/Source/CParse/util.c new file mode 100644 index 0000000000..00863c0357 --- /dev/null +++ b/contrib/tools/swig/Source/CParse/util.c @@ -0,0 +1,126 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * util.c + * + * Parsing utilities. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" + +/* ----------------------------------------------------------------------------- + * Swig_cparse_replace_descriptor() + * + * Replaces type descriptor string $descriptor() with the SWIG type descriptor + * string. + * ----------------------------------------------------------------------------- */ + +void Swig_cparse_replace_descriptor(String *s) { + char tmp[512]; + String *arg = 0; + SwigType *t; + char *c = 0; + + while ((c = strstr(Char(s), "$descriptor("))) { + char *d = tmp; + int level = 0; + while (*c) { + if (*c == '(') + level++; + if (*c == ')') { + level--; + if (level == 0) { + break; + } + } + *d = *c; + d++; + c++; + } + *d = 0; + arg = NewString(tmp + 12); + t = Swig_cparse_type(arg); + Delete(arg); + arg = 0; + + if (t) { + String *mangle; + String *descriptor; + + mangle = SwigType_manglestr(t); + descriptor = NewStringf("SWIGTYPE%s", mangle); + SwigType_remember(t); + *d = ')'; + d++; + *d = 0; + Replace(s, tmp, descriptor, DOH_REPLACE_ANY); + Delete(mangle); + Delete(descriptor); + Delete(t); + } else { + Swig_error(Getfile(s), Getline(s), "Bad $descriptor() macro.\n"); + break; + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_cparse_smartptr() + * + * Parse the type in smartptr feature and convert into a SwigType. + * Error out if the parsing fails as this is like a parser syntax error. + * ----------------------------------------------------------------------------- */ + +SwigType *Swig_cparse_smartptr(Node *n) { + SwigType *smart = 0; + String *smartptr = Getattr(n, "feature:smartptr"); + if (smartptr) { + SwigType *cpt = Swig_cparse_type(smartptr); + if (cpt) { + smart = SwigType_typedef_resolve_all(cpt); + Delete(cpt); + } else { + Swig_error(Getfile(n), Getline(n), "Invalid type (%s) in 'smartptr' feature for class %s.\n", smartptr, SwigType_namestr(Getattr(n, "name"))); + } + } + return smart; +} + +/* ----------------------------------------------------------------------------- + * cparse_normalize_void() + * + * This function is used to replace arguments of the form (void) with empty + * arguments in C++ + * ----------------------------------------------------------------------------- */ + +void cparse_normalize_void(Node *n) { + String *decl = Getattr(n, "decl"); + Parm *parms = Getattr(n, "parms"); + + if (SwigType_isfunction(decl)) { + if ((ParmList_len(parms) == 1) && (SwigType_type(Getattr(parms, "type")) == T_VOID)) { + Replaceall(decl, "f(void).", "f()."); + Delattr(n, "parms"); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_cparse_new_node() + * + * Create an empty parse node, setting file and line number information + * ----------------------------------------------------------------------------- */ + +Node *Swig_cparse_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; +} |