diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2009-08-18 20:56:02 +0000 |
---|---|---|
committer | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-09-25 16:59:08 +0000 |
commit | 9f8a09ed743cedd9547bf0661d518647966ab114 (patch) | |
tree | 9c7803d3b27a8ec22e91792ac7f7932efa128b20 /Source | |
download | swig-tarball-9f8a09ed743cedd9547bf0661d518647966ab114.tar.gz |
Imported from /srv/lorry/lorry-area/swig-tarball/swig-1.3.40.tar.gz.HEADswig-1.3.40master
Diffstat (limited to 'Source')
87 files changed, 97517 insertions, 0 deletions
diff --git a/Source/CParse/cparse.h b/Source/CParse/cparse.h new file mode 100644 index 0000000..5679771 --- /dev/null +++ b/Source/CParse/cparse.h @@ -0,0 +1,74 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * cparse.h + * + * SWIG parser module. + * ----------------------------------------------------------------------------- */ + +/* $Id: cparse.h 11097 2009-01-30 10:27:37Z bhy $ */ + +#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_start_line; + + extern void Swig_cparse_cplusplus(int); + extern void scanner_file(File *); + extern void scanner_next_token(int); + extern void skip_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(); + 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 void cparse_normalize_void(Node *); + extern Parm *Swig_cparse_parm(String *s); + extern ParmList *Swig_cparse_parms(String *s); + + +/* 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); \ + } +#endif diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c new file mode 100644 index 0000000..9128a2b --- /dev/null +++ b/Source/CParse/cscanner.c @@ -0,0 +1,930 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.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 accomodate 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. + * ----------------------------------------------------------------------------- */ + +char cvsroot_cscanner_c[] = "$Id: cscanner.c 11123 2009-02-08 22:30:10Z wsfulton $"; + +#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; + +/* 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; +static int expanding_macro = 0; +static int follow_locators = 0; + +/* ----------------------------------------------------------------------------- + * Swig_cparse_cplusplus() + * ----------------------------------------------------------------------------- */ + +void Swig_cparse_cplusplus(int v) { + cparse_cplusplus = v; +} + +/* ---------------------------------------------------------------------- + * locator() + * + * Support for locator strings. These are strings of the form + * @SWIG:filename,line,id@ emitted by the SWIG preprocessor. They + * are primarily used for macro line number reporting + * ---------------------------------------------------------------------- */ + +typedef struct Locator { + String *filename; + int line_number; + struct Locator *next; +} Locator; + +static Locator *locs = 0; + +/* we just use the locator to mark when active/deactive the linecounting */ + +static void scanner_locator(String *loc) { + if (!follow_locators) { + if (Equal(loc, "/*@SWIG@*/")) { + /* End locator. */ + if (expanding_macro) + --expanding_macro; + } else { + /* Begin locator. */ + ++expanding_macro; + } + /* Freeze line number processing in Scanner */ + Scanner_freeze_line(scan,expanding_macro); + } else { + int c; + Locator *l; + Seek(loc, 7, SEEK_SET); + c = Getc(loc); + if (c == '@') { + /* Empty locator. We pop the last location off */ + if (locs) { + Scanner_set_location(scan,locs->filename,locs->line_number); + cparse_file = locs->filename; + cparse_line = locs->line_number; + l = locs->next; + free(locs); + locs = l; + } + return; + } + + /* We're going to push a new location */ + l = (Locator *) malloc(sizeof(Locator)); + l->filename = cparse_file; + l->line_number = cparse_line; + l->next = locs; + locs = l; + + /* Now, parse the new location out of the locator string */ + { + String *fn = NewStringEmpty(); + /* Putc(c, fn); */ + + while ((c = Getc(loc)) != EOF) { + if ((c == '@') || (c == ',')) + break; + Putc(c, fn); + } + cparse_file = Swig_copy_string(Char(fn)); + Clear(fn); + cparse_line = 1; + /* Get the line number */ + while ((c = Getc(loc)) != EOF) { + if ((c == '@') || (c == ',')) + break; + Putc(c, fn); + } + cparse_line = atoi(Char(fn)); + Clear(fn); + + /* Get the rest of it */ + while ((c = Getc(loc)) != EOF) { + if (c == '@') + break; + Putc(c, fn); + } + /* Printf(stderr,"location: %s:%d\n",cparse_file,cparse_line); */ + Scanner_set_location(scan,cparse_file,cparse_line); + Delete(fn); + } + } +} + +void Swig_cparse_follow_locators(int v) { + follow_locators = v; +} + + +/* ---------------------------------------------------------------------------- + * scanner_init() + * + * Initialize buffers + * ------------------------------------------------------------------------- */ + +void scanner_init() { + 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) { + Clear(scanner_ccode); + + if (Scanner_skip_balanced(scan,startchar,endchar) < 0) { + Swig_error(Scanner_file(scan),Scanner_errline(scan), "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; +} + +/* ---------------------------------------------------------------------------- + * 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 '}'. 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. + * ------------------------------------------------------------------------- */ + +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 '}'\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_PERIOD: + return PERIOD; + case SWIG_TOKEN_MODULO: + return MODULO; + case SWIG_TOKEN_COLON: + return COLON; + case SWIG_TOKEN_DCOLONSTAR: + return DSTAR; + + 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; + + /* 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_CHAR: + yylval.str = NewString(Scanner_text(scan)); + if (Len(yylval.str) == 0) { + Swig_error(cparse_file, cparse_line, "Empty character constant\n"); + Printf(stdout,"%d\n", Len(Scanner_text(scan))); + } + return CHARCONST; + + /* 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_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: + { + String *cmt = Scanner_text(scan); + char *loc = Char(cmt); + if ((strncmp(loc,"/*@SWIG",7) == 0) && (loc[Len(cmt)-3] == '@')) { + scanner_locator(cmt); + } + } + 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() { + check_typedef = 1; +} + +void scanner_ignore_typedef() { + check_typedef = 0; +} + +void scanner_last_id(int x) { + last_id = x; +} + +void scanner_clear_rename() { + rename_active = 0; +} + +/* Used to push a ficticious 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() { + return main_input_file; +} + +/* ---------------------------------------------------------------------------- + * int yylex() + * + * Gets the lexene and returns tokens. + * ------------------------------------------------------------------------- */ + +int yylex(void) { + + int l; + char *yytext; + + if (!scan_init) { + scanner_init(); + } + + if (next_token) { + l = next_token; + next_token = 0; + return l; + } + + l = yylook(); + + /* Printf(stdout, "%s:%d:::%d: '%s'\n", cparse_file, cparse_line, 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: + 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; + 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, "virtual") == 0) + return (VIRTUAL); + 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. + + */ + + nexttok = Scanner_token(scan); + 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_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 { + 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 COPERATOR; + } + } + if (termtoken) + Scanner_pushtoken(scan, termtoken, termvalue); + return (OPERATOR); + } + } + if (strcmp(yytext, "throw") == 0) + return (THROW); + 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, "export") == 0) + return (yylex()); + if (strcmp(yytext, "typename") == 0) + return (TYPENAME); + if (strcmp(yytext, "template") == 0) { + yylval.ivalue = cparse_line; + return (TEMPLATE); + } + if (strcmp(yytext, "delete") == 0) { + return (DELETE_KW); + } + if (strcmp(yytext, "using") == 0) { + return (USING); + } + if (strcmp(yytext, "namespace") == 0) { + return (NAMESPACE); + } + } 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.ivalue = 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()); + + /* SWIG directives */ + } else { + 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, "%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.ivalue = 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); + } + /* 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(); + default: + return (l); + } +} diff --git a/Source/CParse/parser.c b/Source/CParse/parser.c new file mode 100644 index 0000000..e8c8111 --- /dev/null +++ b/Source/CParse/parser.c @@ -0,0 +1,10438 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ID = 258, + HBLOCK = 259, + POUND = 260, + STRING = 261, + INCLUDE = 262, + IMPORT = 263, + INSERT = 264, + CHARCONST = 265, + NUM_INT = 266, + NUM_FLOAT = 267, + NUM_UNSIGNED = 268, + NUM_LONG = 269, + NUM_ULONG = 270, + NUM_LONGLONG = 271, + NUM_ULONGLONG = 272, + TYPEDEF = 273, + TYPE_INT = 274, + TYPE_UNSIGNED = 275, + TYPE_SHORT = 276, + TYPE_LONG = 277, + TYPE_FLOAT = 278, + TYPE_DOUBLE = 279, + TYPE_CHAR = 280, + TYPE_WCHAR = 281, + TYPE_VOID = 282, + TYPE_SIGNED = 283, + TYPE_BOOL = 284, + TYPE_COMPLEX = 285, + TYPE_TYPEDEF = 286, + TYPE_RAW = 287, + TYPE_NON_ISO_INT8 = 288, + TYPE_NON_ISO_INT16 = 289, + TYPE_NON_ISO_INT32 = 290, + TYPE_NON_ISO_INT64 = 291, + LPAREN = 292, + RPAREN = 293, + COMMA = 294, + SEMI = 295, + EXTERN = 296, + INIT = 297, + LBRACE = 298, + RBRACE = 299, + PERIOD = 300, + CONST_QUAL = 301, + VOLATILE = 302, + REGISTER = 303, + STRUCT = 304, + UNION = 305, + EQUAL = 306, + SIZEOF = 307, + MODULE = 308, + LBRACKET = 309, + RBRACKET = 310, + ILLEGAL = 311, + CONSTANT = 312, + NAME = 313, + RENAME = 314, + NAMEWARN = 315, + EXTEND = 316, + PRAGMA = 317, + FEATURE = 318, + VARARGS = 319, + ENUM = 320, + CLASS = 321, + TYPENAME = 322, + PRIVATE = 323, + PUBLIC = 324, + PROTECTED = 325, + COLON = 326, + STATIC = 327, + VIRTUAL = 328, + FRIEND = 329, + THROW = 330, + CATCH = 331, + EXPLICIT = 332, + USING = 333, + NAMESPACE = 334, + NATIVE = 335, + INLINE = 336, + TYPEMAP = 337, + EXCEPT = 338, + ECHO = 339, + APPLY = 340, + CLEAR = 341, + SWIGTEMPLATE = 342, + FRAGMENT = 343, + WARN = 344, + LESSTHAN = 345, + GREATERTHAN = 346, + MODULO = 347, + DELETE_KW = 348, + LESSTHANOREQUALTO = 349, + GREATERTHANOREQUALTO = 350, + EQUALTO = 351, + NOTEQUALTO = 352, + QUESTIONMARK = 353, + TYPES = 354, + PARMS = 355, + NONID = 356, + DSTAR = 357, + DCNOT = 358, + TEMPLATE = 359, + OPERATOR = 360, + COPERATOR = 361, + PARSETYPE = 362, + PARSEPARM = 363, + PARSEPARMS = 364, + CAST = 365, + LOR = 366, + LAND = 367, + OR = 368, + XOR = 369, + AND = 370, + RSHIFT = 371, + LSHIFT = 372, + MINUS = 373, + PLUS = 374, + MODULUS = 375, + SLASH = 376, + STAR = 377, + LNOT = 378, + NOT = 379, + UMINUS = 380, + DCOLON = 381 + }; +#endif +/* Tokens. */ +#define ID 258 +#define HBLOCK 259 +#define POUND 260 +#define STRING 261 +#define INCLUDE 262 +#define IMPORT 263 +#define INSERT 264 +#define CHARCONST 265 +#define NUM_INT 266 +#define NUM_FLOAT 267 +#define NUM_UNSIGNED 268 +#define NUM_LONG 269 +#define NUM_ULONG 270 +#define NUM_LONGLONG 271 +#define NUM_ULONGLONG 272 +#define TYPEDEF 273 +#define TYPE_INT 274 +#define TYPE_UNSIGNED 275 +#define TYPE_SHORT 276 +#define TYPE_LONG 277 +#define TYPE_FLOAT 278 +#define TYPE_DOUBLE 279 +#define TYPE_CHAR 280 +#define TYPE_WCHAR 281 +#define TYPE_VOID 282 +#define TYPE_SIGNED 283 +#define TYPE_BOOL 284 +#define TYPE_COMPLEX 285 +#define TYPE_TYPEDEF 286 +#define TYPE_RAW 287 +#define TYPE_NON_ISO_INT8 288 +#define TYPE_NON_ISO_INT16 289 +#define TYPE_NON_ISO_INT32 290 +#define TYPE_NON_ISO_INT64 291 +#define LPAREN 292 +#define RPAREN 293 +#define COMMA 294 +#define SEMI 295 +#define EXTERN 296 +#define INIT 297 +#define LBRACE 298 +#define RBRACE 299 +#define PERIOD 300 +#define CONST_QUAL 301 +#define VOLATILE 302 +#define REGISTER 303 +#define STRUCT 304 +#define UNION 305 +#define EQUAL 306 +#define SIZEOF 307 +#define MODULE 308 +#define LBRACKET 309 +#define RBRACKET 310 +#define ILLEGAL 311 +#define CONSTANT 312 +#define NAME 313 +#define RENAME 314 +#define NAMEWARN 315 +#define EXTEND 316 +#define PRAGMA 317 +#define FEATURE 318 +#define VARARGS 319 +#define ENUM 320 +#define CLASS 321 +#define TYPENAME 322 +#define PRIVATE 323 +#define PUBLIC 324 +#define PROTECTED 325 +#define COLON 326 +#define STATIC 327 +#define VIRTUAL 328 +#define FRIEND 329 +#define THROW 330 +#define CATCH 331 +#define EXPLICIT 332 +#define USING 333 +#define NAMESPACE 334 +#define NATIVE 335 +#define INLINE 336 +#define TYPEMAP 337 +#define EXCEPT 338 +#define ECHO 339 +#define APPLY 340 +#define CLEAR 341 +#define SWIGTEMPLATE 342 +#define FRAGMENT 343 +#define WARN 344 +#define LESSTHAN 345 +#define GREATERTHAN 346 +#define MODULO 347 +#define DELETE_KW 348 +#define LESSTHANOREQUALTO 349 +#define GREATERTHANOREQUALTO 350 +#define EQUALTO 351 +#define NOTEQUALTO 352 +#define QUESTIONMARK 353 +#define TYPES 354 +#define PARMS 355 +#define NONID 356 +#define DSTAR 357 +#define DCNOT 358 +#define TEMPLATE 359 +#define OPERATOR 360 +#define COPERATOR 361 +#define PARSETYPE 362 +#define PARSEPARM 363 +#define PARSEPARMS 364 +#define CAST 365 +#define LOR 366 +#define LAND 367 +#define OR 368 +#define XOR 369 +#define AND 370 +#define RSHIFT 371 +#define LSHIFT 372 +#define MINUS 373 +#define PLUS 374 +#define MODULUS 375 +#define SLASH 376 +#define STAR 377 +#define LNOT 378 +#define NOT 379 +#define UMINUS 380 +#define DCOLON 381 + + + + +/* Copy the first part of user declarations. */ +#line 12 "parser.y" + + +#define yylex yylex + +char cvsroot_parser_y[] = "$Id: parser.y 11582 2009-08-15 10:40:19Z wsfulton $"; + +#include "swig.h" +#include "cparse.h" +#include "preprocessor.h" +#include <ctype.h> + +/* We do this for portability */ +#undef alloca +#define alloca malloc + +/* ----------------------------------------------------------------------------- + * Externals + * ----------------------------------------------------------------------------- */ + +int yyparse(); + +/* NEW Variables */ + +static Node *top = 0; /* Top of the generated parse tree */ +static int unnamed = 0; /* Unnamed datatype counter */ +static Hash *extendhash = 0; /* Hash table of added methods */ +static Hash *classes = 0; /* Hash table of classes */ +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 char *last_cpptype = 0; +static int inherit_list = 0; +static Parm *template_parameters = 0; +static int extendmode = 0; +static int compact_default_args = 0; +static int template_reduce = 0; +static int cparse_externc = 0; + +static int max_class_levels = 0; +static int class_level = 0; +static Node **class_decl = NULL; + +/* ----------------------------------------------------------------------------- + * 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 = NewHash(); + set_nodeType(n,tag); + Setfile(n,cparse_file); + Setline(n,cparse_line); + return n; +} + +/* Copies a node. Does not copy tree links or symbol table data (except for + sym:name) */ + +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; + } + /* Looks okay. Just copy the data using Copy */ + ci = Copy(k.item); + Setattr(nn, key, ci); + Delete(ci); + } + return nn; +} + +/* ----------------------------------------------------------------------------- + * Variables + * ----------------------------------------------------------------------------- */ + +static char *typemap_lang = 0; /* Current language setting */ + +static int cplus_mode = 0; +static String *class_rename = 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) 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_node_scope(String *cname); + + +Hash *Swig_cparse_features(void) { + static Hash *features_hash = 0; + if (!features_hash) features_hash = NewHash(); + return features_hash; +} + +static String *feature_identifier_fix(String *s) { + if (SwigType_istemplate(s)) { + String *tp, *ts, *ta, *tq; + tp = SwigType_templateprefix(s); + 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); + } +} + +/* 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) { + 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; + return Swig_name_make(n,Namespaceprefix,name,decl,add_oldname); +} + +/* Generate an unnamed identifier */ +static String *make_unnamed() { + unnamed++; + return NewStringf("$unnamed%d$",unnamed); +} + +/* Return if the node is a friend declaration */ +static int is_friend(Node *n) { + return Cmp(Getattr(n,"storage"),"friend") == 0; +} + +static int is_operator(String *name) { + return Strncmp(name,"operator ", 9) == 0; +} + + +/* Add declaration list to symbol table */ +static int add_only_one = 0; + +static void add_symbols(Node *n) { + String *decl; + String *wrn = 0; + if (inclass && n) { + cparse_normalize_void(n); + } + while (n) { + String *symname = 0; + /* for friends, we need to pop the scope once */ + String *old_prefix = 0; + Symtab *old_scope = 0; + int isfriend = inclass && is_friend(n); + int iscdecl = Cmp(nodeType(n),"cdecl") == 0; + int only_csymbol = 0; + if (extendmode) { + Setattr(n,"isextension","1"); + } + + 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 (!Getattr(n,"parentNode") && class_level) set_parentNode(n,class_decl[class_level - 1]); + */ + Setattr(n,"ismember","1"); + } + } + 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; + } + } + } 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)) { + 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) { + wrn = Swig_name_warning(n, Namespaceprefix, symname,0); + } + } else { + String *name = Getattr(n,"name"); + SwigType *fdecl = Copy(decl); + SwigType *fun = SwigType_pop_function(fdecl); + if (iscdecl) { + Setattr(n,"kind","function"); + } + + Swig_features_get(Swig_cparse_features(),Namespaceprefix,name,fun,n); + + symname = make_name(n, name,fun); + wrn = Swig_name_warning(n, Namespaceprefix,symname,fun); + + Delete(fdecl); + Delete(fun); + + } + if (!symname) { + n = nextSibling(n); + continue; + } + if (only_csymbol || GetFlag(n,"feature:ignore")) { + /* Only add to C symbol table and continue */ + Swig_symbol_add(0, n); + } else if (strncmp(Char(symname),"$ignore",7) == 0) { + char *c = Char(symname)+7; + SetFlag(n,"feature:ignore"); + if (strlen(c)) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0,Getfile(n), Getline(n), "%s\n",c+1); + SWIG_WARN_NODE_END(n); + } + Swig_symbol_add(0, n); + } else { + Node *c; + if ((wrn) && (Len(wrn))) { + String *metaname = symname; + if (!Getmeta(metaname,"already_warned")) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0,Getfile(n),Getline(n), "%s\n", wrn); + SWIG_WARN_NODE_END(n); + Setmeta(metaname,"already_warned","1"); + } + } + c = Swig_symbol_add(symname,n); + + if (c != n) { + /* symbol conflict attempting to add in the new symbol */ + if (Getattr(n,"sym:weak")) { + Setattr(n,"sym:name",symname); + } else { + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + int redefined = Swig_need_redefined_warn(n,c,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"))) { + 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) { + inclass = 1; + 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 = 0; + current_class = 0; + } + } 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); + } +} + +/* Extension merge. This function is used to handle the %extend directive + when it appears before a class definition. To handle this, the %extend + actually needs to take precedence. Therefore, we will selectively nuke symbols + from the current symbol table, replacing them with the added methods */ + +static void merge_extensions(Node *cls, Node *am) { + Node *n; + Node *csym; + + n = firstChild(am); + while (n) { + String *symname; + if (Strcmp(nodeType(n),"constructor") == 0) { + symname = Getattr(n,"sym:name"); + if (symname) { + if (Strcmp(symname,Getattr(n,"name")) == 0) { + /* If the name and the sym:name of a constructor are the same, + then it hasn't been renamed. However---the name of the class + itself might have been renamed so we need to do a consistency + check here */ + if (Getattr(cls,"sym:name")) { + Setattr(n,"sym:name", Getattr(cls,"sym:name")); + } + } + } + } + + symname = Getattr(n,"sym:name"); + DohIncref(symname); + if ((symname) && (!Getattr(n,"error"))) { + /* Remove node from its symbol table */ + Swig_symbol_remove(n); + csym = Swig_symbol_add(symname,n); + if (csym != n) { + /* Conflict with previous definition. Nuke previous definition */ + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + Printf(ec,"Identifier '%s' redefined by %%extend (ignored),",symname); + Printf(en,"%%extend definition of '%s'.",symname); + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(csym),Getline(csym),"%s\n",ec); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); + SWIG_WARN_NODE_END(n); + Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(csym),Getline(csym),ec, + Getfile(n),Getline(n),en); + Setattr(csym,"error",e); + Delete(e); + Delete(en); + Delete(ec); + Swig_symbol_remove(csym); /* Remove class definition */ + Swig_symbol_add(symname,n); /* Insert extend definition */ + } + } + n = nextSibling(n); + } +} + +static void append_previous_extension(Node *cls, Node *am) { + Node *n, *ne; + Node *pe = 0; + Node *ae = 0; + + if (!am) return; + + n = firstChild(am); + while (n) { + ne = nextSibling(n); + set_nextSibling(n,0); + /* typemaps and fragments need to be prepended */ + if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) { + if (!pe) pe = new_node("extend"); + appendChild(pe, n); + } else { + if (!ae) ae = new_node("extend"); + appendChild(ae, n); + } + n = ne; + } + if (pe) prependChild(cls,pe); + if (ae) appendChild(cls,ae); +} + + +/* Check for unused %extend. Special case, don't report unused + extensions for templates */ + +static void check_extensions() { + Iterator ki; + + if (!extendhash) return; + for (ki = First(extendhash); ki.key; ki = Next(ki)) { + if (!Strchr(ki.key,'<')) { + SWIG_WARN_NODE_BEGIN(ki.item); + Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", ki.key); + SWIG_WARN_NODE_END(ki.item); + } + } +} + +/* Check a set of declarations to see if any are pure-abstract */ + +static List *pure_abstract(Node *n) { + List *abs = 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 (!abs) { + abs = NewList(); + } + Append(abs,n); + Setattr(n,"abstract","1"); + } + } + } else if (Cmp(nodeType(n),"destructor") == 0) { + if (Cmp(Getattr(n,"value"),"0") == 0) { + if (!abs) { + abs = NewList(); + } + Append(abs,n); + Setattr(n,"abstract","1"); + } + } + n = nextSibling(n); + } + return abs; +} + +/* Make a classname */ + +static String *make_class_name(String *name) { + String *nname = 0; + if (Namespaceprefix) { + nname= NewStringf("%s::%s", Namespaceprefix, name); + } else { + nname = NewString(name); + } + if (SwigType_istemplate(nname)) { + String *prefix, *args, *qargs; + prefix = SwigType_templateprefix(nname); + args = SwigType_templateargs(nname); + qargs = Swig_symbol_type_qualify(args,0); + Append(prefix,qargs); + Delete(nname); + Delete(args); + Delete(qargs); + nname = prefix; + } + return nname; +} + +static List *make_inherit_list(String *clsname, List *names) { + int i, ilen; + String *derived; + List *bases = NewList(); + + if (Namespaceprefix) derived = NewStringf("%s::%s", Namespaceprefix,clsname); + else derived = NewString(clsname); + + ilen = Len(names); + for (i = 0; i < ilen; i++) { + Node *s; + String *base; + String *n = Getitem(names,i); + /* Try to figure out where this symbol is */ + s = Swig_symbol_clookup(n,0); + if (s) { + while (s && (Strcmp(nodeType(s),"class") != 0)) { + /* Not a class. Could be a typedef though. */ + String *storage = Getattr(s,"storage"); + if (storage && (Strcmp(storage,"typedef") == 0)) { + String *nn = Getattr(s,"type"); + s = Swig_symbol_clookup(nn,Getattr(s,"sym:symtab")); + } else { + break; + } + } + if (s && ((Strcmp(nodeType(s),"class") == 0) || (Strcmp(nodeType(s),"template") == 0))) { + String *q = Swig_symbol_qualified(s); + Append(bases,s); + if (q) { + base = NewStringf("%s::%s", q, Getattr(s,"name")); + Delete(q); + } else { + base = NewString(Getattr(s,"name")); + } + } else { + base = NewString(n); + } + } else { + base = NewString(n); + } + if (base) { + Swig_name_inherit(base,derived); + Delete(base); + } + } + return bases; +} + +/* If the class name is qualified. We need to create or lookup namespace entries */ + +static Symtab *get_global_scope() { + Symtab *symtab = Swig_symbol_current(); + Node *pn = parentNode(symtab); + while (pn) { + symtab = pn; + pn = parentNode(symtab); + if (!pn) break; + } + 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); + size_t 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; +} + + +static Node *nscope = 0; +static Node *nscope_inner = 0; +static String *resolve_node_scope(String *cname) { + Symtab *gscope = 0; + nscope = 0; + nscope_inner = 0; + if (Swig_scopename_check(cname)) { + Node *ns; + String *prefix = Swig_scopename_prefix(cname); + String *base = Swig_scopename_last(cname); + if (prefix && (Strncmp(prefix,"::",2) == 0)) { + /* Use the global scope */ + String *nprefix = NewString(Char(prefix)+2); + Delete(prefix); + prefix= nprefix; + gscope = get_global_scope(); + } + if (!prefix || (Len(prefix) == 0)) { + /* Use the global scope, but we need to add a 'global' namespace. */ + if (!gscope) gscope = get_global_scope(); + /* 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; + 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 = base; + } + 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; + String *sname; + Iterator si; + String *name = NewString(prefix); + scopes = NewList(); + while (name) { + String *base = Swig_scopename_last(name); + String *tprefix = Swig_scopename_prefix(name); + Insert(scopes,0,base); + Delete(base); + Delete(name); + name = tprefix; + } + 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); + ns1 = Swig_symbol_clookup(sname,0); + /* 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 = base; + Delete(scopes); + } + } + Delete(prefix); + } + return cname; +} + + + + + +/* Structures for handling code fragments built for nested classes */ + +typedef struct Nested { + String *code; /* Associated code fragment */ + int line; /* line number where it starts */ + char *name; /* Name associated with this nested class */ + char *kind; /* Kind of class */ + int unnamed; /* unnamed class */ + SwigType *type; /* Datatype associated with the name */ + struct Nested *next; /* Next code fragment in list */ +} Nested; + +/* Some internal variables for saving nested class information */ + +static Nested *nested_list = 0; + +/* Add a function to the nested list */ + +static void add_nested(Nested *n) { + Nested *n1; + if (!nested_list) nested_list = n; + else { + n1 = nested_list; + while (n1->next) n1 = n1->next; + n1->next = n; + } +} + +/* Strips C-style and C++-style comments from string in-place. */ +static void strip_comments(char *string) { + int state = 0; /* + * 0 - not in comment + * 1 - in c-style comment + * 2 - in c++-style comment + * 3 - in string + * 4 - after reading / not in comments + * 5 - after reading * in c-style comments + * 6 - after reading \ in strings + */ + char * c = string; + while (*c) { + switch (state) { + case 0: + if (*c == '\"') + state = 3; + else if (*c == '/') + state = 4; + break; + case 1: + if (*c == '*') + state = 5; + *c = ' '; + break; + case 2: + if (*c == '\n') + state = 0; + else + *c = ' '; + break; + case 3: + if (*c == '\"') + state = 0; + else if (*c == '\\') + state = 6; + break; + case 4: + if (*c == '/') { + *(c-1) = ' '; + *c = ' '; + state = 2; + } else if (*c == '*') { + *(c-1) = ' '; + *c = ' '; + state = 1; + } else + state = 0; + break; + case 5: + if (*c == '/') + state = 0; + else + state = 1; + *c = ' '; + break; + case 6: + state = 3; + break; + } + ++c; + } +} + +/* Dump all of the nested class declarations to the inline processor + * However. We need to do a few name replacements and other munging + * first. This function must be called before closing a class! */ + +static Node *dump_nested(const char *parent) { + Nested *n,*n1; + Node *ret = 0; + n = nested_list; + if (!parent) { + nested_list = 0; + return 0; + } + while (n) { + Node *retx; + SwigType *nt; + /* Token replace the name of the parent class */ + Replace(n->code, "$classname", parent, DOH_REPLACE_ANY); + + /* Fix up the name of the datatype (for building typedefs and other stuff) */ + Append(n->type,parent); + Append(n->type,"_"); + Append(n->type,n->name); + + /* Add the appropriate declaration to the C++ processor */ + retx = new_node("cdecl"); + Setattr(retx,"name",n->name); + nt = Copy(n->type); + Setattr(retx,"type",nt); + Delete(nt); + Setattr(retx,"nested",parent); + if (n->unnamed) { + Setattr(retx,"unnamed","1"); + } + + add_symbols(retx); + if (ret) { + set_nextSibling(retx,ret); + Delete(ret); + } + ret = retx; + + /* Insert a forward class declaration */ + /* Disabled: [ 597599 ] union in class: incorrect scope + retx = new_node("classforward"); + Setattr(retx,"kind",n->kind); + Setattr(retx,"name",Copy(n->type)); + Setattr(retx,"sym:name", make_name(n->type,0)); + set_nextSibling(retx,ret); + ret = retx; + */ + + /* Strip comments - further code may break in presence of comments. */ + strip_comments(Char(n->code)); + + /* Make all SWIG created typedef structs/unions/classes unnamed else + redefinition errors occur - nasty hack alert.*/ + + { + const char* types_array[3] = {"struct", "union", "class"}; + int i; + for (i=0; i<3; i++) { + char* code_ptr = Char(n->code); + while (code_ptr) { + /* Replace struct name (as in 'struct name {...}' ) with whitespace + name will be between struct and opening brace */ + + code_ptr = strstr(code_ptr, types_array[i]); + if (code_ptr) { + char *open_bracket_pos; + code_ptr += strlen(types_array[i]); + open_bracket_pos = strchr(code_ptr, '{'); + if (open_bracket_pos) { + /* Make sure we don't have something like struct A a; */ + char* semi_colon_pos = strchr(code_ptr, ';'); + if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) + while (code_ptr < open_bracket_pos) + *code_ptr++ = ' '; + } + } + } + } + } + + { + /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ + char* code_ptr = Char(n->code); + while (code_ptr) { + code_ptr = strstr(code_ptr, "%constant"); + if (code_ptr) { + char* directive_end_pos = strchr(code_ptr, ';'); + if (directive_end_pos) { + while (code_ptr <= directive_end_pos) + *code_ptr++ = ' '; + } + } + } + } + { + Node *head = new_node("insert"); + String *code = NewStringf("\n%s\n",n->code); + Setattr(head,"code", code); + Delete(code); + set_nextSibling(head,ret); + Delete(ret); + ret = head; + } + + /* Dump the code to the scanner */ + start_inline(Char(n->code),n->line); + + n1 = n->next; + Delete(n->code); + free(n); + n = n1; + } + nested_list = 0; + return ret; +} + +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); */ + + 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 (Cmp(Getattr(n,"storage"),"externc") == 0) { + 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")) { + 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; + } + } +} + +/* ----------------------------------------------------------------------------- + * tag_nodes() + * + * Used by the parser to mark subtypes with extra information. + * ----------------------------------------------------------------------------- */ + +static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) { + while (n) { + Setattr(n, attrname, value); + tag_nodes(firstChild(n), attrname, value); + n = nextSibling(n); + } +} + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 1440 "parser.y" +{ + char *id; + List *bases; + struct Define { + String *val; + String *rawval; + int type; + String *qualifier; + String *bitfield; + Parm *throws; + String *throwf; + } dtype; + struct { + char *type; + String *filename; + int line; + } loc; + struct { + char *id; + SwigType *type; + String *defarg; + ParmList *parms; + short have_parms; + ParmList *throws; + String *throwf; + } decl; + Parm *tparms; + struct { + String *method; + Hash *kwargs; + } tmap; + struct { + String *type; + String *us; + } ptype; + SwigType *type; + String *str; + Parm *p; + ParmList *pl; + int ivalue; + Node *node; +} +/* Line 187 of yacc.c. */ +#line 1819 "y.tab.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 1832 "y.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 55 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 3902 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 127 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 148 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 467 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 904 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 381 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 9, 12, 16, 19, 25, 29, + 32, 34, 36, 38, 40, 42, 44, 46, 49, 51, + 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, + 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, + 92, 100, 106, 110, 116, 122, 126, 129, 132, 138, + 141, 147, 150, 155, 157, 159, 167, 175, 181, 182, + 190, 192, 194, 197, 200, 202, 208, 214, 220, 224, + 229, 233, 241, 250, 256, 260, 262, 264, 268, 270, + 275, 283, 290, 292, 294, 302, 312, 321, 332, 338, + 346, 353, 362, 364, 366, 372, 377, 383, 391, 393, + 397, 404, 411, 420, 422, 425, 429, 431, 434, 438, + 445, 451, 461, 464, 466, 468, 470, 471, 478, 484, + 486, 491, 493, 495, 498, 504, 511, 516, 524, 533, + 540, 542, 544, 546, 548, 550, 552, 553, 563, 564, + 573, 575, 578, 583, 584, 591, 595, 597, 599, 601, + 603, 605, 607, 609, 612, 614, 616, 618, 622, 624, + 628, 633, 634, 641, 642, 648, 654, 657, 658, 665, + 667, 669, 670, 674, 676, 678, 680, 682, 684, 686, + 688, 690, 694, 696, 698, 700, 702, 704, 706, 708, + 710, 712, 719, 726, 734, 743, 752, 760, 766, 769, + 772, 775, 776, 784, 785, 792, 793, 802, 804, 806, + 808, 810, 812, 814, 816, 818, 820, 822, 824, 826, + 828, 831, 834, 837, 842, 845, 851, 853, 856, 858, + 860, 862, 864, 866, 868, 870, 873, 875, 879, 881, + 884, 892, 896, 898, 901, 903, 907, 909, 911, 913, + 916, 922, 925, 928, 930, 933, 936, 938, 940, 942, + 944, 947, 951, 953, 956, 960, 965, 971, 976, 978, + 981, 985, 990, 996, 1000, 1005, 1010, 1012, 1015, 1020, + 1025, 1031, 1035, 1040, 1045, 1047, 1050, 1053, 1057, 1059, + 1062, 1064, 1067, 1071, 1076, 1080, 1085, 1088, 1092, 1096, + 1101, 1105, 1109, 1112, 1115, 1117, 1119, 1122, 1124, 1126, + 1128, 1130, 1133, 1135, 1138, 1142, 1144, 1146, 1148, 1151, + 1154, 1156, 1158, 1161, 1163, 1165, 1168, 1170, 1172, 1174, + 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, + 1196, 1197, 1200, 1202, 1204, 1208, 1210, 1212, 1216, 1218, + 1220, 1222, 1224, 1226, 1228, 1234, 1236, 1238, 1242, 1247, + 1253, 1259, 1266, 1269, 1272, 1274, 1276, 1278, 1280, 1282, + 1284, 1286, 1290, 1294, 1298, 1302, 1306, 1310, 1314, 1318, + 1322, 1326, 1330, 1334, 1338, 1342, 1346, 1350, 1356, 1359, + 1362, 1365, 1368, 1371, 1373, 1374, 1378, 1380, 1382, 1386, + 1389, 1394, 1396, 1398, 1400, 1402, 1404, 1406, 1408, 1410, + 1412, 1414, 1416, 1421, 1427, 1429, 1433, 1437, 1442, 1447, + 1451, 1454, 1456, 1458, 1462, 1465, 1469, 1471, 1473, 1475, + 1477, 1479, 1482, 1487, 1489, 1493, 1495, 1499, 1503, 1506, + 1509, 1512, 1515, 1518, 1523, 1525, 1529, 1531, 1535, 1539, + 1542, 1545, 1548, 1551, 1553, 1555, 1557, 1559, 1563, 1565, + 1569, 1575, 1577, 1581, 1585, 1591, 1593, 1595 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 128, 0, -1, 129, -1, 107, 215, 40, -1, 107, + 1, -1, 108, 215, 40, -1, 108, 1, -1, 109, + 37, 212, 38, 40, -1, 109, 1, 40, -1, 129, + 130, -1, 274, -1, 131, -1, 168, -1, 176, -1, + 40, -1, 1, -1, 175, -1, 1, 106, -1, 132, + -1, 134, -1, 135, -1, 136, -1, 137, -1, 138, + -1, 141, -1, 142, -1, 145, -1, 146, -1, 147, + -1, 148, -1, 149, -1, 150, -1, 153, -1, 155, + -1, 158, -1, 160, -1, 165, -1, 166, -1, 167, + -1, -1, 61, 271, 264, 43, 133, 193, 44, -1, + 85, 164, 43, 162, 44, -1, 86, 162, 40, -1, + 57, 3, 51, 237, 40, -1, 57, 231, 223, 220, + 40, -1, 57, 1, 40, -1, 84, 4, -1, 84, + 269, -1, 83, 37, 3, 38, 43, -1, 83, 43, + -1, 83, 37, 3, 38, 40, -1, 83, 40, -1, + 269, 43, 215, 44, -1, 269, -1, 139, -1, 88, + 37, 140, 39, 272, 38, 4, -1, 88, 37, 140, + 39, 272, 38, 43, -1, 88, 37, 140, 38, 40, + -1, -1, 144, 271, 269, 54, 143, 129, 55, -1, + 7, -1, 8, -1, 81, 4, -1, 81, 43, -1, + 4, -1, 9, 37, 262, 38, 269, -1, 9, 37, + 262, 38, 4, -1, 9, 37, 262, 38, 43, -1, + 53, 271, 262, -1, 58, 37, 262, 38, -1, 58, + 37, 38, -1, 80, 37, 3, 38, 211, 3, 40, + -1, 80, 37, 3, 38, 211, 231, 223, 40, -1, + 62, 152, 3, 51, 151, -1, 62, 152, 3, -1, + 269, -1, 4, -1, 37, 3, 38, -1, 274, -1, + 154, 223, 262, 40, -1, 154, 37, 272, 38, 223, + 256, 40, -1, 154, 37, 272, 38, 269, 40, -1, + 59, -1, 60, -1, 63, 37, 262, 38, 223, 256, + 156, -1, 63, 37, 262, 39, 273, 38, 223, 256, + 40, -1, 63, 37, 262, 157, 38, 223, 256, 156, + -1, 63, 37, 262, 39, 273, 157, 38, 223, 256, + 40, -1, 63, 37, 262, 38, 156, -1, 63, 37, + 262, 39, 273, 38, 40, -1, 63, 37, 262, 157, + 38, 156, -1, 63, 37, 262, 39, 273, 157, 38, + 40, -1, 270, -1, 40, -1, 100, 37, 212, 38, + 40, -1, 39, 262, 51, 273, -1, 39, 262, 51, + 273, 157, -1, 64, 37, 159, 38, 223, 256, 40, + -1, 212, -1, 11, 39, 215, -1, 82, 37, 161, + 38, 162, 270, -1, 82, 37, 161, 38, 162, 40, + -1, 82, 37, 161, 38, 162, 51, 164, 40, -1, + 272, -1, 164, 163, -1, 39, 164, 163, -1, 274, + -1, 231, 222, -1, 37, 212, 38, -1, 37, 212, + 38, 37, 212, 38, -1, 99, 37, 212, 38, 156, + -1, 87, 37, 263, 38, 267, 90, 216, 91, 40, + -1, 89, 269, -1, 170, -1, 174, -1, 173, -1, + -1, 41, 269, 43, 169, 129, 44, -1, 211, 231, + 223, 172, 171, -1, 40, -1, 39, 223, 172, 171, + -1, 43, -1, 220, -1, 229, 220, -1, 75, 37, + 212, 38, 220, -1, 229, 75, 37, 212, 38, 220, + -1, 211, 65, 3, 40, -1, 211, 65, 239, 43, + 240, 44, 40, -1, 211, 65, 239, 43, 240, 44, + 223, 171, -1, 211, 231, 37, 212, 38, 257, -1, + 177, -1, 181, -1, 182, -1, 189, -1, 190, -1, + 200, -1, -1, 211, 254, 264, 247, 43, 178, 193, + 44, 180, -1, -1, 211, 254, 43, 179, 193, 44, + 223, 171, -1, 40, -1, 223, 171, -1, 211, 254, + 264, 40, -1, -1, 104, 90, 185, 91, 183, 184, + -1, 104, 254, 264, -1, 170, -1, 177, -1, 197, + -1, 182, -1, 181, -1, 199, -1, 186, -1, 187, + 188, -1, 274, -1, 253, -1, 215, -1, 39, 187, + 188, -1, 274, -1, 78, 264, 40, -1, 78, 79, + 264, 40, -1, -1, 79, 264, 43, 191, 129, 44, + -1, -1, 79, 43, 192, 129, 44, -1, 79, 3, + 51, 264, 40, -1, 196, 193, -1, -1, 61, 43, + 194, 193, 44, 193, -1, 142, -1, 274, -1, -1, + 1, 195, 193, -1, 168, -1, 197, -1, 198, -1, + 201, -1, 207, -1, 199, -1, 181, -1, 202, -1, + 211, 264, 40, -1, 189, -1, 182, -1, 200, -1, + 166, -1, 167, -1, 210, -1, 141, -1, 165, -1, + 40, -1, 211, 231, 37, 212, 38, 257, -1, 124, + 266, 37, 212, 38, 208, -1, 73, 124, 266, 37, + 212, 38, 209, -1, 211, 106, 231, 228, 37, 212, + 38, 209, -1, 211, 106, 231, 115, 37, 212, 38, + 209, -1, 211, 106, 231, 37, 212, 38, 209, -1, + 76, 37, 212, 38, 43, -1, 69, 71, -1, 68, + 71, -1, 70, 71, -1, -1, 211, 254, 3, 43, + 203, 206, 40, -1, -1, 211, 254, 43, 204, 206, + 40, -1, -1, 211, 254, 264, 71, 250, 43, 205, + 40, -1, 223, -1, 274, -1, 150, -1, 136, -1, + 148, -1, 153, -1, 155, -1, 158, -1, 146, -1, + 160, -1, 134, -1, 135, -1, 137, -1, 256, 40, + -1, 256, 43, -1, 256, 40, -1, 256, 51, 237, + 40, -1, 256, 43, -1, 211, 231, 71, 243, 40, + -1, 41, -1, 41, 269, -1, 72, -1, 18, -1, + 73, -1, 74, -1, 77, -1, 274, -1, 213, -1, + 215, 214, -1, 274, -1, 39, 215, 214, -1, 274, + -1, 232, 221, -1, 104, 90, 254, 91, 254, 264, + 220, -1, 45, 45, 45, -1, 217, -1, 219, 218, + -1, 274, -1, 39, 219, 218, -1, 274, -1, 215, + -1, 244, -1, 51, 237, -1, 51, 237, 54, 243, + 55, -1, 51, 43, -1, 71, 243, -1, 274, -1, + 223, 220, -1, 226, 220, -1, 220, -1, 223, -1, + 226, -1, 274, -1, 228, 224, -1, 228, 115, 224, + -1, 225, -1, 115, 224, -1, 264, 102, 224, -1, + 228, 264, 102, 224, -1, 228, 264, 102, 115, 224, + -1, 264, 102, 115, 224, -1, 264, -1, 124, 264, + -1, 37, 264, 38, -1, 37, 228, 224, 38, -1, + 37, 264, 102, 224, 38, -1, 224, 54, 55, -1, + 224, 54, 243, 55, -1, 224, 37, 212, 38, -1, + 264, -1, 124, 264, -1, 37, 228, 225, 38, -1, + 37, 115, 225, 38, -1, 37, 264, 102, 225, 38, + -1, 225, 54, 55, -1, 225, 54, 243, 55, -1, + 225, 37, 212, 38, -1, 228, -1, 228, 227, -1, + 228, 115, -1, 228, 115, 227, -1, 227, -1, 115, + 227, -1, 115, -1, 264, 102, -1, 228, 264, 102, + -1, 228, 264, 102, 227, -1, 227, 54, 55, -1, + 227, 54, 243, 55, -1, 54, 55, -1, 54, 243, + 55, -1, 37, 226, 38, -1, 227, 37, 212, 38, + -1, 37, 212, 38, -1, 122, 229, 228, -1, 122, + 228, -1, 122, 229, -1, 122, -1, 230, -1, 230, + 229, -1, 46, -1, 47, -1, 48, -1, 232, -1, + 229, 233, -1, 233, -1, 233, 229, -1, 229, 233, + 229, -1, 234, -1, 29, -1, 27, -1, 31, 261, + -1, 65, 264, -1, 32, -1, 264, -1, 254, 264, + -1, 235, -1, 236, -1, 236, 235, -1, 19, -1, + 21, -1, 22, -1, 25, -1, 26, -1, 23, -1, + 24, -1, 28, -1, 20, -1, 30, -1, 33, -1, + 34, -1, 35, -1, 36, -1, -1, 238, 243, -1, + 3, -1, 274, -1, 240, 39, 241, -1, 241, -1, + 3, -1, 3, 51, 242, -1, 274, -1, 243, -1, + 244, -1, 231, -1, 245, -1, 269, -1, 52, 37, + 231, 221, 38, -1, 246, -1, 10, -1, 37, 243, + 38, -1, 37, 243, 38, 243, -1, 37, 243, 228, + 38, 243, -1, 37, 243, 115, 38, 243, -1, 37, + 243, 228, 115, 38, 243, -1, 115, 243, -1, 122, + 243, -1, 11, -1, 12, -1, 13, -1, 14, -1, + 15, -1, 16, -1, 17, -1, 243, 119, 243, -1, + 243, 118, 243, -1, 243, 122, 243, -1, 243, 121, + 243, -1, 243, 120, 243, -1, 243, 115, 243, -1, + 243, 113, 243, -1, 243, 114, 243, -1, 243, 117, + 243, -1, 243, 116, 243, -1, 243, 112, 243, -1, + 243, 111, 243, -1, 243, 96, 243, -1, 243, 97, + 243, -1, 243, 95, 243, -1, 243, 94, 243, -1, + 243, 98, 243, 71, 243, -1, 118, 243, -1, 119, + 243, -1, 124, 243, -1, 123, 243, -1, 231, 37, + -1, 248, -1, -1, 71, 249, 250, -1, 274, -1, + 251, -1, 250, 39, 251, -1, 255, 264, -1, 255, + 252, 255, 264, -1, 69, -1, 68, -1, 70, -1, + 66, -1, 67, -1, 253, -1, 49, -1, 50, -1, + 73, -1, 274, -1, 229, -1, 75, 37, 212, 38, + -1, 229, 75, 37, 212, 38, -1, 274, -1, 256, + 258, 40, -1, 256, 258, 43, -1, 37, 212, 38, + 40, -1, 37, 212, 38, 43, -1, 51, 237, 40, + -1, 71, 259, -1, 274, -1, 260, -1, 259, 39, + 260, -1, 264, 37, -1, 90, 216, 91, -1, 274, + -1, 3, -1, 269, -1, 262, -1, 274, -1, 266, + 265, -1, 101, 126, 266, 265, -1, 266, -1, 101, + 126, 266, -1, 105, -1, 101, 126, 105, -1, 126, + 266, 265, -1, 126, 266, -1, 126, 105, -1, 103, + 266, -1, 3, 261, -1, 3, 268, -1, 101, 126, + 3, 268, -1, 3, -1, 101, 126, 3, -1, 105, + -1, 101, 126, 105, -1, 126, 3, 268, -1, 126, + 3, -1, 126, 105, -1, 103, 3, -1, 269, 6, + -1, 6, -1, 269, -1, 43, -1, 4, -1, 37, + 272, 38, -1, 274, -1, 262, 51, 273, -1, 262, + 51, 273, 39, 272, -1, 262, -1, 262, 39, 272, + -1, 262, 51, 139, -1, 262, 51, 139, 39, 272, + -1, 269, -1, 245, -1, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 1593, 1593, 1606, 1610, 1613, 1616, 1619, 1622, 1627, + 1632, 1637, 1638, 1639, 1640, 1641, 1647, 1663, 1673, 1674, + 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, + 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1700, + 1700, 1772, 1782, 1793, 1814, 1836, 1847, 1856, 1875, 1881, + 1887, 1892, 1899, 1906, 1910, 1923, 1932, 1947, 1960, 1960, + 2015, 2016, 2023, 2043, 2074, 2078, 2088, 2093, 2111, 2151, + 2157, 2170, 2176, 2202, 2208, 2215, 2216, 2219, 2220, 2228, + 2274, 2320, 2331, 2334, 2361, 2367, 2373, 2379, 2387, 2393, + 2399, 2405, 2413, 2414, 2415, 2418, 2423, 2433, 2469, 2470, + 2500, 2517, 2525, 2538, 2563, 2569, 2573, 2576, 2587, 2592, + 2605, 2617, 2890, 2900, 2907, 2908, 2912, 2912, 2943, 3004, + 3008, 3030, 3036, 3042, 3048, 3054, 3067, 3082, 3092, 3170, + 3221, 3222, 3223, 3224, 3225, 3226, 3232, 3232, 3464, 3464, + 3586, 3587, 3599, 3619, 3619, 3854, 3860, 3863, 3866, 3869, + 3872, 3875, 3880, 3910, 3914, 3917, 3920, 3925, 3929, 3934, + 3944, 3975, 3975, 4004, 4004, 4026, 4053, 4068, 4068, 4078, + 4079, 4080, 4080, 4096, 4097, 4114, 4115, 4116, 4117, 4118, + 4119, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, + 4129, 4138, 4163, 4187, 4228, 4243, 4261, 4280, 4287, 4294, + 4302, 4325, 4325, 4360, 4360, 4391, 4391, 4409, 4410, 4416, + 4419, 4423, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, + 4436, 4441, 4448, 4456, 4464, 4475, 4481, 4482, 4490, 4491, + 4492, 4493, 4494, 4495, 4502, 4513, 4517, 4520, 4524, 4528, + 4538, 4546, 4554, 4567, 4571, 4574, 4578, 4582, 4610, 4618, + 4629, 4643, 4652, 4660, 4670, 4674, 4678, 4685, 4702, 4719, + 4727, 4735, 4744, 4748, 4757, 4768, 4780, 4790, 4803, 4810, + 4818, 4834, 4842, 4853, 4864, 4875, 4894, 4902, 4919, 4927, + 4934, 4945, 4956, 4967, 4986, 4992, 4998, 5005, 5014, 5017, + 5026, 5033, 5040, 5050, 5061, 5072, 5083, 5090, 5097, 5100, + 5117, 5127, 5134, 5140, 5145, 5151, 5155, 5161, 5162, 5163, + 5169, 5175, 5179, 5180, 5184, 5191, 5194, 5195, 5196, 5197, + 5198, 5200, 5203, 5208, 5233, 5236, 5290, 5294, 5298, 5302, + 5306, 5310, 5314, 5318, 5322, 5326, 5330, 5334, 5338, 5342, + 5348, 5348, 5374, 5375, 5378, 5391, 5399, 5407, 5424, 5427, + 5442, 5443, 5462, 5463, 5467, 5472, 5473, 5487, 5494, 5511, + 5518, 5525, 5533, 5537, 5543, 5544, 5545, 5546, 5547, 5548, + 5549, 5552, 5556, 5560, 5564, 5568, 5572, 5576, 5580, 5584, + 5588, 5592, 5596, 5600, 5604, 5618, 5625, 5629, 5635, 5639, + 5643, 5647, 5651, 5667, 5672, 5672, 5673, 5676, 5693, 5702, + 5715, 5728, 5729, 5730, 5734, 5738, 5744, 5747, 5751, 5757, + 5758, 5761, 5766, 5771, 5776, 5783, 5790, 5797, 5805, 5813, + 5821, 5822, 5825, 5826, 5829, 5835, 5841, 5844, 5845, 5848, + 5849, 5852, 5857, 5861, 5864, 5867, 5870, 5875, 5879, 5882, + 5889, 5895, 5904, 5909, 5913, 5916, 5919, 5922, 5927, 5931, + 5934, 5937, 5943, 5948, 5951, 5954, 5958, 5963, 5976, 5980, + 5985, 5991, 5995, 6000, 6004, 6011, 6014, 6019 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "ID", "HBLOCK", "POUND", "STRING", + "INCLUDE", "IMPORT", "INSERT", "CHARCONST", "NUM_INT", "NUM_FLOAT", + "NUM_UNSIGNED", "NUM_LONG", "NUM_ULONG", "NUM_LONGLONG", "NUM_ULONGLONG", + "TYPEDEF", "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", "LPAREN", "RPAREN", "COMMA", "SEMI", "EXTERN", + "INIT", "LBRACE", "RBRACE", "PERIOD", "CONST_QUAL", "VOLATILE", + "REGISTER", "STRUCT", "UNION", "EQUAL", "SIZEOF", "MODULE", "LBRACKET", + "RBRACKET", "ILLEGAL", "CONSTANT", "NAME", "RENAME", "NAMEWARN", + "EXTEND", "PRAGMA", "FEATURE", "VARARGS", "ENUM", "CLASS", "TYPENAME", + "PRIVATE", "PUBLIC", "PROTECTED", "COLON", "STATIC", "VIRTUAL", "FRIEND", + "THROW", "CATCH", "EXPLICIT", "USING", "NAMESPACE", "NATIVE", "INLINE", + "TYPEMAP", "EXCEPT", "ECHO", "APPLY", "CLEAR", "SWIGTEMPLATE", + "FRAGMENT", "WARN", "LESSTHAN", "GREATERTHAN", "MODULO", "DELETE_KW", + "LESSTHANOREQUALTO", "GREATERTHANOREQUALTO", "EQUALTO", "NOTEQUALTO", + "QUESTIONMARK", "TYPES", "PARMS", "NONID", "DSTAR", "DCNOT", "TEMPLATE", + "OPERATOR", "COPERATOR", "PARSETYPE", "PARSEPARM", "PARSEPARMS", "CAST", + "LOR", "LAND", "OR", "XOR", "AND", "RSHIFT", "LSHIFT", "MINUS", "PLUS", + "MODULUS", "SLASH", "STAR", "LNOT", "NOT", "UMINUS", "DCOLON", "$accept", + "program", "interface", "declaration", "swig_directive", + "extend_directive", "@1", "apply_directive", "clear_directive", + "constant_directive", "echo_directive", "except_directive", "stringtype", + "fname", "fragment_directive", "include_directive", "@2", "includetype", + "inline_directive", "insert_directive", "module_directive", + "name_directive", "native_directive", "pragma_directive", "pragma_arg", + "pragma_lang", "rename_directive", "rename_namewarn", + "feature_directive", "stringbracesemi", "featattr", "varargs_directive", + "varargs_parms", "typemap_directive", "typemap_type", "tm_list", + "tm_tail", "typemap_parm", "types_directive", "template_directive", + "warn_directive", "c_declaration", "@3", "c_decl", "c_decl_tail", + "initializer", "c_enum_forward_decl", "c_enum_decl", + "c_constructor_decl", "cpp_declaration", "cpp_class_decl", "@4", "@5", + "cpp_opt_declarators", "cpp_forward_class_decl", "cpp_template_decl", + "@6", "cpp_temp_possible", "template_parms", "templateparameters", + "templateparameter", "templateparameterstail", "cpp_using_decl", + "cpp_namespace_decl", "@7", "@8", "cpp_members", "@9", "@10", + "cpp_member", "cpp_constructor_decl", "cpp_destructor_decl", + "cpp_conversion_operator", "cpp_catch_decl", "cpp_protection_decl", + "cpp_nested", "@11", "@12", "@13", "nested_decl", "cpp_swig_directive", + "cpp_end", "cpp_vend", "anonymous_bitfield", "storage_class", "parms", + "rawparms", "ptail", "parm", "valparms", "rawvalparms", "valptail", + "valparm", "def_args", "parameter_declarator", + "typemap_parameter_declarator", "declarator", "notso_direct_declarator", + "direct_declarator", "abstract_declarator", "direct_abstract_declarator", + "pointer", "type_qualifier", "type_qualifier_raw", "type", "rawtype", + "type_right", "primitive_type", "primitive_type_list", "type_specifier", + "definetype", "@14", "ename", "enumlist", "edecl", "etype", "expr", + "valexpr", "exprnum", "exprcompound", "inherit", "raw_inherit", "@15", + "base_list", "base_specifier", "access_specifier", "templcpptype", + "cpptype", "opt_virtual", "cpp_const", "ctor_end", "ctor_initializer", + "mem_initializer_list", "mem_initializer", "template_decl", "idstring", + "idstringopt", "idcolon", "idcolontail", "idtemplate", "idcolonnt", + "idcolontailnt", "string", "stringbrace", "options", "kwargs", + "stringnum", "empty", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint16 yyr1[] = +{ + 0, 127, 128, 128, 128, 128, 128, 128, 128, 129, + 129, 130, 130, 130, 130, 130, 130, 130, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 133, + 132, 134, 135, 136, 136, 136, 137, 137, 138, 138, + 138, 138, 139, 140, 140, 141, 141, 141, 143, 142, + 144, 144, 145, 145, 146, 146, 146, 146, 147, 148, + 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, + 153, 153, 154, 154, 155, 155, 155, 155, 155, 155, + 155, 155, 156, 156, 156, 157, 157, 158, 159, 159, + 160, 160, 160, 161, 162, 163, 163, 164, 164, 164, + 165, 166, 167, 168, 168, 168, 169, 168, 170, 171, + 171, 171, 172, 172, 172, 172, 173, 174, 174, 175, + 176, 176, 176, 176, 176, 176, 178, 177, 179, 177, + 180, 180, 181, 183, 182, 182, 184, 184, 184, 184, + 184, 184, 185, 186, 186, 187, 187, 188, 188, 189, + 189, 191, 190, 192, 190, 190, 193, 194, 193, 193, + 193, 195, 193, 196, 196, 196, 196, 196, 196, 196, + 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, + 196, 197, 198, 198, 199, 199, 199, 200, 201, 201, + 201, 203, 202, 204, 202, 205, 202, 206, 206, 207, + 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, + 208, 208, 209, 209, 209, 210, 211, 211, 211, 211, + 211, 211, 211, 211, 212, 213, 213, 214, 214, 215, + 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, + 220, 220, 220, 220, 221, 221, 221, 222, 222, 222, + 223, 223, 223, 223, 223, 223, 223, 223, 224, 224, + 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, + 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, + 226, 226, 226, 226, 227, 227, 227, 227, 227, 227, + 227, 228, 228, 228, 228, 229, 229, 230, 230, 230, + 231, 232, 232, 232, 232, 233, 233, 233, 233, 233, + 233, 233, 233, 234, 235, 235, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 238, 237, 239, 239, 240, 240, 241, 241, 241, 242, + 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, + 244, 244, 244, 244, 245, 245, 245, 245, 245, 245, + 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, + 246, 246, 246, 247, 249, 248, 248, 250, 250, 251, + 251, 252, 252, 252, 253, 253, 254, 254, 254, 255, + 255, 256, 256, 256, 256, 257, 257, 257, 257, 257, + 258, 258, 259, 259, 260, 261, 261, 262, 262, 263, + 263, 264, 264, 264, 264, 264, 264, 265, 265, 265, + 265, 266, 267, 267, 267, 267, 267, 267, 268, 268, + 268, 268, 269, 269, 270, 270, 270, 271, 271, 272, + 272, 272, 272, 272, 272, 273, 273, 274 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 3, 2, 3, 2, 5, 3, 2, + 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 7, 5, 3, 5, 5, 3, 2, 2, 5, 2, + 5, 2, 4, 1, 1, 7, 7, 5, 0, 7, + 1, 1, 2, 2, 1, 5, 5, 5, 3, 4, + 3, 7, 8, 5, 3, 1, 1, 3, 1, 4, + 7, 6, 1, 1, 7, 9, 8, 10, 5, 7, + 6, 8, 1, 1, 5, 4, 5, 7, 1, 3, + 6, 6, 8, 1, 2, 3, 1, 2, 3, 6, + 5, 9, 2, 1, 1, 1, 0, 6, 5, 1, + 4, 1, 1, 2, 5, 6, 4, 7, 8, 6, + 1, 1, 1, 1, 1, 1, 0, 9, 0, 8, + 1, 2, 4, 0, 6, 3, 1, 1, 1, 1, + 1, 1, 1, 2, 1, 1, 1, 3, 1, 3, + 4, 0, 6, 0, 5, 5, 2, 0, 6, 1, + 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 6, 7, 8, 8, 7, 5, 2, 2, + 2, 0, 7, 0, 6, 0, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 4, 2, 5, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 3, 1, 2, + 7, 3, 1, 2, 1, 3, 1, 1, 1, 2, + 5, 2, 2, 1, 2, 2, 1, 1, 1, 1, + 2, 3, 1, 2, 3, 4, 5, 4, 1, 2, + 3, 4, 5, 3, 4, 4, 1, 2, 4, 4, + 5, 3, 4, 4, 1, 2, 2, 3, 1, 2, + 1, 2, 3, 4, 3, 4, 2, 3, 3, 4, + 3, 3, 2, 2, 1, 1, 2, 1, 1, 1, + 1, 2, 1, 2, 3, 1, 1, 1, 2, 2, + 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 2, 1, 1, 3, 1, 1, 3, 1, 1, + 1, 1, 1, 1, 5, 1, 1, 3, 4, 5, + 5, 6, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 5, 2, 2, + 2, 2, 2, 1, 0, 3, 1, 1, 3, 2, + 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 5, 1, 3, 3, 4, 4, 3, + 2, 1, 1, 3, 2, 3, 1, 1, 1, 1, + 1, 2, 4, 1, 3, 1, 3, 3, 2, 2, + 2, 2, 2, 4, 1, 3, 1, 3, 3, 2, + 2, 2, 2, 1, 1, 1, 1, 3, 1, 3, + 5, 1, 3, 3, 5, 1, 1, 0 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 467, 0, 0, 0, 0, 0, 10, 4, 467, 326, + 334, 327, 328, 331, 332, 329, 330, 317, 333, 316, + 335, 467, 320, 336, 337, 338, 339, 0, 307, 308, + 309, 407, 408, 0, 404, 405, 0, 0, 435, 0, + 0, 305, 467, 312, 315, 323, 324, 406, 0, 321, + 433, 6, 0, 0, 467, 1, 15, 64, 60, 61, + 0, 229, 14, 226, 467, 0, 0, 82, 83, 467, + 467, 0, 0, 228, 230, 231, 0, 232, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 11, 18, 19, 20, 21, 22, 23, + 24, 25, 467, 26, 27, 28, 29, 30, 31, 32, + 0, 33, 34, 35, 36, 37, 38, 12, 113, 115, + 114, 16, 13, 130, 131, 132, 133, 134, 135, 0, + 233, 467, 441, 426, 318, 0, 319, 0, 0, 3, + 311, 306, 467, 340, 0, 0, 290, 304, 0, 256, + 239, 467, 262, 467, 288, 284, 276, 253, 313, 325, + 322, 0, 0, 431, 5, 8, 0, 234, 467, 236, + 17, 0, 453, 227, 0, 0, 458, 0, 467, 0, + 310, 0, 0, 0, 0, 78, 0, 467, 467, 0, + 0, 467, 163, 0, 0, 62, 63, 0, 0, 51, + 49, 46, 47, 467, 0, 467, 0, 467, 467, 0, + 112, 467, 467, 0, 0, 0, 0, 0, 0, 276, + 467, 0, 0, 356, 364, 365, 366, 367, 368, 369, + 370, 0, 0, 0, 0, 0, 0, 0, 0, 247, + 0, 242, 467, 351, 310, 0, 350, 352, 355, 353, + 244, 241, 436, 434, 0, 314, 467, 290, 0, 0, + 284, 321, 251, 249, 0, 296, 0, 350, 252, 467, + 0, 263, 289, 268, 302, 303, 277, 254, 467, 0, + 255, 467, 0, 286, 260, 285, 268, 291, 440, 439, + 438, 0, 0, 235, 238, 427, 0, 428, 452, 116, + 461, 0, 68, 45, 340, 0, 467, 70, 0, 0, + 0, 74, 0, 0, 0, 98, 0, 0, 159, 0, + 467, 161, 0, 0, 103, 0, 0, 0, 107, 257, + 258, 259, 42, 0, 104, 106, 429, 0, 430, 54, + 0, 53, 0, 0, 152, 467, 156, 406, 154, 145, + 0, 427, 0, 0, 0, 0, 0, 0, 0, 268, + 0, 467, 0, 343, 467, 467, 138, 322, 0, 0, + 362, 388, 389, 363, 391, 390, 425, 0, 243, 246, + 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 432, 0, + 290, 284, 321, 0, 276, 300, 298, 286, 0, 276, + 291, 0, 341, 297, 284, 321, 269, 467, 0, 301, + 0, 281, 0, 0, 294, 0, 261, 287, 292, 0, + 264, 437, 7, 467, 0, 467, 0, 0, 457, 0, + 0, 69, 39, 77, 0, 0, 0, 0, 0, 0, + 0, 160, 0, 0, 467, 467, 0, 0, 108, 0, + 467, 0, 0, 0, 0, 0, 143, 0, 153, 158, + 58, 0, 0, 0, 0, 79, 0, 126, 467, 0, + 321, 0, 0, 122, 467, 0, 142, 394, 0, 393, + 396, 357, 0, 304, 0, 467, 467, 386, 385, 383, + 384, 0, 382, 381, 377, 378, 376, 380, 379, 372, + 371, 375, 374, 373, 0, 0, 291, 279, 278, 292, + 0, 0, 0, 268, 270, 291, 0, 273, 0, 283, + 282, 299, 295, 0, 265, 293, 267, 237, 66, 67, + 65, 0, 462, 463, 466, 465, 459, 43, 44, 0, + 76, 73, 75, 456, 93, 455, 0, 88, 467, 454, + 92, 0, 465, 0, 0, 99, 467, 197, 165, 164, + 0, 226, 0, 0, 50, 48, 467, 41, 105, 444, + 0, 446, 0, 57, 0, 0, 110, 467, 467, 467, + 467, 0, 0, 346, 0, 345, 348, 467, 467, 0, + 119, 121, 118, 0, 123, 171, 190, 0, 0, 0, + 0, 230, 0, 217, 218, 210, 219, 188, 169, 215, + 211, 209, 212, 213, 214, 216, 189, 185, 186, 173, + 179, 183, 182, 0, 0, 174, 175, 178, 184, 176, + 180, 177, 187, 0, 233, 467, 136, 358, 0, 304, + 303, 0, 0, 0, 245, 0, 467, 280, 250, 271, + 0, 275, 274, 266, 117, 0, 0, 0, 467, 0, + 411, 0, 414, 0, 0, 0, 0, 90, 467, 0, + 162, 227, 467, 0, 101, 0, 100, 0, 0, 0, + 442, 0, 467, 0, 52, 146, 147, 150, 149, 144, + 148, 151, 0, 157, 0, 0, 81, 0, 467, 0, + 467, 340, 467, 129, 0, 467, 467, 0, 167, 199, + 198, 200, 0, 0, 0, 166, 0, 0, 0, 321, + 409, 395, 397, 0, 410, 0, 360, 359, 0, 354, + 387, 240, 272, 464, 460, 40, 0, 467, 0, 84, + 465, 95, 89, 467, 0, 0, 97, 71, 0, 0, + 109, 451, 449, 450, 445, 447, 0, 55, 56, 0, + 59, 80, 347, 349, 344, 127, 0, 0, 0, 0, + 0, 421, 467, 0, 0, 172, 0, 0, 467, 0, + 0, 467, 0, 467, 203, 322, 181, 467, 402, 401, + 403, 467, 399, 0, 361, 0, 0, 467, 96, 0, + 91, 467, 86, 72, 102, 448, 443, 0, 128, 0, + 419, 420, 422, 0, 415, 416, 124, 120, 467, 0, + 467, 0, 139, 467, 0, 0, 0, 0, 201, 467, + 467, 398, 0, 0, 94, 412, 0, 85, 0, 111, + 417, 418, 0, 424, 125, 0, 0, 467, 0, 467, + 467, 467, 225, 467, 0, 207, 208, 0, 400, 140, + 137, 0, 413, 87, 423, 168, 467, 192, 0, 467, + 0, 0, 191, 0, 204, 205, 141, 193, 0, 220, + 221, 196, 467, 467, 202, 0, 222, 224, 340, 195, + 194, 206, 0, 223 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 4, 5, 92, 93, 94, 549, 613, 614, 615, + 616, 99, 339, 340, 617, 618, 589, 102, 103, 619, + 105, 620, 107, 621, 551, 184, 622, 110, 623, 557, + 447, 624, 314, 625, 323, 206, 334, 207, 626, 627, + 628, 629, 435, 118, 602, 482, 119, 120, 121, 122, + 123, 735, 485, 870, 630, 631, 587, 699, 343, 344, + 345, 468, 632, 127, 454, 320, 633, 786, 717, 634, + 635, 636, 637, 638, 639, 640, 863, 839, 895, 864, + 641, 877, 887, 642, 643, 258, 167, 293, 168, 240, + 241, 378, 242, 149, 150, 328, 151, 271, 152, 153, + 154, 218, 40, 41, 243, 180, 43, 44, 45, 46, + 263, 264, 362, 594, 595, 772, 245, 267, 247, 248, + 488, 489, 645, 731, 732, 801, 47, 48, 733, 888, + 713, 780, 821, 822, 132, 300, 337, 49, 163, 50, + 582, 690, 249, 560, 175, 301, 546, 169 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -550 +static const yytype_int16 yypact[] = +{ + 590, 3291, 3341, 121, 117, 2846, -550, -550, -67, -550, + -550, -550, -550, -550, -550, -550, -550, -550, -550, -550, + -550, -67, -550, -550, -550, -550, -550, 115, -550, -550, + -550, -550, -550, 191, -550, -550, 75, 161, -550, 156, + 3797, 717, 325, 717, -550, -550, 1803, -550, 191, -550, + 100, -550, 221, 227, 3549, -550, 166, -550, -550, -550, + 288, -550, -550, 318, 298, 3401, 303, -550, -550, 298, + 311, 333, 366, -550, -550, -550, 392, -550, 116, 42, + 420, 106, 431, 429, 384, 3599, 3599, 442, 455, 318, + 465, 600, -550, -550, -550, -550, -550, -550, -550, -550, + -550, -550, 298, -550, -550, -550, -550, -550, -550, -550, + 983, -550, -550, -550, -550, -550, -550, -550, -550, -550, + -550, -550, -550, -550, -550, -550, -550, -550, -550, 3648, + -550, 1740, -550, -550, -550, 296, -550, 49, 461, -550, + 717, -550, 2522, 463, 1862, 2350, 87, 241, 191, -550, + -550, 104, 323, 104, 356, 176, 252, -550, -550, -550, + -550, 518, 77, -550, -550, -550, 484, -550, 487, -550, + -550, 377, -550, 126, 377, 377, -550, 532, 108, 1003, + -550, 256, 191, 530, 571, -550, 377, 1522, 3549, 191, + 562, 129, -550, 573, 616, -550, -550, 377, 620, -550, + -550, -550, 623, 3549, 583, 228, 592, 596, 377, 318, + 623, 3549, 3549, 191, 318, 270, 381, 377, 312, 535, + 194, 1014, 85, -550, -550, -550, -550, -550, -550, -550, + -550, 2350, 610, 2350, 2350, 2350, 2350, 2350, 2350, -550, + 557, -550, 613, 621, 113, 1699, -8, -550, -550, 623, + -550, -550, -550, 100, 568, -550, 2626, 742, 615, 626, + 928, 561, -550, 614, 2350, -550, 1825, -550, 1699, 2626, + 191, 387, 356, -550, -550, 552, -550, -550, 3549, 1984, + -550, 3549, 2106, 87, 387, 356, 575, 720, -550, -550, + 100, 635, 3549, -550, -550, -550, 641, 623, -550, -550, + 330, 646, -550, -550, -550, 715, 104, -550, 649, 650, + 657, 652, 53, 667, 669, -550, 673, 684, -550, 191, + -550, -550, 688, 698, -550, 700, 703, 3599, -550, -550, + -550, -550, -550, 3599, -550, -550, -550, 705, -550, -550, + 207, 131, 706, 655, -550, 708, -550, 43, -550, -550, + 20, 317, 933, 933, 648, 722, 105, 738, 381, 681, + 720, 83, 745, -550, 2687, 625, -550, 287, 1197, 3698, + 1163, -550, -550, -550, -550, -550, -550, 1740, -550, -550, + -550, 2350, 2350, 2350, 2350, 2350, 2350, 2350, 2350, 2350, + 2350, 2350, 2350, 2350, 2350, 2350, 2350, 2350, -550, 461, + 443, 341, 689, 284, -550, -550, -550, 443, 394, 696, + 933, 2350, 1699, -550, 970, 13, -550, 3549, 2228, -550, + 752, -550, 1947, 762, -550, 2069, 387, 356, 1027, 381, + 387, -550, -550, 487, 304, -550, 377, 1212, -550, 765, + 766, -550, -550, -550, 509, 651, 1958, 770, 3549, 1003, + 779, -550, 769, 2935, -550, 865, 3599, 497, 787, 782, + 596, 281, 789, 377, 3549, 538, -550, 3549, -550, -550, + -550, 933, 299, 381, 25, -550, 874, -550, 829, 793, + 648, 801, 690, -550, 203, 1621, -550, -550, 798, -550, + -550, 2350, 1404, 2472, 15, 325, 613, 1057, 1057, 1122, + 1122, 2716, 1382, 1479, 1489, 1249, 1163, 828, 828, 692, + 692, -550, -550, -550, 191, 696, -550, -550, -550, 443, + 407, 2191, 493, 696, -550, 381, 808, -550, 2313, -550, + -550, -550, -550, 381, 387, 356, 387, -550, -550, -550, + 623, 3024, -550, 809, -550, 131, 811, -550, -550, 1621, + -550, -550, 623, -550, -550, -550, 814, -550, 674, 623, + -550, 802, 78, 265, 651, -550, 674, -550, -550, -550, + 3113, 318, 3747, 351, -550, -550, 3549, -550, -550, 213, + 736, -550, 774, -550, 818, 821, -550, 730, 708, -550, + 674, 230, 381, 816, 94, -550, -550, 823, 3549, 1003, + -550, -550, -550, 831, -550, -550, -550, 830, 813, 815, + 817, 748, 518, -550, -550, -550, -550, -550, -550, -550, + -550, -550, -550, -550, -550, -550, -550, -550, -550, -550, + -550, -550, -550, 836, 1621, -550, -550, -550, -550, -550, + -550, -550, -550, 3450, 845, 822, -550, 1699, 2350, 2472, + 2740, 2350, 852, 853, -550, 2350, 104, -550, -550, -550, + 498, -550, -550, 387, -550, 377, 377, 855, 3549, 871, + 835, 538, -550, 1212, 879, 377, 875, -550, 674, 877, + -550, 623, -1, 1003, -550, 3599, -550, 882, 912, 84, + -550, 111, 1740, 196, -550, -550, -550, -550, -550, -550, + -550, -550, 3500, -550, 3202, 884, -550, 2350, 829, 926, + 3549, -550, 851, -550, 887, 625, 3549, 1621, -550, -550, + -550, -550, 518, 889, 1003, -550, 3698, 41, 212, 890, + -550, 888, -550, 369, -550, 1621, 1699, 1699, 2350, -550, + 1837, -550, -550, -550, -550, -550, 894, 3549, 916, -550, + 623, 917, -550, 674, 948, 538, -550, -550, 918, 922, + -550, -550, 213, -550, 213, -550, 873, -550, -550, 1032, + -550, -550, -550, 1699, -550, -550, 690, 929, 931, 191, + 505, -550, 104, 690, 930, -550, 1621, 932, 3549, 690, + -15, 2687, 2350, 19, -550, 198, -550, 822, -550, -550, + -550, 822, -550, 934, 1699, 936, 949, 3549, -550, 950, + -550, 674, -550, -550, -550, -550, -550, 951, -550, 514, + -550, 953, -550, 935, -550, -550, -550, -550, 104, 956, + 3549, 959, -550, 3549, 965, 967, 972, 1618, -550, 1003, + 822, -550, 191, 978, -550, -550, 973, -550, 974, -550, + -550, -550, 191, -550, -550, 1621, 975, 674, 985, 3549, + 3549, 823, -550, 1003, 981, -550, -550, 372, -550, -550, + -550, 690, -550, -550, -550, -550, 674, -550, 543, 674, + 987, 990, -550, 996, -550, -550, -550, -550, 447, -550, + -550, -550, 674, 674, -550, 997, -550, -550, -550, -550, + -550, -550, 999, -550 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -550, -550, -314, -550, -550, -550, -550, 10, 12, 23, + 24, -550, 605, -550, 28, 30, -550, -550, -550, 35, + -550, 36, -550, 38, -550, -550, 50, -550, 54, -446, + -549, 55, -550, 63, -550, -311, 545, -84, 66, 70, + 72, 76, -550, 425, -377, 332, -550, -550, -550, -550, + 467, -550, -550, -550, -2, 5, -550, -550, -550, -550, + 588, 468, 81, -550, -550, -550, -536, -550, -550, -550, + 472, -550, 473, 90, -550, -550, -550, -550, -550, 199, + -550, -550, -375, -550, -3, 186, -550, 628, 222, 373, + -550, 570, 691, -97, 572, -550, -44, -117, -181, -112, + -121, -22, -34, -550, 576, 45, -36, -550, 1028, -550, + -286, -550, -550, -550, 365, -550, 966, -119, -410, -550, + -550, -550, -550, 236, 280, -550, -201, -33, 277, -493, + 219, -550, -550, 234, 1061, -114, -550, 739, -142, -113, + -550, -202, 726, 516, 183, -165, -409, 0 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -468 +static const yytype_int16 yytable[] = +{ + 6, 204, 129, 124, 140, 130, 453, 141, 133, 158, + 125, 347, 246, 667, 676, 95, 459, 96, 439, 586, + 155, 133, 833, 131, 253, 272, 298, 544, 97, 98, + 259, -248, 324, 100, 285, 101, 544, 563, 284, 757, + 104, 106, 157, 108, 8, 191, 42, 42, 288, 290, + 355, 524, 8, 651, 277, 109, 280, 296, 213, 111, + 112, 302, 838, 524, 176, 671, 217, 308, 113, 176, + 185, 114, 312, 679, 470, 115, 403, 116, 791, 408, + 8, 117, -155, -248, 298, 192, 126, 762, 8, 131, + 8, 445, 446, 330, 336, 128, 222, 705, 725, 42, + 834, 284, 176, 357, 712, 254, 255, 147, 8, 131, + 195, 398, 792, 275, 764, 525, 8, 55, 677, 8, + 260, 541, 53, 477, 269, 274, -342, 592, 366, -428, + 652, 250, 298, 708, -155, 306, 272, 298, 709, 285, + 570, 144, 36, 36, 259, 573, 38, 38, 431, 196, + 142, 157, -467, 157, 252, 143, 216, 259, 54, 304, + 135, 329, 427, 147, 143, 148, 426, 144, 294, 299, + 430, 403, 408, 131, 464, 145, 244, 365, 133, 8, + 319, 785, 289, 155, 145, 755, 36, 42, 36, 763, + 38, 133, 38, 353, 8, 189, 139, 361, 131, 803, + 767, 137, 808, 161, -467, 331, 36, 335, 338, 440, + 38, 270, 348, 269, 36, 793, 765, 36, 38, 131, + 363, 38, 155, 39, 52, 749, 162, 147, 146, 520, + 144, 8, 42, 42, 401, 147, 298, 148, 486, 768, + 166, 426, 379, 430, 157, 462, 463, 414, 42, 460, + 829, 138, 182, 419, 143, 794, 42, 42, 246, 295, + 809, 164, 172, 544, 751, 142, 347, 165, 483, 840, + 706, 542, 170, 351, 145, 704, 172, 36, 603, 272, + 285, 38, 144, 353, 579, 214, 427, 28, 29, 30, + 520, 283, 36, 285, 307, 36, 38, 522, 584, 38, + 270, 42, 8, 674, 675, 172, 157, 535, 538, 812, + 172, 534, 536, 36, 42, 8, 688, 38, 848, 875, + 6, 278, 517, 42, 172, 171, 42, 486, 8, 36, + -467, 484, 561, 38, 473, 174, 305, 42, 279, 689, + 181, 251, 353, 146, 8, 469, 494, 539, 183, 356, + 147, 133, 148, 239, 287, 553, 522, 172, 487, 534, + 278, 133, 142, 147, 878, 157, 514, 490, 712, 436, + 186, 36, 8, 315, 316, 38, 143, 279, 256, 144, + 295, 437, 580, 172, 8, 352, 581, 604, 201, 326, + 172, 684, 147, 281, 555, 144, 145, 342, 535, 818, + 36, 558, 685, 187, 38, 566, 827, 131, 660, 42, + 282, 797, 832, 36, 216, 885, 663, 38, 356, -467, + -467, 147, 244, 148, 417, 778, 36, 358, 590, 188, + 38, 278, 518, 294, 346, 6, 270, 798, 799, 800, + 146, 418, 36, -467, 278, 657, 38, 147, 279, 148, + 129, 124, 572, 130, 6, 130, 407, 194, 125, 650, + 335, 279, 42, 95, 420, 96, 198, 423, 197, 199, + 36, 274, 200, 155, 38, 660, 97, 98, 596, 208, + 256, 100, 36, 101, 157, 644, 38, 896, 104, 106, + 897, 108, 209, 42, 886, 157, 379, 144, 898, 723, + 743, 744, 211, 109, 891, 270, 262, 111, 112, 42, + 31, 32, 42, 550, 433, 172, 113, 899, 900, 114, + 678, 8, 291, 115, 670, 116, 292, 34, 35, 117, + 417, 659, 670, 310, 126, 417, 742, 574, 129, 124, + 575, 130, 553, 128, 172, 824, 125, 418, 825, 644, + 479, 95, 418, 96, 850, 715, 670, 851, 672, 741, + 815, 561, 816, 670, 97, 98, 672, 129, 124, 100, + 130, 101, 303, 246, 311, 125, 104, 106, 554, 108, + 95, 555, 96, 889, 702, 697, 890, 130, 469, 6, + 672, 109, 698, 97, 98, 111, 112, 672, 100, 239, + 101, 759, 318, 526, 113, 104, 106, 114, 108, 787, + 728, 115, 902, 116, 140, 650, 321, 117, 483, 322, + 109, 42, 126, 325, 111, 112, 327, 274, 419, 298, + 753, 128, 332, 113, 644, 333, 114, 360, 556, 758, + 115, 179, 116, 42, 670, 734, 117, 369, 376, 31, + 32, 126, 377, 405, 8, 553, 157, 172, 380, 399, + 128, 205, 205, 410, 406, 776, 34, 35, 411, 222, + 565, 28, 29, 30, 147, 432, 143, 428, 672, 434, + 789, 484, 133, 365, 438, 826, 585, 441, 305, 346, + 212, 554, 250, 442, 555, 443, 145, 1, 2, 3, + 481, 129, 124, 444, 130, 221, 448, 449, 596, 125, + 811, 450, 781, 42, 95, 157, 96, 644, 8, 670, + 28, 29, 30, 8, 451, 365, 455, 97, 98, 599, + 600, 854, 100, 601, 101, 644, 456, 244, 457, 104, + 106, 458, 108, 461, 465, 8, 466, 467, 61, 669, + 471, 556, 36, 672, 109, 42, 38, 356, 111, 112, + 472, 42, 687, 28, 29, 30, 216, 113, 835, 353, + 114, 571, 136, 147, 115, 148, 116, 670, 475, 142, + 117, 156, 157, 476, 714, 126, 644, 160, 478, 173, + 529, 516, 42, 133, 128, 865, 144, 734, 519, 871, + 531, 734, 73, 74, 75, 547, 548, 77, 564, 568, + 202, 672, 395, 396, 397, 210, 36, 190, 193, 865, + 38, 36, 567, 670, 576, 38, 577, 670, 157, 583, + 352, 597, 593, 42, 91, 429, 42, 147, 598, 866, + 734, 646, 670, 36, 270, 670, 661, 38, 665, 219, + 666, 668, 42, 673, 746, 644, 693, 672, 670, 670, + 710, 672, 691, 866, 692, 694, 148, 707, 716, 28, + 29, 30, 722, 718, 711, 42, 672, 8, 42, 672, + 724, 261, 8, 61, 719, 273, 720, 276, 721, -170, + 738, 739, 672, 672, 286, 730, 777, 297, 669, 745, + 297, 297, 784, 205, 42, 42, 571, 297, 747, 205, + 748, 356, 297, 754, 239, 761, 305, 756, 219, 752, + 760, 309, 779, 297, 771, 782, 788, 797, 317, 8, + 796, 8, 805, 806, 297, 341, 8, 73, 74, 75, + 350, 297, 77, 297, 156, 495, 393, 394, 395, 396, + 397, 8, 349, 807, 354, 273, 675, 359, 813, 136, + 219, 367, 814, 305, 817, 142, 775, 819, 828, 830, + 305, 820, 853, 8, 831, 36, 844, 836, 843, 38, + 36, 8, 144, 156, 38, 305, 8, 845, 810, 533, + 847, 849, 852, 846, 216, 402, 404, 857, 270, 409, + 855, 147, 859, 148, 860, 578, 8, 269, 415, 416, + 861, 872, 695, 876, 873, 305, 856, 8, 869, 858, + 215, 884, 273, 879, 144, 892, 273, 36, 893, 36, + 8, 38, 205, 38, 36, 8, 894, 901, 38, 903, + 305, 216, 543, 407, 354, 880, 881, 783, 147, 36, + 148, 364, 148, 38, 696, 588, 703, 148, 452, 700, + 701, 537, 883, 216, 269, 766, 654, 653, 496, 791, + 147, 36, 148, 774, 159, 38, 867, 841, 842, 36, + 882, 144, 134, 38, 36, 407, 874, 0, 38, 686, + 0, 404, 404, 216, 270, 474, 0, 273, 216, 273, + 147, 0, 148, 480, 36, 147, 0, 148, 38, 0, + 266, 268, 0, 0, 0, 36, 0, 0, 216, 38, + 0, 0, 0, 0, 0, 147, 0, 148, 36, 216, + 0, 0, 38, 36, 0, 0, 147, 38, 148, 0, + 515, 0, 533, 0, 0, 0, 0, 216, 683, 404, + 0, 270, 0, 523, 147, 0, 148, 0, 0, 0, + 540, 0, 297, 545, 0, 0, 0, 273, 273, 0, + 552, 559, 562, 391, 392, 393, 394, 395, 396, 397, + 0, 0, 0, 0, 219, 0, 0, 0, 219, 297, + 0, 559, 0, 0, 0, 0, 0, 368, 591, 370, + 371, 372, 373, 374, 375, 0, 0, 0, 0, 0, + 404, 219, 273, 0, 0, 273, 381, 382, 172, 727, + 0, 0, 0, 224, 225, 226, 227, 228, 229, 230, + 412, 0, 0, 0, 156, 491, 0, 0, 391, 392, + 393, 394, 395, 396, 397, 422, 0, 0, 425, 0, + 0, 0, 0, 656, 0, 0, 0, 381, 382, 383, + 384, 205, 0, 0, 273, 0, 0, 0, 0, 0, + 0, 0, 273, 0, 0, 0, 0, 0, 769, 391, + 392, 393, 394, 395, 396, 397, 0, 0, 0, 0, + 559, 381, 382, 383, 384, 385, 0, 681, 0, 559, + 0, 0, 790, 219, 0, 0, 0, 0, 386, 387, + 388, 389, 492, 391, 392, 393, 394, 395, 396, 493, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 273, 0, 0, 0, 0, 0, 0, 219, 0, + 0, 0, 0, 381, 382, 383, 384, 497, 498, 499, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 390, 391, 392, 393, 394, 395, + 396, 397, 0, 0, 0, 0, 0, 521, 0, 0, + 0, 0, 729, 0, 528, 0, 0, 0, 0, 0, + 0, 297, 297, 0, 0, 0, 0, 559, 0, 750, + 0, 297, 0, 0, 0, 0, 0, 8, 0, 0, + 172, 0, 0, 219, 223, 224, 225, 226, 227, 228, + 229, 230, 219, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 231, 648, 0, 0, 0, 0, 0, 219, 0, + 28, 29, 30, 31, 32, 0, 232, 647, 506, 513, + 0, 0, 0, 219, 0, 0, 219, 795, 0, 33, + 34, 35, 802, 0, 0, 0, 381, 382, 383, 384, + 0, 559, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 219, 387, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 36, 0, 0, 219, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 823, 233, + 0, 0, 234, 235, 0, 8, 236, 237, 238, 0, + 480, 0, 0, 313, 0, 0, 0, 0, 0, 0, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, + 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, + 30, 31, 32, 381, 382, 383, 384, 0, 219, 0, + 0, 868, 219, 381, 382, 383, 384, 33, 34, 35, + 0, 823, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 219, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 0, 0, 736, 373, 0, 737, 0, 0, + 0, 740, 605, 36, -467, 57, 37, 38, 58, 59, + 60, 0, 0, 0, 0, 0, 0, 0, 0, 61, + -467, -467, -467, -467, -467, -467, -467, -467, -467, -467, + -467, -467, -467, -467, -467, -467, -467, -467, 862, 0, + 0, 606, 63, 0, 0, -467, 0, -467, -467, -467, + -467, -467, 0, 773, 0, 0, 0, 0, 65, 66, + 67, 68, 607, 70, 71, 72, -467, -467, -467, 608, + 609, 610, 0, 73, 611, 75, 0, 76, 77, 78, + 0, 0, 0, 82, 804, 84, 85, 86, 87, 88, + 89, 0, 381, 382, 383, 384, 385, 0, 0, 0, + 90, 0, -467, 0, 0, 91, -467, -467, 0, 386, + 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 0, 0, 8, 0, 612, 172, 0, 0, 0, + 223, 224, 225, 226, 227, 228, 229, 230, 837, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 231, 0, 0, + 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, + 32, 0, 232, 381, 382, 383, 384, 385, 0, 0, + 0, 0, 0, 0, 0, 33, 34, 35, 0, 0, + 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 9, 10, 11, 12, 13, 14, 15, 16, + 0, 18, 0, 20, 0, 0, 23, 24, 25, 26, + 0, 36, 0, 0, 37, 38, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 233, 0, 0, 234, 235, + 0, 0, 236, 237, 238, 8, 0, 0, 172, 0, + 0, 0, 223, 224, 225, 226, 227, 228, 229, 230, + 413, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 231, + 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, + 30, 31, 32, 0, 232, 0, 0, 265, 0, 381, + 382, 383, 384, 385, 0, 0, 0, 33, 34, 35, + 0, 381, 382, 383, 384, 0, 386, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 386, 387, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 0, 295, 0, 36, 172, 0, 0, 38, 0, 224, + 225, 226, 227, 228, 229, 230, 0, 233, 0, 0, + 234, 235, 0, 0, 236, 237, 238, 8, 0, 0, + 172, 0, 0, 0, 223, 224, 225, 226, 227, 228, + 229, 230, 530, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 231, 0, 0, 0, 0, 0, 0, 0, 0, + 28, 29, 30, 31, 32, 0, 232, 0, 0, 421, + 0, 381, 382, 383, 384, 385, 0, 0, 0, 33, + 34, 35, 0, 0, 0, 0, 0, 0, 386, 387, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 36, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, + 0, 0, 234, 235, 0, 0, 236, 237, 238, 8, + 0, 0, 172, 0, 0, 0, 223, 224, 225, 226, + 227, 228, 229, 230, 532, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 231, 0, 0, 0, 0, 0, 0, + 0, 0, 28, 29, 30, 31, 32, 0, 232, 0, + 0, 424, 0, 381, 382, 383, 384, 385, 0, 0, + 0, 33, 34, 35, 0, 0, 0, 0, 0, 0, + 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 233, 0, 0, 234, 235, 0, 0, 236, 237, + 238, 8, 0, 0, 172, 0, 0, 0, 223, 224, + 225, 226, 227, 228, 229, 230, 658, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 231, 0, 0, 0, 0, + 0, 0, 0, 0, 28, 29, 30, 31, 32, 0, + 232, 0, 0, 527, 0, 381, 382, 383, 384, 385, + 0, 0, 0, 33, 34, 35, 0, 0, 0, 0, + 0, 0, 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, + 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 233, 0, 0, 234, 235, 0, 0, + 236, 237, 238, 8, 0, 0, 172, 0, 0, 0, + 223, 224, 225, 226, 227, 228, 229, 230, 662, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 231, 0, 0, + 0, 0, 0, 0, 0, 0, 28, 29, 30, 31, + 32, 0, 232, 0, 0, 0, 0, 381, 382, 383, + 384, 385, 0, 0, 0, 33, 34, 35, 0, 0, + 0, 0, 0, 0, 386, 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 36, 0, 0, 0, 38, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 233, 0, 0, 234, 235, + 0, 0, 236, 237, 238, 8, 0, 0, 172, 0, + 0, 0, 223, 224, 225, 226, 227, 228, 229, 230, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 231, + 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, + 30, 31, 32, 0, 232, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 256, + 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, + 30, 31, 32, 36, 0, 0, 144, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, + 234, 235, 0, 0, 649, 237, 238, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 0, 0, 37, 38, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 257, 0, 0, + 0, 0, 0, 0, 147, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 256, 0, 0, 0, 0, 0, 0, + 0, 27, 28, 29, 30, 31, 32, 0, 0, 0, + 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 33, 34, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 0, 0, 0, 36, 0, 0, + 37, 38, 27, 28, 29, 30, 31, 32, 0, 0, + 0, 400, 0, 8, 0, 0, 0, 0, 147, 0, + 0, 0, 33, 34, 35, 0, 0, 0, 0, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 655, 36, 31, + 32, 37, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 352, 0, 0, 33, 34, 35, 0, 147, + 381, 382, 383, 384, 385, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397, 0, + 0, 36, 0, 0, 0, 38, -2, 56, 0, -467, + 57, 0, 0, 58, 59, 60, 0, 0, 0, 0, + 0, 0, 147, 0, 61, -467, -467, -467, -467, -467, + -467, -467, -467, -467, -467, -467, -467, -467, -467, -467, + -467, -467, -467, 0, 0, 0, 62, 63, 0, 0, + 0, 0, -467, -467, -467, -467, -467, 0, 0, 64, + 0, 0, 0, 65, 66, 67, 68, 69, 70, 71, + 72, -467, -467, -467, 0, 0, 0, 0, 73, 74, + 75, 0, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 56, 0, -467, 57, + 0, 0, 58, 59, 60, 90, 0, -467, 0, 0, + 91, -467, 0, 61, -467, -467, -467, -467, -467, -467, + -467, -467, -467, -467, -467, -467, -467, -467, -467, -467, + -467, -467, 0, 0, 0, 62, 63, 0, 0, 569, + 0, -467, -467, -467, -467, -467, 0, 0, 64, 0, + 0, 0, 65, 66, 67, 68, 69, 70, 71, 72, + -467, -467, -467, 0, 0, 0, 0, 73, 74, 75, + 0, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 56, 0, -467, 57, 0, + 0, 58, 59, 60, 90, 0, -467, 0, 0, 91, + -467, 0, 61, -467, -467, -467, -467, -467, -467, -467, + -467, -467, -467, -467, -467, -467, -467, -467, -467, -467, + -467, 0, 0, 0, 62, 63, 0, 0, 664, 0, + -467, -467, -467, -467, -467, 0, 0, 64, 0, 0, + 0, 65, 66, 67, 68, 69, 70, 71, 72, -467, + -467, -467, 0, 0, 0, 0, 73, 74, 75, 0, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 56, 0, -467, 57, 0, 0, + 58, 59, 60, 90, 0, -467, 0, 0, 91, -467, + 0, 61, -467, -467, -467, -467, -467, -467, -467, -467, + -467, -467, -467, -467, -467, -467, -467, -467, -467, -467, + 0, 0, 0, 62, 63, 0, 0, 680, 0, -467, + -467, -467, -467, -467, 0, 0, 64, 0, 0, 0, + 65, 66, 67, 68, 69, 70, 71, 72, -467, -467, + -467, 0, 0, 0, 0, 73, 74, 75, 0, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 56, 0, -467, 57, 0, 0, 58, + 59, 60, 90, 0, -467, 0, 0, 91, -467, 0, + 61, -467, -467, -467, -467, -467, -467, -467, -467, -467, + -467, -467, -467, -467, -467, -467, -467, -467, -467, 0, + 0, 0, 62, 63, 0, 0, 0, 0, -467, -467, + -467, -467, -467, 0, 0, 64, 0, 770, 0, 65, + 66, 67, 68, 69, 70, 71, 72, -467, -467, -467, + 0, 0, 0, 0, 73, 74, 75, 0, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 7, 0, 8, 0, 0, 0, 0, 0, + 0, 90, 0, -467, 0, 0, 91, -467, 0, 0, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, + 31, 32, 51, 0, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 33, 34, 35, 0, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, + 31, 32, 36, 0, 0, 37, 38, 0, 0, 0, + 0, 0, 177, 0, 178, 0, 33, 34, 35, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, + 0, 0, 36, 0, 0, 37, 38, 28, 29, 30, + 31, 32, 0, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 33, 34, 35, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 28, 29, 30, 31, + 32, 0, 36, 8, 0, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 0, 220, 34, 35, 0, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 28, 29, 30, 31, + 32, 36, 8, 0, 0, 38, 726, 0, 0, 0, + 0, 0, 0, 0, 0, 33, 34, 35, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, + 0, 36, 8, 0, 0, 38, 726, 0, 0, 0, + 0, 0, 0, 0, 33, 34, 35, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 203, 0, 0, 0, + 0, 0, 0, 0, 0, 28, 29, 30, 31, 32, + 36, 8, 0, 37, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 34, 35, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 28, 29, 30, 31, 32, 0, + 36, 8, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 220, 34, 35, 0, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 28, 29, 30, 31, 32, 36, + 682, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 33, 34, 35, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 28, 29, 30, 31, 32, 0, 36, + 8, 0, 0, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 33, 34, 35, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 31, 32, 36, 0, + 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 33, 34, 35, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, + 0, 0, 38 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 85, 5, 5, 40, 5, 320, 41, 8, 43, + 5, 212, 131, 549, 563, 5, 327, 5, 304, 465, + 42, 21, 37, 90, 137, 146, 6, 437, 5, 5, + 142, 39, 197, 5, 155, 5, 446, 446, 155, 40, + 5, 5, 42, 5, 3, 3, 1, 2, 161, 162, + 215, 38, 3, 38, 151, 5, 153, 171, 91, 5, + 5, 175, 43, 38, 64, 558, 110, 181, 5, 69, + 70, 5, 186, 566, 54, 5, 257, 5, 37, 260, + 3, 5, 39, 91, 6, 43, 5, 3, 3, 90, + 3, 38, 39, 205, 208, 5, 129, 590, 634, 54, + 115, 218, 102, 217, 597, 138, 140, 122, 3, 90, + 4, 253, 71, 147, 3, 102, 3, 0, 564, 3, + 142, 435, 1, 40, 37, 147, 43, 102, 43, 51, + 115, 131, 6, 39, 91, 179, 257, 6, 44, 260, + 454, 54, 101, 101, 256, 456, 105, 105, 290, 43, + 37, 151, 39, 153, 105, 51, 115, 269, 37, 51, + 45, 205, 283, 122, 51, 124, 283, 54, 168, 43, + 287, 352, 353, 90, 43, 71, 131, 221, 178, 3, + 51, 717, 105, 205, 71, 678, 101, 142, 101, 105, + 105, 191, 105, 215, 3, 79, 40, 3, 90, 735, + 4, 126, 751, 103, 91, 205, 101, 207, 208, 306, + 105, 124, 212, 37, 101, 3, 105, 101, 105, 90, + 220, 105, 244, 1, 2, 671, 126, 122, 115, 410, + 54, 3, 187, 188, 256, 122, 6, 124, 40, 43, + 54, 358, 242, 360, 244, 38, 39, 269, 203, 333, + 786, 90, 69, 275, 51, 43, 211, 212, 377, 3, + 753, 40, 6, 673, 673, 37, 467, 40, 365, 71, + 40, 436, 106, 3, 71, 589, 6, 101, 75, 400, + 401, 105, 54, 305, 3, 102, 407, 46, 47, 48, + 471, 115, 101, 414, 38, 101, 105, 414, 463, 105, + 124, 256, 3, 38, 39, 6, 306, 428, 4, 755, + 6, 428, 429, 101, 269, 3, 103, 105, 811, 855, + 320, 37, 38, 278, 6, 37, 281, 40, 3, 101, + 43, 365, 446, 105, 356, 37, 37, 292, 54, 126, + 37, 45, 364, 115, 3, 345, 368, 43, 37, 37, + 122, 351, 124, 131, 102, 4, 473, 6, 71, 476, + 37, 361, 37, 122, 857, 365, 399, 367, 861, 39, + 37, 101, 3, 187, 188, 105, 51, 54, 37, 54, + 3, 51, 101, 6, 3, 115, 105, 484, 4, 203, + 6, 40, 122, 37, 43, 54, 71, 211, 519, 776, + 101, 445, 51, 37, 105, 449, 783, 90, 525, 364, + 54, 39, 789, 101, 115, 43, 533, 105, 37, 102, + 103, 122, 377, 124, 37, 711, 101, 115, 472, 37, + 105, 37, 38, 433, 212, 435, 124, 68, 69, 70, + 115, 54, 101, 126, 37, 38, 105, 122, 54, 124, + 453, 453, 455, 453, 454, 455, 115, 37, 453, 493, + 460, 54, 417, 453, 278, 453, 37, 281, 37, 40, + 101, 493, 43, 495, 105, 592, 453, 453, 478, 37, + 37, 453, 101, 453, 484, 485, 105, 40, 453, 453, + 43, 453, 37, 448, 871, 495, 496, 54, 51, 612, + 665, 666, 37, 453, 879, 124, 43, 453, 453, 464, + 49, 50, 467, 4, 292, 6, 453, 892, 893, 453, + 564, 3, 38, 453, 558, 453, 39, 66, 67, 453, + 37, 38, 566, 3, 453, 37, 38, 40, 541, 541, + 43, 541, 4, 453, 6, 40, 541, 54, 43, 549, + 364, 541, 54, 541, 40, 599, 590, 43, 558, 656, + 762, 675, 764, 597, 541, 541, 566, 570, 570, 541, + 570, 541, 40, 692, 3, 570, 541, 541, 40, 541, + 570, 43, 570, 40, 587, 587, 43, 587, 588, 589, + 590, 541, 587, 570, 570, 541, 541, 597, 570, 377, + 570, 685, 40, 417, 541, 570, 570, 541, 570, 722, + 643, 541, 898, 541, 650, 649, 43, 541, 715, 3, + 570, 576, 541, 3, 570, 570, 43, 649, 650, 6, + 674, 541, 40, 570, 634, 39, 570, 102, 100, 683, + 570, 65, 570, 598, 678, 645, 570, 37, 91, 49, + 50, 570, 39, 38, 3, 4, 656, 6, 37, 91, + 570, 85, 86, 102, 38, 709, 66, 67, 54, 702, + 448, 46, 47, 48, 122, 40, 51, 102, 678, 38, + 724, 715, 682, 727, 38, 782, 464, 38, 37, 467, + 90, 40, 692, 43, 43, 38, 71, 107, 108, 109, + 75, 704, 704, 51, 704, 129, 39, 38, 708, 704, + 754, 38, 712, 668, 704, 715, 704, 717, 3, 753, + 46, 47, 48, 3, 40, 769, 38, 704, 704, 39, + 40, 828, 704, 43, 704, 735, 38, 692, 38, 704, + 704, 38, 704, 38, 38, 3, 91, 39, 18, 75, + 102, 100, 101, 753, 704, 710, 105, 37, 704, 704, + 38, 716, 576, 46, 47, 48, 115, 704, 790, 791, + 704, 41, 33, 122, 704, 124, 704, 811, 40, 37, + 704, 42, 782, 102, 598, 704, 786, 48, 43, 63, + 38, 102, 747, 793, 704, 839, 54, 797, 102, 843, + 38, 801, 72, 73, 74, 40, 40, 77, 38, 40, + 84, 811, 120, 121, 122, 89, 101, 78, 79, 863, + 105, 101, 43, 857, 37, 105, 44, 861, 828, 40, + 115, 38, 3, 788, 104, 115, 791, 122, 37, 839, + 840, 43, 876, 101, 124, 879, 38, 105, 39, 110, + 39, 37, 807, 51, 668, 855, 38, 857, 892, 893, + 37, 861, 126, 863, 90, 44, 124, 51, 37, 46, + 47, 48, 124, 43, 51, 830, 876, 3, 833, 879, + 44, 142, 3, 18, 71, 146, 71, 148, 71, 44, + 38, 38, 892, 893, 155, 73, 710, 171, 75, 44, + 174, 175, 716, 327, 859, 860, 41, 181, 37, 333, + 75, 37, 186, 38, 692, 3, 37, 40, 179, 40, + 38, 182, 71, 197, 40, 38, 37, 39, 189, 3, + 40, 3, 38, 747, 208, 209, 3, 72, 73, 74, + 214, 215, 77, 217, 205, 369, 118, 119, 120, 121, + 122, 3, 213, 37, 215, 216, 39, 218, 40, 220, + 221, 222, 40, 37, 91, 37, 40, 38, 38, 37, + 37, 40, 37, 3, 788, 101, 40, 791, 44, 105, + 101, 3, 54, 244, 105, 37, 3, 38, 40, 115, + 40, 40, 39, 807, 115, 256, 257, 38, 124, 260, + 44, 122, 37, 124, 37, 460, 3, 37, 269, 270, + 38, 38, 587, 38, 40, 37, 830, 3, 40, 833, + 37, 40, 283, 38, 54, 38, 287, 101, 38, 101, + 3, 105, 456, 105, 101, 3, 40, 40, 105, 40, + 37, 115, 437, 115, 305, 859, 860, 715, 122, 101, + 124, 37, 124, 105, 587, 467, 588, 124, 319, 587, + 587, 433, 863, 115, 37, 692, 496, 495, 377, 37, + 122, 101, 124, 708, 46, 105, 840, 797, 801, 101, + 861, 54, 21, 105, 101, 115, 852, -1, 105, 573, + -1, 352, 353, 115, 124, 356, -1, 358, 115, 360, + 122, -1, 124, 364, 101, 122, -1, 124, 105, -1, + 144, 145, -1, -1, -1, 101, -1, -1, 115, 105, + -1, -1, -1, -1, -1, 122, -1, 124, 101, 115, + -1, -1, 105, 101, -1, -1, 122, 105, 124, -1, + 401, -1, 115, -1, -1, -1, -1, 115, 572, 410, + -1, 124, -1, 414, 122, -1, 124, -1, -1, -1, + 434, -1, 436, 437, -1, -1, -1, 428, 429, -1, + 444, 445, 446, 116, 117, 118, 119, 120, 121, 122, + -1, -1, -1, -1, 445, -1, -1, -1, 449, 463, + -1, 465, -1, -1, -1, -1, -1, 231, 472, 233, + 234, 235, 236, 237, 238, -1, -1, -1, -1, -1, + 471, 472, 473, -1, -1, 476, 94, 95, 6, 643, + -1, -1, -1, 11, 12, 13, 14, 15, 16, 17, + 264, -1, -1, -1, 495, 38, -1, -1, 116, 117, + 118, 119, 120, 121, 122, 279, -1, -1, 282, -1, + -1, -1, -1, 514, -1, -1, -1, 94, 95, 96, + 97, 685, -1, -1, 525, -1, -1, -1, -1, -1, + -1, -1, 533, -1, -1, -1, -1, -1, 702, 116, + 117, 118, 119, 120, 121, 122, -1, -1, -1, -1, + 564, 94, 95, 96, 97, 98, -1, 571, -1, 573, + -1, -1, 726, 564, -1, -1, -1, -1, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 592, -1, -1, -1, -1, -1, -1, 599, -1, + -1, -1, -1, 94, 95, 96, 97, 381, 382, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 115, 116, 117, 118, 119, 120, + 121, 122, -1, -1, -1, -1, -1, 411, -1, -1, + -1, -1, 643, -1, 418, -1, -1, -1, -1, -1, + -1, 665, 666, -1, -1, -1, -1, 671, -1, 673, + -1, 675, -1, -1, -1, -1, -1, 3, -1, -1, + 6, -1, -1, 674, 10, 11, 12, 13, 14, 15, + 16, 17, 683, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, -1, -1, -1, -1, -1, 709, -1, + 46, 47, 48, 49, 50, -1, 52, 491, 492, 493, + -1, -1, -1, 724, -1, -1, 727, 728, -1, 65, + 66, 67, 733, -1, -1, -1, 94, 95, 96, 97, + -1, 755, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 754, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 101, -1, -1, 769, 105, + -1, -1, -1, -1, -1, -1, -1, -1, 779, 115, + -1, -1, 118, 119, -1, 3, 122, 123, 124, -1, + 791, -1, -1, 11, -1, -1, -1, -1, -1, -1, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, + -1, -1, -1, -1, -1, -1, -1, 45, 46, 47, + 48, 49, 50, 94, 95, 96, 97, -1, 839, -1, + -1, 842, 843, 94, 95, 96, 97, 65, 66, 67, + -1, 852, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 863, 114, 115, 116, 117, 118, 119, 120, + 121, 122, -1, -1, 648, 649, -1, 651, -1, -1, + -1, 655, 1, 101, 3, 4, 104, 105, 7, 8, + 9, -1, -1, -1, -1, -1, -1, -1, -1, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 40, -1, + -1, 40, 41, -1, -1, 44, -1, 46, 47, 48, + 49, 50, -1, 707, -1, -1, -1, -1, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, -1, 72, 73, 74, -1, 76, 77, 78, + -1, -1, -1, 82, 738, 84, 85, 86, 87, 88, + 89, -1, 94, 95, 96, 97, 98, -1, -1, -1, + 99, -1, 101, -1, -1, 104, 105, 106, -1, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, -1, -1, 3, -1, 124, 6, -1, -1, -1, + 10, 11, 12, 13, 14, 15, 16, 17, 792, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, + -1, -1, -1, -1, -1, 45, 46, 47, 48, 49, + 50, -1, 52, 94, 95, 96, 97, 98, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, -1, -1, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 19, 20, 21, 22, 23, 24, 25, 26, + -1, 28, -1, 30, -1, -1, 33, 34, 35, 36, + -1, 101, -1, -1, 104, 105, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 115, -1, -1, 118, 119, + -1, -1, 122, 123, 124, 3, -1, -1, 6, -1, + -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, + 55, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + -1, -1, -1, -1, -1, -1, -1, -1, 46, 47, + 48, 49, 50, -1, 52, -1, -1, 55, -1, 94, + 95, 96, 97, 98, -1, -1, -1, 65, 66, 67, + -1, 94, 95, 96, 97, -1, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + -1, 3, -1, 101, 6, -1, -1, 105, -1, 11, + 12, 13, 14, 15, 16, 17, -1, 115, -1, -1, + 118, 119, -1, -1, 122, 123, 124, 3, -1, -1, + 6, -1, -1, -1, 10, 11, 12, 13, 14, 15, + 16, 17, 55, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, + 46, 47, 48, 49, 50, -1, 52, -1, -1, 55, + -1, 94, 95, 96, 97, 98, -1, -1, -1, 65, + 66, 67, -1, -1, -1, -1, -1, -1, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 101, -1, -1, -1, 105, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 115, + -1, -1, 118, 119, -1, -1, 122, 123, 124, 3, + -1, -1, 6, -1, -1, -1, 10, 11, 12, 13, + 14, 15, 16, 17, 55, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, -1, -1, -1, -1, -1, -1, + -1, -1, 46, 47, 48, 49, 50, -1, 52, -1, + -1, 55, -1, 94, 95, 96, 97, 98, -1, -1, + -1, 65, 66, 67, -1, -1, -1, -1, -1, -1, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 101, -1, -1, + -1, 105, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 115, -1, -1, 118, 119, -1, -1, 122, 123, + 124, 3, -1, -1, 6, -1, -1, -1, 10, 11, + 12, 13, 14, 15, 16, 17, 55, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, -1, -1, -1, -1, + -1, -1, -1, -1, 46, 47, 48, 49, 50, -1, + 52, -1, -1, 55, -1, 94, 95, 96, 97, 98, + -1, -1, -1, 65, 66, 67, -1, -1, -1, -1, + -1, -1, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, + -1, -1, -1, 105, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 115, -1, -1, 118, 119, -1, -1, + 122, 123, 124, 3, -1, -1, 6, -1, -1, -1, + 10, 11, 12, 13, 14, 15, 16, 17, 55, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, + -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, + 50, -1, 52, -1, -1, -1, -1, 94, 95, 96, + 97, 98, -1, -1, -1, 65, 66, 67, -1, -1, + -1, -1, -1, -1, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 101, -1, -1, -1, 105, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 115, -1, -1, 118, 119, + -1, -1, 122, 123, 124, 3, -1, -1, 6, -1, + -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + -1, -1, -1, -1, -1, -1, -1, -1, 46, 47, + 48, 49, 50, -1, 52, 3, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + -1, -1, -1, -1, -1, -1, -1, 45, 46, 47, + 48, 49, 50, 101, -1, -1, 54, 105, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 118, 119, -1, -1, 122, 123, 124, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 101, -1, -1, 104, 105, -1, 3, + -1, -1, -1, -1, -1, -1, -1, 115, -1, -1, + -1, -1, -1, -1, 122, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, -1, -1, -1, -1, -1, -1, + -1, 45, 46, 47, 48, 49, 50, -1, -1, -1, + 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 65, 66, 67, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, 101, -1, -1, + 104, 105, 45, 46, 47, 48, 49, 50, -1, -1, + -1, 115, -1, 3, -1, -1, -1, -1, 122, -1, + -1, -1, 65, 66, 67, -1, -1, -1, -1, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 71, 101, 49, + 50, 104, 105, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 115, -1, -1, 65, 66, 67, -1, 122, + 94, 95, 96, 97, 98, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, -1, + -1, 101, -1, -1, -1, 105, 0, 1, -1, 3, + 4, -1, -1, 7, 8, 9, -1, -1, -1, -1, + -1, -1, 122, -1, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, -1, -1, -1, 40, 41, -1, -1, + -1, -1, 46, 47, 48, 49, 50, -1, -1, 53, + -1, -1, -1, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, -1, -1, -1, -1, 72, 73, + 74, -1, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 1, -1, 3, 4, + -1, -1, 7, 8, 9, 99, -1, 101, -1, -1, + 104, 105, -1, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, -1, -1, 40, 41, -1, -1, 44, + -1, 46, 47, 48, 49, 50, -1, -1, 53, -1, + -1, -1, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, -1, -1, -1, -1, 72, 73, 74, + -1, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 1, -1, 3, 4, -1, + -1, 7, 8, 9, 99, -1, 101, -1, -1, 104, + 105, -1, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, -1, -1, -1, 40, 41, -1, -1, 44, -1, + 46, 47, 48, 49, 50, -1, -1, 53, -1, -1, + -1, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, -1, -1, -1, -1, 72, 73, 74, -1, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 1, -1, 3, 4, -1, -1, + 7, 8, 9, 99, -1, 101, -1, -1, 104, 105, + -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, -1, -1, 40, 41, -1, -1, 44, -1, 46, + 47, 48, 49, 50, -1, -1, 53, -1, -1, -1, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, -1, -1, -1, -1, 72, 73, 74, -1, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 1, -1, 3, 4, -1, -1, 7, + 8, 9, 99, -1, 101, -1, -1, 104, 105, -1, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, + -1, -1, 40, 41, -1, -1, -1, -1, 46, 47, + 48, 49, 50, -1, -1, 53, -1, 55, -1, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + -1, -1, -1, -1, 72, 73, 74, -1, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 1, -1, 3, -1, -1, -1, -1, -1, + -1, 99, -1, 101, -1, -1, 104, 105, -1, -1, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, -1, -1, 45, 46, 47, 48, + 49, 50, 1, -1, 3, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, -1, -1, 45, 46, 47, 48, + 49, 50, 101, -1, -1, 104, 105, -1, -1, -1, + -1, -1, 1, -1, 3, -1, 65, 66, 67, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, 101, -1, -1, 104, 105, 46, 47, 48, + 49, 50, -1, 3, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 65, 66, 67, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, + 50, -1, 101, 3, -1, -1, 105, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, -1, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 46, 47, 48, 49, + 50, 101, 3, -1, -1, 105, 106, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, + -1, -1, -1, -1, 45, 46, 47, 48, 49, 50, + -1, 101, 3, -1, -1, 105, 106, -1, -1, -1, + -1, -1, -1, -1, 65, 66, 67, -1, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, -1, -1, -1, + -1, -1, -1, -1, -1, 46, 47, 48, 49, 50, + 101, 3, -1, 104, 105, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 65, 66, 67, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 46, 47, 48, 49, 50, -1, + 101, 3, -1, -1, 105, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, -1, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 46, 47, 48, 49, 50, 101, + 3, -1, -1, 105, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 46, 47, 48, 49, 50, -1, 101, + 3, -1, -1, 105, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, -1, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 49, 50, 101, -1, + -1, -1, 105, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, + -1, -1, 105 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint16 yystos[] = +{ + 0, 107, 108, 109, 128, 129, 274, 1, 3, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 45, 46, 47, + 48, 49, 50, 65, 66, 67, 101, 104, 105, 215, + 229, 230, 232, 233, 234, 235, 236, 253, 254, 264, + 266, 1, 215, 1, 37, 0, 1, 4, 7, 8, + 9, 18, 40, 41, 53, 57, 58, 59, 60, 61, + 62, 63, 64, 72, 73, 74, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 99, 104, 130, 131, 132, 134, 135, 136, 137, 138, + 141, 142, 144, 145, 146, 147, 148, 149, 150, 153, + 154, 155, 158, 160, 165, 166, 167, 168, 170, 173, + 174, 175, 176, 177, 181, 182, 189, 190, 200, 211, + 274, 90, 261, 274, 261, 45, 264, 126, 90, 40, + 233, 229, 37, 51, 54, 71, 115, 122, 124, 220, + 221, 223, 225, 226, 227, 228, 264, 274, 229, 235, + 264, 103, 126, 265, 40, 40, 212, 213, 215, 274, + 106, 37, 6, 269, 37, 271, 274, 1, 3, 231, + 232, 37, 271, 37, 152, 274, 37, 37, 37, 79, + 264, 3, 43, 264, 37, 4, 43, 37, 37, 40, + 43, 4, 269, 37, 164, 231, 162, 164, 37, 37, + 269, 37, 90, 254, 271, 37, 115, 223, 228, 264, + 65, 231, 254, 10, 11, 12, 13, 14, 15, 16, + 17, 37, 52, 115, 118, 119, 122, 123, 124, 215, + 216, 217, 219, 231, 232, 243, 244, 245, 246, 269, + 274, 45, 105, 266, 254, 229, 37, 115, 212, 226, + 228, 264, 43, 237, 238, 55, 243, 244, 243, 37, + 124, 224, 227, 264, 228, 229, 264, 220, 37, 54, + 220, 37, 54, 115, 224, 227, 264, 102, 266, 105, + 266, 38, 39, 214, 274, 3, 262, 269, 6, 43, + 262, 272, 262, 40, 51, 37, 223, 38, 262, 264, + 3, 3, 262, 11, 159, 212, 212, 264, 40, 51, + 192, 43, 3, 161, 272, 3, 212, 43, 222, 223, + 226, 274, 40, 39, 163, 274, 262, 263, 274, 139, + 140, 269, 212, 185, 186, 187, 215, 253, 274, 264, + 269, 3, 115, 228, 264, 272, 37, 262, 115, 264, + 102, 3, 239, 274, 37, 223, 43, 264, 243, 37, + 243, 243, 243, 243, 243, 243, 91, 39, 218, 274, + 37, 94, 95, 96, 97, 98, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 265, 91, + 115, 228, 264, 225, 264, 38, 38, 115, 225, 264, + 102, 54, 243, 55, 228, 264, 264, 37, 54, 228, + 212, 55, 243, 212, 55, 243, 224, 227, 102, 115, + 224, 265, 40, 215, 38, 169, 39, 51, 38, 237, + 220, 38, 43, 38, 51, 38, 39, 157, 39, 38, + 38, 40, 264, 129, 191, 38, 38, 38, 38, 162, + 164, 38, 38, 39, 43, 38, 91, 39, 188, 274, + 54, 102, 38, 228, 264, 40, 102, 40, 43, 212, + 264, 75, 172, 220, 229, 179, 40, 71, 247, 248, + 274, 38, 115, 122, 228, 231, 219, 243, 243, 243, + 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 254, 264, 102, 38, 38, 102, + 225, 243, 224, 264, 38, 102, 212, 55, 243, 38, + 55, 38, 55, 115, 224, 227, 224, 214, 4, 43, + 269, 129, 272, 139, 245, 269, 273, 40, 40, 133, + 4, 151, 269, 4, 40, 43, 100, 156, 223, 269, + 270, 262, 269, 273, 38, 215, 223, 43, 40, 44, + 129, 41, 211, 162, 40, 43, 37, 44, 163, 3, + 101, 105, 267, 40, 272, 215, 156, 183, 187, 143, + 223, 269, 102, 3, 240, 241, 274, 38, 37, 39, + 40, 43, 171, 75, 220, 1, 40, 61, 68, 69, + 70, 73, 124, 134, 135, 136, 137, 141, 142, 146, + 148, 150, 153, 155, 158, 160, 165, 166, 167, 168, + 181, 182, 189, 193, 196, 197, 198, 199, 200, 201, + 202, 207, 210, 211, 274, 249, 43, 243, 38, 122, + 229, 38, 115, 221, 218, 71, 264, 38, 55, 38, + 224, 38, 55, 224, 44, 39, 39, 193, 37, 75, + 229, 256, 274, 51, 38, 39, 157, 156, 223, 256, + 44, 269, 3, 231, 40, 51, 270, 212, 103, 126, + 268, 126, 90, 38, 44, 170, 177, 181, 182, 184, + 197, 199, 211, 188, 129, 256, 40, 51, 39, 44, + 37, 51, 256, 257, 212, 223, 37, 195, 43, 71, + 71, 71, 124, 266, 44, 193, 106, 231, 254, 264, + 73, 250, 251, 255, 274, 178, 243, 243, 38, 38, + 243, 220, 38, 272, 272, 44, 212, 37, 75, 156, + 269, 273, 40, 223, 38, 256, 40, 40, 223, 164, + 38, 3, 3, 105, 3, 105, 216, 4, 43, 231, + 55, 40, 242, 243, 241, 40, 223, 212, 237, 71, + 258, 274, 38, 172, 212, 193, 194, 266, 37, 223, + 231, 37, 71, 3, 43, 264, 40, 39, 68, 69, + 70, 252, 264, 193, 243, 38, 212, 37, 157, 256, + 40, 223, 156, 40, 40, 268, 268, 91, 171, 38, + 40, 259, 260, 264, 40, 43, 220, 171, 38, 193, + 37, 212, 171, 37, 115, 228, 212, 243, 43, 204, + 71, 251, 255, 44, 40, 38, 212, 40, 256, 40, + 40, 43, 39, 37, 220, 44, 212, 38, 212, 37, + 37, 38, 40, 203, 206, 223, 274, 250, 264, 40, + 180, 223, 38, 40, 260, 193, 38, 208, 256, 38, + 212, 212, 257, 206, 40, 43, 171, 209, 256, 40, + 43, 209, 38, 38, 40, 205, 40, 43, 51, 209, + 209, 40, 237, 40 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 1593 "parser.y" + { + if (!classes) classes = NewHash(); + Setattr((yyvsp[(1) - (1)].node),"classes",classes); + Setattr((yyvsp[(1) - (1)].node),"name",ModuleName); + + if ((!module_node) && ModuleName) { + module_node = new_node("module"); + Setattr(module_node,"name",ModuleName); + } + Setattr((yyvsp[(1) - (1)].node),"module",module_node); + check_extensions(); + top = (yyvsp[(1) - (1)].node); + } + break; + + case 3: +#line 1606 "parser.y" + { + top = Copy(Getattr((yyvsp[(2) - (3)].p),"type")); + Delete((yyvsp[(2) - (3)].p)); + } + break; + + case 4: +#line 1610 "parser.y" + { + top = 0; + } + break; + + case 5: +#line 1613 "parser.y" + { + top = (yyvsp[(2) - (3)].p); + } + break; + + case 6: +#line 1616 "parser.y" + { + top = 0; + } + break; + + case 7: +#line 1619 "parser.y" + { + top = (yyvsp[(3) - (5)].pl); + } + break; + + case 8: +#line 1622 "parser.y" + { + top = 0; + } + break; + + case 9: +#line 1627 "parser.y" + { + /* add declaration to end of linked list (the declaration isn't always a single declaration, sometimes it is a linked list itself) */ + appendChild((yyvsp[(1) - (2)].node),(yyvsp[(2) - (2)].node)); + (yyval.node) = (yyvsp[(1) - (2)].node); + } + break; + + case 10: +#line 1632 "parser.y" + { + (yyval.node) = new_node("top"); + } + break; + + case 11: +#line 1637 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 12: +#line 1638 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 13: +#line 1639 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 14: +#line 1640 "parser.y" + { (yyval.node) = 0; } + break; + + case 15: +#line 1641 "parser.y" + { + (yyval.node) = 0; + Swig_error(cparse_file, cparse_line,"Syntax error in input(1).\n"); + exit(1); + } + break; + + case 16: +#line 1647 "parser.y" + { + if ((yyval.node)) { + add_symbols((yyval.node)); + } + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 17: +#line 1663 "parser.y" + { + (yyval.node) = 0; + skip_decl(); + } + break; + + case 18: +#line 1673 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 19: +#line 1674 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 20: +#line 1675 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 21: +#line 1676 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 22: +#line 1677 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 23: +#line 1678 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 24: +#line 1679 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 25: +#line 1680 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 26: +#line 1681 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 27: +#line 1682 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 28: +#line 1683 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 29: +#line 1684 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 30: +#line 1685 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 31: +#line 1686 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 32: +#line 1687 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 33: +#line 1688 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 34: +#line 1689 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 35: +#line 1690 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 36: +#line 1691 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 37: +#line 1692 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 38: +#line 1693 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 39: +#line 1700 "parser.y" + { + Node *cls; + String *clsname; + cplus_mode = CPLUS_PUBLIC; + if (!classes) classes = NewHash(); + if (!extendhash) extendhash = NewHash(); + clsname = make_class_name((yyvsp[(3) - (4)].str)); + cls = Getattr(classes,clsname); + if (!cls) { + /* No previous definition. Create a new scope */ + Node *am = Getattr(extendhash,clsname); + if (!am) { + Swig_symbol_newscope(); + Swig_symbol_setscopename((yyvsp[(3) - (4)].str)); + prev_symtab = 0; + } else { + prev_symtab = Swig_symbol_setscope(Getattr(am,"symtab")); + } + current_class = 0; + } else { + /* Previous class definition. Use its symbol table */ + prev_symtab = Swig_symbol_setscope(Getattr(cls,"symtab")); + current_class = cls; + extendmode = 1; + } + Classprefix = NewString((yyvsp[(3) - (4)].str)); + Namespaceprefix= Swig_symbol_qualifiedscopename(0); + Delete(clsname); + } + break; + + case 40: +#line 1728 "parser.y" + { + String *clsname; + extendmode = 0; + (yyval.node) = new_node("extend"); + Setattr((yyval.node),"symtab",Swig_symbol_popscope()); + if (prev_symtab) { + Swig_symbol_setscope(prev_symtab); + } + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + clsname = make_class_name((yyvsp[(3) - (7)].str)); + Setattr((yyval.node),"name",clsname); + + /* Mark members as extend */ + + tag_nodes((yyvsp[(6) - (7)].node),"feature:extend",(char*) "1"); + if (current_class) { + /* We add the extension to the previously defined class */ + appendChild((yyval.node),(yyvsp[(6) - (7)].node)); + appendChild(current_class,(yyval.node)); + } else { + /* We store the extensions in the extensions hash */ + Node *am = Getattr(extendhash,clsname); + if (am) { + /* Append the members to the previous extend methods */ + appendChild(am,(yyvsp[(6) - (7)].node)); + } else { + appendChild((yyval.node),(yyvsp[(6) - (7)].node)); + Setattr(extendhash,clsname,(yyval.node)); + } + } + current_class = 0; + Delete(Classprefix); + Delete(clsname); + Classprefix = 0; + prev_symtab = 0; + (yyval.node) = 0; + + } + break; + + case 41: +#line 1772 "parser.y" + { + (yyval.node) = new_node("apply"); + Setattr((yyval.node),"pattern",Getattr((yyvsp[(2) - (5)].p),"pattern")); + appendChild((yyval.node),(yyvsp[(4) - (5)].p)); + } + break; + + case 42: +#line 1782 "parser.y" + { + (yyval.node) = new_node("clear"); + appendChild((yyval.node),(yyvsp[(2) - (3)].p)); + } + break; + + case 43: +#line 1793 "parser.y" + { + if (((yyvsp[(4) - (5)].dtype).type != T_ERROR) && ((yyvsp[(4) - (5)].dtype).type != T_SYMBOL)) { + SwigType *type = NewSwigType((yyvsp[(4) - (5)].dtype).type); + (yyval.node) = new_node("constant"); + Setattr((yyval.node),"name",(yyvsp[(2) - (5)].id)); + Setattr((yyval.node),"type",type); + Setattr((yyval.node),"value",(yyvsp[(4) - (5)].dtype).val); + if ((yyvsp[(4) - (5)].dtype).rawval) Setattr((yyval.node),"rawval", (yyvsp[(4) - (5)].dtype).rawval); + Setattr((yyval.node),"storage","%constant"); + SetFlag((yyval.node),"feature:immutable"); + add_symbols((yyval.node)); + Delete(type); + } else { + if ((yyvsp[(4) - (5)].dtype).type == T_ERROR) { + Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line,"Unsupported constant value (ignored)\n"); + } + (yyval.node) = 0; + } + + } + break; + + case 44: +#line 1814 "parser.y" + { + if (((yyvsp[(4) - (5)].dtype).type != T_ERROR) && ((yyvsp[(4) - (5)].dtype).type != T_SYMBOL)) { + SwigType_push((yyvsp[(2) - (5)].type),(yyvsp[(3) - (5)].decl).type); + /* Sneaky callback function trick */ + if (SwigType_isfunction((yyvsp[(2) - (5)].type))) { + SwigType_add_pointer((yyvsp[(2) - (5)].type)); + } + (yyval.node) = new_node("constant"); + Setattr((yyval.node),"name",(yyvsp[(3) - (5)].decl).id); + Setattr((yyval.node),"type",(yyvsp[(2) - (5)].type)); + Setattr((yyval.node),"value",(yyvsp[(4) - (5)].dtype).val); + if ((yyvsp[(4) - (5)].dtype).rawval) Setattr((yyval.node),"rawval", (yyvsp[(4) - (5)].dtype).rawval); + Setattr((yyval.node),"storage","%constant"); + SetFlag((yyval.node),"feature:immutable"); + add_symbols((yyval.node)); + } else { + if ((yyvsp[(4) - (5)].dtype).type == T_ERROR) { + Swig_warning(WARN_PARSE_UNSUPPORTED_VALUE,cparse_file,cparse_line,"Unsupported constant value\n"); + } + (yyval.node) = 0; + } + } + break; + + case 45: +#line 1836 "parser.y" + { + Swig_warning(WARN_PARSE_BAD_VALUE,cparse_file,cparse_line,"Bad constant value (ignored).\n"); + (yyval.node) = 0; + } + break; + + case 46: +#line 1847 "parser.y" + { + char temp[64]; + Replace((yyvsp[(2) - (2)].str),"$file",cparse_file, DOH_REPLACE_ANY); + sprintf(temp,"%d", cparse_line); + Replace((yyvsp[(2) - (2)].str),"$line",temp,DOH_REPLACE_ANY); + Printf(stderr,"%s\n", (yyvsp[(2) - (2)].str)); + Delete((yyvsp[(2) - (2)].str)); + (yyval.node) = 0; + } + break; + + case 47: +#line 1856 "parser.y" + { + char temp[64]; + String *s = NewString((yyvsp[(2) - (2)].id)); + 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); + (yyval.node) = 0; + } + break; + + case 48: +#line 1875 "parser.y" + { + skip_balanced('{','}'); + (yyval.node) = 0; + Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); + } + break; + + case 49: +#line 1881 "parser.y" + { + skip_balanced('{','}'); + (yyval.node) = 0; + Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); + } + break; + + case 50: +#line 1887 "parser.y" + { + (yyval.node) = 0; + Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); + } + break; + + case 51: +#line 1892 "parser.y" + { + (yyval.node) = 0; + Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated. Use %%exception instead.\n"); + } + break; + + case 52: +#line 1899 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"value",(yyvsp[(1) - (4)].id)); + Setattr((yyval.node),"type",Getattr((yyvsp[(3) - (4)].p),"type")); + } + break; + + case 53: +#line 1906 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"value",(yyvsp[(1) - (1)].id)); + } + break; + + case 54: +#line 1910 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 55: +#line 1923 "parser.y" + { + Hash *p = (yyvsp[(5) - (7)].node); + (yyval.node) = new_node("fragment"); + Setattr((yyval.node),"value",Getattr((yyvsp[(3) - (7)].node),"value")); + Setattr((yyval.node),"type",Getattr((yyvsp[(3) - (7)].node),"type")); + Setattr((yyval.node),"section",Getattr(p,"name")); + Setattr((yyval.node),"kwargs",nextSibling(p)); + Setattr((yyval.node),"code",(yyvsp[(7) - (7)].str)); + } + break; + + case 56: +#line 1932 "parser.y" + { + Hash *p = (yyvsp[(5) - (7)].node); + String *code; + skip_balanced('{','}'); + (yyval.node) = new_node("fragment"); + Setattr((yyval.node),"value",Getattr((yyvsp[(3) - (7)].node),"value")); + Setattr((yyval.node),"type",Getattr((yyvsp[(3) - (7)].node),"type")); + Setattr((yyval.node),"section",Getattr(p,"name")); + Setattr((yyval.node),"kwargs",nextSibling(p)); + Delitem(scanner_ccode,0); + Delitem(scanner_ccode,DOH_END); + code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + break; + + case 57: +#line 1947 "parser.y" + { + (yyval.node) = new_node("fragment"); + Setattr((yyval.node),"value",Getattr((yyvsp[(3) - (5)].node),"value")); + Setattr((yyval.node),"type",Getattr((yyvsp[(3) - (5)].node),"type")); + Setattr((yyval.node),"emitonly","1"); + } + break; + + case 58: +#line 1960 "parser.y" + { + (yyvsp[(1) - (4)].loc).filename = Copy(cparse_file); + (yyvsp[(1) - (4)].loc).line = cparse_line; + scanner_set_location(NewString((yyvsp[(3) - (4)].id)),1); + if ((yyvsp[(2) - (4)].node)) { + String *maininput = Getattr((yyvsp[(2) - (4)].node), "maininput"); + if (maininput) + scanner_set_main_input_file(NewString(maininput)); + } + } + break; + + case 59: +#line 1969 "parser.y" + { + String *mname = 0; + (yyval.node) = (yyvsp[(6) - (7)].node); + scanner_set_location((yyvsp[(1) - (7)].loc).filename,(yyvsp[(1) - (7)].loc).line); + if (strcmp((yyvsp[(1) - (7)].loc).type,"include") == 0) set_nodeType((yyval.node),"include"); + if (strcmp((yyvsp[(1) - (7)].loc).type,"import") == 0) { + mname = (yyvsp[(2) - (7)].node) ? Getattr((yyvsp[(2) - (7)].node),"module") : 0; + set_nodeType((yyval.node),"import"); + if (import_mode) --import_mode; + } + + Setattr((yyval.node),"name",(yyvsp[(3) - (7)].id)); + /* Search for the module (if any) */ + { + Node *n = firstChild((yyval.node)); + while (n) { + if (Strcmp(nodeType(n),"module") == 0) { + if (mname) { + Setattr(n,"name", mname); + mname = 0; + } + Setattr((yyval.node),"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); + appendChild(nint,mnode); + Delete(mnode); + appendChild(nint,firstChild((yyval.node))); + (yyval.node) = nint; + Setattr((yyval.node),"module",mname); + } + } + Setattr((yyval.node),"options",(yyvsp[(2) - (7)].node)); + } + break; + + case 60: +#line 2015 "parser.y" + { (yyval.loc).type = (char *) "include"; } + break; + + case 61: +#line 2016 "parser.y" + { (yyval.loc).type = (char *) "import"; ++import_mode;} + break; + + case 62: +#line 2023 "parser.y" + { + String *cpps; + if (Namespaceprefix) { + Swig_error(cparse_file, cparse_start_line, "%%inline directive inside a namespace is disallowed.\n"); + + (yyval.node) = 0; + } else { + (yyval.node) = new_node("insert"); + Setattr((yyval.node),"code",(yyvsp[(2) - (2)].str)); + /* Need to run through the preprocessor */ + Setline((yyvsp[(2) - (2)].str),cparse_start_line); + Setfile((yyvsp[(2) - (2)].str),cparse_file); + Seek((yyvsp[(2) - (2)].str),0,SEEK_SET); + cpps = Preprocessor_parse((yyvsp[(2) - (2)].str)); + start_inline(Char(cpps), cparse_start_line); + Delete((yyvsp[(2) - (2)].str)); + Delete(cpps); + } + + } + break; + + case 63: +#line 2043 "parser.y" + { + 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"); + + (yyval.node) = 0; + } else { + String *code; + (yyval.node) = new_node("insert"); + Delitem(scanner_ccode,0); + Delitem(scanner_ccode,DOH_END); + code = Copy(scanner_ccode); + Setattr((yyval.node),"code", code); + Delete(code); + cpps=Copy(scanner_ccode); + start_inline(Char(cpps), start_line); + Delete(cpps); + } + } + break; + + case 64: +#line 2074 "parser.y" + { + (yyval.node) = new_node("insert"); + Setattr((yyval.node),"code",(yyvsp[(1) - (1)].str)); + } + break; + + case 65: +#line 2078 "parser.y" + { + String *code = NewStringEmpty(); + (yyval.node) = new_node("insert"); + Setattr((yyval.node),"section",(yyvsp[(3) - (5)].id)); + Setattr((yyval.node),"code",code); + if (Swig_insert_file((yyvsp[(5) - (5)].id),code) < 0) { + Swig_error(cparse_file, cparse_line, "Couldn't find '%s'.\n", (yyvsp[(5) - (5)].id)); + (yyval.node) = 0; + } + } + break; + + case 66: +#line 2088 "parser.y" + { + (yyval.node) = new_node("insert"); + Setattr((yyval.node),"section",(yyvsp[(3) - (5)].id)); + Setattr((yyval.node),"code",(yyvsp[(5) - (5)].str)); + } + break; + + case 67: +#line 2093 "parser.y" + { + String *code; + skip_balanced('{','}'); + (yyval.node) = new_node("insert"); + Setattr((yyval.node),"section",(yyvsp[(3) - (5)].id)); + Delitem(scanner_ccode,0); + Delitem(scanner_ccode,DOH_END); + code = Copy(scanner_ccode); + Setattr((yyval.node),"code", code); + Delete(code); + } + break; + + case 68: +#line 2111 "parser.y" + { + (yyval.node) = new_node("module"); + if ((yyvsp[(2) - (3)].node)) { + Setattr((yyval.node),"options",(yyvsp[(2) - (3)].node)); + if (Getattr((yyvsp[(2) - (3)].node),"directors")) { + Wrapper_director_mode_set(1); + } + if (Getattr((yyvsp[(2) - (3)].node),"dirprot")) { + Wrapper_director_protected_mode_set(1); + } + if (Getattr((yyvsp[(2) - (3)].node),"allprotected")) { + Wrapper_all_protected_mode_set(1); + } + if (Getattr((yyvsp[(2) - (3)].node),"templatereduce")) { + template_reduce = 1; + } + if (Getattr((yyvsp[(2) - (3)].node),"notemplatereduce")) { + template_reduce = 0; + } + } + if (!ModuleName) ModuleName = NewString((yyvsp[(3) - (3)].id)); + if (!import_mode) { + /* first module included, we apply global + ModuleName, which can be modify by -module */ + String *mname = Copy(ModuleName); + Setattr((yyval.node),"name",mname); + Delete(mname); + } else { + /* import mode, we just pass the idstring */ + Setattr((yyval.node),"name",(yyvsp[(3) - (3)].id)); + } + if (!module_node) module_node = (yyval.node); + } + break; + + case 69: +#line 2151 "parser.y" + { + Swig_warning(WARN_DEPRECATED_NAME,cparse_file,cparse_line, "%%name is deprecated. Use %%rename instead.\n"); + Delete(yyrename); + yyrename = NewString((yyvsp[(3) - (4)].id)); + (yyval.node) = 0; + } + break; + + case 70: +#line 2157 "parser.y" + { + Swig_warning(WARN_DEPRECATED_NAME,cparse_file,cparse_line, "%%name is deprecated. Use %%rename instead.\n"); + (yyval.node) = 0; + Swig_error(cparse_file,cparse_line,"Missing argument to %%name directive.\n"); + } + break; + + case 71: +#line 2170 "parser.y" + { + (yyval.node) = new_node("native"); + Setattr((yyval.node),"name",(yyvsp[(3) - (7)].id)); + Setattr((yyval.node),"wrap:name",(yyvsp[(6) - (7)].id)); + add_symbols((yyval.node)); + } + break; + + case 72: +#line 2176 "parser.y" + { + if (!SwigType_isfunction((yyvsp[(7) - (8)].decl).type)) { + Swig_error(cparse_file,cparse_line,"%%native declaration '%s' is not a function.\n", (yyvsp[(7) - (8)].decl).id); + (yyval.node) = 0; + } else { + Delete(SwigType_pop_function((yyvsp[(7) - (8)].decl).type)); + /* Need check for function here */ + SwigType_push((yyvsp[(6) - (8)].type),(yyvsp[(7) - (8)].decl).type); + (yyval.node) = new_node("native"); + Setattr((yyval.node),"name",(yyvsp[(3) - (8)].id)); + Setattr((yyval.node),"wrap:name",(yyvsp[(7) - (8)].decl).id); + Setattr((yyval.node),"type",(yyvsp[(6) - (8)].type)); + Setattr((yyval.node),"parms",(yyvsp[(7) - (8)].decl).parms); + Setattr((yyval.node),"decl",(yyvsp[(7) - (8)].decl).type); + } + add_symbols((yyval.node)); + } + break; + + case 73: +#line 2202 "parser.y" + { + (yyval.node) = new_node("pragma"); + Setattr((yyval.node),"lang",(yyvsp[(2) - (5)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (5)].id)); + Setattr((yyval.node),"value",(yyvsp[(5) - (5)].str)); + } + break; + + case 74: +#line 2208 "parser.y" + { + (yyval.node) = new_node("pragma"); + Setattr((yyval.node),"lang",(yyvsp[(2) - (3)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (3)].id)); + } + break; + + case 75: +#line 2215 "parser.y" + { (yyval.str) = NewString((yyvsp[(1) - (1)].id)); } + break; + + case 76: +#line 2216 "parser.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); } + break; + + case 77: +#line 2219 "parser.y" + { (yyval.id) = (yyvsp[(2) - (3)].id); } + break; + + case 78: +#line 2220 "parser.y" + { (yyval.id) = (char *) "swig"; } + break; + + case 79: +#line 2228 "parser.y" + { + SwigType *t = (yyvsp[(2) - (4)].decl).type; + Hash *kws = NewHash(); + String *fixname; + fixname = feature_identifier_fix((yyvsp[(2) - (4)].decl).id); + Setattr(kws,"name",(yyvsp[(3) - (4)].id)); + 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 ((yyvsp[(1) - (4)].ivalue)) { + Swig_name_rename_add(Namespaceprefix, nname,decl,kws,(yyvsp[(2) - (4)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,nname,decl,kws); + } + Delete(nname); + } else { + if ((yyvsp[(1) - (4)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(fixname),decl,kws,(yyvsp[(2) - (4)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,(fixname),decl,kws); + } + } + Delete(decl); + } else if (SwigType_ispointer(t)) { + String *nname = NewStringf("*%s",fixname); + if ((yyvsp[(1) - (4)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(nname),0,kws,(yyvsp[(2) - (4)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,(nname),0,kws); + } + Delete(nname); + } + } else { + if ((yyvsp[(1) - (4)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(fixname),0,kws,(yyvsp[(2) - (4)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,(fixname),0,kws); + } + } + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 80: +#line 2274 "parser.y" + { + String *fixname; + Hash *kws = (yyvsp[(3) - (7)].node); + SwigType *t = (yyvsp[(5) - (7)].decl).type; + fixname = feature_identifier_fix((yyvsp[(5) - (7)].decl).id); + if (!Len(t)) t = 0; + /* Special declarator check */ + if (t) { + if ((yyvsp[(6) - (7)].dtype).qualifier) SwigType_push(t,(yyvsp[(6) - (7)].dtype).qualifier); + if (SwigType_isfunction(t)) { + SwigType *decl = SwigType_pop_function(t); + if (SwigType_ispointer(t)) { + String *nname = NewStringf("*%s",fixname); + if ((yyvsp[(1) - (7)].ivalue)) { + Swig_name_rename_add(Namespaceprefix, nname,decl,kws,(yyvsp[(5) - (7)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,nname,decl,kws); + } + Delete(nname); + } else { + if ((yyvsp[(1) - (7)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(fixname),decl,kws,(yyvsp[(5) - (7)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,(fixname),decl,kws); + } + } + Delete(decl); + } else if (SwigType_ispointer(t)) { + String *nname = NewStringf("*%s",fixname); + if ((yyvsp[(1) - (7)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(nname),0,kws,(yyvsp[(5) - (7)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,(nname),0,kws); + } + Delete(nname); + } + } else { + if ((yyvsp[(1) - (7)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(fixname),0,kws,(yyvsp[(5) - (7)].decl).parms); + } else { + Swig_name_namewarn_add(Namespaceprefix,(fixname),0,kws); + } + } + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 81: +#line 2320 "parser.y" + { + if ((yyvsp[(1) - (6)].ivalue)) { + Swig_name_rename_add(Namespaceprefix,(yyvsp[(5) - (6)].id),0,(yyvsp[(3) - (6)].node),0); + } else { + Swig_name_namewarn_add(Namespaceprefix,(yyvsp[(5) - (6)].id),0,(yyvsp[(3) - (6)].node)); + } + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 82: +#line 2331 "parser.y" + { + (yyval.ivalue) = 1; + } + break; + + case 83: +#line 2334 "parser.y" + { + (yyval.ivalue) = 0; + } + break; + + case 84: +#line 2361 "parser.y" + { + String *val = (yyvsp[(7) - (7)].str) ? NewString((yyvsp[(7) - (7)].str)) : NewString("1"); + new_feature((yyvsp[(3) - (7)].id), val, 0, (yyvsp[(5) - (7)].decl).id, (yyvsp[(5) - (7)].decl).type, (yyvsp[(5) - (7)].decl).parms, (yyvsp[(6) - (7)].dtype).qualifier); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 85: +#line 2367 "parser.y" + { + String *val = Len((yyvsp[(5) - (9)].id)) ? NewString((yyvsp[(5) - (9)].id)) : 0; + new_feature((yyvsp[(3) - (9)].id), val, 0, (yyvsp[(7) - (9)].decl).id, (yyvsp[(7) - (9)].decl).type, (yyvsp[(7) - (9)].decl).parms, (yyvsp[(8) - (9)].dtype).qualifier); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 86: +#line 2373 "parser.y" + { + String *val = (yyvsp[(8) - (8)].str) ? NewString((yyvsp[(8) - (8)].str)) : NewString("1"); + new_feature((yyvsp[(3) - (8)].id), val, (yyvsp[(4) - (8)].node), (yyvsp[(6) - (8)].decl).id, (yyvsp[(6) - (8)].decl).type, (yyvsp[(6) - (8)].decl).parms, (yyvsp[(7) - (8)].dtype).qualifier); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 87: +#line 2379 "parser.y" + { + String *val = Len((yyvsp[(5) - (10)].id)) ? NewString((yyvsp[(5) - (10)].id)) : 0; + new_feature((yyvsp[(3) - (10)].id), val, (yyvsp[(6) - (10)].node), (yyvsp[(8) - (10)].decl).id, (yyvsp[(8) - (10)].decl).type, (yyvsp[(8) - (10)].decl).parms, (yyvsp[(9) - (10)].dtype).qualifier); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 88: +#line 2387 "parser.y" + { + String *val = (yyvsp[(5) - (5)].str) ? NewString((yyvsp[(5) - (5)].str)) : NewString("1"); + new_feature((yyvsp[(3) - (5)].id), val, 0, 0, 0, 0, 0); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 89: +#line 2393 "parser.y" + { + String *val = Len((yyvsp[(5) - (7)].id)) ? NewString((yyvsp[(5) - (7)].id)) : 0; + new_feature((yyvsp[(3) - (7)].id), val, 0, 0, 0, 0, 0); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 90: +#line 2399 "parser.y" + { + String *val = (yyvsp[(6) - (6)].str) ? NewString((yyvsp[(6) - (6)].str)) : NewString("1"); + new_feature((yyvsp[(3) - (6)].id), val, (yyvsp[(4) - (6)].node), 0, 0, 0, 0); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 91: +#line 2405 "parser.y" + { + String *val = Len((yyvsp[(5) - (8)].id)) ? NewString((yyvsp[(5) - (8)].id)) : 0; + new_feature((yyvsp[(3) - (8)].id), val, (yyvsp[(6) - (8)].node), 0, 0, 0, 0); + (yyval.node) = 0; + scanner_clear_rename(); + } + break; + + case 92: +#line 2413 "parser.y" + { (yyval.str) = (yyvsp[(1) - (1)].str); } + break; + + case 93: +#line 2414 "parser.y" + { (yyval.str) = 0; } + break; + + case 94: +#line 2415 "parser.y" + { (yyval.str) = (yyvsp[(3) - (5)].pl); } + break; + + case 95: +#line 2418 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"name",(yyvsp[(2) - (4)].id)); + Setattr((yyval.node),"value",(yyvsp[(4) - (4)].id)); + } + break; + + case 96: +#line 2423 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"name",(yyvsp[(2) - (5)].id)); + Setattr((yyval.node),"value",(yyvsp[(4) - (5)].id)); + set_nextSibling((yyval.node),(yyvsp[(5) - (5)].node)); + } + break; + + case 97: +#line 2433 "parser.y" + { + Parm *val; + String *name; + SwigType *t; + if (Namespaceprefix) name = NewStringf("%s::%s", Namespaceprefix, (yyvsp[(5) - (7)].decl).id); + else name = NewString((yyvsp[(5) - (7)].decl).id); + val = (yyvsp[(3) - (7)].pl); + if ((yyvsp[(5) - (7)].decl).parms) { + Setmeta(val,"parms",(yyvsp[(5) - (7)].decl).parms); + } + t = (yyvsp[(5) - (7)].decl).type; + if (!Len(t)) t = 0; + if (t) { + if ((yyvsp[(6) - (7)].dtype).qualifier) SwigType_push(t,(yyvsp[(6) - (7)].dtype).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); + (yyval.node) = 0; + } + break; + + case 98: +#line 2469 "parser.y" + { (yyval.pl) = (yyvsp[(1) - (1)].pl); } + break; + + case 99: +#line 2470 "parser.y" + { + int i; + int n; + Parm *p; + n = atoi(Char((yyvsp[(1) - (3)].dtype).val)); + if (n <= 0) { + Swig_error(cparse_file, cparse_line,"Argument count in %%varargs must be positive.\n"); + (yyval.pl) = 0; + } else { + (yyval.pl) = Copy((yyvsp[(3) - (3)].p)); + Setattr((yyval.pl),"name","VARARGS_SENTINEL"); + for (i = 0; i < n; i++) { + p = Copy((yyvsp[(3) - (3)].p)); + set_nextSibling(p,(yyval.pl)); + Delete((yyval.pl)); + (yyval.pl) = p; + } + } + } + break; + + case 100: +#line 2500 "parser.y" + { + (yyval.node) = 0; + if ((yyvsp[(3) - (6)].tmap).method) { + String *code = 0; + (yyval.node) = new_node("typemap"); + Setattr((yyval.node),"method",(yyvsp[(3) - (6)].tmap).method); + if ((yyvsp[(3) - (6)].tmap).kwargs) { + ParmList *kw = (yyvsp[(3) - (6)].tmap).kwargs; + code = remove_block(kw, (yyvsp[(6) - (6)].str)); + Setattr((yyval.node),"kwargs", (yyvsp[(3) - (6)].tmap).kwargs); + } + code = code ? code : NewString((yyvsp[(6) - (6)].str)); + Setattr((yyval.node),"code", code); + Delete(code); + appendChild((yyval.node),(yyvsp[(5) - (6)].p)); + } + } + break; + + case 101: +#line 2517 "parser.y" + { + (yyval.node) = 0; + if ((yyvsp[(3) - (6)].tmap).method) { + (yyval.node) = new_node("typemap"); + Setattr((yyval.node),"method",(yyvsp[(3) - (6)].tmap).method); + appendChild((yyval.node),(yyvsp[(5) - (6)].p)); + } + } + break; + + case 102: +#line 2525 "parser.y" + { + (yyval.node) = 0; + if ((yyvsp[(3) - (8)].tmap).method) { + (yyval.node) = new_node("typemapcopy"); + Setattr((yyval.node),"method",(yyvsp[(3) - (8)].tmap).method); + Setattr((yyval.node),"pattern", Getattr((yyvsp[(7) - (8)].p),"pattern")); + appendChild((yyval.node),(yyvsp[(5) - (8)].p)); + } + } + break; + + case 103: +#line 2538 "parser.y" + { + Hash *p; + String *name; + p = nextSibling((yyvsp[(1) - (1)].node)); + if (p && (!Getattr(p,"value"))) { + /* this is the deprecated two argument typemap form */ + Swig_warning(WARN_DEPRECATED_TYPEMAP_LANG,cparse_file, cparse_line, + "Specifying the language name in %%typemap is deprecated - use #ifdef SWIG<LANG> instead.\n"); + /* two argument typemap form */ + name = Getattr((yyvsp[(1) - (1)].node),"name"); + if (!name || (Strcmp(name,typemap_lang))) { + (yyval.tmap).method = 0; + (yyval.tmap).kwargs = 0; + } else { + (yyval.tmap).method = Getattr(p,"name"); + (yyval.tmap).kwargs = nextSibling(p); + } + } else { + /* one-argument typemap-form */ + (yyval.tmap).method = Getattr((yyvsp[(1) - (1)].node),"name"); + (yyval.tmap).kwargs = p; + } + } + break; + + case 104: +#line 2563 "parser.y" + { + (yyval.p) = (yyvsp[(1) - (2)].p); + set_nextSibling((yyval.p),(yyvsp[(2) - (2)].p)); + } + break; + + case 105: +#line 2569 "parser.y" + { + (yyval.p) = (yyvsp[(2) - (3)].p); + set_nextSibling((yyval.p),(yyvsp[(3) - (3)].p)); + } + break; + + case 106: +#line 2573 "parser.y" + { (yyval.p) = 0;} + break; + + case 107: +#line 2576 "parser.y" + { + Parm *parm; + SwigType_push((yyvsp[(1) - (2)].type),(yyvsp[(2) - (2)].decl).type); + (yyval.p) = new_node("typemapitem"); + parm = NewParm((yyvsp[(1) - (2)].type),(yyvsp[(2) - (2)].decl).id); + Setattr((yyval.p),"pattern",parm); + Setattr((yyval.p),"parms", (yyvsp[(2) - (2)].decl).parms); + Delete(parm); + /* $$ = NewParm($1,$2.id); + Setattr($$,"parms",$2.parms); */ + } + break; + + case 108: +#line 2587 "parser.y" + { + (yyval.p) = new_node("typemapitem"); + Setattr((yyval.p),"pattern",(yyvsp[(2) - (3)].pl)); + /* Setattr($$,"multitype",$2); */ + } + break; + + case 109: +#line 2592 "parser.y" + { + (yyval.p) = new_node("typemapitem"); + Setattr((yyval.p),"pattern", (yyvsp[(2) - (6)].pl)); + /* Setattr($$,"multitype",$2); */ + Setattr((yyval.p),"parms",(yyvsp[(5) - (6)].pl)); + } + break; + + case 110: +#line 2605 "parser.y" + { + (yyval.node) = new_node("types"); + Setattr((yyval.node),"parms",(yyvsp[(3) - (5)].pl)); + if ((yyvsp[(5) - (5)].str)) + Setattr((yyval.node),"convcode",NewString((yyvsp[(5) - (5)].str))); + } + break; + + case 111: +#line 2617 "parser.y" + { + Parm *p, *tp; + Node *n; + Node *tnode = 0; + Symtab *tscope = 0; + int specialized = 0; + + (yyval.node) = 0; + + tscope = Swig_symbol_current(); /* Get the current scope */ + + /* If the class name is qualified, we need to create or lookup namespace entries */ + if (!inclass) { + (yyvsp[(5) - (9)].str) = resolve_node_scope((yyvsp[(5) - (9)].str)); + } + + /* + 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((yyvsp[(5) - (9)].str),(yyvsp[(7) - (9)].p),tscope); + + /* Patch the argument types to respect namespaces */ + p = (yyvsp[(7) - (9)].p); + 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; + 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; + } + if (nnisclass && !specialized && ((ParmList_len((yyvsp[(7) - (9)].p)) > 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((yyvsp[(7) - (9)].p)) < ParmList_numrequired(tparms)))) { + Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. %d required.\n", ParmList_numrequired(tparms)); + } else if (!nnisclass && ((ParmList_len((yyvsp[(7) - (9)].p)) != 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((yyvsp[(5) - (9)].str)); + int def_supplied = 0; + /* Expand the template */ + Node *templ = Swig_symbol_clookup((yyvsp[(5) - (9)].str),0); + Parm *targs = templ ? Getattr(templ,"templateparms") : 0; + + ParmList *temparms; + if (specialized) temparms = CopyParmList((yyvsp[(7) - (9)].p)); + else temparms = CopyParmList(tparms); + + /* Create typedef's and arguments */ + p = (yyvsp[(7) - (9)].p); + 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; + } + } + + templnode = copy_node(nn); + /* 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"); + } + if ((yyvsp[(3) - (9)].id)) { + /* + 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 = (yyvsp[(3) - (9)].id); + 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); + Delete(nname); + Setattr(templnode,"feature:onlychildren", + "typemap,typemapitem,typemapcopy,typedef,types,fragment"); + } + Delattr(templnode,"templatetype"); + Setattr(templnode,"template",nn); + tnode = templnode; + Setfile(templnode,cparse_file); + Setline(templnode,cparse_line); + Delete(temparms); + + add_symbols_copy(templnode); + + if (Strcmp(nodeType(templnode),"class") == 0) { + + /* Identify pure abstract methods */ + Setattr(templnode,"abstract", pure_abstract(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 = make_inherit_list(Getattr(templnode,"name"),baselist); + 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 addmethods for this class */ + + /* !!! This may be broken. We may have to add the + addmethods at the beginning of the class */ + + if (extendhash) { + 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(extendhash,clsname); + if (am) { + Symtab *st = Swig_symbol_current(); + Swig_symbol_setscope(Getattr(templnode,"symtab")); + /* Printf(stdout,"%s: %s %x %x\n", Getattr(templnode,"name"), clsname, Swig_symbol_current(), Getattr(templnode,"symtab")); */ + merge_extensions(templnode,am); + Swig_symbol_setscope(st); + append_previous_extension(templnode,am); + Delattr(extendhash,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 (nscope_inner) { + /* non-global namespace */ + if (templnode) { + appendChild(nscope_inner,templnode); + Delete(templnode); + if (nscope) (yyval.node) = nscope; + } + } else { + /* global namespace */ + if (!linklistend) { + (yyval.node) = 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. */ + } + } + Swig_symbol_setscope(tscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + break; + + case 112: +#line 2890 "parser.y" + { + Swig_warning(0,cparse_file, cparse_line,"%s\n", (yyvsp[(2) - (2)].id)); + (yyval.node) = 0; + } + break; + + case 113: +#line 2900 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + if ((yyval.node)) { + add_symbols((yyval.node)); + default_arguments((yyval.node)); + } + } + break; + + case 114: +#line 2907 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 115: +#line 2908 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 116: +#line 2912 "parser.y" + { + if (Strcmp((yyvsp[(2) - (3)].id),"C") == 0) { + cparse_externc = 1; + } + } + break; + + case 117: +#line 2916 "parser.y" + { + cparse_externc = 0; + if (Strcmp((yyvsp[(2) - (6)].id),"C") == 0) { + Node *n = firstChild((yyvsp[(5) - (6)].node)); + (yyval.node) = new_node("extern"); + Setattr((yyval.node),"name",(yyvsp[(2) - (6)].id)); + appendChild((yyval.node),n); + while (n) { + SwigType *decl = Getattr(n,"decl"); + if (SwigType_isfunction(decl)) { + Setattr(n,"storage","externc"); + } + n = nextSibling(n); + } + } else { + Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", (yyvsp[(2) - (6)].id)); + (yyval.node) = new_node("extern"); + Setattr((yyval.node),"name",(yyvsp[(2) - (6)].id)); + appendChild((yyval.node),firstChild((yyvsp[(5) - (6)].node))); + } + } + break; + + case 118: +#line 2943 "parser.y" + { + (yyval.node) = new_node("cdecl"); + if ((yyvsp[(4) - (5)].dtype).qualifier) SwigType_push((yyvsp[(3) - (5)].decl).type,(yyvsp[(4) - (5)].dtype).qualifier); + Setattr((yyval.node),"type",(yyvsp[(2) - (5)].type)); + Setattr((yyval.node),"storage",(yyvsp[(1) - (5)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (5)].decl).id); + Setattr((yyval.node),"decl",(yyvsp[(3) - (5)].decl).type); + Setattr((yyval.node),"parms",(yyvsp[(3) - (5)].decl).parms); + Setattr((yyval.node),"value",(yyvsp[(4) - (5)].dtype).val); + Setattr((yyval.node),"throws",(yyvsp[(4) - (5)].dtype).throws); + Setattr((yyval.node),"throw",(yyvsp[(4) - (5)].dtype).throwf); + if (!(yyvsp[(5) - (5)].node)) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + } else { + Node *n = (yyvsp[(5) - (5)].node); + /* Inherit attributes */ + while (n) { + String *type = Copy((yyvsp[(2) - (5)].type)); + Setattr(n,"type",type); + Setattr(n,"storage",(yyvsp[(1) - (5)].id)); + n = nextSibling(n); + Delete(type); + } + } + if ((yyvsp[(4) - (5)].dtype).bitfield) { + Setattr((yyval.node),"bitfield", (yyvsp[(4) - (5)].dtype).bitfield); + } + + /* Look for "::" declarations (ignored) */ + if (Strstr((yyvsp[(3) - (5)].decl).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((yyvsp[(3) - (5)].decl).id); + if (p) { + if ((Namespaceprefix && Strcmp(p,Namespaceprefix) == 0) || + (inclass && Strcmp(p,Classprefix) == 0)) { + String *lstr = Swig_scopename_last((yyvsp[(3) - (5)].decl).id); + Setattr((yyval.node),"name",lstr); + Delete(lstr); + set_nextSibling((yyval.node),(yyvsp[(5) - (5)].node)); + } else { + Delete((yyval.node)); + (yyval.node) = (yyvsp[(5) - (5)].node); + } + Delete(p); + } else { + Delete((yyval.node)); + (yyval.node) = (yyvsp[(5) - (5)].node); + } + } else { + set_nextSibling((yyval.node),(yyvsp[(5) - (5)].node)); + } + } + break; + + case 119: +#line 3004 "parser.y" + { + (yyval.node) = 0; + Clear(scanner_ccode); + } + break; + + case 120: +#line 3008 "parser.y" + { + (yyval.node) = new_node("cdecl"); + if ((yyvsp[(3) - (4)].dtype).qualifier) SwigType_push((yyvsp[(2) - (4)].decl).type,(yyvsp[(3) - (4)].dtype).qualifier); + Setattr((yyval.node),"name",(yyvsp[(2) - (4)].decl).id); + Setattr((yyval.node),"decl",(yyvsp[(2) - (4)].decl).type); + Setattr((yyval.node),"parms",(yyvsp[(2) - (4)].decl).parms); + Setattr((yyval.node),"value",(yyvsp[(3) - (4)].dtype).val); + Setattr((yyval.node),"throws",(yyvsp[(3) - (4)].dtype).throws); + Setattr((yyval.node),"throw",(yyvsp[(3) - (4)].dtype).throwf); + if ((yyvsp[(3) - (4)].dtype).bitfield) { + Setattr((yyval.node),"bitfield", (yyvsp[(3) - (4)].dtype).bitfield); + } + if (!(yyvsp[(4) - (4)].node)) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + } else { + set_nextSibling((yyval.node),(yyvsp[(4) - (4)].node)); + } + } + break; + + case 121: +#line 3030 "parser.y" + { + skip_balanced('{','}'); + (yyval.node) = 0; + } + break; + + case 122: +#line 3036 "parser.y" + { + (yyval.dtype) = (yyvsp[(1) - (1)].dtype); + (yyval.dtype).qualifier = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 123: +#line 3042 "parser.y" + { + (yyval.dtype) = (yyvsp[(2) - (2)].dtype); + (yyval.dtype).qualifier = (yyvsp[(1) - (2)].str); + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 124: +#line 3048 "parser.y" + { + (yyval.dtype) = (yyvsp[(5) - (5)].dtype); + (yyval.dtype).qualifier = 0; + (yyval.dtype).throws = (yyvsp[(3) - (5)].pl); + (yyval.dtype).throwf = NewString("1"); + } + break; + + case 125: +#line 3054 "parser.y" + { + (yyval.dtype) = (yyvsp[(6) - (6)].dtype); + (yyval.dtype).qualifier = (yyvsp[(1) - (6)].str); + (yyval.dtype).throws = (yyvsp[(4) - (6)].pl); + (yyval.dtype).throwf = NewString("1"); + } + break; + + case 126: +#line 3067 "parser.y" + { + SwigType *ty = 0; + (yyval.node) = new_node("enumforward"); + ty = NewStringf("enum %s", (yyvsp[(3) - (4)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (4)].id)); + Setattr((yyval.node),"type",ty); + Setattr((yyval.node),"sym:weak", "1"); + add_symbols((yyval.node)); + } + break; + + case 127: +#line 3082 "parser.y" + { + SwigType *ty = 0; + (yyval.node) = new_node("enum"); + ty = NewStringf("enum %s", (yyvsp[(3) - (7)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (7)].id)); + Setattr((yyval.node),"type",ty); + appendChild((yyval.node),(yyvsp[(5) - (7)].node)); + add_symbols((yyval.node)); /* Add to tag space */ + add_symbols((yyvsp[(5) - (7)].node)); /* Add enum values to id space */ + } + break; + + case 128: +#line 3092 "parser.y" + { + Node *n; + SwigType *ty = 0; + String *unnamed = 0; + int unnamedinstance = 0; + + (yyval.node) = new_node("enum"); + if ((yyvsp[(3) - (8)].id)) { + Setattr((yyval.node),"name",(yyvsp[(3) - (8)].id)); + ty = NewStringf("enum %s", (yyvsp[(3) - (8)].id)); + } else if ((yyvsp[(7) - (8)].decl).id) { + unnamed = make_unnamed(); + ty = NewStringf("enum %s", unnamed); + Setattr((yyval.node),"unnamed",unnamed); + /* name is not set for unnamed enum instances, e.g. enum { foo } Instance; */ + if ((yyvsp[(1) - (8)].id) && Cmp((yyvsp[(1) - (8)].id),"typedef") == 0) { + Setattr((yyval.node),"name",(yyvsp[(7) - (8)].decl).id); + } else { + unnamedinstance = 1; + } + Setattr((yyval.node),"storage",(yyvsp[(1) - (8)].id)); + } + if ((yyvsp[(7) - (8)].decl).id && Cmp((yyvsp[(1) - (8)].id),"typedef") == 0) { + Setattr((yyval.node),"tdname",(yyvsp[(7) - (8)].decl).id); + Setattr((yyval.node),"allows_typedef","1"); + } + appendChild((yyval.node),(yyvsp[(5) - (8)].node)); + n = new_node("cdecl"); + Setattr(n,"type",ty); + Setattr(n,"name",(yyvsp[(7) - (8)].decl).id); + Setattr(n,"storage",(yyvsp[(1) - (8)].id)); + Setattr(n,"decl",(yyvsp[(7) - (8)].decl).type); + Setattr(n,"parms",(yyvsp[(7) - (8)].decl).parms); + Setattr(n,"unnamed",unnamed); + + if (unnamedinstance) { + SwigType *cty = NewString("enum "); + Setattr((yyval.node),"type",cty); + Setattr((yyval.node),"unnamedinstance","1"); + Setattr(n,"unnamedinstance","1"); + Delete(cty); + } + if ((yyvsp[(8) - (8)].node)) { + Node *p = (yyvsp[(8) - (8)].node); + set_nextSibling(n,p); + while (p) { + SwigType *cty = Copy(ty); + Setattr(p,"type",cty); + Setattr(p,"unnamed",unnamed); + Setattr(p,"storage",(yyvsp[(1) - (8)].id)); + 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 ((yyvsp[(7) - (8)].decl).id && (yyvsp[(3) - (8)].id) && Cmp((yyvsp[(1) - (8)].id),"typedef") == 0) { + String *name = NewString((yyvsp[(7) - (8)].decl).id); + Setattr((yyval.node), "parser:makename", name); + Delete(name); + } + + add_symbols((yyval.node)); /* Add enum to tag space */ + set_nextSibling((yyval.node),n); + Delete(n); + add_symbols((yyvsp[(5) - (8)].node)); /* Add enum values to id space */ + add_symbols(n); + Delete(unnamed); + } + break; + + case 129: +#line 3170 "parser.y" + { + /* 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; + (yyval.node) = 0; + + if ((ParmList_len((yyvsp[(4) - (6)].pl)) == 1) && (!Swig_scopename_check((yyvsp[(2) - (6)].type)))) { + SwigType *ty = Getattr((yyvsp[(4) - (6)].pl),"type"); + String *name = Getattr((yyvsp[(4) - (6)].pl),"name"); + err = 1; + if (!name) { + (yyval.node) = new_node("cdecl"); + Setattr((yyval.node),"type",(yyvsp[(2) - (6)].type)); + Setattr((yyval.node),"storage",(yyvsp[(1) - (6)].id)); + Setattr((yyval.node),"name",ty); + + if ((yyvsp[(6) - (6)].decl).have_parms) { + SwigType *decl = NewStringEmpty(); + SwigType_add_function(decl,(yyvsp[(6) - (6)].decl).parms); + Setattr((yyval.node),"decl",decl); + Setattr((yyval.node),"parms",(yyvsp[(6) - (6)].decl).parms); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + } + if ((yyvsp[(6) - (6)].decl).defarg) { + Setattr((yyval.node),"value",(yyvsp[(6) - (6)].decl).defarg); + } + Setattr((yyval.node),"throws",(yyvsp[(6) - (6)].decl).throws); + Setattr((yyval.node),"throw",(yyvsp[(6) - (6)].decl).throwf); + err = 0; + } + } + if (err) { + Swig_error(cparse_file,cparse_line,"Syntax error in input(2).\n"); + exit(1); + } + } + break; + + case 130: +#line 3221 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 131: +#line 3222 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 132: +#line 3223 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 133: +#line 3224 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 134: +#line 3225 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 135: +#line 3226 "parser.y" + { (yyval.node) = 0; } + break; + + case 136: +#line 3232 "parser.y" + { + List *bases = 0; + Node *scope = 0; + (yyval.node) = new_node("class"); + Setline((yyval.node),cparse_start_line); + Setattr((yyval.node),"kind",(yyvsp[(2) - (5)].id)); + if ((yyvsp[(4) - (5)].bases)) { + Setattr((yyval.node),"baselist", Getattr((yyvsp[(4) - (5)].bases),"public")); + Setattr((yyval.node),"protectedbaselist", Getattr((yyvsp[(4) - (5)].bases),"protected")); + Setattr((yyval.node),"privatebaselist", Getattr((yyvsp[(4) - (5)].bases),"private")); + } + Setattr((yyval.node),"allows_typedef","1"); + + /* preserve the current scope */ + prev_symtab = Swig_symbol_current(); + + /* If the class name is qualified. We need to create or lookup namespace/scope entries */ + scope = resolve_node_scope((yyvsp[(3) - (5)].str)); + Setfile(scope,cparse_file); + Setline(scope,cparse_line); + (yyvsp[(3) - (5)].str) = scope; + + /* support for old nested classes "pseudo" support, such as: + + %rename(Ala__Ola) Ala::Ola; + class Ala::Ola { + public: + Ola() {} + }; + + this should disappear when a proper implementation is added. + */ + if (nscope_inner && Strcmp(nodeType(nscope_inner),"namespace") != 0) { + if (Namespaceprefix) { + String *name = NewStringf("%s::%s", Namespaceprefix, (yyvsp[(3) - (5)].str)); + (yyvsp[(3) - (5)].str) = name; + Namespaceprefix = 0; + nscope_inner = 0; + } + } + Setattr((yyval.node),"name",(yyvsp[(3) - (5)].str)); + + Delete(class_rename); + class_rename = make_name((yyval.node),(yyvsp[(3) - (5)].str),0); + Classprefix = NewString((yyvsp[(3) - (5)].str)); + /* Deal with inheritance */ + if ((yyvsp[(4) - (5)].bases)) { + bases = make_inherit_list((yyvsp[(3) - (5)].str),Getattr((yyvsp[(4) - (5)].bases),"public")); + } + if (SwigType_istemplate((yyvsp[(3) - (5)].str))) { + String *fbase, *tbase, *prefix; + prefix = SwigType_templateprefix((yyvsp[(3) - (5)].str)); + if (Namespaceprefix) { + fbase = NewStringf("%s::%s", Namespaceprefix,(yyvsp[(3) - (5)].str)); + tbase = NewStringf("%s::%s", Namespaceprefix, prefix); + } else { + fbase = Copy((yyvsp[(3) - (5)].str)); + tbase = Copy(prefix); + } + Swig_name_inherit(tbase,fbase); + Delete(fbase); + Delete(tbase); + Delete(prefix); + } + if (strcmp((yyvsp[(2) - (5)].id),"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + Swig_symbol_newscope(); + Swig_symbol_setscopename((yyvsp[(3) - (5)].str)); + 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); + } + 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); + } + } + if (class_level >= max_class_levels) { + if (!max_class_levels) { + max_class_levels = 16; + } else { + max_class_levels *= 2; + } + class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); + if (!class_decl) { + Swig_error(cparse_file, cparse_line, "realloc() failed\n"); + } + } + class_decl[class_level++] = (yyval.node); + inclass = 1; + } + break; + + case 137: +#line 3346 "parser.y" + { + Node *p; + SwigType *ty; + Symtab *cscope = prev_symtab; + Node *am = 0; + String *scpname = 0; + (yyval.node) = class_decl[--class_level]; + inclass = 0; + + /* Check for pure-abstract class */ + Setattr((yyval.node),"abstract", pure_abstract((yyvsp[(7) - (9)].node))); + + /* This bit of code merges in a previously defined %extend directive (if any) */ + + if (extendhash) { + String *clsname = Swig_symbol_qualifiedscopename(0); + am = Getattr(extendhash,clsname); + if (am) { + merge_extensions((yyval.node),am); + Delattr(extendhash,clsname); + } + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes,scpname,(yyval.node)); + Delete(scpname); + + appendChild((yyval.node),(yyvsp[(7) - (9)].node)); + + if (am) append_previous_extension((yyval.node),am); + + p = (yyvsp[(9) - (9)].node); + if (p) { + set_nextSibling((yyval.node),p); + } + + if (cparse_cplusplus && !cparse_externc) { + ty = NewString((yyvsp[(3) - (9)].str)); + } else { + ty = NewStringf("%s %s", (yyvsp[(2) - (9)].id),(yyvsp[(3) - (9)].str)); + } + while (p) { + Setattr(p,"storage",(yyvsp[(1) - (9)].id)); + Setattr(p,"type",ty); + p = nextSibling(p); + } + /* Dump nested classes */ + { + String *name = (yyvsp[(3) - (9)].str); + if ((yyvsp[(9) - (9)].node)) { + SwigType *decltype = Getattr((yyvsp[(9) - (9)].node),"decl"); + if (Cmp((yyvsp[(1) - (9)].id),"typedef") == 0) { + if (!decltype || !Len(decltype)) { + String *cname; + name = Getattr((yyvsp[(9) - (9)].node),"name"); + cname = Copy(name); + Setattr((yyval.node),"tdname",cname); + Delete(cname); + + /* Use typedef name as class name */ + if (class_rename && (Strcmp(class_rename,(yyvsp[(3) - (9)].str)) == 0)) { + Delete(class_rename); + class_rename = NewString(name); + } + if (!Getattr(classes,name)) { + Setattr(classes,name,(yyval.node)); + } + Setattr((yyval.node),"decl",decltype); + } + } + } + appendChild((yyval.node),dump_nested(Char(name))); + } + + 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((yyval.node),pa); + Delete(pa); + } + + Setattr((yyval.node),"symtab",Swig_symbol_popscope()); + + Classprefix = 0; + if (nscope_inner) { + /* this is tricky */ + /* we add the declaration in the original namespace */ + appendChild(nscope_inner,(yyval.node)); + Swig_symbol_setscope(Getattr(nscope_inner,"symtab")); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols((yyval.node)); + if (nscope) (yyval.node) = nscope; + /* but the variable definition in the current scope */ + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols((yyvsp[(9) - (9)].node)); + } else { + Delete(yyrename); + yyrename = Copy(class_rename); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + + add_symbols((yyval.node)); + add_symbols((yyvsp[(9) - (9)].node)); + } + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + break; + + case 138: +#line 3464 "parser.y" + { + String *unnamed; + unnamed = make_unnamed(); + (yyval.node) = new_node("class"); + Setline((yyval.node),cparse_start_line); + Setattr((yyval.node),"kind",(yyvsp[(2) - (3)].id)); + Setattr((yyval.node),"storage",(yyvsp[(1) - (3)].id)); + Setattr((yyval.node),"unnamed",unnamed); + Setattr((yyval.node),"allows_typedef","1"); + Delete(class_rename); + class_rename = make_name((yyval.node),0,0); + if (strcmp((yyvsp[(2) - (3)].id),"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + Swig_symbol_newscope(); + cparse_start_line = cparse_line; + if (class_level >= max_class_levels) { + if (!max_class_levels) { + max_class_levels = 16; + } else { + max_class_levels *= 2; + } + class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); + if (!class_decl) { + Swig_error(cparse_file, cparse_line, "realloc() failed\n"); + } + } + class_decl[class_level++] = (yyval.node); + inclass = 1; + Classprefix = NewStringEmpty(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + break; + + case 139: +#line 3498 "parser.y" + { + String *unnamed; + Node *n; + Classprefix = 0; + (yyval.node) = class_decl[--class_level]; + inclass = 0; + unnamed = Getattr((yyval.node),"unnamed"); + + /* Check for pure-abstract class */ + Setattr((yyval.node),"abstract", pure_abstract((yyvsp[(5) - (8)].node))); + + n = new_node("cdecl"); + Setattr(n,"name",(yyvsp[(7) - (8)].decl).id); + Setattr(n,"unnamed",unnamed); + Setattr(n,"type",unnamed); + Setattr(n,"decl",(yyvsp[(7) - (8)].decl).type); + Setattr(n,"parms",(yyvsp[(7) - (8)].decl).parms); + Setattr(n,"storage",(yyvsp[(1) - (8)].id)); + if ((yyvsp[(8) - (8)].node)) { + Node *p = (yyvsp[(8) - (8)].node); + set_nextSibling(n,p); + while (p) { + String *type = Copy(unnamed); + Setattr(p,"name",(yyvsp[(7) - (8)].decl).id); + Setattr(p,"unnamed",unnamed); + Setattr(p,"type",type); + Delete(type); + Setattr(p,"storage",(yyvsp[(1) - (8)].id)); + p = nextSibling(p); + } + } + set_nextSibling((yyval.node),n); + Delete(n); + { + /* If a proper typedef name was given, we'll use it to set the scope name */ + String *name = 0; + if ((yyvsp[(1) - (8)].id) && (strcmp((yyvsp[(1) - (8)].id),"typedef") == 0)) { + if (!Len((yyvsp[(7) - (8)].decl).type)) { + String *scpname = 0; + name = (yyvsp[(7) - (8)].decl).id; + Setattr((yyval.node),"tdname",name); + Setattr((yyval.node),"name",name); + Swig_symbol_setscopename(name); + + /* If a proper name was given, we use that as the typedef, not unnamed */ + Clear(unnamed); + Append(unnamed, name); + + n = nextSibling(n); + set_nextSibling((yyval.node),n); + + /* Check for previous extensions */ + if (extendhash) { + String *clsname = Swig_symbol_qualifiedscopename(0); + Node *am = Getattr(extendhash,clsname); + if (am) { + /* Merge the extension into the symbol table */ + merge_extensions((yyval.node),am); + append_previous_extension((yyval.node),am); + Delattr(extendhash,clsname); + } + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes,scpname,(yyval.node)); + Delete(scpname); + } else { + Swig_symbol_setscopename((char*)"<unnamed>"); + } + } + appendChild((yyval.node),(yyvsp[(5) - (8)].node)); + appendChild((yyval.node),dump_nested(Char(name))); + } + /* Pop the scope */ + Setattr((yyval.node),"symtab",Swig_symbol_popscope()); + if (class_rename) { + Delete(yyrename); + yyrename = NewString(class_rename); + } + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols((yyval.node)); + add_symbols(n); + Delete(unnamed); + } + break; + + case 140: +#line 3586 "parser.y" + { (yyval.node) = 0; } + break; + + case 141: +#line 3587 "parser.y" + { + (yyval.node) = new_node("cdecl"); + Setattr((yyval.node),"name",(yyvsp[(1) - (2)].decl).id); + Setattr((yyval.node),"decl",(yyvsp[(1) - (2)].decl).type); + Setattr((yyval.node),"parms",(yyvsp[(1) - (2)].decl).parms); + set_nextSibling((yyval.node),(yyvsp[(2) - (2)].node)); + } + break; + + case 142: +#line 3599 "parser.y" + { + if ((yyvsp[(1) - (4)].id) && (Strcmp((yyvsp[(1) - (4)].id),"friend") == 0)) { + /* Ignore */ + (yyval.node) = 0; + } else { + (yyval.node) = new_node("classforward"); + Setfile((yyval.node),cparse_file); + Setline((yyval.node),cparse_line); + Setattr((yyval.node),"kind",(yyvsp[(2) - (4)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (4)].str)); + Setattr((yyval.node),"sym:weak", "1"); + add_symbols((yyval.node)); + } + } + break; + + case 143: +#line 3619 "parser.y" + { template_parameters = (yyvsp[(3) - (4)].tparms); } + break; + + case 144: +#line 3619 "parser.y" + { + 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 = (yyvsp[(6) - (6)].node); + 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); + (yyvsp[(6) - (6)].node) = ni; + } + + template_parameters = 0; + (yyval.node) = (yyvsp[(6) - (6)].node); + if ((yyval.node)) tname = Getattr((yyval.node),"name"); + + /* Check if the class is a template specialization */ + if (((yyval.node)) && (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((yyval.node)),Getline((yyval.node)),"Specialization of non-template '%s'.\n", tbase); + SWIG_WARN_NODE_END(tempn); + tempn = 0; + error = 1; + } + Delete(tbase); + } + Setattr((yyval.node),"specialization","1"); + Setattr((yyval.node),"templatetype",nodeType((yyval.node))); + set_nodeType((yyval.node),"template"); + /* Template partial specialization */ + if (tempn && ((yyvsp[(3) - (6)].tparms)) && ((yyvsp[(6) - (6)].node))) { + List *tlist; + String *targs = SwigType_templateargs(tname); + tlist = SwigType_parmlist(targs); + /* Printf(stdout,"targs = '%s' %s\n", targs, tlist); */ + if (!Getattr((yyval.node),"sym:weak")) { + Setattr((yyval.node),"sym:typename","1"); + } + + if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) { + Swig_error(Getfile((yyval.node)),Getline((yyval.node)),"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 = (yyvsp[(3) - (6)].tparms); + 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((yyval.node),"templateparms",tp); + Delete(tp); + } +#if 0 + /* Patch the parameter list */ + if (tempn) { + Parm *p,*p1; + ParmList *tp = CopyParmList(Getattr(tempn,"templateparms")); + p = (yyvsp[(3) - (6)].tparms); + 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((yyval.node),"templateparms",tp); + Delete(tp); + } else { + Setattr((yyval.node),"templateparms",(yyvsp[(3) - (6)].tparms)); + } +#endif + Delattr((yyval.node),"specialization"); + Setattr((yyval.node),"partialspecialization","1"); + /* Create a specialized name for matching */ + { + Parm *p = (yyvsp[(3) - (6)].tparms); + String *fname = NewString(Getattr((yyval.node),"name")); + String *ffname = 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; + 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); + Append(ffname,ttr); + tt = Next(tt); + if (tt.item) Putc(',',ffname); + Delete(rtt); + Delete(ttr); + } + Delete(tparms); + Append(ffname,")>"); + } + { + 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)); */ + Append(partials,ffname); + } + Setattr((yyval.node),"partialargs",ffname); + Swig_symbol_cadd(ffname,(yyval.node)); + } + } + Delete(tlist); + Delete(targs); + } else { + /* Need to resolve exact specialization name */ + /* add default args from generic template */ + String *ty = Swig_symbol_template_deftype(tname,0); + String *fname = Swig_symbol_type_qualify(ty,0); + Swig_symbol_cadd(fname,(yyval.node)); + Delete(ty); + Delete(fname); + } + } else if ((yyval.node)) { + Setattr((yyval.node),"templatetype",nodeType((yyvsp[(6) - (6)].node))); + set_nodeType((yyval.node),"template"); + Setattr((yyval.node),"templateparms", (yyvsp[(3) - (6)].tparms)); + if (!Getattr((yyval.node),"sym:weak")) { + Setattr((yyval.node),"sym:typename","1"); + } + add_symbols((yyval.node)); + default_arguments((yyval.node)); + /* We also place a fully parameterized version in the symbol table */ + { + Parm *p; + String *fname = NewStringf("%s<(", Getattr((yyval.node),"name")); + p = (yyvsp[(3) - (6)].tparms); + 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,(yyval.node)); + } + } + (yyval.node) = ntop; + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + if (error) (yyval.node) = 0; + } + break; + + case 145: +#line 3854 "parser.y" + { + Swig_warning(WARN_PARSE_EXPLICIT_TEMPLATE, cparse_file, cparse_line, "Explicit template instantiation ignored.\n"); + (yyval.node) = 0; + } + break; + + case 146: +#line 3860 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 147: +#line 3863 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 148: +#line 3866 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 149: +#line 3869 "parser.y" + { + (yyval.node) = 0; + } + break; + + case 150: +#line 3872 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 151: +#line 3875 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 152: +#line 3880 "parser.y" + { + /* Rip out the parameter names */ + Parm *p = (yyvsp[(1) - (1)].pl); + (yyval.tparms) = (yyvsp[(1) - (1)].pl); + + 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 { + /* + Swig_error(cparse_file, cparse_line, "Missing template parameter name\n"); + $$.rparms = 0; + $$.parms = 0; + break; */ + } + } + p = nextSibling(p); + } + } + break; + + case 153: +#line 3910 "parser.y" + { + set_nextSibling((yyvsp[(1) - (2)].p),(yyvsp[(2) - (2)].pl)); + (yyval.pl) = (yyvsp[(1) - (2)].p); + } + break; + + case 154: +#line 3914 "parser.y" + { (yyval.pl) = 0; } + break; + + case 155: +#line 3917 "parser.y" + { + (yyval.p) = NewParm(NewString((yyvsp[(1) - (1)].id)), 0); + } + break; + + case 156: +#line 3920 "parser.y" + { + (yyval.p) = (yyvsp[(1) - (1)].p); + } + break; + + case 157: +#line 3925 "parser.y" + { + set_nextSibling((yyvsp[(2) - (3)].p),(yyvsp[(3) - (3)].pl)); + (yyval.pl) = (yyvsp[(2) - (3)].p); + } + break; + + case 158: +#line 3929 "parser.y" + { (yyval.pl) = 0; } + break; + + case 159: +#line 3934 "parser.y" + { + String *uname = Swig_symbol_type_qualify((yyvsp[(2) - (3)].str),0); + String *name = Swig_scopename_last((yyvsp[(2) - (3)].str)); + (yyval.node) = new_node("using"); + Setattr((yyval.node),"uname",uname); + Setattr((yyval.node),"name", name); + Delete(uname); + Delete(name); + add_symbols((yyval.node)); + } + break; + + case 160: +#line 3944 "parser.y" + { + Node *n = Swig_symbol_clookup((yyvsp[(3) - (4)].str),0); + if (!n) { + Swig_error(cparse_file, cparse_line, "Nothing known about namespace '%s'\n", (yyvsp[(3) - (4)].str)); + (yyval.node) = 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"); + (yyval.node) = new_node("using"); + Setattr((yyval.node),"node",n); + Setattr((yyval.node),"namespace", (yyvsp[(3) - (4)].str)); + if (current != symtab) { + Swig_symbol_inherit(symtab); + } + } else { + Swig_error(cparse_file, cparse_line, "'%s' is not a namespace.\n", (yyvsp[(3) - (4)].str)); + (yyval.node) = 0; + } + } else { + (yyval.node) = 0; + } + } + } + break; + + case 161: +#line 3975 "parser.y" + { + Hash *h; + (yyvsp[(1) - (3)].node) = Swig_symbol_current(); + h = Swig_symbol_clookup((yyvsp[(2) - (3)].str),0); + if (h && ((yyvsp[(1) - (3)].node) == Getattr(h,"sym:symtab")) && (Strcmp(nodeType(h),"namespace") == 0)) { + 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", + (yyvsp[(2) - (3)].str), Getattr(h,"name")); + (yyvsp[(2) - (3)].str) = Getattr(h,"name"); + } + Swig_symbol_setscope(Getattr(h,"symtab")); + } else { + Swig_symbol_newscope(); + Swig_symbol_setscopename((yyvsp[(2) - (3)].str)); + } + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + break; + + case 162: +#line 3993 "parser.y" + { + Node *n = (yyvsp[(5) - (6)].node); + set_nodeType(n,"namespace"); + Setattr(n,"name",(yyvsp[(2) - (6)].str)); + Setattr(n,"symtab", Swig_symbol_popscope()); + Swig_symbol_setscope((yyvsp[(1) - (6)].node)); + (yyval.node) = n; + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols((yyval.node)); + } + break; + + case 163: +#line 4004 "parser.y" + { + Hash *h; + (yyvsp[(1) - (2)].node) = Swig_symbol_current(); + h = Swig_symbol_clookup((char *)" ",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; + } + break; + + case 164: +#line 4016 "parser.y" + { + (yyval.node) = (yyvsp[(4) - (5)].node); + set_nodeType((yyval.node),"namespace"); + Setattr((yyval.node),"unnamed","1"); + Setattr((yyval.node),"symtab", Swig_symbol_popscope()); + Swig_symbol_setscope((yyvsp[(1) - (5)].node)); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols((yyval.node)); + } + break; + + case 165: +#line 4026 "parser.y" + { + /* Namespace alias */ + Node *n; + (yyval.node) = new_node("namespace"); + Setattr((yyval.node),"name",(yyvsp[(2) - (5)].id)); + Setattr((yyval.node),"alias",(yyvsp[(4) - (5)].str)); + n = Swig_symbol_clookup((yyvsp[(4) - (5)].str),0); + if (!n) { + Swig_error(cparse_file, cparse_line, "Unknown namespace '%s'\n", (yyvsp[(4) - (5)].str)); + (yyval.node) = 0; + } else { + if (Strcmp(nodeType(n),"namespace") != 0) { + Swig_error(cparse_file, cparse_line, "'%s' is not a namespace\n",(yyvsp[(4) - (5)].str)); + (yyval.node) = 0; + } else { + while (Getattr(n,"alias")) { + n = Getattr(n,"namespace"); + } + Setattr((yyval.node),"namespace",n); + add_symbols((yyval.node)); + /* Set up a scope alias */ + Swig_symbol_alias((yyvsp[(2) - (5)].id),Getattr(n,"symtab")); + } + } + } + break; + + case 166: +#line 4053 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (2)].node); + /* Insert cpp_member (including any siblings) to the front of the cpp_members linked list */ + if ((yyval.node)) { + Node *p = (yyval.node); + Node *pp =0; + while (p) { + pp = p; + p = nextSibling(p); + } + set_nextSibling(pp,(yyvsp[(2) - (2)].node)); + } else { + (yyval.node) = (yyvsp[(2) - (2)].node); + } + } + break; + + case 167: +#line 4068 "parser.y" + { + if (cplus_mode != CPLUS_PUBLIC) { + Swig_error(cparse_file,cparse_line,"%%extend can only be used in a public section\n"); + } + } + break; + + case 168: +#line 4072 "parser.y" + { + (yyval.node) = new_node("extend"); + tag_nodes((yyvsp[(4) - (6)].node),"feature:extend",(char*) "1"); + appendChild((yyval.node),(yyvsp[(4) - (6)].node)); + set_nextSibling((yyval.node),(yyvsp[(6) - (6)].node)); + } + break; + + case 169: +#line 4078 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 170: +#line 4079 "parser.y" + { (yyval.node) = 0;} + break; + + case 171: +#line 4080 "parser.y" + { + int start_line = cparse_line; + skip_decl(); + Swig_error(cparse_file,start_line,"Syntax error in input(3).\n"); + exit(1); + } + break; + + case 172: +#line 4085 "parser.y" + { + (yyval.node) = (yyvsp[(3) - (3)].node); + } + break; + + case 173: +#line 4096 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 174: +#line 4097 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + if (extendmode) { + String *symname; + symname= make_name((yyval.node),Getattr((yyval.node),"name"), Getattr((yyval.node),"decl")); + if (Strcmp(symname,Getattr((yyval.node),"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((yyval.node)); + default_arguments((yyval.node)); + } + break; + + case 175: +#line 4114 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 176: +#line 4115 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 177: +#line 4116 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 178: +#line 4117 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 179: +#line 4118 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 180: +#line 4119 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 181: +#line 4120 "parser.y" + { (yyval.node) = 0; } + break; + + case 182: +#line 4121 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 183: +#line 4122 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 184: +#line 4123 "parser.y" + { (yyval.node) = 0; } + break; + + case 185: +#line 4124 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 186: +#line 4125 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 187: +#line 4126 "parser.y" + { (yyval.node) = 0; } + break; + + case 188: +#line 4127 "parser.y" + {(yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 189: +#line 4128 "parser.y" + {(yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 190: +#line 4129 "parser.y" + { (yyval.node) = 0; } + break; + + case 191: +#line 4138 "parser.y" + { + if (Classprefix) { + SwigType *decl = NewStringEmpty(); + (yyval.node) = new_node("constructor"); + Setattr((yyval.node),"storage",(yyvsp[(1) - (6)].id)); + Setattr((yyval.node),"name",(yyvsp[(2) - (6)].type)); + Setattr((yyval.node),"parms",(yyvsp[(4) - (6)].pl)); + SwigType_add_function(decl,(yyvsp[(4) - (6)].pl)); + Setattr((yyval.node),"decl",decl); + Setattr((yyval.node),"throws",(yyvsp[(6) - (6)].decl).throws); + Setattr((yyval.node),"throw",(yyvsp[(6) - (6)].decl).throwf); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + SetFlag((yyval.node),"feature:new"); + } else { + (yyval.node) = 0; + } + } + break; + + case 192: +#line 4163 "parser.y" + { + String *name = NewStringf("%s",(yyvsp[(2) - (6)].str)); + if (*(Char(name)) != '~') Insert(name,0,"~"); + (yyval.node) = new_node("destructor"); + Setattr((yyval.node),"name",name); + Delete(name); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + { + String *decl = NewStringEmpty(); + SwigType_add_function(decl,(yyvsp[(4) - (6)].pl)); + Setattr((yyval.node),"decl",decl); + Delete(decl); + } + Setattr((yyval.node),"throws",(yyvsp[(6) - (6)].dtype).throws); + Setattr((yyval.node),"throw",(yyvsp[(6) - (6)].dtype).throwf); + add_symbols((yyval.node)); + } + break; + + case 193: +#line 4187 "parser.y" + { + String *name; + char *c = 0; + (yyval.node) = new_node("destructor"); + /* Check for template names. If the class is a template + and the constructor is missing the template part, we + add it */ + if (Classprefix) { + c = strchr(Char(Classprefix),'<'); + if (c && !Strchr((yyvsp[(3) - (7)].str),'<')) { + (yyvsp[(3) - (7)].str) = NewStringf("%s%s",(yyvsp[(3) - (7)].str),c); + } + } + Setattr((yyval.node),"storage","virtual"); + name = NewStringf("%s",(yyvsp[(3) - (7)].str)); + if (*(Char(name)) != '~') Insert(name,0,"~"); + Setattr((yyval.node),"name",name); + Delete(name); + Setattr((yyval.node),"throws",(yyvsp[(7) - (7)].dtype).throws); + Setattr((yyval.node),"throw",(yyvsp[(7) - (7)].dtype).throwf); + if ((yyvsp[(7) - (7)].dtype).val) { + Setattr((yyval.node),"value","0"); + } + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr((yyval.node),"code",code); + Delete(code); + } + { + String *decl = NewStringEmpty(); + SwigType_add_function(decl,(yyvsp[(5) - (7)].pl)); + Setattr((yyval.node),"decl",decl); + Delete(decl); + } + + add_symbols((yyval.node)); + } + break; + + case 194: +#line 4228 "parser.y" + { + (yyval.node) = new_node("cdecl"); + Setattr((yyval.node),"type",(yyvsp[(3) - (8)].type)); + Setattr((yyval.node),"name",(yyvsp[(2) - (8)].str)); + Setattr((yyval.node),"storage",(yyvsp[(1) - (8)].id)); + + SwigType_add_function((yyvsp[(4) - (8)].type),(yyvsp[(6) - (8)].pl)); + if ((yyvsp[(8) - (8)].dtype).qualifier) { + SwigType_push((yyvsp[(4) - (8)].type),(yyvsp[(8) - (8)].dtype).qualifier); + } + Setattr((yyval.node),"decl",(yyvsp[(4) - (8)].type)); + Setattr((yyval.node),"parms",(yyvsp[(6) - (8)].pl)); + Setattr((yyval.node),"conversion_operator","1"); + add_symbols((yyval.node)); + } + break; + + case 195: +#line 4243 "parser.y" + { + SwigType *decl; + (yyval.node) = new_node("cdecl"); + Setattr((yyval.node),"type",(yyvsp[(3) - (8)].type)); + Setattr((yyval.node),"name",(yyvsp[(2) - (8)].str)); + Setattr((yyval.node),"storage",(yyvsp[(1) - (8)].id)); + decl = NewStringEmpty(); + SwigType_add_reference(decl); + SwigType_add_function(decl,(yyvsp[(6) - (8)].pl)); + if ((yyvsp[(8) - (8)].dtype).qualifier) { + SwigType_push(decl,(yyvsp[(8) - (8)].dtype).qualifier); + } + Setattr((yyval.node),"decl",decl); + Setattr((yyval.node),"parms",(yyvsp[(6) - (8)].pl)); + Setattr((yyval.node),"conversion_operator","1"); + add_symbols((yyval.node)); + } + break; + + case 196: +#line 4261 "parser.y" + { + String *t = NewStringEmpty(); + (yyval.node) = new_node("cdecl"); + Setattr((yyval.node),"type",(yyvsp[(3) - (7)].type)); + Setattr((yyval.node),"name",(yyvsp[(2) - (7)].str)); + Setattr((yyval.node),"storage",(yyvsp[(1) - (7)].id)); + SwigType_add_function(t,(yyvsp[(5) - (7)].pl)); + if ((yyvsp[(7) - (7)].dtype).qualifier) { + SwigType_push(t,(yyvsp[(7) - (7)].dtype).qualifier); + } + Setattr((yyval.node),"decl",t); + Setattr((yyval.node),"parms",(yyvsp[(5) - (7)].pl)); + Setattr((yyval.node),"conversion_operator","1"); + add_symbols((yyval.node)); + } + break; + + case 197: +#line 4280 "parser.y" + { + skip_balanced('{','}'); + (yyval.node) = 0; + } + break; + + case 198: +#line 4287 "parser.y" + { + (yyval.node) = new_node("access"); + Setattr((yyval.node),"kind","public"); + cplus_mode = CPLUS_PUBLIC; + } + break; + + case 199: +#line 4294 "parser.y" + { + (yyval.node) = new_node("access"); + Setattr((yyval.node),"kind","private"); + cplus_mode = CPLUS_PRIVATE; + } + break; + + case 200: +#line 4302 "parser.y" + { + (yyval.node) = new_node("access"); + Setattr((yyval.node),"kind","protected"); + cplus_mode = CPLUS_PROTECTED; + } + break; + + case 201: +#line 4325 "parser.y" + { cparse_start_line = cparse_line; skip_balanced('{','}'); + } + break; + + case 202: +#line 4326 "parser.y" + { + (yyval.node) = 0; + if (cplus_mode == CPLUS_PUBLIC) { + if ((yyvsp[(6) - (7)].decl).id && strcmp((yyvsp[(2) - (7)].id), "class") != 0) { + Nested *n = (Nested *) malloc(sizeof(Nested)); + n->code = NewStringEmpty(); + Printv(n->code, "typedef ", (yyvsp[(2) - (7)].id), " ", + Char(scanner_ccode), " $classname_", (yyvsp[(6) - (7)].decl).id, ";\n", NIL); + + n->name = Swig_copy_string((yyvsp[(6) - (7)].decl).id); + n->line = cparse_start_line; + n->type = NewStringEmpty(); + n->kind = (yyvsp[(2) - (7)].id); + n->unnamed = 0; + SwigType_push(n->type, (yyvsp[(6) - (7)].decl).type); + n->next = 0; + add_nested(n); + } else { + Swig_warning(WARN_PARSE_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", (yyvsp[(2) - (7)].id)); + if (strcmp((yyvsp[(2) - (7)].id), "class") == 0) { + /* For now, just treat the nested class as a forward + * declaration (SF bug #909387). */ + (yyval.node) = new_node("classforward"); + Setfile((yyval.node),cparse_file); + Setline((yyval.node),cparse_line); + Setattr((yyval.node),"kind",(yyvsp[(2) - (7)].id)); + Setattr((yyval.node),"name",(yyvsp[(3) - (7)].id)); + Setattr((yyval.node),"sym:weak", "1"); + add_symbols((yyval.node)); + } + } + } + } + break; + + case 203: +#line 4360 "parser.y" + { cparse_start_line = cparse_line; skip_balanced('{','}'); + } + break; + + case 204: +#line 4361 "parser.y" + { + (yyval.node) = 0; + if (cplus_mode == CPLUS_PUBLIC) { + if (strcmp((yyvsp[(2) - (6)].id),"class") == 0) { + Swig_warning(WARN_PARSE_NESTED_CLASS,cparse_file, cparse_line,"Nested class not currently supported (ignored)\n"); + /* Generate some code for a new class */ + } else if ((yyvsp[(5) - (6)].decl).id) { + /* Generate some code for a new class */ + Nested *n = (Nested *) malloc(sizeof(Nested)); + n->code = NewStringEmpty(); + Printv(n->code, "typedef ", (yyvsp[(2) - (6)].id), " " , + Char(scanner_ccode), " $classname_", (yyvsp[(5) - (6)].decl).id, ";\n",NIL); + n->name = Swig_copy_string((yyvsp[(5) - (6)].decl).id); + n->line = cparse_start_line; + n->type = NewStringEmpty(); + n->kind = (yyvsp[(2) - (6)].id); + n->unnamed = 1; + SwigType_push(n->type,(yyvsp[(5) - (6)].decl).type); + n->next = 0; + add_nested(n); + } else { + Swig_warning(WARN_PARSE_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", (yyvsp[(2) - (6)].id)); + } + } + } + break; + + case 205: +#line 4391 "parser.y" + { cparse_start_line = cparse_line; skip_balanced('{','}'); + } + break; + + case 206: +#line 4392 "parser.y" + { + (yyval.node) = 0; + if (cplus_mode == CPLUS_PUBLIC) { + Swig_warning(WARN_PARSE_NESTED_CLASS,cparse_file, cparse_line,"Nested class not currently supported (ignored)\n"); + } + } + break; + + case 207: +#line 4409 "parser.y" + { (yyval.decl) = (yyvsp[(1) - (1)].decl);} + break; + + case 208: +#line 4410 "parser.y" + { (yyval.decl).id = 0; } + break; + + case 209: +#line 4416 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 210: +#line 4419 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 211: +#line 4423 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 212: +#line 4426 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 213: +#line 4427 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 214: +#line 4428 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 215: +#line 4429 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 216: +#line 4430 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 217: +#line 4431 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 218: +#line 4432 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 219: +#line 4433 "parser.y" + { (yyval.node) = (yyvsp[(1) - (1)].node); } + break; + + case 220: +#line 4436 "parser.y" + { + Clear(scanner_ccode); + (yyval.dtype).throws = (yyvsp[(1) - (2)].dtype).throws; + (yyval.dtype).throwf = (yyvsp[(1) - (2)].dtype).throwf; + } + break; + + case 221: +#line 4441 "parser.y" + { + skip_balanced('{','}'); + (yyval.dtype).throws = (yyvsp[(1) - (2)].dtype).throws; + (yyval.dtype).throwf = (yyvsp[(1) - (2)].dtype).throwf; + } + break; + + case 222: +#line 4448 "parser.y" + { + Clear(scanner_ccode); + (yyval.dtype).val = 0; + (yyval.dtype).qualifier = (yyvsp[(1) - (2)].dtype).qualifier; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = (yyvsp[(1) - (2)].dtype).throws; + (yyval.dtype).throwf = (yyvsp[(1) - (2)].dtype).throwf; + } + break; + + case 223: +#line 4456 "parser.y" + { + Clear(scanner_ccode); + (yyval.dtype).val = (yyvsp[(3) - (4)].dtype).val; + (yyval.dtype).qualifier = (yyvsp[(1) - (4)].dtype).qualifier; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = (yyvsp[(1) - (4)].dtype).throws; + (yyval.dtype).throwf = (yyvsp[(1) - (4)].dtype).throwf; + } + break; + + case 224: +#line 4464 "parser.y" + { + skip_balanced('{','}'); + (yyval.dtype).val = 0; + (yyval.dtype).qualifier = (yyvsp[(1) - (2)].dtype).qualifier; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = (yyvsp[(1) - (2)].dtype).throws; + (yyval.dtype).throwf = (yyvsp[(1) - (2)].dtype).throwf; + } + break; + + case 225: +#line 4475 "parser.y" + { } + break; + + case 226: +#line 4481 "parser.y" + { (yyval.id) = "extern"; } + break; + + case 227: +#line 4482 "parser.y" + { + if (strcmp((yyvsp[(2) - (2)].id),"C") == 0) { + (yyval.id) = "externc"; + } else { + Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", (yyvsp[(2) - (2)].id)); + (yyval.id) = 0; + } + } + break; + + case 228: +#line 4490 "parser.y" + { (yyval.id) = "static"; } + break; + + case 229: +#line 4491 "parser.y" + { (yyval.id) = "typedef"; } + break; + + case 230: +#line 4492 "parser.y" + { (yyval.id) = "virtual"; } + break; + + case 231: +#line 4493 "parser.y" + { (yyval.id) = "friend"; } + break; + + case 232: +#line 4494 "parser.y" + { (yyval.id) = "explicit"; } + break; + + case 233: +#line 4495 "parser.y" + { (yyval.id) = 0; } + break; + + case 234: +#line 4502 "parser.y" + { + Parm *p; + (yyval.pl) = (yyvsp[(1) - (1)].pl); + p = (yyvsp[(1) - (1)].pl); + while (p) { + Replace(Getattr(p,"type"),"typename ", "", DOH_REPLACE_ANY); + p = nextSibling(p); + } + } + break; + + case 235: +#line 4513 "parser.y" + { + set_nextSibling((yyvsp[(1) - (2)].p),(yyvsp[(2) - (2)].pl)); + (yyval.pl) = (yyvsp[(1) - (2)].p); + } + break; + + case 236: +#line 4517 "parser.y" + { (yyval.pl) = 0; } + break; + + case 237: +#line 4520 "parser.y" + { + set_nextSibling((yyvsp[(2) - (3)].p),(yyvsp[(3) - (3)].pl)); + (yyval.pl) = (yyvsp[(2) - (3)].p); + } + break; + + case 238: +#line 4524 "parser.y" + { (yyval.pl) = 0; } + break; + + case 239: +#line 4528 "parser.y" + { + SwigType_push((yyvsp[(1) - (2)].type),(yyvsp[(2) - (2)].decl).type); + (yyval.p) = NewParm((yyvsp[(1) - (2)].type),(yyvsp[(2) - (2)].decl).id); + Setfile((yyval.p),cparse_file); + Setline((yyval.p),cparse_line); + if ((yyvsp[(2) - (2)].decl).defarg) { + Setattr((yyval.p),"value",(yyvsp[(2) - (2)].decl).defarg); + } + } + break; + + case 240: +#line 4538 "parser.y" + { + (yyval.p) = NewParm(NewStringf("template<class> %s %s", (yyvsp[(5) - (7)].id),(yyvsp[(6) - (7)].str)), 0); + Setfile((yyval.p),cparse_file); + Setline((yyval.p),cparse_line); + if ((yyvsp[(7) - (7)].dtype).val) { + Setattr((yyval.p),"value",(yyvsp[(7) - (7)].dtype).val); + } + } + break; + + case 241: +#line 4546 "parser.y" + { + SwigType *t = NewString("v(...)"); + (yyval.p) = NewParm(t, 0); + Setfile((yyval.p),cparse_file); + Setline((yyval.p),cparse_line); + } + break; + + case 242: +#line 4554 "parser.y" + { + Parm *p; + (yyval.p) = (yyvsp[(1) - (1)].p); + p = (yyvsp[(1) - (1)].p); + while (p) { + if (Getattr(p,"type")) { + Replace(Getattr(p,"type"),"typename ", "", DOH_REPLACE_ANY); + } + p = nextSibling(p); + } + } + break; + + case 243: +#line 4567 "parser.y" + { + set_nextSibling((yyvsp[(1) - (2)].p),(yyvsp[(2) - (2)].p)); + (yyval.p) = (yyvsp[(1) - (2)].p); + } + break; + + case 244: +#line 4571 "parser.y" + { (yyval.p) = 0; } + break; + + case 245: +#line 4574 "parser.y" + { + set_nextSibling((yyvsp[(2) - (3)].p),(yyvsp[(3) - (3)].p)); + (yyval.p) = (yyvsp[(2) - (3)].p); + } + break; + + case 246: +#line 4578 "parser.y" + { (yyval.p) = 0; } + break; + + case 247: +#line 4582 "parser.y" + { + (yyval.p) = (yyvsp[(1) - (1)].p); + { + /* We need to make a possible adjustment for integer parameters. */ + SwigType *type; + Node *n = 0; + + while (!n) { + type = Getattr((yyvsp[(1) - (1)].p),"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((yyvsp[(1) - (1)].p),"type",v); + Delete(v); + n = 0; + } + } + } else { + break; + } + } + } + + } + break; + + case 248: +#line 4610 "parser.y" + { + (yyval.p) = NewParm(0,0); + Setfile((yyval.p),cparse_file); + Setline((yyval.p),cparse_line); + Setattr((yyval.p),"value",(yyvsp[(1) - (1)].dtype).val); + } + break; + + case 249: +#line 4618 "parser.y" + { + (yyval.dtype) = (yyvsp[(2) - (2)].dtype); + if ((yyvsp[(2) - (2)].dtype).type == T_ERROR) { + Swig_warning(WARN_PARSE_BAD_DEFAULT,cparse_file, cparse_line, "Can't set default argument (ignored)\n"); + (yyval.dtype).val = 0; + (yyval.dtype).rawval = 0; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + } + break; + + case 250: +#line 4629 "parser.y" + { + (yyval.dtype) = (yyvsp[(2) - (5)].dtype); + if ((yyvsp[(2) - (5)].dtype).type == T_ERROR) { + Swig_warning(WARN_PARSE_BAD_DEFAULT,cparse_file, cparse_line, "Can't set default argument (ignored)\n"); + (yyval.dtype) = (yyvsp[(2) - (5)].dtype); + (yyval.dtype).val = 0; + (yyval.dtype).rawval = 0; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } else { + (yyval.dtype).val = NewStringf("%s[%s]",(yyvsp[(2) - (5)].dtype).val,(yyvsp[(4) - (5)].dtype).val); + } + } + break; + + case 251: +#line 4643 "parser.y" + { + skip_balanced('{','}'); + (yyval.dtype).val = 0; + (yyval.dtype).rawval = 0; + (yyval.dtype).type = T_INT; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 252: +#line 4652 "parser.y" + { + (yyval.dtype).val = 0; + (yyval.dtype).rawval = 0; + (yyval.dtype).type = 0; + (yyval.dtype).bitfield = (yyvsp[(2) - (2)].dtype).val; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 253: +#line 4660 "parser.y" + { + (yyval.dtype).val = 0; + (yyval.dtype).rawval = 0; + (yyval.dtype).type = T_INT; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 254: +#line 4670 "parser.y" + { + (yyval.decl) = (yyvsp[(1) - (2)].decl); + (yyval.decl).defarg = (yyvsp[(2) - (2)].dtype).rawval ? (yyvsp[(2) - (2)].dtype).rawval : (yyvsp[(2) - (2)].dtype).val; + } + break; + + case 255: +#line 4674 "parser.y" + { + (yyval.decl) = (yyvsp[(1) - (2)].decl); + (yyval.decl).defarg = (yyvsp[(2) - (2)].dtype).rawval ? (yyvsp[(2) - (2)].dtype).rawval : (yyvsp[(2) - (2)].dtype).val; + } + break; + + case 256: +#line 4678 "parser.y" + { + (yyval.decl).type = 0; + (yyval.decl).id = 0; + (yyval.decl).defarg = (yyvsp[(1) - (1)].dtype).rawval ? (yyvsp[(1) - (1)].dtype).rawval : (yyvsp[(1) - (1)].dtype).val; + } + break; + + case 257: +#line 4685 "parser.y" + { + (yyval.decl) = (yyvsp[(1) - (1)].decl); + if (SwigType_isfunction((yyvsp[(1) - (1)].decl).type)) { + Delete(SwigType_pop_function((yyvsp[(1) - (1)].decl).type)); + } else if (SwigType_isarray((yyvsp[(1) - (1)].decl).type)) { + SwigType *ta = SwigType_pop_arrays((yyvsp[(1) - (1)].decl).type); + if (SwigType_isfunction((yyvsp[(1) - (1)].decl).type)) { + Delete(SwigType_pop_function((yyvsp[(1) - (1)].decl).type)); + } else { + (yyval.decl).parms = 0; + } + SwigType_push((yyvsp[(1) - (1)].decl).type,ta); + Delete(ta); + } else { + (yyval.decl).parms = 0; + } + } + break; + + case 258: +#line 4702 "parser.y" + { + (yyval.decl) = (yyvsp[(1) - (1)].decl); + if (SwigType_isfunction((yyvsp[(1) - (1)].decl).type)) { + Delete(SwigType_pop_function((yyvsp[(1) - (1)].decl).type)); + } else if (SwigType_isarray((yyvsp[(1) - (1)].decl).type)) { + SwigType *ta = SwigType_pop_arrays((yyvsp[(1) - (1)].decl).type); + if (SwigType_isfunction((yyvsp[(1) - (1)].decl).type)) { + Delete(SwigType_pop_function((yyvsp[(1) - (1)].decl).type)); + } else { + (yyval.decl).parms = 0; + } + SwigType_push((yyvsp[(1) - (1)].decl).type,ta); + Delete(ta); + } else { + (yyval.decl).parms = 0; + } + } + break; + + case 259: +#line 4719 "parser.y" + { + (yyval.decl).type = 0; + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + } + break; + + case 260: +#line 4727 "parser.y" + { + (yyval.decl) = (yyvsp[(2) - (2)].decl); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(1) - (2)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(1) - (2)].type); + } + break; + + case 261: +#line 4735 "parser.y" + { + (yyval.decl) = (yyvsp[(3) - (3)].decl); + SwigType_add_reference((yyvsp[(1) - (3)].type)); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(1) - (3)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(1) - (3)].type); + } + break; + + case 262: +#line 4744 "parser.y" + { + (yyval.decl) = (yyvsp[(1) - (1)].decl); + if (!(yyval.decl).type) (yyval.decl).type = NewStringEmpty(); + } + break; + + case 263: +#line 4748 "parser.y" + { + (yyval.decl) = (yyvsp[(2) - (2)].decl); + (yyval.decl).type = NewStringEmpty(); + SwigType_add_reference((yyval.decl).type); + if ((yyvsp[(2) - (2)].decl).type) { + SwigType_push((yyval.decl).type,(yyvsp[(2) - (2)].decl).type); + Delete((yyvsp[(2) - (2)].decl).type); + } + } + break; + + case 264: +#line 4757 "parser.y" + { + SwigType *t = NewStringEmpty(); + + (yyval.decl) = (yyvsp[(3) - (3)].decl); + SwigType_add_memberpointer(t,(yyvsp[(1) - (3)].str)); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 265: +#line 4768 "parser.y" + { + SwigType *t = NewStringEmpty(); + (yyval.decl) = (yyvsp[(4) - (4)].decl); + SwigType_add_memberpointer(t,(yyvsp[(2) - (4)].str)); + SwigType_push((yyvsp[(1) - (4)].type),t); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(1) - (4)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(1) - (4)].type); + Delete(t); + } + break; + + case 266: +#line 4780 "parser.y" + { + (yyval.decl) = (yyvsp[(5) - (5)].decl); + SwigType_add_memberpointer((yyvsp[(1) - (5)].type),(yyvsp[(2) - (5)].str)); + SwigType_add_reference((yyvsp[(1) - (5)].type)); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(1) - (5)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(1) - (5)].type); + } + break; + + case 267: +#line 4790 "parser.y" + { + SwigType *t = NewStringEmpty(); + (yyval.decl) = (yyvsp[(4) - (4)].decl); + SwigType_add_memberpointer(t,(yyvsp[(1) - (4)].str)); + SwigType_add_reference(t); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 268: +#line 4803 "parser.y" + { + /* Note: This is non-standard C. Template declarator is allowed to follow an identifier */ + (yyval.decl).id = Char((yyvsp[(1) - (1)].str)); + (yyval.decl).type = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 269: +#line 4810 "parser.y" + { + (yyval.decl).id = Char(NewStringf("~%s",(yyvsp[(2) - (2)].str))); + (yyval.decl).type = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 270: +#line 4818 "parser.y" + { + (yyval.decl).id = Char((yyvsp[(2) - (3)].str)); + (yyval.decl).type = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 271: +#line 4834 "parser.y" + { + (yyval.decl) = (yyvsp[(3) - (4)].decl); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(2) - (4)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(2) - (4)].type); + } + break; + + case 272: +#line 4842 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(4) - (5)].decl); + t = NewStringEmpty(); + SwigType_add_memberpointer(t,(yyvsp[(2) - (5)].str)); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 273: +#line 4853 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (3)].decl); + t = NewStringEmpty(); + SwigType_add_array(t,(char*)""); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 274: +#line 4864 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (4)].decl); + t = NewStringEmpty(); + SwigType_add_array(t,(yyvsp[(3) - (4)].dtype).val); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 275: +#line 4875 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (4)].decl); + t = NewStringEmpty(); + SwigType_add_function(t,(yyvsp[(3) - (4)].pl)); + if (!(yyval.decl).have_parms) { + (yyval.decl).parms = (yyvsp[(3) - (4)].pl); + (yyval.decl).have_parms = 1; + } + if (!(yyval.decl).type) { + (yyval.decl).type = t; + } else { + SwigType_push(t, (yyval.decl).type); + Delete((yyval.decl).type); + (yyval.decl).type = t; + } + } + break; + + case 276: +#line 4894 "parser.y" + { + /* Note: This is non-standard C. Template declarator is allowed to follow an identifier */ + (yyval.decl).id = Char((yyvsp[(1) - (1)].str)); + (yyval.decl).type = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 277: +#line 4902 "parser.y" + { + (yyval.decl).id = Char(NewStringf("~%s",(yyvsp[(2) - (2)].str))); + (yyval.decl).type = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 278: +#line 4919 "parser.y" + { + (yyval.decl) = (yyvsp[(3) - (4)].decl); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(2) - (4)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(2) - (4)].type); + } + break; + + case 279: +#line 4927 "parser.y" + { + (yyval.decl) = (yyvsp[(3) - (4)].decl); + if (!(yyval.decl).type) { + (yyval.decl).type = NewStringEmpty(); + } + SwigType_add_reference((yyval.decl).type); + } + break; + + case 280: +#line 4934 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(4) - (5)].decl); + t = NewStringEmpty(); + SwigType_add_memberpointer(t,(yyvsp[(2) - (5)].str)); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 281: +#line 4945 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (3)].decl); + t = NewStringEmpty(); + SwigType_add_array(t,(char*)""); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 282: +#line 4956 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (4)].decl); + t = NewStringEmpty(); + SwigType_add_array(t,(yyvsp[(3) - (4)].dtype).val); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 283: +#line 4967 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (4)].decl); + t = NewStringEmpty(); + SwigType_add_function(t,(yyvsp[(3) - (4)].pl)); + if (!(yyval.decl).have_parms) { + (yyval.decl).parms = (yyvsp[(3) - (4)].pl); + (yyval.decl).have_parms = 1; + } + if (!(yyval.decl).type) { + (yyval.decl).type = t; + } else { + SwigType_push(t, (yyval.decl).type); + Delete((yyval.decl).type); + (yyval.decl).type = t; + } + } + break; + + case 284: +#line 4986 "parser.y" + { + (yyval.decl).type = (yyvsp[(1) - (1)].type); + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 285: +#line 4992 "parser.y" + { + (yyval.decl) = (yyvsp[(2) - (2)].decl); + SwigType_push((yyvsp[(1) - (2)].type),(yyvsp[(2) - (2)].decl).type); + (yyval.decl).type = (yyvsp[(1) - (2)].type); + Delete((yyvsp[(2) - (2)].decl).type); + } + break; + + case 286: +#line 4998 "parser.y" + { + (yyval.decl).type = (yyvsp[(1) - (2)].type); + SwigType_add_reference((yyval.decl).type); + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 287: +#line 5005 "parser.y" + { + (yyval.decl) = (yyvsp[(3) - (3)].decl); + SwigType_add_reference((yyvsp[(1) - (3)].type)); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(1) - (3)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(1) - (3)].type); + } + break; + + case 288: +#line 5014 "parser.y" + { + (yyval.decl) = (yyvsp[(1) - (1)].decl); + } + break; + + case 289: +#line 5017 "parser.y" + { + (yyval.decl) = (yyvsp[(2) - (2)].decl); + (yyval.decl).type = NewStringEmpty(); + SwigType_add_reference((yyval.decl).type); + if ((yyvsp[(2) - (2)].decl).type) { + SwigType_push((yyval.decl).type,(yyvsp[(2) - (2)].decl).type); + Delete((yyvsp[(2) - (2)].decl).type); + } + } + break; + + case 290: +#line 5026 "parser.y" + { + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + (yyval.decl).type = NewStringEmpty(); + SwigType_add_reference((yyval.decl).type); + } + break; + + case 291: +#line 5033 "parser.y" + { + (yyval.decl).type = NewStringEmpty(); + SwigType_add_memberpointer((yyval.decl).type,(yyvsp[(1) - (2)].str)); + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + } + break; + + case 292: +#line 5040 "parser.y" + { + SwigType *t = NewStringEmpty(); + (yyval.decl).type = (yyvsp[(1) - (3)].type); + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + SwigType_add_memberpointer(t,(yyvsp[(2) - (3)].str)); + SwigType_push((yyval.decl).type,t); + Delete(t); + } + break; + + case 293: +#line 5050 "parser.y" + { + (yyval.decl) = (yyvsp[(4) - (4)].decl); + SwigType_add_memberpointer((yyvsp[(1) - (4)].type),(yyvsp[(2) - (4)].str)); + if ((yyval.decl).type) { + SwigType_push((yyvsp[(1) - (4)].type),(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = (yyvsp[(1) - (4)].type); + } + break; + + case 294: +#line 5061 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (3)].decl); + t = NewStringEmpty(); + SwigType_add_array(t,(char*)""); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 295: +#line 5072 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (4)].decl); + t = NewStringEmpty(); + SwigType_add_array(t,(yyvsp[(3) - (4)].dtype).val); + if ((yyval.decl).type) { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + } + (yyval.decl).type = t; + } + break; + + case 296: +#line 5083 "parser.y" + { + (yyval.decl).type = NewStringEmpty(); + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + SwigType_add_array((yyval.decl).type,(char*)""); + } + break; + + case 297: +#line 5090 "parser.y" + { + (yyval.decl).type = NewStringEmpty(); + (yyval.decl).id = 0; + (yyval.decl).parms = 0; + (yyval.decl).have_parms = 0; + SwigType_add_array((yyval.decl).type,(yyvsp[(2) - (3)].dtype).val); + } + break; + + case 298: +#line 5097 "parser.y" + { + (yyval.decl) = (yyvsp[(2) - (3)].decl); + } + break; + + case 299: +#line 5100 "parser.y" + { + SwigType *t; + (yyval.decl) = (yyvsp[(1) - (4)].decl); + t = NewStringEmpty(); + SwigType_add_function(t,(yyvsp[(3) - (4)].pl)); + if (!(yyval.decl).type) { + (yyval.decl).type = t; + } else { + SwigType_push(t,(yyval.decl).type); + Delete((yyval.decl).type); + (yyval.decl).type = t; + } + if (!(yyval.decl).have_parms) { + (yyval.decl).parms = (yyvsp[(3) - (4)].pl); + (yyval.decl).have_parms = 1; + } + } + break; + + case 300: +#line 5117 "parser.y" + { + (yyval.decl).type = NewStringEmpty(); + SwigType_add_function((yyval.decl).type,(yyvsp[(2) - (3)].pl)); + (yyval.decl).parms = (yyvsp[(2) - (3)].pl); + (yyval.decl).have_parms = 1; + (yyval.decl).id = 0; + } + break; + + case 301: +#line 5127 "parser.y" + { + (yyval.type) = NewStringEmpty(); + SwigType_add_pointer((yyval.type)); + SwigType_push((yyval.type),(yyvsp[(2) - (3)].str)); + SwigType_push((yyval.type),(yyvsp[(3) - (3)].type)); + Delete((yyvsp[(3) - (3)].type)); + } + break; + + case 302: +#line 5134 "parser.y" + { + (yyval.type) = NewStringEmpty(); + SwigType_add_pointer((yyval.type)); + SwigType_push((yyval.type),(yyvsp[(2) - (2)].type)); + Delete((yyvsp[(2) - (2)].type)); + } + break; + + case 303: +#line 5140 "parser.y" + { + (yyval.type) = NewStringEmpty(); + SwigType_add_pointer((yyval.type)); + SwigType_push((yyval.type),(yyvsp[(2) - (2)].str)); + } + break; + + case 304: +#line 5145 "parser.y" + { + (yyval.type) = NewStringEmpty(); + SwigType_add_pointer((yyval.type)); + } + break; + + case 305: +#line 5151 "parser.y" + { + (yyval.str) = NewStringEmpty(); + if ((yyvsp[(1) - (1)].id)) SwigType_add_qualifier((yyval.str),(yyvsp[(1) - (1)].id)); + } + break; + + case 306: +#line 5155 "parser.y" + { + (yyval.str) = (yyvsp[(2) - (2)].str); + if ((yyvsp[(1) - (2)].id)) SwigType_add_qualifier((yyval.str),(yyvsp[(1) - (2)].id)); + } + break; + + case 307: +#line 5161 "parser.y" + { (yyval.id) = "const"; } + break; + + case 308: +#line 5162 "parser.y" + { (yyval.id) = "volatile"; } + break; + + case 309: +#line 5163 "parser.y" + { (yyval.id) = 0; } + break; + + case 310: +#line 5169 "parser.y" + { + (yyval.type) = (yyvsp[(1) - (1)].type); + Replace((yyval.type),"typename ","", DOH_REPLACE_ANY); + } + break; + + case 311: +#line 5175 "parser.y" + { + (yyval.type) = (yyvsp[(2) - (2)].type); + SwigType_push((yyval.type),(yyvsp[(1) - (2)].str)); + } + break; + + case 312: +#line 5179 "parser.y" + { (yyval.type) = (yyvsp[(1) - (1)].type); } + break; + + case 313: +#line 5180 "parser.y" + { + (yyval.type) = (yyvsp[(1) - (2)].type); + SwigType_push((yyval.type),(yyvsp[(2) - (2)].str)); + } + break; + + case 314: +#line 5184 "parser.y" + { + (yyval.type) = (yyvsp[(2) - (3)].type); + SwigType_push((yyval.type),(yyvsp[(3) - (3)].str)); + SwigType_push((yyval.type),(yyvsp[(1) - (3)].str)); + } + break; + + case 315: +#line 5191 "parser.y" + { (yyval.type) = (yyvsp[(1) - (1)].type); + /* Printf(stdout,"primitive = '%s'\n", $$);*/ + } + break; + + case 316: +#line 5194 "parser.y" + { (yyval.type) = (yyvsp[(1) - (1)].type); } + break; + + case 317: +#line 5195 "parser.y" + { (yyval.type) = (yyvsp[(1) - (1)].type); } + break; + + case 318: +#line 5196 "parser.y" + { (yyval.type) = NewStringf("%s%s",(yyvsp[(1) - (2)].type),(yyvsp[(2) - (2)].id)); } + break; + + case 319: +#line 5197 "parser.y" + { (yyval.type) = NewStringf("enum %s", (yyvsp[(2) - (2)].str)); } + break; + + case 320: +#line 5198 "parser.y" + { (yyval.type) = (yyvsp[(1) - (1)].type); } + break; + + case 321: +#line 5200 "parser.y" + { + (yyval.type) = (yyvsp[(1) - (1)].str); + } + break; + + case 322: +#line 5203 "parser.y" + { + (yyval.type) = NewStringf("%s %s", (yyvsp[(1) - (2)].id), (yyvsp[(2) - (2)].str)); + } + break; + + case 323: +#line 5208 "parser.y" + { + if (!(yyvsp[(1) - (1)].ptype).type) (yyvsp[(1) - (1)].ptype).type = NewString("int"); + if ((yyvsp[(1) - (1)].ptype).us) { + (yyval.type) = NewStringf("%s %s", (yyvsp[(1) - (1)].ptype).us, (yyvsp[(1) - (1)].ptype).type); + Delete((yyvsp[(1) - (1)].ptype).us); + Delete((yyvsp[(1) - (1)].ptype).type); + } else { + (yyval.type) = (yyvsp[(1) - (1)].ptype).type; + } + if (Cmp((yyval.type),"signed int") == 0) { + Delete((yyval.type)); + (yyval.type) = NewString("int"); + } else if (Cmp((yyval.type),"signed long") == 0) { + Delete((yyval.type)); + (yyval.type) = NewString("long"); + } else if (Cmp((yyval.type),"signed short") == 0) { + Delete((yyval.type)); + (yyval.type) = NewString("short"); + } else if (Cmp((yyval.type),"signed long long") == 0) { + Delete((yyval.type)); + (yyval.type) = NewString("long long"); + } + } + break; + + case 324: +#line 5233 "parser.y" + { + (yyval.ptype) = (yyvsp[(1) - (1)].ptype); + } + break; + + case 325: +#line 5236 "parser.y" + { + if ((yyvsp[(1) - (2)].ptype).us && (yyvsp[(2) - (2)].ptype).us) { + Swig_error(cparse_file, cparse_line, "Extra %s specifier.\n", (yyvsp[(2) - (2)].ptype).us); + } + (yyval.ptype) = (yyvsp[(2) - (2)].ptype); + if ((yyvsp[(1) - (2)].ptype).us) (yyval.ptype).us = (yyvsp[(1) - (2)].ptype).us; + if ((yyvsp[(1) - (2)].ptype).type) { + if (!(yyvsp[(2) - (2)].ptype).type) (yyval.ptype).type = (yyvsp[(1) - (2)].ptype).type; + else { + int err = 0; + if ((Cmp((yyvsp[(1) - (2)].ptype).type,"long") == 0)) { + if ((Cmp((yyvsp[(2) - (2)].ptype).type,"long") == 0) || (Strncmp((yyvsp[(2) - (2)].ptype).type,"double",6) == 0)) { + (yyval.ptype).type = NewStringf("long %s", (yyvsp[(2) - (2)].ptype).type); + } else if (Cmp((yyvsp[(2) - (2)].ptype).type,"int") == 0) { + (yyval.ptype).type = (yyvsp[(1) - (2)].ptype).type; + } else { + err = 1; + } + } else if ((Cmp((yyvsp[(1) - (2)].ptype).type,"short")) == 0) { + if (Cmp((yyvsp[(2) - (2)].ptype).type,"int") == 0) { + (yyval.ptype).type = (yyvsp[(1) - (2)].ptype).type; + } else { + err = 1; + } + } else if (Cmp((yyvsp[(1) - (2)].ptype).type,"int") == 0) { + (yyval.ptype).type = (yyvsp[(2) - (2)].ptype).type; + } else if (Cmp((yyvsp[(1) - (2)].ptype).type,"double") == 0) { + if (Cmp((yyvsp[(2) - (2)].ptype).type,"long") == 0) { + (yyval.ptype).type = NewString("long double"); + } else if (Cmp((yyvsp[(2) - (2)].ptype).type,"complex") == 0) { + (yyval.ptype).type = NewString("double complex"); + } else { + err = 1; + } + } else if (Cmp((yyvsp[(1) - (2)].ptype).type,"float") == 0) { + if (Cmp((yyvsp[(2) - (2)].ptype).type,"complex") == 0) { + (yyval.ptype).type = NewString("float complex"); + } else { + err = 1; + } + } else if (Cmp((yyvsp[(1) - (2)].ptype).type,"complex") == 0) { + (yyval.ptype).type = NewStringf("%s complex", (yyvsp[(2) - (2)].ptype).type); + } else { + err = 1; + } + if (err) { + Swig_error(cparse_file, cparse_line, "Extra %s specifier.\n", (yyvsp[(1) - (2)].ptype).type); + } + } + } + } + break; + + case 326: +#line 5290 "parser.y" + { + (yyval.ptype).type = NewString("int"); + (yyval.ptype).us = 0; + } + break; + + case 327: +#line 5294 "parser.y" + { + (yyval.ptype).type = NewString("short"); + (yyval.ptype).us = 0; + } + break; + + case 328: +#line 5298 "parser.y" + { + (yyval.ptype).type = NewString("long"); + (yyval.ptype).us = 0; + } + break; + + case 329: +#line 5302 "parser.y" + { + (yyval.ptype).type = NewString("char"); + (yyval.ptype).us = 0; + } + break; + + case 330: +#line 5306 "parser.y" + { + (yyval.ptype).type = NewString("wchar_t"); + (yyval.ptype).us = 0; + } + break; + + case 331: +#line 5310 "parser.y" + { + (yyval.ptype).type = NewString("float"); + (yyval.ptype).us = 0; + } + break; + + case 332: +#line 5314 "parser.y" + { + (yyval.ptype).type = NewString("double"); + (yyval.ptype).us = 0; + } + break; + + case 333: +#line 5318 "parser.y" + { + (yyval.ptype).us = NewString("signed"); + (yyval.ptype).type = 0; + } + break; + + case 334: +#line 5322 "parser.y" + { + (yyval.ptype).us = NewString("unsigned"); + (yyval.ptype).type = 0; + } + break; + + case 335: +#line 5326 "parser.y" + { + (yyval.ptype).type = NewString("complex"); + (yyval.ptype).us = 0; + } + break; + + case 336: +#line 5330 "parser.y" + { + (yyval.ptype).type = NewString("__int8"); + (yyval.ptype).us = 0; + } + break; + + case 337: +#line 5334 "parser.y" + { + (yyval.ptype).type = NewString("__int16"); + (yyval.ptype).us = 0; + } + break; + + case 338: +#line 5338 "parser.y" + { + (yyval.ptype).type = NewString("__int32"); + (yyval.ptype).us = 0; + } + break; + + case 339: +#line 5342 "parser.y" + { + (yyval.ptype).type = NewString("__int64"); + (yyval.ptype).us = 0; + } + break; + + case 340: +#line 5348 "parser.y" + { /* scanner_check_typedef(); */ } + break; + + case 341: +#line 5348 "parser.y" + { + (yyval.dtype) = (yyvsp[(2) - (2)].dtype); + if ((yyval.dtype).type == T_STRING) { + (yyval.dtype).rawval = NewStringf("\"%(escape)s\"",(yyval.dtype).val); + } else if ((yyval.dtype).type != T_CHAR) { + (yyval.dtype).rawval = 0; + } + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + scanner_ignore_typedef(); + } + break; + + case 342: +#line 5374 "parser.y" + { (yyval.id) = (yyvsp[(1) - (1)].id); } + break; + + case 343: +#line 5375 "parser.y" + { (yyval.id) = (char *) 0;} + break; + + case 344: +#line 5378 "parser.y" + { + + /* Ignore if there is a trailing comma in the enum list */ + if ((yyvsp[(3) - (3)].node)) { + Node *leftSibling = Getattr((yyvsp[(1) - (3)].node),"_last"); + if (!leftSibling) { + leftSibling=(yyvsp[(1) - (3)].node); + } + set_nextSibling(leftSibling,(yyvsp[(3) - (3)].node)); + Setattr((yyvsp[(1) - (3)].node),"_last",(yyvsp[(3) - (3)].node)); + } + (yyval.node) = (yyvsp[(1) - (3)].node); + } + break; + + case 345: +#line 5391 "parser.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + if ((yyvsp[(1) - (1)].node)) { + Setattr((yyvsp[(1) - (1)].node),"_last",(yyvsp[(1) - (1)].node)); + } + } + break; + + case 346: +#line 5399 "parser.y" + { + SwigType *type = NewSwigType(T_INT); + (yyval.node) = new_node("enumitem"); + Setattr((yyval.node),"name",(yyvsp[(1) - (1)].id)); + Setattr((yyval.node),"type",type); + SetFlag((yyval.node),"feature:immutable"); + Delete(type); + } + break; + + case 347: +#line 5407 "parser.y" + { + (yyval.node) = new_node("enumitem"); + Setattr((yyval.node),"name",(yyvsp[(1) - (3)].id)); + Setattr((yyval.node),"enumvalue", (yyvsp[(3) - (3)].dtype).val); + if ((yyvsp[(3) - (3)].dtype).type == T_CHAR) { + SwigType *type = NewSwigType(T_CHAR); + Setattr((yyval.node),"value",NewStringf("\'%(escape)s\'", (yyvsp[(3) - (3)].dtype).val)); + Setattr((yyval.node),"type",type); + Delete(type); + } else { + SwigType *type = NewSwigType(T_INT); + Setattr((yyval.node),"value",(yyvsp[(1) - (3)].id)); + Setattr((yyval.node),"type",type); + Delete(type); + } + SetFlag((yyval.node),"feature:immutable"); + } + break; + + case 348: +#line 5424 "parser.y" + { (yyval.node) = 0; } + break; + + case 349: +#line 5427 "parser.y" + { + (yyval.dtype) = (yyvsp[(1) - (1)].dtype); + if (((yyval.dtype).type != T_INT) && ((yyval.dtype).type != T_UINT) && + ((yyval.dtype).type != T_LONG) && ((yyval.dtype).type != T_ULONG) && + ((yyval.dtype).type != T_SHORT) && ((yyval.dtype).type != T_USHORT) && + ((yyval.dtype).type != T_SCHAR) && ((yyval.dtype).type != T_UCHAR) && + ((yyval.dtype).type != T_CHAR)) { + Swig_error(cparse_file,cparse_line,"Type error. Expecting an int\n"); + } + if ((yyval.dtype).type == T_CHAR) (yyval.dtype).type = T_INT; + } + break; + + case 350: +#line 5442 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 351: +#line 5443 "parser.y" + { + Node *n; + (yyval.dtype).val = (yyvsp[(1) - (1)].type); + (yyval.dtype).type = T_INT; + /* Check if value is in scope */ + n = Swig_symbol_clookup((yyvsp[(1) - (1)].type),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) { + (yyval.dtype).val = NewStringf("%s::%s", q, Getattr(n,"name")); + Delete(q); + } + } + } + } + break; + + case 352: +#line 5462 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 353: +#line 5463 "parser.y" + { + (yyval.dtype).val = NewString((yyvsp[(1) - (1)].id)); + (yyval.dtype).type = T_STRING; + } + break; + + case 354: +#line 5467 "parser.y" + { + SwigType_push((yyvsp[(3) - (5)].type),(yyvsp[(4) - (5)].decl).type); + (yyval.dtype).val = NewStringf("sizeof(%s)",SwigType_str((yyvsp[(3) - (5)].type),0)); + (yyval.dtype).type = T_ULONG; + } + break; + + case 355: +#line 5472 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 356: +#line 5473 "parser.y" + { + (yyval.dtype).val = NewString((yyvsp[(1) - (1)].str)); + if (Len((yyval.dtype).val)) { + (yyval.dtype).rawval = NewStringf("'%(escape)s'", (yyval.dtype).val); + } else { + (yyval.dtype).rawval = NewString("'\\0'"); + } + (yyval.dtype).type = T_CHAR; + (yyval.dtype).bitfield = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 357: +#line 5487 "parser.y" + { + (yyval.dtype).val = NewStringf("(%s)",(yyvsp[(2) - (3)].dtype).val); + (yyval.dtype).type = (yyvsp[(2) - (3)].dtype).type; + } + break; + + case 358: +#line 5494 "parser.y" + { + (yyval.dtype) = (yyvsp[(4) - (4)].dtype); + if ((yyvsp[(4) - (4)].dtype).type != T_STRING) { + switch ((yyvsp[(2) - (4)].dtype).type) { + case T_FLOAT: + case T_DOUBLE: + case T_LONGDOUBLE: + case T_FLTCPLX: + case T_DBLCPLX: + (yyval.dtype).val = NewStringf("(%s)%s", (yyvsp[(2) - (4)].dtype).val, (yyvsp[(4) - (4)].dtype).val); /* SwigType_str and decimal points don't mix! */ + break; + default: + (yyval.dtype).val = NewStringf("(%s) %s", SwigType_str((yyvsp[(2) - (4)].dtype).val,0), (yyvsp[(4) - (4)].dtype).val); + break; + } + } + } + break; + + case 359: +#line 5511 "parser.y" + { + (yyval.dtype) = (yyvsp[(5) - (5)].dtype); + if ((yyvsp[(5) - (5)].dtype).type != T_STRING) { + SwigType_push((yyvsp[(2) - (5)].dtype).val,(yyvsp[(3) - (5)].type)); + (yyval.dtype).val = NewStringf("(%s) %s", SwigType_str((yyvsp[(2) - (5)].dtype).val,0), (yyvsp[(5) - (5)].dtype).val); + } + } + break; + + case 360: +#line 5518 "parser.y" + { + (yyval.dtype) = (yyvsp[(5) - (5)].dtype); + if ((yyvsp[(5) - (5)].dtype).type != T_STRING) { + SwigType_add_reference((yyvsp[(2) - (5)].dtype).val); + (yyval.dtype).val = NewStringf("(%s) %s", SwigType_str((yyvsp[(2) - (5)].dtype).val,0), (yyvsp[(5) - (5)].dtype).val); + } + } + break; + + case 361: +#line 5525 "parser.y" + { + (yyval.dtype) = (yyvsp[(6) - (6)].dtype); + if ((yyvsp[(6) - (6)].dtype).type != T_STRING) { + SwigType_push((yyvsp[(2) - (6)].dtype).val,(yyvsp[(3) - (6)].type)); + SwigType_add_reference((yyvsp[(2) - (6)].dtype).val); + (yyval.dtype).val = NewStringf("(%s) %s", SwigType_str((yyvsp[(2) - (6)].dtype).val,0), (yyvsp[(6) - (6)].dtype).val); + } + } + break; + + case 362: +#line 5533 "parser.y" + { + (yyval.dtype) = (yyvsp[(2) - (2)].dtype); + (yyval.dtype).val = NewStringf("&%s",(yyvsp[(2) - (2)].dtype).val); + } + break; + + case 363: +#line 5537 "parser.y" + { + (yyval.dtype) = (yyvsp[(2) - (2)].dtype); + (yyval.dtype).val = NewStringf("*%s",(yyvsp[(2) - (2)].dtype).val); + } + break; + + case 364: +#line 5543 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 365: +#line 5544 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 366: +#line 5545 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 367: +#line 5546 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 368: +#line 5547 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 369: +#line 5548 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 370: +#line 5549 "parser.y" + { (yyval.dtype) = (yyvsp[(1) - (1)].dtype); } + break; + + case 371: +#line 5552 "parser.y" + { + (yyval.dtype).val = NewStringf("%s+%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 372: +#line 5556 "parser.y" + { + (yyval.dtype).val = NewStringf("%s-%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 373: +#line 5560 "parser.y" + { + (yyval.dtype).val = NewStringf("%s*%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 374: +#line 5564 "parser.y" + { + (yyval.dtype).val = NewStringf("%s/%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 375: +#line 5568 "parser.y" + { + (yyval.dtype).val = NewStringf("%s%%%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 376: +#line 5572 "parser.y" + { + (yyval.dtype).val = NewStringf("%s&%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 377: +#line 5576 "parser.y" + { + (yyval.dtype).val = NewStringf("%s|%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 378: +#line 5580 "parser.y" + { + (yyval.dtype).val = NewStringf("%s^%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote((yyvsp[(1) - (3)].dtype).type,(yyvsp[(3) - (3)].dtype).type); + } + break; + + case 379: +#line 5584 "parser.y" + { + (yyval.dtype).val = NewStringf("%s << %s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote_type((yyvsp[(1) - (3)].dtype).type); + } + break; + + case 380: +#line 5588 "parser.y" + { + (yyval.dtype).val = NewStringf("%s >> %s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = promote_type((yyvsp[(1) - (3)].dtype).type); + } + break; + + case 381: +#line 5592 "parser.y" + { + (yyval.dtype).val = NewStringf("%s&&%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 382: +#line 5596 "parser.y" + { + (yyval.dtype).val = NewStringf("%s||%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 383: +#line 5600 "parser.y" + { + (yyval.dtype).val = NewStringf("%s==%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 384: +#line 5604 "parser.y" + { + (yyval.dtype).val = NewStringf("%s!=%s",(yyvsp[(1) - (3)].dtype).val,(yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 385: +#line 5618 "parser.y" + { + /* Putting >= in the expression literally causes an infinite + * loop somewhere in the type system. Just workaround for now + * - SWIG_GE is defined in swiglabels.swg. */ + (yyval.dtype).val = NewStringf("%s SWIG_GE %s", (yyvsp[(1) - (3)].dtype).val, (yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 386: +#line 5625 "parser.y" + { + (yyval.dtype).val = NewStringf("%s SWIG_LE %s", (yyvsp[(1) - (3)].dtype).val, (yyvsp[(3) - (3)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 387: +#line 5629 "parser.y" + { + (yyval.dtype).val = NewStringf("%s?%s:%s", (yyvsp[(1) - (5)].dtype).val, (yyvsp[(3) - (5)].dtype).val, (yyvsp[(5) - (5)].dtype).val); + /* This may not be exactly right, but is probably good enough + * for the purposes of parsing constant expressions. */ + (yyval.dtype).type = promote((yyvsp[(3) - (5)].dtype).type, (yyvsp[(5) - (5)].dtype).type); + } + break; + + case 388: +#line 5635 "parser.y" + { + (yyval.dtype).val = NewStringf("-%s",(yyvsp[(2) - (2)].dtype).val); + (yyval.dtype).type = (yyvsp[(2) - (2)].dtype).type; + } + break; + + case 389: +#line 5639 "parser.y" + { + (yyval.dtype).val = NewStringf("+%s",(yyvsp[(2) - (2)].dtype).val); + (yyval.dtype).type = (yyvsp[(2) - (2)].dtype).type; + } + break; + + case 390: +#line 5643 "parser.y" + { + (yyval.dtype).val = NewStringf("~%s",(yyvsp[(2) - (2)].dtype).val); + (yyval.dtype).type = (yyvsp[(2) - (2)].dtype).type; + } + break; + + case 391: +#line 5647 "parser.y" + { + (yyval.dtype).val = NewStringf("!%s",(yyvsp[(2) - (2)].dtype).val); + (yyval.dtype).type = T_INT; + } + break; + + case 392: +#line 5651 "parser.y" + { + String *qty; + skip_balanced('(',')'); + qty = Swig_symbol_type_qualify((yyvsp[(1) - (2)].type),0); + if (SwigType_istemplate(qty)) { + String *nstr = SwigType_namestr(qty); + Delete(qty); + qty = nstr; + } + (yyval.dtype).val = NewStringf("%s%s",qty,scanner_ccode); + Clear(scanner_ccode); + (yyval.dtype).type = T_INT; + Delete(qty); + } + break; + + case 393: +#line 5667 "parser.y" + { + (yyval.bases) = (yyvsp[(1) - (1)].bases); + } + break; + + case 394: +#line 5672 "parser.y" + { inherit_list = 1; } + break; + + case 395: +#line 5672 "parser.y" + { (yyval.bases) = (yyvsp[(3) - (3)].bases); inherit_list = 0; } + break; + + case 396: +#line 5673 "parser.y" + { (yyval.bases) = 0; } + break; + + case 397: +#line 5676 "parser.y" + { + Hash *list = NewHash(); + Node *base = (yyvsp[(1) - (1)].node); + 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); + (yyval.bases) = list; + } + break; + + case 398: +#line 5693 "parser.y" + { + Hash *list = (yyvsp[(1) - (3)].bases); + Node *base = (yyvsp[(3) - (3)].node); + Node *name = Getattr(base,"name"); + Append(Getattr(list,Getattr(base,"access")),name); + (yyval.bases) = list; + } + break; + + case 399: +#line 5702 "parser.y" + { + (yyval.node) = NewHash(); + Setfile((yyval.node),cparse_file); + Setline((yyval.node),cparse_line); + Setattr((yyval.node),"name",(yyvsp[(2) - (2)].str)); + if (last_cpptype && (Strcmp(last_cpptype,"struct") != 0)) { + Setattr((yyval.node),"access","private"); + Swig_warning(WARN_PARSE_NO_ACCESS,cparse_file,cparse_line, + "No access specifier given for base class %s (ignored).\n",(yyvsp[(2) - (2)].str)); + } else { + Setattr((yyval.node),"access","public"); + } + } + break; + + case 400: +#line 5715 "parser.y" + { + (yyval.node) = NewHash(); + Setfile((yyval.node),cparse_file); + Setline((yyval.node),cparse_line); + Setattr((yyval.node),"name",(yyvsp[(4) - (4)].str)); + Setattr((yyval.node),"access",(yyvsp[(2) - (4)].id)); + if (Strcmp((yyvsp[(2) - (4)].id),"public") != 0) { + Swig_warning(WARN_PARSE_PRIVATE_INHERIT, cparse_file, + cparse_line,"%s inheritance ignored.\n", (yyvsp[(2) - (4)].id)); + } + } + break; + + case 401: +#line 5728 "parser.y" + { (yyval.id) = (char*)"public"; } + break; + + case 402: +#line 5729 "parser.y" + { (yyval.id) = (char*)"private"; } + break; + + case 403: +#line 5730 "parser.y" + { (yyval.id) = (char*)"protected"; } + break; + + case 404: +#line 5734 "parser.y" + { + (yyval.id) = (char*)"class"; + if (!inherit_list) last_cpptype = (yyval.id); + } + break; + + case 405: +#line 5738 "parser.y" + { + (yyval.id) = (char *)"typename"; + if (!inherit_list) last_cpptype = (yyval.id); + } + break; + + case 406: +#line 5744 "parser.y" + { + (yyval.id) = (yyvsp[(1) - (1)].id); + } + break; + + case 407: +#line 5747 "parser.y" + { + (yyval.id) = (char*)"struct"; + if (!inherit_list) last_cpptype = (yyval.id); + } + break; + + case 408: +#line 5751 "parser.y" + { + (yyval.id) = (char*)"union"; + if (!inherit_list) last_cpptype = (yyval.id); + } + break; + + case 411: +#line 5761 "parser.y" + { + (yyval.dtype).qualifier = (yyvsp[(1) - (1)].str); + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 412: +#line 5766 "parser.y" + { + (yyval.dtype).qualifier = 0; + (yyval.dtype).throws = (yyvsp[(3) - (4)].pl); + (yyval.dtype).throwf = NewString("1"); + } + break; + + case 413: +#line 5771 "parser.y" + { + (yyval.dtype).qualifier = (yyvsp[(1) - (5)].str); + (yyval.dtype).throws = (yyvsp[(4) - (5)].pl); + (yyval.dtype).throwf = NewString("1"); + } + break; + + case 414: +#line 5776 "parser.y" + { + (yyval.dtype).qualifier = 0; + (yyval.dtype).throws = 0; + (yyval.dtype).throwf = 0; + } + break; + + case 415: +#line 5783 "parser.y" + { + Clear(scanner_ccode); + (yyval.decl).have_parms = 0; + (yyval.decl).defarg = 0; + (yyval.decl).throws = (yyvsp[(1) - (3)].dtype).throws; + (yyval.decl).throwf = (yyvsp[(1) - (3)].dtype).throwf; + } + break; + + case 416: +#line 5790 "parser.y" + { + skip_balanced('{','}'); + (yyval.decl).have_parms = 0; + (yyval.decl).defarg = 0; + (yyval.decl).throws = (yyvsp[(1) - (3)].dtype).throws; + (yyval.decl).throwf = (yyvsp[(1) - (3)].dtype).throwf; + } + break; + + case 417: +#line 5797 "parser.y" + { + Clear(scanner_ccode); + (yyval.decl).parms = (yyvsp[(2) - (4)].pl); + (yyval.decl).have_parms = 1; + (yyval.decl).defarg = 0; + (yyval.decl).throws = 0; + (yyval.decl).throwf = 0; + } + break; + + case 418: +#line 5805 "parser.y" + { + skip_balanced('{','}'); + (yyval.decl).parms = (yyvsp[(2) - (4)].pl); + (yyval.decl).have_parms = 1; + (yyval.decl).defarg = 0; + (yyval.decl).throws = 0; + (yyval.decl).throwf = 0; + } + break; + + case 419: +#line 5813 "parser.y" + { + (yyval.decl).have_parms = 0; + (yyval.decl).defarg = (yyvsp[(2) - (3)].dtype).val; + (yyval.decl).throws = 0; + (yyval.decl).throwf = 0; + } + break; + + case 424: +#line 5829 "parser.y" + { + skip_balanced('(',')'); + Clear(scanner_ccode); + } + break; + + case 425: +#line 5835 "parser.y" + { + String *s = NewStringEmpty(); + SwigType_add_template(s,(yyvsp[(2) - (3)].p)); + (yyval.id) = Char(s); + scanner_last_id(1); + } + break; + + case 426: +#line 5841 "parser.y" + { (yyval.id) = (char*)""; } + break; + + case 427: +#line 5844 "parser.y" + { (yyval.id) = (yyvsp[(1) - (1)].id); } + break; + + case 428: +#line 5845 "parser.y" + { (yyval.id) = (yyvsp[(1) - (1)].id); } + break; + + case 429: +#line 5848 "parser.y" + { (yyval.id) = (yyvsp[(1) - (1)].id); } + break; + + case 430: +#line 5849 "parser.y" + { (yyval.id) = 0; } + break; + + case 431: +#line 5852 "parser.y" + { + (yyval.str) = 0; + if (!(yyval.str)) (yyval.str) = NewStringf("%s%s", (yyvsp[(1) - (2)].str),(yyvsp[(2) - (2)].str)); + Delete((yyvsp[(2) - (2)].str)); + } + break; + + case 432: +#line 5857 "parser.y" + { + (yyval.str) = NewStringf("::%s%s",(yyvsp[(3) - (4)].str),(yyvsp[(4) - (4)].str)); + Delete((yyvsp[(4) - (4)].str)); + } + break; + + case 433: +#line 5861 "parser.y" + { + (yyval.str) = NewString((yyvsp[(1) - (1)].str)); + } + break; + + case 434: +#line 5864 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(3) - (3)].str)); + } + break; + + case 435: +#line 5867 "parser.y" + { + (yyval.str) = NewString((yyvsp[(1) - (1)].str)); + } + break; + + case 436: +#line 5870 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(3) - (3)].str)); + } + break; + + case 437: +#line 5875 "parser.y" + { + (yyval.str) = NewStringf("::%s%s",(yyvsp[(2) - (3)].str),(yyvsp[(3) - (3)].str)); + Delete((yyvsp[(3) - (3)].str)); + } + break; + + case 438: +#line 5879 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(2) - (2)].str)); + } + break; + + case 439: +#line 5882 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(2) - (2)].str)); + } + break; + + case 440: +#line 5889 "parser.y" + { + (yyval.str) = NewStringf("::~%s",(yyvsp[(2) - (2)].str)); + } + break; + + case 441: +#line 5895 "parser.y" + { + (yyval.str) = NewStringf("%s%s",(yyvsp[(1) - (2)].id),(yyvsp[(2) - (2)].id)); + /* if (Len($2)) { + scanner_last_id(1); + } */ + } + break; + + case 442: +#line 5904 "parser.y" + { + (yyval.str) = 0; + if (!(yyval.str)) (yyval.str) = NewStringf("%s%s", (yyvsp[(1) - (2)].id),(yyvsp[(2) - (2)].str)); + Delete((yyvsp[(2) - (2)].str)); + } + break; + + case 443: +#line 5909 "parser.y" + { + (yyval.str) = NewStringf("::%s%s",(yyvsp[(3) - (4)].id),(yyvsp[(4) - (4)].str)); + Delete((yyvsp[(4) - (4)].str)); + } + break; + + case 444: +#line 5913 "parser.y" + { + (yyval.str) = NewString((yyvsp[(1) - (1)].id)); + } + break; + + case 445: +#line 5916 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(3) - (3)].id)); + } + break; + + case 446: +#line 5919 "parser.y" + { + (yyval.str) = NewString((yyvsp[(1) - (1)].str)); + } + break; + + case 447: +#line 5922 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(3) - (3)].str)); + } + break; + + case 448: +#line 5927 "parser.y" + { + (yyval.str) = NewStringf("::%s%s",(yyvsp[(2) - (3)].id),(yyvsp[(3) - (3)].str)); + Delete((yyvsp[(3) - (3)].str)); + } + break; + + case 449: +#line 5931 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(2) - (2)].id)); + } + break; + + case 450: +#line 5934 "parser.y" + { + (yyval.str) = NewStringf("::%s",(yyvsp[(2) - (2)].str)); + } + break; + + case 451: +#line 5937 "parser.y" + { + (yyval.str) = NewStringf("::~%s",(yyvsp[(2) - (2)].id)); + } + break; + + case 452: +#line 5943 "parser.y" + { + (yyval.id) = (char *) malloc(strlen((yyvsp[(1) - (2)].id))+strlen((yyvsp[(2) - (2)].id))+1); + strcpy((yyval.id),(yyvsp[(1) - (2)].id)); + strcat((yyval.id),(yyvsp[(2) - (2)].id)); + } + break; + + case 453: +#line 5948 "parser.y" + { (yyval.id) = (yyvsp[(1) - (1)].id);} + break; + + case 454: +#line 5951 "parser.y" + { + (yyval.str) = NewString((yyvsp[(1) - (1)].id)); + } + break; + + case 455: +#line 5954 "parser.y" + { + skip_balanced('{','}'); + (yyval.str) = NewString(scanner_ccode); + } + break; + + case 456: +#line 5958 "parser.y" + { + (yyval.str) = (yyvsp[(1) - (1)].str); + } + break; + + case 457: +#line 5963 "parser.y" + { + Hash *n; + (yyval.node) = NewHash(); + n = (yyvsp[(2) - (3)].node); + while(n) { + String *name, *value; + name = Getattr(n,"name"); + value = Getattr(n,"value"); + if (!value) value = (String *) "1"; + Setattr((yyval.node),name, value); + n = nextSibling(n); + } + } + break; + + case 458: +#line 5976 "parser.y" + { (yyval.node) = 0; } + break; + + case 459: +#line 5980 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"name",(yyvsp[(1) - (3)].id)); + Setattr((yyval.node),"value",(yyvsp[(3) - (3)].id)); + } + break; + + case 460: +#line 5985 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"name",(yyvsp[(1) - (5)].id)); + Setattr((yyval.node),"value",(yyvsp[(3) - (5)].id)); + set_nextSibling((yyval.node),(yyvsp[(5) - (5)].node)); + } + break; + + case 461: +#line 5991 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"name",(yyvsp[(1) - (1)].id)); + } + break; + + case 462: +#line 5995 "parser.y" + { + (yyval.node) = NewHash(); + Setattr((yyval.node),"name",(yyvsp[(1) - (3)].id)); + set_nextSibling((yyval.node),(yyvsp[(3) - (3)].node)); + } + break; + + case 463: +#line 6000 "parser.y" + { + (yyval.node) = (yyvsp[(3) - (3)].node); + Setattr((yyval.node),"name",(yyvsp[(1) - (3)].id)); + } + break; + + case 464: +#line 6004 "parser.y" + { + (yyval.node) = (yyvsp[(3) - (5)].node); + Setattr((yyval.node),"name",(yyvsp[(1) - (5)].id)); + set_nextSibling((yyval.node),(yyvsp[(5) - (5)].node)); + } + break; + + case 465: +#line 6011 "parser.y" + { + (yyval.id) = (yyvsp[(1) - (1)].id); + } + break; + + case 466: +#line 6014 "parser.y" + { + (yyval.id) = Char((yyvsp[(1) - (1)].dtype).val); + } + break; + + +/* Line 1267 of yacc.c. */ +#line 10178 "y.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 6021 "parser.y" + + +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) { + String *ns; + char *cs = Char(s); + if (cs && cs[0] != '(') { + ns = NewStringf("(%s);",s); + } else { + ns = NewStringf("%s;",s); + } + 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/Source/CParse/parser.h b/Source/CParse/parser.h new file mode 100644 index 0000000..47c4459 --- /dev/null +++ b/Source/CParse/parser.h @@ -0,0 +1,351 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + ID = 258, + HBLOCK = 259, + POUND = 260, + STRING = 261, + INCLUDE = 262, + IMPORT = 263, + INSERT = 264, + CHARCONST = 265, + NUM_INT = 266, + NUM_FLOAT = 267, + NUM_UNSIGNED = 268, + NUM_LONG = 269, + NUM_ULONG = 270, + NUM_LONGLONG = 271, + NUM_ULONGLONG = 272, + TYPEDEF = 273, + TYPE_INT = 274, + TYPE_UNSIGNED = 275, + TYPE_SHORT = 276, + TYPE_LONG = 277, + TYPE_FLOAT = 278, + TYPE_DOUBLE = 279, + TYPE_CHAR = 280, + TYPE_WCHAR = 281, + TYPE_VOID = 282, + TYPE_SIGNED = 283, + TYPE_BOOL = 284, + TYPE_COMPLEX = 285, + TYPE_TYPEDEF = 286, + TYPE_RAW = 287, + TYPE_NON_ISO_INT8 = 288, + TYPE_NON_ISO_INT16 = 289, + TYPE_NON_ISO_INT32 = 290, + TYPE_NON_ISO_INT64 = 291, + LPAREN = 292, + RPAREN = 293, + COMMA = 294, + SEMI = 295, + EXTERN = 296, + INIT = 297, + LBRACE = 298, + RBRACE = 299, + PERIOD = 300, + CONST_QUAL = 301, + VOLATILE = 302, + REGISTER = 303, + STRUCT = 304, + UNION = 305, + EQUAL = 306, + SIZEOF = 307, + MODULE = 308, + LBRACKET = 309, + RBRACKET = 310, + ILLEGAL = 311, + CONSTANT = 312, + NAME = 313, + RENAME = 314, + NAMEWARN = 315, + EXTEND = 316, + PRAGMA = 317, + FEATURE = 318, + VARARGS = 319, + ENUM = 320, + CLASS = 321, + TYPENAME = 322, + PRIVATE = 323, + PUBLIC = 324, + PROTECTED = 325, + COLON = 326, + STATIC = 327, + VIRTUAL = 328, + FRIEND = 329, + THROW = 330, + CATCH = 331, + EXPLICIT = 332, + USING = 333, + NAMESPACE = 334, + NATIVE = 335, + INLINE = 336, + TYPEMAP = 337, + EXCEPT = 338, + ECHO = 339, + APPLY = 340, + CLEAR = 341, + SWIGTEMPLATE = 342, + FRAGMENT = 343, + WARN = 344, + LESSTHAN = 345, + GREATERTHAN = 346, + MODULO = 347, + DELETE_KW = 348, + LESSTHANOREQUALTO = 349, + GREATERTHANOREQUALTO = 350, + EQUALTO = 351, + NOTEQUALTO = 352, + QUESTIONMARK = 353, + TYPES = 354, + PARMS = 355, + NONID = 356, + DSTAR = 357, + DCNOT = 358, + TEMPLATE = 359, + OPERATOR = 360, + COPERATOR = 361, + PARSETYPE = 362, + PARSEPARM = 363, + PARSEPARMS = 364, + CAST = 365, + LOR = 366, + LAND = 367, + OR = 368, + XOR = 369, + AND = 370, + RSHIFT = 371, + LSHIFT = 372, + MINUS = 373, + PLUS = 374, + MODULUS = 375, + SLASH = 376, + STAR = 377, + LNOT = 378, + NOT = 379, + UMINUS = 380, + DCOLON = 381 + }; +#endif +/* Tokens. */ +#define ID 258 +#define HBLOCK 259 +#define POUND 260 +#define STRING 261 +#define INCLUDE 262 +#define IMPORT 263 +#define INSERT 264 +#define CHARCONST 265 +#define NUM_INT 266 +#define NUM_FLOAT 267 +#define NUM_UNSIGNED 268 +#define NUM_LONG 269 +#define NUM_ULONG 270 +#define NUM_LONGLONG 271 +#define NUM_ULONGLONG 272 +#define TYPEDEF 273 +#define TYPE_INT 274 +#define TYPE_UNSIGNED 275 +#define TYPE_SHORT 276 +#define TYPE_LONG 277 +#define TYPE_FLOAT 278 +#define TYPE_DOUBLE 279 +#define TYPE_CHAR 280 +#define TYPE_WCHAR 281 +#define TYPE_VOID 282 +#define TYPE_SIGNED 283 +#define TYPE_BOOL 284 +#define TYPE_COMPLEX 285 +#define TYPE_TYPEDEF 286 +#define TYPE_RAW 287 +#define TYPE_NON_ISO_INT8 288 +#define TYPE_NON_ISO_INT16 289 +#define TYPE_NON_ISO_INT32 290 +#define TYPE_NON_ISO_INT64 291 +#define LPAREN 292 +#define RPAREN 293 +#define COMMA 294 +#define SEMI 295 +#define EXTERN 296 +#define INIT 297 +#define LBRACE 298 +#define RBRACE 299 +#define PERIOD 300 +#define CONST_QUAL 301 +#define VOLATILE 302 +#define REGISTER 303 +#define STRUCT 304 +#define UNION 305 +#define EQUAL 306 +#define SIZEOF 307 +#define MODULE 308 +#define LBRACKET 309 +#define RBRACKET 310 +#define ILLEGAL 311 +#define CONSTANT 312 +#define NAME 313 +#define RENAME 314 +#define NAMEWARN 315 +#define EXTEND 316 +#define PRAGMA 317 +#define FEATURE 318 +#define VARARGS 319 +#define ENUM 320 +#define CLASS 321 +#define TYPENAME 322 +#define PRIVATE 323 +#define PUBLIC 324 +#define PROTECTED 325 +#define COLON 326 +#define STATIC 327 +#define VIRTUAL 328 +#define FRIEND 329 +#define THROW 330 +#define CATCH 331 +#define EXPLICIT 332 +#define USING 333 +#define NAMESPACE 334 +#define NATIVE 335 +#define INLINE 336 +#define TYPEMAP 337 +#define EXCEPT 338 +#define ECHO 339 +#define APPLY 340 +#define CLEAR 341 +#define SWIGTEMPLATE 342 +#define FRAGMENT 343 +#define WARN 344 +#define LESSTHAN 345 +#define GREATERTHAN 346 +#define MODULO 347 +#define DELETE_KW 348 +#define LESSTHANOREQUALTO 349 +#define GREATERTHANOREQUALTO 350 +#define EQUALTO 351 +#define NOTEQUALTO 352 +#define QUESTIONMARK 353 +#define TYPES 354 +#define PARMS 355 +#define NONID 356 +#define DSTAR 357 +#define DCNOT 358 +#define TEMPLATE 359 +#define OPERATOR 360 +#define COPERATOR 361 +#define PARSETYPE 362 +#define PARSEPARM 363 +#define PARSEPARMS 364 +#define CAST 365 +#define LOR 366 +#define LAND 367 +#define OR 368 +#define XOR 369 +#define AND 370 +#define RSHIFT 371 +#define LSHIFT 372 +#define MINUS 373 +#define PLUS 374 +#define MODULUS 375 +#define SLASH 376 +#define STAR 377 +#define LNOT 378 +#define NOT 379 +#define UMINUS 380 +#define DCOLON 381 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 1440 "parser.y" +{ + char *id; + List *bases; + struct Define { + String *val; + String *rawval; + int type; + String *qualifier; + String *bitfield; + Parm *throws; + String *throwf; + } dtype; + struct { + char *type; + String *filename; + int line; + } loc; + struct { + char *id; + SwigType *type; + String *defarg; + ParmList *parms; + short have_parms; + ParmList *throws; + String *throwf; + } decl; + Parm *tparms; + struct { + String *method; + Hash *kwargs; + } tmap; + struct { + String *type; + String *us; + } ptype; + SwigType *type; + String *str; + Parm *p; + ParmList *pl; + int ivalue; + Node *node; +} +/* Line 1489 of yacc.c. */ +#line 344 "y.tab.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y new file mode 100644 index 0000000..9a36030 --- /dev/null +++ b/Source/CParse/parser.y @@ -0,0 +1,6066 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.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. + * ----------------------------------------------------------------------------- */ + +%{ + +#define yylex yylex + +char cvsroot_parser_y[] = "$Id: parser.y 11582 2009-08-15 10:40:19Z wsfulton $"; + +#include "swig.h" +#include "cparse.h" +#include "preprocessor.h" +#include <ctype.h> + +/* We do this for portability */ +#undef alloca +#define alloca malloc + +/* ----------------------------------------------------------------------------- + * Externals + * ----------------------------------------------------------------------------- */ + +int yyparse(); + +/* NEW Variables */ + +static Node *top = 0; /* Top of the generated parse tree */ +static int unnamed = 0; /* Unnamed datatype counter */ +static Hash *extendhash = 0; /* Hash table of added methods */ +static Hash *classes = 0; /* Hash table of classes */ +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 char *last_cpptype = 0; +static int inherit_list = 0; +static Parm *template_parameters = 0; +static int extendmode = 0; +static int compact_default_args = 0; +static int template_reduce = 0; +static int cparse_externc = 0; + +static int max_class_levels = 0; +static int class_level = 0; +static Node **class_decl = NULL; + +/* ----------------------------------------------------------------------------- + * 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 = NewHash(); + set_nodeType(n,tag); + Setfile(n,cparse_file); + Setline(n,cparse_line); + return n; +} + +/* Copies a node. Does not copy tree links or symbol table data (except for + sym:name) */ + +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; + } + /* Looks okay. Just copy the data using Copy */ + ci = Copy(k.item); + Setattr(nn, key, ci); + Delete(ci); + } + return nn; +} + +/* ----------------------------------------------------------------------------- + * Variables + * ----------------------------------------------------------------------------- */ + +static char *typemap_lang = 0; /* Current language setting */ + +static int cplus_mode = 0; +static String *class_rename = 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) 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_node_scope(String *cname); + + +Hash *Swig_cparse_features(void) { + static Hash *features_hash = 0; + if (!features_hash) features_hash = NewHash(); + return features_hash; +} + +static String *feature_identifier_fix(String *s) { + if (SwigType_istemplate(s)) { + String *tp, *ts, *ta, *tq; + tp = SwigType_templateprefix(s); + 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); + } +} + +/* 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) { + 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; + return Swig_name_make(n,Namespaceprefix,name,decl,add_oldname); +} + +/* Generate an unnamed identifier */ +static String *make_unnamed() { + unnamed++; + return NewStringf("$unnamed%d$",unnamed); +} + +/* Return if the node is a friend declaration */ +static int is_friend(Node *n) { + return Cmp(Getattr(n,"storage"),"friend") == 0; +} + +static int is_operator(String *name) { + return Strncmp(name,"operator ", 9) == 0; +} + + +/* Add declaration list to symbol table */ +static int add_only_one = 0; + +static void add_symbols(Node *n) { + String *decl; + String *wrn = 0; + if (inclass && n) { + cparse_normalize_void(n); + } + while (n) { + String *symname = 0; + /* for friends, we need to pop the scope once */ + String *old_prefix = 0; + Symtab *old_scope = 0; + int isfriend = inclass && is_friend(n); + int iscdecl = Cmp(nodeType(n),"cdecl") == 0; + int only_csymbol = 0; + if (extendmode) { + Setattr(n,"isextension","1"); + } + + 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 (!Getattr(n,"parentNode") && class_level) set_parentNode(n,class_decl[class_level - 1]); + */ + Setattr(n,"ismember","1"); + } + } + 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; + } + } + } 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)) { + 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) { + wrn = Swig_name_warning(n, Namespaceprefix, symname,0); + } + } else { + String *name = Getattr(n,"name"); + SwigType *fdecl = Copy(decl); + SwigType *fun = SwigType_pop_function(fdecl); + if (iscdecl) { + Setattr(n,"kind","function"); + } + + Swig_features_get(Swig_cparse_features(),Namespaceprefix,name,fun,n); + + symname = make_name(n, name,fun); + wrn = Swig_name_warning(n, Namespaceprefix,symname,fun); + + Delete(fdecl); + Delete(fun); + + } + if (!symname) { + n = nextSibling(n); + continue; + } + if (only_csymbol || GetFlag(n,"feature:ignore")) { + /* Only add to C symbol table and continue */ + Swig_symbol_add(0, n); + } else if (strncmp(Char(symname),"$ignore",7) == 0) { + char *c = Char(symname)+7; + SetFlag(n,"feature:ignore"); + if (strlen(c)) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0,Getfile(n), Getline(n), "%s\n",c+1); + SWIG_WARN_NODE_END(n); + } + Swig_symbol_add(0, n); + } else { + Node *c; + if ((wrn) && (Len(wrn))) { + String *metaname = symname; + if (!Getmeta(metaname,"already_warned")) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0,Getfile(n),Getline(n), "%s\n", wrn); + SWIG_WARN_NODE_END(n); + Setmeta(metaname,"already_warned","1"); + } + } + c = Swig_symbol_add(symname,n); + + if (c != n) { + /* symbol conflict attempting to add in the new symbol */ + if (Getattr(n,"sym:weak")) { + Setattr(n,"sym:name",symname); + } else { + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + int redefined = Swig_need_redefined_warn(n,c,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"))) { + 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) { + inclass = 1; + 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 = 0; + current_class = 0; + } + } 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); + } +} + +/* Extension merge. This function is used to handle the %extend directive + when it appears before a class definition. To handle this, the %extend + actually needs to take precedence. Therefore, we will selectively nuke symbols + from the current symbol table, replacing them with the added methods */ + +static void merge_extensions(Node *cls, Node *am) { + Node *n; + Node *csym; + + n = firstChild(am); + while (n) { + String *symname; + if (Strcmp(nodeType(n),"constructor") == 0) { + symname = Getattr(n,"sym:name"); + if (symname) { + if (Strcmp(symname,Getattr(n,"name")) == 0) { + /* If the name and the sym:name of a constructor are the same, + then it hasn't been renamed. However---the name of the class + itself might have been renamed so we need to do a consistency + check here */ + if (Getattr(cls,"sym:name")) { + Setattr(n,"sym:name", Getattr(cls,"sym:name")); + } + } + } + } + + symname = Getattr(n,"sym:name"); + DohIncref(symname); + if ((symname) && (!Getattr(n,"error"))) { + /* Remove node from its symbol table */ + Swig_symbol_remove(n); + csym = Swig_symbol_add(symname,n); + if (csym != n) { + /* Conflict with previous definition. Nuke previous definition */ + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + Printf(ec,"Identifier '%s' redefined by %%extend (ignored),",symname); + Printf(en,"%%extend definition of '%s'.",symname); + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(csym),Getline(csym),"%s\n",ec); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); + SWIG_WARN_NODE_END(n); + Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(csym),Getline(csym),ec, + Getfile(n),Getline(n),en); + Setattr(csym,"error",e); + Delete(e); + Delete(en); + Delete(ec); + Swig_symbol_remove(csym); /* Remove class definition */ + Swig_symbol_add(symname,n); /* Insert extend definition */ + } + } + n = nextSibling(n); + } +} + +static void append_previous_extension(Node *cls, Node *am) { + Node *n, *ne; + Node *pe = 0; + Node *ae = 0; + + if (!am) return; + + n = firstChild(am); + while (n) { + ne = nextSibling(n); + set_nextSibling(n,0); + /* typemaps and fragments need to be prepended */ + if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) { + if (!pe) pe = new_node("extend"); + appendChild(pe, n); + } else { + if (!ae) ae = new_node("extend"); + appendChild(ae, n); + } + n = ne; + } + if (pe) prependChild(cls,pe); + if (ae) appendChild(cls,ae); +} + + +/* Check for unused %extend. Special case, don't report unused + extensions for templates */ + +static void check_extensions() { + Iterator ki; + + if (!extendhash) return; + for (ki = First(extendhash); ki.key; ki = Next(ki)) { + if (!Strchr(ki.key,'<')) { + SWIG_WARN_NODE_BEGIN(ki.item); + Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", ki.key); + SWIG_WARN_NODE_END(ki.item); + } + } +} + +/* Check a set of declarations to see if any are pure-abstract */ + +static List *pure_abstract(Node *n) { + List *abs = 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 (!abs) { + abs = NewList(); + } + Append(abs,n); + Setattr(n,"abstract","1"); + } + } + } else if (Cmp(nodeType(n),"destructor") == 0) { + if (Cmp(Getattr(n,"value"),"0") == 0) { + if (!abs) { + abs = NewList(); + } + Append(abs,n); + Setattr(n,"abstract","1"); + } + } + n = nextSibling(n); + } + return abs; +} + +/* Make a classname */ + +static String *make_class_name(String *name) { + String *nname = 0; + if (Namespaceprefix) { + nname= NewStringf("%s::%s", Namespaceprefix, name); + } else { + nname = NewString(name); + } + if (SwigType_istemplate(nname)) { + String *prefix, *args, *qargs; + prefix = SwigType_templateprefix(nname); + args = SwigType_templateargs(nname); + qargs = Swig_symbol_type_qualify(args,0); + Append(prefix,qargs); + Delete(nname); + Delete(args); + Delete(qargs); + nname = prefix; + } + return nname; +} + +static List *make_inherit_list(String *clsname, List *names) { + int i, ilen; + String *derived; + List *bases = NewList(); + + if (Namespaceprefix) derived = NewStringf("%s::%s", Namespaceprefix,clsname); + else derived = NewString(clsname); + + ilen = Len(names); + for (i = 0; i < ilen; i++) { + Node *s; + String *base; + String *n = Getitem(names,i); + /* Try to figure out where this symbol is */ + s = Swig_symbol_clookup(n,0); + if (s) { + while (s && (Strcmp(nodeType(s),"class") != 0)) { + /* Not a class. Could be a typedef though. */ + String *storage = Getattr(s,"storage"); + if (storage && (Strcmp(storage,"typedef") == 0)) { + String *nn = Getattr(s,"type"); + s = Swig_symbol_clookup(nn,Getattr(s,"sym:symtab")); + } else { + break; + } + } + if (s && ((Strcmp(nodeType(s),"class") == 0) || (Strcmp(nodeType(s),"template") == 0))) { + String *q = Swig_symbol_qualified(s); + Append(bases,s); + if (q) { + base = NewStringf("%s::%s", q, Getattr(s,"name")); + Delete(q); + } else { + base = NewString(Getattr(s,"name")); + } + } else { + base = NewString(n); + } + } else { + base = NewString(n); + } + if (base) { + Swig_name_inherit(base,derived); + Delete(base); + } + } + return bases; +} + +/* If the class name is qualified. We need to create or lookup namespace entries */ + +static Symtab *get_global_scope() { + Symtab *symtab = Swig_symbol_current(); + Node *pn = parentNode(symtab); + while (pn) { + symtab = pn; + pn = parentNode(symtab); + if (!pn) break; + } + 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); + size_t 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; +} + + +static Node *nscope = 0; +static Node *nscope_inner = 0; +static String *resolve_node_scope(String *cname) { + Symtab *gscope = 0; + nscope = 0; + nscope_inner = 0; + if (Swig_scopename_check(cname)) { + Node *ns; + String *prefix = Swig_scopename_prefix(cname); + String *base = Swig_scopename_last(cname); + if (prefix && (Strncmp(prefix,"::",2) == 0)) { + /* Use the global scope */ + String *nprefix = NewString(Char(prefix)+2); + Delete(prefix); + prefix= nprefix; + gscope = get_global_scope(); + } + if (!prefix || (Len(prefix) == 0)) { + /* Use the global scope, but we need to add a 'global' namespace. */ + if (!gscope) gscope = get_global_scope(); + /* 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; + 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 = base; + } + 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; + String *sname; + Iterator si; + String *name = NewString(prefix); + scopes = NewList(); + while (name) { + String *base = Swig_scopename_last(name); + String *tprefix = Swig_scopename_prefix(name); + Insert(scopes,0,base); + Delete(base); + Delete(name); + name = tprefix; + } + 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); + ns1 = Swig_symbol_clookup(sname,0); + /* 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 = base; + Delete(scopes); + } + } + Delete(prefix); + } + return cname; +} + + + + + +/* Structures for handling code fragments built for nested classes */ + +typedef struct Nested { + String *code; /* Associated code fragment */ + int line; /* line number where it starts */ + char *name; /* Name associated with this nested class */ + char *kind; /* Kind of class */ + int unnamed; /* unnamed class */ + SwigType *type; /* Datatype associated with the name */ + struct Nested *next; /* Next code fragment in list */ +} Nested; + +/* Some internal variables for saving nested class information */ + +static Nested *nested_list = 0; + +/* Add a function to the nested list */ + +static void add_nested(Nested *n) { + Nested *n1; + if (!nested_list) nested_list = n; + else { + n1 = nested_list; + while (n1->next) n1 = n1->next; + n1->next = n; + } +} + +/* Strips C-style and C++-style comments from string in-place. */ +static void strip_comments(char *string) { + int state = 0; /* + * 0 - not in comment + * 1 - in c-style comment + * 2 - in c++-style comment + * 3 - in string + * 4 - after reading / not in comments + * 5 - after reading * in c-style comments + * 6 - after reading \ in strings + */ + char * c = string; + while (*c) { + switch (state) { + case 0: + if (*c == '\"') + state = 3; + else if (*c == '/') + state = 4; + break; + case 1: + if (*c == '*') + state = 5; + *c = ' '; + break; + case 2: + if (*c == '\n') + state = 0; + else + *c = ' '; + break; + case 3: + if (*c == '\"') + state = 0; + else if (*c == '\\') + state = 6; + break; + case 4: + if (*c == '/') { + *(c-1) = ' '; + *c = ' '; + state = 2; + } else if (*c == '*') { + *(c-1) = ' '; + *c = ' '; + state = 1; + } else + state = 0; + break; + case 5: + if (*c == '/') + state = 0; + else + state = 1; + *c = ' '; + break; + case 6: + state = 3; + break; + } + ++c; + } +} + +/* Dump all of the nested class declarations to the inline processor + * However. We need to do a few name replacements and other munging + * first. This function must be called before closing a class! */ + +static Node *dump_nested(const char *parent) { + Nested *n,*n1; + Node *ret = 0; + n = nested_list; + if (!parent) { + nested_list = 0; + return 0; + } + while (n) { + Node *retx; + SwigType *nt; + /* Token replace the name of the parent class */ + Replace(n->code, "$classname", parent, DOH_REPLACE_ANY); + + /* Fix up the name of the datatype (for building typedefs and other stuff) */ + Append(n->type,parent); + Append(n->type,"_"); + Append(n->type,n->name); + + /* Add the appropriate declaration to the C++ processor */ + retx = new_node("cdecl"); + Setattr(retx,"name",n->name); + nt = Copy(n->type); + Setattr(retx,"type",nt); + Delete(nt); + Setattr(retx,"nested",parent); + if (n->unnamed) { + Setattr(retx,"unnamed","1"); + } + + add_symbols(retx); + if (ret) { + set_nextSibling(retx,ret); + Delete(ret); + } + ret = retx; + + /* Insert a forward class declaration */ + /* Disabled: [ 597599 ] union in class: incorrect scope + retx = new_node("classforward"); + Setattr(retx,"kind",n->kind); + Setattr(retx,"name",Copy(n->type)); + Setattr(retx,"sym:name", make_name(n->type,0)); + set_nextSibling(retx,ret); + ret = retx; + */ + + /* Strip comments - further code may break in presence of comments. */ + strip_comments(Char(n->code)); + + /* Make all SWIG created typedef structs/unions/classes unnamed else + redefinition errors occur - nasty hack alert.*/ + + { + const char* types_array[3] = {"struct", "union", "class"}; + int i; + for (i=0; i<3; i++) { + char* code_ptr = Char(n->code); + while (code_ptr) { + /* Replace struct name (as in 'struct name {...}' ) with whitespace + name will be between struct and opening brace */ + + code_ptr = strstr(code_ptr, types_array[i]); + if (code_ptr) { + char *open_bracket_pos; + code_ptr += strlen(types_array[i]); + open_bracket_pos = strchr(code_ptr, '{'); + if (open_bracket_pos) { + /* Make sure we don't have something like struct A a; */ + char* semi_colon_pos = strchr(code_ptr, ';'); + if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) + while (code_ptr < open_bracket_pos) + *code_ptr++ = ' '; + } + } + } + } + } + + { + /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ + char* code_ptr = Char(n->code); + while (code_ptr) { + code_ptr = strstr(code_ptr, "%constant"); + if (code_ptr) { + char* directive_end_pos = strchr(code_ptr, ';'); + if (directive_end_pos) { + while (code_ptr <= directive_end_pos) + *code_ptr++ = ' '; + } + } + } + } + { + Node *head = new_node("insert"); + String *code = NewStringf("\n%s\n",n->code); + Setattr(head,"code", code); + Delete(code); + set_nextSibling(head,ret); + Delete(ret); + ret = head; + } + + /* Dump the code to the scanner */ + start_inline(Char(n->code),n->line); + + n1 = n->next; + Delete(n->code); + free(n); + n = n1; + } + nested_list = 0; + return ret; +} + +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); */ + + 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 (Cmp(Getattr(n,"storage"),"externc") == 0) { + 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")) { + 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; + } + } +} + +/* ----------------------------------------------------------------------------- + * tag_nodes() + * + * Used by the parser to mark subtypes with extra information. + * ----------------------------------------------------------------------------- */ + +static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) { + while (n) { + Setattr(n, attrname, value); + tag_nodes(firstChild(n), attrname, value); + n = nextSibling(n); + } +} + +%} + +%union { + char *id; + List *bases; + struct Define { + String *val; + String *rawval; + int type; + String *qualifier; + String *bitfield; + Parm *throws; + String *throwf; + } dtype; + struct { + char *type; + String *filename; + int line; + } loc; + struct { + char *id; + SwigType *type; + String *defarg; + ParmList *parms; + short have_parms; + ParmList *throws; + String *throwf; + } decl; + Parm *tparms; + struct { + String *method; + Hash *kwargs; + } tmap; + struct { + String *type; + String *us; + } ptype; + SwigType *type; + String *str; + Parm *p; + ParmList *pl; + int ivalue; + Node *node; +}; + +%token <id> ID +%token <str> HBLOCK +%token <id> POUND +%token <id> STRING +%token <loc> INCLUDE IMPORT INSERT +%token <str> CHARCONST +%token <dtype> NUM_INT NUM_FLOAT NUM_UNSIGNED NUM_LONG NUM_ULONG NUM_LONGLONG NUM_ULONGLONG +%token <ivalue> TYPEDEF +%token <type> TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_TYPEDEF TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64 +%token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE PERIOD +%token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET +%token 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 USING +%token <node> NAMESPACE +%token NATIVE INLINE +%token TYPEMAP EXCEPT ECHO APPLY CLEAR SWIGTEMPLATE FRAGMENT +%token WARN +%token LESSTHAN GREATERTHAN MODULO DELETE_KW +%token LESSTHANOREQUALTO GREATERTHANOREQUALTO EQUALTO NOTEQUALTO +%token QUESTIONMARK +%token TYPES PARMS +%token NONID DSTAR DCNOT +%token <ivalue> TEMPLATE +%token <str> OPERATOR +%token <str> COPERATOR +%token PARSETYPE PARSEPARM PARSEPARMS + +%left CAST +%left QUESTIONMARK +%left LOR +%left LAND +%left OR +%left XOR +%left AND +%left EQUALTO NOTEQUALTO +%left GREATERTHAN LESSTHAN GREATERTHANOREQUALTO LESSTHANOREQUALTO +%left LSHIFT RSHIFT +%left PLUS MINUS +%left STAR SLASH MODULUS +%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_decl c_enum_forward_decl c_constructor_decl ; +%type <node> enumlist edecl; + +/* C++ declarations */ +%type <node> cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl; +%type <node> cpp_members cpp_member; +%type <node> cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator; +%type <node> cpp_swig_directive cpp_temp_possible cpp_nested cpp_opt_declarators ; +%type <node> cpp_using_decl cpp_namespace_decl cpp_catch_decl ; +%type <node> kwargs options; + +/* Misc */ +%type <dtype> initializer cpp_const ; +%type <id> storage_class; +%type <pl> parms ptail rawparms varargs_parms; +%type <pl> templateparameters templateparameterstail; +%type <p> parm valparm rawvalparms valparms valptail ; +%type <p> typemap_parm tm_list tm_tail ; +%type <p> templateparameter ; +%type <id> templcpptype cpptype access_specifier; +%type <node> base_specifier +%type <type> type rawtype type_right ; +%type <bases> base_list inherit raw_inherit; +%type <dtype> definetype def_args etype; +%type <dtype> expr exprnum exprcompound valexpr; +%type <id> ename ; +%type <id> template_decl; +%type <str> type_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 typemap_parameter_declarator nested_decl; +%type <decl> abstract_declarator direct_abstract_declarator ctor_end; +%type <tmap> typemap_type; +%type <str> idcolon idcolontail idcolonnt idcolontailnt idtemplate stringbrace stringbracesemi; +%type <id> string stringnum ; +%type <tparms> template_parms; +%type <dtype> cpp_end cpp_vend; +%type <ivalue> rename_namewarn; +%type <ptype> type_specifier primitive_type_list ; +%type <node> fname stringtype; +%type <node> featattr; + +%% + +/* ====================================================================== + * 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); + check_extensions(); + 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) */ + appendChild($1,$2); + $$ = $1; + } + | empty { + $$ = new_node("top"); + } + ; + +declaration : swig_directive { $$ = $1; } + | c_declaration { $$ = $1; } + | cpp_declaration { $$ = $1; } + | SEMI { $$ = 0; } + | error { + $$ = 0; + Swig_error(cparse_file, cparse_line,"Syntax error in input(1).\n"); + exit(1); + } +/* 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 + COPERATOR token---discarding the rest of the definition. Ugh. + + */ + + | error COPERATOR { + $$ = 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 idcolon LBRACE { + Node *cls; + String *clsname; + cplus_mode = CPLUS_PUBLIC; + if (!classes) classes = NewHash(); + if (!extendhash) extendhash = NewHash(); + clsname = make_class_name($3); + cls = Getattr(classes,clsname); + if (!cls) { + /* No previous definition. Create a new scope */ + Node *am = Getattr(extendhash,clsname); + if (!am) { + Swig_symbol_newscope(); + Swig_symbol_setscopename($3); + prev_symtab = 0; + } else { + prev_symtab = Swig_symbol_setscope(Getattr(am,"symtab")); + } + current_class = 0; + } else { + /* Previous class definition. Use its symbol table */ + prev_symtab = Swig_symbol_setscope(Getattr(cls,"symtab")); + current_class = cls; + extendmode = 1; + } + Classprefix = NewString($3); + 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($3); + Setattr($$,"name",clsname); + + /* Mark members as extend */ + + tag_nodes($6,"feature:extend",(char*) "1"); + if (current_class) { + /* We add the extension to the previously defined class */ + appendChild($$,$6); + appendChild(current_class,$$); + } else { + /* We store the extensions in the extensions hash */ + Node *am = Getattr(extendhash,clsname); + if (am) { + /* Append the members to the previous extend methods */ + appendChild(am,$6); + } else { + appendChild($$,$6); + Setattr(extendhash,clsname,$$); + } + } + current_class = 0; + Delete(Classprefix); + Delete(clsname); + Classprefix = 0; + prev_symtab = 0; + $$ = 0; + + } + ; + +/* ------------------------------------------------------------ + %apply + ------------------------------------------------------------ */ + +apply_directive : APPLY typemap_parm LBRACE tm_list RBRACE { + $$ = new_node("apply"); + Setattr($$,"pattern",Getattr($2,"pattern")); + appendChild($$,$4); + }; + +/* ------------------------------------------------------------ + %clear + ------------------------------------------------------------ */ + +clear_directive : CLEAR tm_list SEMI { + $$ = new_node("clear"); + appendChild($$,$2); + } + ; + +/* ------------------------------------------------------------ + %constant name = value; + %constant type name = value; + ------------------------------------------------------------ */ + +constant_directive : CONSTANT ID 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; + } + } + | CONSTANT error SEMI { + Swig_warning(WARN_PARSE_BAD_VALUE,cparse_file,cparse_line,"Bad constant value (ignored).\n"); + $$ = 0; + } + ; + +/* ------------------------------------------------------------ + %echo "text" + %echo %{ ... %} + ------------------------------------------------------------ */ + +echo_directive : ECHO HBLOCK { + char temp[64]; + Replace($2,"$file",cparse_file, DOH_REPLACE_ANY); + sprintf(temp,"%d", cparse_line); + Replace($2,"$line",temp,DOH_REPLACE_ANY); + Printf(stderr,"%s\n", $2); + Delete($2); + $$ = 0; + } + | ECHO string { + char temp[64]; + String *s = NewString($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 ID 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 ID 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 "filename" [option1="xyz", ...] [ declarations ] + %importfile "filename" [option1="xyz", ...] [ declarations ] + ------------------------------------------------------------ */ + +include_directive: includetype options string LBRACKET { + $1.filename = Copy(cparse_file); + $1.line = cparse_line; + scanner_set_location(NewString($3),1); + if ($2) { + String *maininput = Getattr($2, "maininput"); + if (maininput) + scanner_set_main_input_file(NewString(maininput)); + } + } interface RBRACKET { + String *mname = 0; + $$ = $6; + scanner_set_location($1.filename,$1.line); + 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); + appendChild(nint,mnode); + Delete(mnode); + appendChild(nint,firstChild($$)); + $$ = nint; + Setattr($$,"module",mname); + } + } + Setattr($$,"options",$2); + } + ; + +includetype : INCLUDE { $$.type = (char *) "include"; } + | IMPORT { $$.type = (char *) "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 */ + Setline($2,cparse_start_line); + Setfile($2,cparse_file); + Seek($2,0,SEEK_SET); + 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 (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 ID RPAREN storage_class ID SEMI { + $$ = new_node("native"); + Setattr($$,"name",$3); + Setattr($$,"wrap:name",$6); + add_symbols($$); + } + | NATIVE LPAREN ID 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 ID EQUAL pragma_arg { + $$ = new_node("pragma"); + Setattr($$,"lang",$2); + Setattr($$,"name",$3); + Setattr($$,"value",$5); + } + | PRAGMA pragma_lang ID { + $$ = new_node("pragma"); + Setattr($$,"lang",$2); + Setattr($$,"name",$3); + } + ; + +pragma_arg : string { $$ = NewString($1); } + | HBLOCK { $$ = $1; } + ; + +pragma_lang : LPAREN ID RPAREN { $$ = $2; } + | empty { $$ = (char *) "swig"; } + ; + +/* ------------------------------------------------------------ + %rename identifier newname; + %rename identifier "newname"; + ------------------------------------------------------------ */ + +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) ? NewString($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) ? NewString($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) ? NewString($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) ? NewString($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 { + $$ = Copy($3); + Setattr($$,"name","VARARGS_SENTINEL"); + for (i = 0; i < n; i++) { + p = Copy($3); + set_nextSibling(p,$$); + Delete($$); + $$ = p; + } + } + } + ; + + +/* ------------------------------------------------------------ + %typemap(method) type { ... } + %typemap(method) type "..." + %typemap(method) type; - typemap deletion + %typemap(method) type1,type2,... = type; - typemap copy + %typemap type1,type2,... = type; - typemap copy + ------------------------------------------------------------ */ + +typemap_directive : TYPEMAP LPAREN typemap_type RPAREN tm_list stringbrace { + $$ = 0; + if ($3.method) { + String *code = 0; + $$ = new_node("typemap"); + Setattr($$,"method",$3.method); + if ($3.kwargs) { + ParmList *kw = $3.kwargs; + code = remove_block(kw, $6); + Setattr($$,"kwargs", $3.kwargs); + } + code = code ? code : NewString($6); + Setattr($$,"code", code); + Delete(code); + appendChild($$,$5); + } + } + | TYPEMAP LPAREN typemap_type RPAREN tm_list SEMI { + $$ = 0; + if ($3.method) { + $$ = new_node("typemap"); + Setattr($$,"method",$3.method); + appendChild($$,$5); + } + } + | TYPEMAP LPAREN typemap_type RPAREN tm_list EQUAL typemap_parm SEMI { + $$ = 0; + if ($3.method) { + $$ = new_node("typemapcopy"); + Setattr($$,"method",$3.method); + Setattr($$,"pattern", Getattr($7,"pattern")); + appendChild($$,$5); + } + } + ; + +/* typemap method type (lang,method) or (method) */ + +typemap_type : kwargs { + Hash *p; + String *name; + p = nextSibling($1); + if (p && (!Getattr(p,"value"))) { + /* this is the deprecated two argument typemap form */ + Swig_warning(WARN_DEPRECATED_TYPEMAP_LANG,cparse_file, cparse_line, + "Specifying the language name in %%typemap is deprecated - use #ifdef SWIG<LANG> instead.\n"); + /* two argument typemap form */ + name = Getattr($1,"name"); + if (!name || (Strcmp(name,typemap_lang))) { + $$.method = 0; + $$.kwargs = 0; + } else { + $$.method = Getattr(p,"name"); + $$.kwargs = nextSibling(p); + } + } else { + /* one-argument typemap-form */ + $$.method = Getattr($1,"name"); + $$.kwargs = p; + } + } + ; + +tm_list : typemap_parm tm_tail { + $$ = $1; + set_nextSibling($$,$2); + } + ; + +tm_tail : COMMA typemap_parm tm_tail { + $$ = $2; + set_nextSibling($$,$3); + } + | empty { $$ = 0;} + ; + +typemap_parm : type typemap_parameter_declarator { + Parm *parm; + SwigType_push($1,$2.type); + $$ = new_node("typemapitem"); + parm = NewParm($1,$2.id); + Setattr($$,"pattern",parm); + Setattr($$,"parms", $2.parms); + Delete(parm); + /* $$ = NewParm($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 *tnode = 0; + Symtab *tscope = 0; + int specialized = 0; + + $$ = 0; + + tscope = Swig_symbol_current(); /* Get the current scope */ + + /* If the class name is qualified, we need to create or lookup namespace entries */ + if (!inclass) { + $5 = resolve_node_scope($5); + } + + /* + 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; + 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; + } + if (nnisclass && !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)))) { + Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. %d required.\n", ParmList_numrequired(tparms)); + } 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; + } + } + + templnode = copy_node(nn); + /* 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"); + } + if ($3) { + /* + 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 = $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); + Delete(nname); + Setattr(templnode,"feature:onlychildren", + "typemap,typemapitem,typemapcopy,typedef,types,fragment"); + } + Delattr(templnode,"templatetype"); + Setattr(templnode,"template",nn); + tnode = templnode; + Setfile(templnode,cparse_file); + Setline(templnode,cparse_line); + Delete(temparms); + + add_symbols_copy(templnode); + + if (Strcmp(nodeType(templnode),"class") == 0) { + + /* Identify pure abstract methods */ + Setattr(templnode,"abstract", pure_abstract(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 = make_inherit_list(Getattr(templnode,"name"),baselist); + 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 addmethods for this class */ + + /* !!! This may be broken. We may have to add the + addmethods at the beginning of the class */ + + if (extendhash) { + 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(extendhash,clsname); + if (am) { + Symtab *st = Swig_symbol_current(); + Swig_symbol_setscope(Getattr(templnode,"symtab")); + /* Printf(stdout,"%s: %s %x %x\n", Getattr(templnode,"name"), clsname, Swig_symbol_current(), Getattr(templnode,"symtab")); */ + merge_extensions(templnode,am); + Swig_symbol_setscope(st); + append_previous_extension(templnode,am); + Delattr(extendhash,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 (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. */ + } + } + 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) { + SwigType *decl = Getattr(n,"decl"); + if (SwigType_isfunction(decl)) { + Setattr(n,"storage","externc"); + } + n = nextSibling(n); + } + } else { + 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)); + } + } + ; + +/* ------------------------------------------------------------ + A C global declaration of some kind (may be variable, function, typedef, etc.) + ------------------------------------------------------------ */ + +c_decl : storage_class type declarator initializer c_decl_tail { + $$ = new_node("cdecl"); + if ($4.qualifier) SwigType_push($3.type,$4.qualifier); + Setattr($$,"type",$2); + 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); + if (!$5) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + } else { + Node *n = $5; + /* Inherit attributes */ + while (n) { + String *type = Copy($2); + Setattr(n,"type",type); + Setattr(n,"storage",$1); + n = nextSibling(n); + Delete(type); + } + } + if ($4.bitfield) { + Setattr($$,"bitfield", $4.bitfield); + } + + /* 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) || + (inclass && Strcmp(p,Classprefix) == 0)) { + String *lstr = Swig_scopename_last($3.id); + Setattr($$,"name",lstr); + Delete(lstr); + set_nextSibling($$,$5); + } else { + Delete($$); + $$ = $5; + } + Delete(p); + } else { + Delete($$); + $$ = $5; + } + } else { + set_nextSibling($$,$5); + } + } + ; + +/* Allow lists of variables and functions to be built up */ + +c_decl_tail : SEMI { + $$ = 0; + Clear(scanner_ccode); + } + | COMMA declarator initializer c_decl_tail { + $$ = new_node("cdecl"); + if ($3.qualifier) SwigType_push($2.type,$3.qualifier); + Setattr($$,"name",$2.id); + Setattr($$,"decl",$2.type); + Setattr($$,"parms",$2.parms); + Setattr($$,"value",$3.val); + Setattr($$,"throws",$3.throws); + Setattr($$,"throw",$3.throwf); + if ($3.bitfield) { + Setattr($$,"bitfield", $3.bitfield); + } + if (!$4) { + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + } else { + set_nextSibling($$,$4); + } + } + | LBRACE { + skip_balanced('{','}'); + $$ = 0; + } + ; + +initializer : def_args { + $$ = $1; + $$.qualifier = 0; + $$.throws = 0; + $$.throwf = 0; + } + | type_qualifier def_args { + $$ = $2; + $$.qualifier = $1; + $$.throws = 0; + $$.throwf = 0; + } + | THROW LPAREN parms RPAREN def_args { + $$ = $5; + $$.qualifier = 0; + $$.throws = $3; + $$.throwf = NewString("1"); + } + | type_qualifier THROW LPAREN parms RPAREN def_args { + $$ = $6; + $$.qualifier = $1; + $$.throws = $4; + $$.throwf = NewString("1"); + } + ; + + +/* ------------------------------------------------------------ + enum Name; + ------------------------------------------------------------ */ + +c_enum_forward_decl : storage_class ENUM ID SEMI { + SwigType *ty = 0; + $$ = new_node("enumforward"); + ty = NewStringf("enum %s", $3); + Setattr($$,"name",$3); + Setattr($$,"type",ty); + Setattr($$,"sym:weak", "1"); + add_symbols($$); + } + ; + +/* ------------------------------------------------------------ + enum { ... } + * ------------------------------------------------------------ */ + +c_enum_decl : storage_class ENUM ename LBRACE enumlist RBRACE SEMI { + SwigType *ty = 0; + $$ = new_node("enum"); + ty = NewStringf("enum %s", $3); + Setattr($$,"name",$3); + Setattr($$,"type",ty); + appendChild($$,$5); + add_symbols($$); /* Add to tag space */ + add_symbols($5); /* Add enum values to id space */ + } + | storage_class ENUM ename LBRACE enumlist RBRACE declarator c_decl_tail { + Node *n; + SwigType *ty = 0; + String *unnamed = 0; + int unnamedinstance = 0; + + $$ = new_node("enum"); + if ($3) { + Setattr($$,"name",$3); + ty = NewStringf("enum %s", $3); + } else if ($7.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",$7.id); + } else { + unnamedinstance = 1; + } + Setattr($$,"storage",$1); + } + if ($7.id && Cmp($1,"typedef") == 0) { + Setattr($$,"tdname",$7.id); + Setattr($$,"allows_typedef","1"); + } + appendChild($$,$5); + n = new_node("cdecl"); + Setattr(n,"type",ty); + Setattr(n,"name",$7.id); + Setattr(n,"storage",$1); + Setattr(n,"decl",$7.type); + Setattr(n,"parms",$7.parms); + Setattr(n,"unnamed",unnamed); + + if (unnamedinstance) { + SwigType *cty = NewString("enum "); + Setattr($$,"type",cty); + Setattr($$,"unnamedinstance","1"); + Setattr(n,"unnamedinstance","1"); + Delete(cty); + } + if ($8) { + Node *p = $8; + 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 ($7.id && $3 && Cmp($1,"typedef") == 0) { + String *name = NewString($7.id); + Setattr($$, "parser:makename", name); + Delete(name); + } + + add_symbols($$); /* Add enum to tag space */ + set_nextSibling($$,n); + Delete(n); + add_symbols($5); /* Add enum values to id space */ + 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); + err = 0; + } + } + if (err) { + Swig_error(cparse_file,cparse_line,"Syntax error in input(2).\n"); + exit(1); + } + } + ; + +/* ====================================================================== + * 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; } + ; + +cpp_class_decl : + +/* A simple class/struct/union definition */ + storage_class cpptype idcolon inherit LBRACE { + List *bases = 0; + Node *scope = 0; + $<node>$ = new_node("class"); + Setline($<node>$,cparse_start_line); + Setattr($<node>$,"kind",$2); + if ($4) { + Setattr($<node>$,"baselist", Getattr($4,"public")); + Setattr($<node>$,"protectedbaselist", Getattr($4,"protected")); + Setattr($<node>$,"privatebaselist", Getattr($4,"private")); + } + Setattr($<node>$,"allows_typedef","1"); + + /* preserve the current scope */ + prev_symtab = Swig_symbol_current(); + + /* If the class name is qualified. We need to create or lookup namespace/scope entries */ + scope = resolve_node_scope($3); + Setfile(scope,cparse_file); + Setline(scope,cparse_line); + $3 = scope; + + /* support for old nested classes "pseudo" support, such as: + + %rename(Ala__Ola) Ala::Ola; + class Ala::Ola { + public: + Ola() {} + }; + + this should disappear when a proper implementation is added. + */ + if (nscope_inner && Strcmp(nodeType(nscope_inner),"namespace") != 0) { + if (Namespaceprefix) { + String *name = NewStringf("%s::%s", Namespaceprefix, $3); + $3 = name; + Namespaceprefix = 0; + nscope_inner = 0; + } + } + Setattr($<node>$,"name",$3); + + Delete(class_rename); + class_rename = make_name($<node>$,$3,0); + Classprefix = NewString($3); + /* Deal with inheritance */ + if ($4) { + bases = make_inherit_list($3,Getattr($4,"public")); + } + if (SwigType_istemplate($3)) { + String *fbase, *tbase, *prefix; + prefix = SwigType_templateprefix($3); + 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); + Delete(prefix); + } + if (strcmp($2,"class") == 0) { + cplus_mode = CPLUS_PRIVATE; + } else { + cplus_mode = CPLUS_PUBLIC; + } + Swig_symbol_newscope(); + Swig_symbol_setscopename($3); + 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); + } + 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); + } + } + if (class_level >= max_class_levels) { + if (!max_class_levels) { + max_class_levels = 16; + } else { + max_class_levels *= 2; + } + class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); + if (!class_decl) { + Swig_error(cparse_file, cparse_line, "realloc() failed\n"); + } + } + class_decl[class_level++] = $<node>$; + inclass = 1; + } cpp_members RBRACE cpp_opt_declarators { + Node *p; + SwigType *ty; + Symtab *cscope = prev_symtab; + Node *am = 0; + String *scpname = 0; + $$ = class_decl[--class_level]; + inclass = 0; + + /* Check for pure-abstract class */ + Setattr($$,"abstract", pure_abstract($7)); + + /* This bit of code merges in a previously defined %extend directive (if any) */ + + if (extendhash) { + String *clsname = Swig_symbol_qualifiedscopename(0); + am = Getattr(extendhash,clsname); + if (am) { + merge_extensions($$,am); + Delattr(extendhash,clsname); + } + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes,scpname,$$); + Delete(scpname); + + appendChild($$,$7); + + if (am) append_previous_extension($$,am); + + p = $9; + if (p) { + set_nextSibling($$,p); + } + + 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); + p = nextSibling(p); + } + /* Dump nested classes */ + { + String *name = $3; + if ($9) { + SwigType *decltype = Getattr($9,"decl"); + if (Cmp($1,"typedef") == 0) { + if (!decltype || !Len(decltype)) { + String *cname; + name = Getattr($9,"name"); + cname = Copy(name); + Setattr($$,"tdname",cname); + Delete(cname); + + /* Use typedef name as class name */ + if (class_rename && (Strcmp(class_rename,$3) == 0)) { + Delete(class_rename); + class_rename = NewString(name); + } + if (!Getattr(classes,name)) { + Setattr(classes,name,$$); + } + Setattr($$,"decl",decltype); + } + } + } + appendChild($$,dump_nested(Char(name))); + } + + 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); + } + + Setattr($$,"symtab",Swig_symbol_popscope()); + + Classprefix = 0; + if (nscope_inner) { + /* this is tricky */ + /* we add the declaration in the original namespace */ + appendChild(nscope_inner,$$); + Swig_symbol_setscope(Getattr(nscope_inner,"symtab")); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($$); + if (nscope) $$ = nscope; + /* but the variable definition in the current scope */ + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($9); + } else { + Delete(yyrename); + yyrename = Copy(class_rename); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + + add_symbols($$); + add_symbols($9); + } + Swig_symbol_setscope(cscope); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } + +/* An unnamed struct, possibly with a typedef */ + + | storage_class cpptype LBRACE { + String *unnamed; + unnamed = make_unnamed(); + $<node>$ = new_node("class"); + Setline($<node>$,cparse_start_line); + Setattr($<node>$,"kind",$2); + Setattr($<node>$,"storage",$1); + Setattr($<node>$,"unnamed",unnamed); + Setattr($<node>$,"allows_typedef","1"); + Delete(class_rename); + 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; + if (class_level >= max_class_levels) { + if (!max_class_levels) { + max_class_levels = 16; + } else { + max_class_levels *= 2; + } + class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); + if (!class_decl) { + Swig_error(cparse_file, cparse_line, "realloc() failed\n"); + } + } + class_decl[class_level++] = $<node>$; + inclass = 1; + Classprefix = NewStringEmpty(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } cpp_members RBRACE declarator c_decl_tail { + String *unnamed; + Node *n; + Classprefix = 0; + $$ = class_decl[--class_level]; + inclass = 0; + unnamed = Getattr($$,"unnamed"); + + /* Check for pure-abstract class */ + Setattr($$,"abstract", pure_abstract($5)); + + n = new_node("cdecl"); + Setattr(n,"name",$7.id); + Setattr(n,"unnamed",unnamed); + Setattr(n,"type",unnamed); + Setattr(n,"decl",$7.type); + Setattr(n,"parms",$7.parms); + Setattr(n,"storage",$1); + if ($8) { + Node *p = $8; + set_nextSibling(n,p); + while (p) { + String *type = Copy(unnamed); + Setattr(p,"name",$7.id); + Setattr(p,"unnamed",unnamed); + Setattr(p,"type",type); + Delete(type); + Setattr(p,"storage",$1); + p = nextSibling(p); + } + } + set_nextSibling($$,n); + Delete(n); + { + /* If a proper typedef name was given, we'll use it to set the scope name */ + String *name = 0; + if ($1 && (strcmp($1,"typedef") == 0)) { + if (!Len($7.type)) { + String *scpname = 0; + name = $7.id; + Setattr($$,"tdname",name); + Setattr($$,"name",name); + Swig_symbol_setscopename(name); + + /* If a proper name was given, we use that as the typedef, not unnamed */ + Clear(unnamed); + Append(unnamed, name); + + n = nextSibling(n); + set_nextSibling($$,n); + + /* Check for previous extensions */ + if (extendhash) { + String *clsname = Swig_symbol_qualifiedscopename(0); + Node *am = Getattr(extendhash,clsname); + if (am) { + /* Merge the extension into the symbol table */ + merge_extensions($$,am); + append_previous_extension($$,am); + Delattr(extendhash,clsname); + } + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes,scpname,$$); + Delete(scpname); + } else { + Swig_symbol_setscopename((char*)"<unnamed>"); + } + } + appendChild($$,$5); + appendChild($$,dump_nested(Char(name))); + } + /* Pop the scope */ + Setattr($$,"symtab",Swig_symbol_popscope()); + if (class_rename) { + Delete(yyrename); + yyrename = NewString(class_rename); + } + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($$); + add_symbols(n); + Delete(unnamed); + } + ; + +cpp_opt_declarators : SEMI { $$ = 0; } + | declarator c_decl_tail { + $$ = new_node("cdecl"); + Setattr($$,"name",$1.id); + Setattr($$,"decl",$1.type); + Setattr($$,"parms",$1.parms); + set_nextSibling($$,$2); + } + ; +/* ------------------------------------------------------------ + class Name; + ------------------------------------------------------------ */ + +cpp_forward_class_decl : storage_class cpptype idcolon SEMI { + if ($1 && (Strcmp($1,"friend") == 0)) { + /* Ignore */ + $$ = 0; + } else { + $$ = new_node("classforward"); + Setfile($$,cparse_file); + Setline($$,cparse_line); + Setattr($$,"kind",$2); + Setattr($$,"name",$3); + Setattr($$,"sym:weak", "1"); + add_symbols($$); + } + } + ; + +/* ------------------------------------------------------------ + template<...> decl + ------------------------------------------------------------ */ + +cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { template_parameters = $3; } cpp_temp_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; + } + + template_parameters = 0; + $$ = $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; + + 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; + 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); + Append(ffname,ttr); + tt = Next(tt); + if (tt.item) Putc(',',ffname); + Delete(rtt); + Delete(ttr); + } + Delete(tparms); + Append(ffname,")>"); + } + { + 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)); */ + Append(partials,ffname); + } + Setattr($$,"partialargs",ffname); + Swig_symbol_cadd(ffname,$$); + } + } + Delete(tlist); + Delete(targs); + } else { + /* Need to resolve exact specialization name */ + /* add default args from generic 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) $$ = 0; + } + | TEMPLATE cpptype idcolon { + Swig_warning(WARN_PARSE_EXPLICIT_TEMPLATE, cparse_file, cparse_line, "Explicit template instantiation ignored.\n"); + $$ = 0; + } + ; + +cpp_temp_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 { + /* + 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 { + $$ = NewParm(NewString($1), 0); + } + | 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; + $1 = Swig_symbol_current(); + h = Swig_symbol_clookup($2,0); + if (h && ($1 == Getattr(h,"sym:symtab")) && (Strcmp(nodeType(h),"namespace") == 0)) { + 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", + $2, Getattr(h,"name")); + $2 = Getattr(h,"name"); + } + Swig_symbol_setscope(Getattr(h,"symtab")); + } else { + Swig_symbol_newscope(); + Swig_symbol_setscopename($2); + } + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + } interface RBRACE { + Node *n = $5; + set_nodeType(n,"namespace"); + Setattr(n,"name",$2); + Setattr(n,"symtab", Swig_symbol_popscope()); + Swig_symbol_setscope($1); + $$ = n; + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($$); + } + | NAMESPACE LBRACE { + Hash *h; + $1 = Swig_symbol_current(); + h = Swig_symbol_clookup((char *)" ",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 ID 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); + } else { + $$ = $2; + } + } + | EXTEND LBRACE { + if (cplus_mode != CPLUS_PUBLIC) { + Swig_error(cparse_file,cparse_line,"%%extend can only be used in a public section\n"); + } + } cpp_members RBRACE cpp_members { + $$ = new_node("extend"); + tag_nodes($4,"feature:extend",(char*) "1"); + appendChild($$,$4); + set_nextSibling($$,$6); + } + | include_directive { $$ = $1; } + | empty { $$ = 0;} + | error { + int start_line = cparse_line; + skip_decl(); + Swig_error(cparse_file,start_line,"Syntax error in input(3).\n"); + exit(1); + } cpp_members { + $$ = $3; + } + ; + +/* ====================================================================== + * C++ Class members + * ====================================================================== */ + +/* A class member. May be data or a function. Static or virtual as well */ + +cpp_member : c_declaration { $$ = $1; } + | cpp_constructor_decl { + $$ = $1; + if (extendmode) { + 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_nested { $$ = $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; } + ; + +/* 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 (Classprefix) { + 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); + if (Len(scanner_ccode)) { + String *code = Copy(scanner_ccode); + Setattr($$,"code",code); + Delete(code); + } + SetFlag($$,"feature:new"); + } 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); + add_symbols($$); + } + +/* A virtual destructor */ + + | VIRTUAL NOT idtemplate LPAREN parms RPAREN cpp_vend { + String *name; + char *c = 0; + $$ = new_node("destructor"); + /* Check for template names. If the class is a template + and the constructor is missing the template part, we + add it */ + if (Classprefix) { + c = strchr(Char(Classprefix),'<'); + if (c && !Strchr($3,'<')) { + $3 = NewStringf("%s%s",$3,c); + } + } + 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); + if ($7.val) { + Setattr($$,"value","0"); + } + 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); + } + + add_symbols($$); + } + ; + + +/* C++ type conversion operator */ +cpp_conversion_operator : storage_class COPERATOR 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); + } + Setattr($$,"decl",$4); + Setattr($$,"parms",$6); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + | storage_class COPERATOR 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); + } + Setattr($$,"decl",decl); + Setattr($$,"parms",$6); + Setattr($$,"conversion_operator","1"); + add_symbols($$); + } + + | storage_class COPERATOR 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); + } + 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; + } + ; + +/* 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; + } + ; + + +/* ---------------------------------------------------------------------- + Nested structure. This is a sick "hack". If we encounter + a nested structure, we're going to grab the text of its definition and + feed it back into the scanner. In the meantime, we need to grab + variable declaration information and generate the associated wrapper + code later. Yikes! + + This really only works in a limited sense. Since we use the + code attached to the nested class to generate both C/C++ code, + it can't have any SWIG directives in it. It also needs to be parsable + by SWIG or this whole thing is going to puke. + ---------------------------------------------------------------------- */ + +/* A struct sname { } id; declaration */ + +cpp_nested : storage_class cpptype ID LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); + } nested_decl SEMI { + $$ = 0; + if (cplus_mode == CPLUS_PUBLIC) { + if ($6.id && strcmp($2, "class") != 0) { + Nested *n = (Nested *) malloc(sizeof(Nested)); + n->code = NewStringEmpty(); + Printv(n->code, "typedef ", $2, " ", + Char(scanner_ccode), " $classname_", $6.id, ";\n", NIL); + + n->name = Swig_copy_string($6.id); + n->line = cparse_start_line; + n->type = NewStringEmpty(); + n->kind = $2; + n->unnamed = 0; + SwigType_push(n->type, $6.type); + n->next = 0; + add_nested(n); + } else { + Swig_warning(WARN_PARSE_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", $2); + if (strcmp($2, "class") == 0) { + /* For now, just treat the nested class as a forward + * declaration (SF bug #909387). */ + $$ = new_node("classforward"); + Setfile($$,cparse_file); + Setline($$,cparse_line); + Setattr($$,"kind",$2); + Setattr($$,"name",$3); + Setattr($$,"sym:weak", "1"); + add_symbols($$); + } + } + } + } +/* A struct { } id; declaration */ + | storage_class cpptype LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); + } nested_decl SEMI { + $$ = 0; + if (cplus_mode == CPLUS_PUBLIC) { + if (strcmp($2,"class") == 0) { + Swig_warning(WARN_PARSE_NESTED_CLASS,cparse_file, cparse_line,"Nested class not currently supported (ignored)\n"); + /* Generate some code for a new class */ + } else if ($5.id) { + /* Generate some code for a new class */ + Nested *n = (Nested *) malloc(sizeof(Nested)); + n->code = NewStringEmpty(); + Printv(n->code, "typedef ", $2, " " , + Char(scanner_ccode), " $classname_", $5.id, ";\n",NIL); + n->name = Swig_copy_string($5.id); + n->line = cparse_start_line; + n->type = NewStringEmpty(); + n->kind = $2; + n->unnamed = 1; + SwigType_push(n->type,$5.type); + n->next = 0; + add_nested(n); + } else { + Swig_warning(WARN_PARSE_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", $2); + } + } + } +/* A 'class name : base_list { };' declaration, always ignored */ +/***** + This fixes derived_nested.i, but it adds one shift/reduce. Anyway, + we are waiting for the nested class support. + *****/ + | storage_class cpptype idcolon COLON base_list LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); + } SEMI { + $$ = 0; + if (cplus_mode == CPLUS_PUBLIC) { + Swig_warning(WARN_PARSE_NESTED_CLASS,cparse_file, cparse_line,"Nested class not currently supported (ignored)\n"); + } + } +/* + | TEMPLATE LESSTHAN template_parms GREATERTHAN cpptype idcolon LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); + } SEMI { + $$ = 0; + if (cplus_mode == CPLUS_PUBLIC) { + Swig_warning(WARN_PARSE_NESTED_CLASS,cparse_file, cparse_line,"Nested class not currently supported (ignored)\n"); + } + } +*/ + ; + +nested_decl : declarator { $$ = $1;} + | empty { $$.id = 0; } + ; + + +/* 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); + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + | cpp_const LBRACE { + skip_balanced('{','}'); + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + ; + +cpp_vend : cpp_const SEMI { + Clear(scanner_ccode); + $$.val = 0; + $$.qualifier = $1.qualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + | cpp_const EQUAL definetype SEMI { + Clear(scanner_ccode); + $$.val = $3.val; + $$.qualifier = $1.qualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + | cpp_const LBRACE { + skip_balanced('{','}'); + $$.val = 0; + $$.qualifier = $1.qualifier; + $$.bitfield = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + ; + + +anonymous_bitfield : storage_class type COLON expr SEMI { }; + +/* ====================================================================== + * PRIMITIVES + * ====================================================================== */ + +storage_class : EXTERN { $$ = "extern"; } + | EXTERN string { + if (strcmp($2,"C") == 0) { + $$ = "externc"; + } else { + Swig_warning(WARN_PARSE_UNDEFINED_EXTERN,cparse_file, cparse_line,"Unrecognized extern type \"%s\".\n", $2); + $$ = 0; + } + } + | STATIC { $$ = "static"; } + | TYPEDEF { $$ = "typedef"; } + | VIRTUAL { $$ = "virtual"; } + | FRIEND { $$ = "friend"; } + | EXPLICIT { $$ = "explicit"; } + | 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; } + ; + +ptail : COMMA parm ptail { + set_nextSibling($2,$3); + $$ = $2; + } + | empty { $$ = 0; } + ; + + +parm : rawtype parameter_declarator { + SwigType_push($1,$2.type); + $$ = NewParm($1,$2.id); + Setfile($$,cparse_file); + Setline($$,cparse_line); + if ($2.defarg) { + Setattr($$,"value",$2.defarg); + } + } + + | TEMPLATE LESSTHAN cpptype GREATERTHAN cpptype idcolon def_args { + $$ = NewParm(NewStringf("template<class> %s %s", $5,$6), 0); + Setfile($$,cparse_file); + Setline($$,cparse_line); + if ($7.val) { + Setattr($$,"value",$7.val); + } + } + | PERIOD PERIOD PERIOD { + SwigType *t = NewString("v(...)"); + $$ = NewParm(t, 0); + Setfile($$,cparse_file); + Setline($$,cparse_line); + } + ; + +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 { + $$ = NewParm(0,0); + Setfile($$,cparse_file); + Setline($$,cparse_line); + Setattr($$,"value",$1.val); + } + ; + +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; + } + } + | 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; + } else { + $$.val = NewStringf("%s[%s]",$2.val,$4.val); + } + } + | EQUAL LBRACE { + skip_balanced('{','}'); + $$.val = 0; + $$.rawval = 0; + $$.type = T_INT; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + } + | COLON expr { + $$.val = 0; + $$.rawval = 0; + $$.type = 0; + $$.bitfield = $2.val; + $$.throws = 0; + $$.throwf = 0; + } + | empty { + $$.val = 0; + $$.rawval = 0; + $$.type = T_INT; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 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; + } + ; + +typemap_parameter_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; + } + } + | 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; + } + | 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); + } + } + | 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; + } + ; + +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 generate 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,(char*)""); + 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 idcolon DSTAR direct_declarator RPAREN { + SwigType *t; + $$ = $4; + t = NewStringEmpty(); + SwigType_add_memberpointer(t,$2); + if ($$.type) { + SwigType_push(t,$$.type); + Delete($$.type); + } + $$.type = t; + } + | direct_declarator LBRACKET RBRACKET { + SwigType *t; + $$ = $1; + t = NewStringEmpty(); + SwigType_add_array(t,(char*)""); + 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; + } + } + ; + +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 AND direct_abstract_declarator { + $$ = $3; + SwigType_add_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); + } + } + | AND { + $$.id = 0; + $$.parms = 0; + $$.have_parms = 0; + $$.type = NewStringEmpty(); + SwigType_add_reference($$.type); + } + | idcolon DSTAR { + $$.type = NewStringEmpty(); + SwigType_add_memberpointer($$.type,$1); + $$.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,(char*)""); + 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,(char*)""); + } + | 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; + } + } + | 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($$); + } + ; + +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); } + | ENUM idcolon { $$ = NewStringf("enum %s", $2); } + | TYPE_RAW { $$ = $1; } + + | idcolon { + $$ = $1; + } + | cpptype idcolon { + $$ = NewStringf("%s %s", $1, $2); + } + ; + +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) { + $$.rawval = 0; + } + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + scanner_ignore_typedef(); + } +/* + | string { + $$.val = NewString($1); + $$.rawval = NewStringf("\"%(escape)s\"",$$.val); + $$.type = T_STRING; + $$.bitfield = 0; + $$.throws = 0; + $$.throwf = 0; + } +*/ + ; + +/* Some stuff for handling enums */ + +ename : ID { $$ = $1; } + | empty { $$ = (char *) 0;} + ; + +enumlist : enumlist COMMA edecl { + + /* Ignore if there is a trailing comma in the enum list */ + if ($3) { + Node *leftSibling = Getattr($1,"_last"); + if (!leftSibling) { + leftSibling=$1; + } + set_nextSibling(leftSibling,$3); + Setattr($1,"_last",$3); + } + $$ = $1; + } + | edecl { + $$ = $1; + if ($1) { + Setattr($1,"_last",$1); + } + } + ; + +edecl : ID { + SwigType *type = NewSwigType(T_INT); + $$ = new_node("enumitem"); + Setattr($$,"name",$1); + Setattr($$,"type",type); + SetFlag($$,"feature:immutable"); + Delete(type); + } + | ID EQUAL etype { + $$ = new_node("enumitem"); + Setattr($$,"name",$1); + Setattr($$,"enumvalue", $3.val); + if ($3.type == T_CHAR) { + SwigType *type = NewSwigType(T_CHAR); + Setattr($$,"value",NewStringf("\'%(escape)s\'", $3.val)); + Setattr($$,"type",type); + Delete(type); + } else { + SwigType *type = NewSwigType(T_INT); + Setattr($$,"value",$1); + Setattr($$,"type",type); + Delete(type); + } + SetFlag($$,"feature:immutable"); + } + | empty { $$ = 0; } + ; + +etype : expr { + $$ = $1; + if (($$.type != T_INT) && ($$.type != T_UINT) && + ($$.type != T_LONG) && ($$.type != T_ULONG) && + ($$.type != T_SHORT) && ($$.type != T_USHORT) && + ($$.type != T_SCHAR) && ($$.type != T_UCHAR) && + ($$.type != T_CHAR)) { + Swig_error(cparse_file,cparse_line,"Type error. Expecting an int\n"); + } + if ($$.type == T_CHAR) $$.type = T_INT; + } + ; + +/* 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); + } + } + } + } + ; + +valexpr : exprnum { $$ = $1; } + | string { + $$.val = NewString($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; + } + | exprcompound { $$ = $1; } + | 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; + } + +/* grouping */ + | LPAREN expr RPAREN %prec CAST { + $$.val = NewStringf("(%s)",$2.val); + $$.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; + } + } + } + | 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 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); + } + } + | 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; } + ; + +exprcompound : expr PLUS expr { + $$.val = NewStringf("%s+%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr MINUS expr { + $$.val = NewStringf("%s-%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr STAR expr { + $$.val = NewStringf("%s*%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr SLASH expr { + $$.val = NewStringf("%s/%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr MODULUS expr { + $$.val = NewStringf("%s%%%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr AND expr { + $$.val = NewStringf("%s&%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr OR expr { + $$.val = NewStringf("%s|%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr XOR expr { + $$.val = NewStringf("%s^%s",$1.val,$3.val); + $$.type = promote($1.type,$3.type); + } + | expr LSHIFT expr { + $$.val = NewStringf("%s << %s",$1.val,$3.val); + $$.type = promote_type($1.type); + } + | expr RSHIFT expr { + $$.val = NewStringf("%s >> %s",$1.val,$3.val); + $$.type = promote_type($1.type); + } + | expr LAND expr { + $$.val = NewStringf("%s&&%s",$1.val,$3.val); + $$.type = T_INT; + } + | expr LOR expr { + $$.val = NewStringf("%s||%s",$1.val,$3.val); + $$.type = T_INT; + } + | expr EQUALTO expr { + $$.val = NewStringf("%s==%s",$1.val,$3.val); + $$.type = T_INT; + } + | expr NOTEQUALTO expr { + $$.val = NewStringf("%s!=%s",$1.val,$3.val); + $$.type = T_INT; + } +/* Sadly this causes 2 reduce-reduce conflicts with templates. FIXME resolve these. + | expr GREATERTHAN expr { + $$.val = NewStringf("%s SWIG_LT %s", $1.val, $3.val); + $$.type = T_INT; + } + | expr LESSTHAN expr { + $$.val = NewStringf("%s SWIG_GT %s", $1.val, $3.val); + $$.type = T_INT; + } +*/ + | expr GREATERTHANOREQUALTO expr { + /* Putting >= in the expression literally causes an infinite + * loop somewhere in the type system. Just workaround for now + * - SWIG_GE is defined in swiglabels.swg. */ + $$.val = NewStringf("%s SWIG_GE %s", $1.val, $3.val); + $$.type = T_INT; + } + | expr LESSTHANOREQUALTO expr { + $$.val = NewStringf("%s SWIG_LE %s", $1.val, $3.val); + $$.type = T_INT; + } + | expr QUESTIONMARK expr COLON expr %prec QUESTIONMARK { + $$.val = NewStringf("%s?%s:%s", $1.val, $3.val, $5.val); + /* 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",$2.val); + $$.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); + } + ; + +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 idcolon { + $$ = NewHash(); + Setfile($$,cparse_file); + Setline($$,cparse_line); + Setattr($$,"name",$2); + if (last_cpptype && (Strcmp(last_cpptype,"struct") != 0)) { + Setattr($$,"access","private"); + Swig_warning(WARN_PARSE_NO_ACCESS,cparse_file,cparse_line, + "No access specifier given for base class %s (ignored).\n",$2); + } else { + Setattr($$,"access","public"); + } + } + | opt_virtual access_specifier opt_virtual idcolon { + $$ = NewHash(); + Setfile($$,cparse_file); + Setline($$,cparse_line); + Setattr($$,"name",$4); + Setattr($$,"access",$2); + if (Strcmp($2,"public") != 0) { + Swig_warning(WARN_PARSE_PRIVATE_INHERIT, cparse_file, + cparse_line,"%s inheritance ignored.\n", $2); + } + } + ; + +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 = $$; + } + ; + +cpptype : templcpptype { + $$ = $1; + } + | STRUCT { + $$ = (char*)"struct"; + if (!inherit_list) last_cpptype = $$; + } + | UNION { + $$ = (char*)"union"; + if (!inherit_list) last_cpptype = $$; + } + ; + +opt_virtual : VIRTUAL + | empty + ; + +cpp_const : type_qualifier { + $$.qualifier = $1; + $$.throws = 0; + $$.throwf = 0; + } + | THROW LPAREN parms RPAREN { + $$.qualifier = 0; + $$.throws = $3; + $$.throwf = NewString("1"); + } + | type_qualifier THROW LPAREN parms RPAREN { + $$.qualifier = $1; + $$.throws = $4; + $$.throwf = NewString("1"); + } + | empty { + $$.qualifier = 0; + $$.throws = 0; + $$.throwf = 0; + } + ; + +ctor_end : cpp_const ctor_initializer SEMI { + Clear(scanner_ccode); + $$.have_parms = 0; + $$.defarg = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + | cpp_const ctor_initializer LBRACE { + skip_balanced('{','}'); + $$.have_parms = 0; + $$.defarg = 0; + $$.throws = $1.throws; + $$.throwf = $1.throwf; + } + | LPAREN parms RPAREN SEMI { + Clear(scanner_ccode); + $$.parms = $2; + $$.have_parms = 1; + $$.defarg = 0; + $$.throws = 0; + $$.throwf = 0; + } + | LPAREN parms RPAREN LBRACE { + skip_balanced('{','}'); + $$.parms = $2; + $$.have_parms = 1; + $$.defarg = 0; + $$.throws = 0; + $$.throwf = 0; + } + | EQUAL definetype SEMI { + $$.have_parms = 0; + $$.defarg = $2.val; + $$.throws = 0; + $$.throwf = 0; + } + ; + +ctor_initializer : COLON mem_initializer_list + | empty + ; + +mem_initializer_list : mem_initializer + | mem_initializer_list COMMA mem_initializer + ; + +mem_initializer : idcolon LPAREN { + skip_balanced('(',')'); + Clear(scanner_ccode); + } + ; + +template_decl : LESSTHAN valparms GREATERTHAN { + String *s = NewStringEmpty(); + SwigType_add_template(s,$2); + $$ = Char(s); + scanner_last_id(1); + } + | empty { $$ = (char*)""; } + ; + +idstring : ID { $$ = $1; } + | string { $$ = $1; } + ; + +idstringopt : idstring { $$ = $1; } + | empty { $$ = 0; } + ; + +idcolon : idtemplate idcolontail { + $$ = 0; + if (!$$) $$ = NewStringf("%s%s", $1,$2); + Delete($2); + } + | NONID DCOLON idtemplate idcolontail { + $$ = NewStringf("::%s%s",$3,$4); + Delete($4); + } + | idtemplate { + $$ = NewString($1); + } + | NONID DCOLON idtemplate { + $$ = NewStringf("::%s",$3); + } + | OPERATOR { + $$ = NewString($1); + } + | NONID DCOLON OPERATOR { + $$ = NewStringf("::%s",$3); + } + ; + +idcolontail : DCOLON idtemplate idcolontail { + $$ = NewStringf("::%s%s",$2,$3); + Delete($3); + } + | DCOLON idtemplate { + $$ = NewStringf("::%s",$2); + } + | DCOLON OPERATOR { + $$ = NewStringf("::%s",$2); + } +/* | DCOLON COPERATOR { + $$ = NewString($2); + } */ + + | DCNOT idtemplate { + $$ = NewStringf("::~%s",$2); + } + ; + + +idtemplate : ID template_decl { + $$ = NewStringf("%s%s",$1,$2); + /* if (Len($2)) { + scanner_last_id(1); + } */ + } + ; + +/* Identifier, but no templates */ +idcolonnt : ID idcolontailnt { + $$ = 0; + if (!$$) $$ = NewStringf("%s%s", $1,$2); + Delete($2); + } + | NONID DCOLON ID idcolontailnt { + $$ = NewStringf("::%s%s",$3,$4); + Delete($4); + } + | ID { + $$ = NewString($1); + } + | NONID DCOLON ID { + $$ = NewStringf("::%s",$3); + } + | OPERATOR { + $$ = NewString($1); + } + | NONID DCOLON OPERATOR { + $$ = NewStringf("::%s",$3); + } + ; + +idcolontailnt : DCOLON ID idcolontailnt { + $$ = NewStringf("::%s%s",$2,$3); + Delete($3); + } + | DCOLON ID { + $$ = NewStringf("::%s",$2); + } + | DCOLON OPERATOR { + $$ = NewStringf("::%s",$2); + } + | DCNOT ID { + $$ = NewStringf("::~%s",$2); + } + ; + +/* Concatenated strings */ +string : string STRING { + $$ = (char *) malloc(strlen($1)+strlen($2)+1); + strcpy($$,$1); + strcat($$,$2); + } + | STRING { $$ = $1;} + ; + +stringbrace : string { + $$ = NewString($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) { + String *ns; + char *cs = Char(s); + if (cs && cs[0] != '(') { + ns = NewStringf("(%s);",s); + } else { + ns = NewStringf("%s;",s); + } + 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/Source/CParse/templ.c b/Source/CParse/templ.c new file mode 100644 index 0000000..3fa4111 --- /dev/null +++ b/Source/CParse/templ.c @@ -0,0 +1,675 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * templ.c + * + * Expands a template into a specialized version. + * ----------------------------------------------------------------------------- */ + +char cvsroot_templ_c[] = "$Id: templ.c 11097 2009-01-30 10:27:37Z bhy $"; + +#include "swig.h" +#include "cparse.h" + +static int template_debug = 0; + + +const char *baselists[3]; + +void SwigType_template_init() { + baselists[0] = "baselist"; + baselists[1] = "protectedbaselist"; + baselists[2] = "privatebaselist"; +} + + +static void add_parms(ParmList *p, List *patchlist, List *typelist) { + while (p) { + SwigType *ty = Getattr(p, "type"); + SwigType *val = Getattr(p, "value"); + Append(typelist, ty); + Append(typelist, val); + 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 int cparse_template_expand(Node *n, String *tname, String *rname, String *templateargs, List *patchlist, List *typelist, List *cpatchlist) { + static int expanded = 0; + int ret; + String *nodeType; + if (!n) + return 0; + nodeType = nodeType(n); + if (Getattr(n, "error")) + return 0; + + if (Equal(nodeType, "template")) { + /* Change the node type back to normal */ + if (!expanded) { + expanded = 1; + set_nodeType(n, Getattr(n, "templatetype")); + ret = cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist); + expanded = 0; + return ret; + } else { + /* Called when template appears inside another template */ + /* Member templates */ + + set_nodeType(n, Getattr(n, "templatetype")); + ret = cparse_template_expand(n, tname, rname, templateargs, patchlist, typelist, cpatchlist); + set_nodeType(n, "template"); + return ret; + } + } 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")); + } + } + + add_parms(Getattr(n, "parms"), cpatchlist, typelist); + add_parms(Getattr(n, "throws"), cpatchlist, typelist); + + } 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(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); + add_parms(Getattr(n, "throws"), cpatchlist, typelist); + } else if (Equal(nodeType, "destructor")) { + 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); + add_parms(Getattr(n, "kwargs"), cpatchlist, typelist); + add_parms(Getattr(n, "pattern"), cpatchlist, typelist); + add_parms(Getattr(n, "throws"), cpatchlist, typelist); + cn = firstChild(n); + while (cn) { + cparse_template_expand(cn, tname, rname, templateargs, patchlist, typelist, cpatchlist); + cn = nextSibling(cn); + } + } + return 0; +} + +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, c - cp); + newarg = Copy(s); + Replace(newarg, prefix, "", DOH_REPLACE_ANY | 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")); + 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, 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"); + while (p && tp) { + String *name, *value, *valuestr, *tydef, *tmp, *tmpr; + int sz, i; + String *dvalue = 0; + String *qvalue = 0; + + name = Getattr(tp, "name"); + value = Getattr(p, "value"); + tydef = Getattr(p, "typedef"); + + 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); + /* Replace(s,name,value, DOH_REPLACE_ID); */ + /* Printf(stdout,"name = '%s', value = '%s', tbase = '%s', iname='%s' s = '%s' --> ", name, dvalue, tbase, iname, s); */ + SwigType_typename_replace(s, name, dvalue); + SwigType_typename_replace(s, tbase, iname); + /* Printf(stdout,"'%s'\n", s); */ + } + + if (!tydef) { + tydef = dvalue; + } + 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,tydef, 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); + } + } + } + + /* 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; +} + +/* ----------------------------------------------------------------------------- + * template_locate() + * + * Search for a template that matches name with given parameters. + * ----------------------------------------------------------------------------- */ + +static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) { + Node *n; + String *tname, *rname = 0; + Node *templ; + List *mpartials = 0; + Parm *p; + Parm *parms; + Parm *targs; + ParmList *expandedparms; + + tname = Copy(name); + parms = CopyParmList(tparms); + + /* Search for generic template */ + templ = Swig_symbol_clookup(name, 0); + + /* Add default values from generic template */ + if (templ) { + Symtab *tsdecl = Getattr(templ, "sym:symtab"); + + targs = Getattr(templ, "templateparms"); + expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, tsdecl); + } else { + expandedparms = parms; + } + + + /* 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); + + if (template_debug) { + Printf(stdout, "\n%s:%d: template_debug: Searching for %s\n", cparse_file, cparse_line, tname); + } + + /* Search for an exact specialization. + Example: template<> class name<int> { ... } */ + { + if (template_debug) { + Printf(stdout, " searching: '%s' (exact specialization)\n", tname); + } + n = Swig_symbol_clookup_local(tname, 0); + if (!n) { + SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope); + if (!Equal(rname, tname)) { + if (template_debug) { + Printf(stdout, " searching: '%s' (exact specialization)\n", rname); + } + n = Swig_symbol_clookup_local(rname, 0); + } + Delete(rname); + } + if (n) { + Node *tn; + String *nodeType = nodeType(n); + if (Equal(nodeType, "template")) + goto success; + tn = Getattr(n, "template"); + if (tn) { + n = tn; + goto success; /* Previously wrapped by a template return that */ + } + 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 specialization. + Example: template<typename T> class name<T *> { ... } */ + + /* Generate reduced template name (stripped of extraneous pointers, etc.) */ + + rname = NewStringf("%s<(", name); + p = parms; + while (p) { + String *t; + t = Getattr(p, "type"); + if (!t) + t = Getattr(p, "value"); + if (t) { + String *ty = Swig_symbol_typedef_reduce(t, tscope); + String *tb = SwigType_base(ty); + String *td = SwigType_default(ty); + Replaceid(td, "enum SWIGTYPE", tb); + Replaceid(td, "SWIGTYPE", tb); + Append(rname, td); + Delete(tb); + Delete(ty); + Delete(td); + } + p = nextSibling(p); + if (p) { + Append(rname, ","); + } + } + Append(rname, ")>"); + + mpartials = NewList(); + if (templ) { + /* First, we search using an exact type prototype */ + Parm *p; + char tmp[32]; + int i; + List *partials; + String *ss; + Iterator pi; + + partials = Getattr(templ, "partials"); + if (partials) { + for (pi = First(partials); pi.item; pi = Next(pi)) { + ss = Copy(pi.item); + p = parms; + i = 1; + while (p) { + String *t, *tn; + sprintf(tmp, "$%d", i); + t = Getattr(p, "type"); + if (!t) + t = Getattr(p, "value"); + if (t) { + String *ty = Swig_symbol_typedef_reduce(t, tscope); + tn = SwigType_base(ty); + Replaceid(ss, tmp, tn); + Delete(tn); + Delete(ty); + } + i++; + p = nextSibling(p); + } + if (template_debug) { + Printf(stdout, " searching: '%s' (partial specialization - %s)\n", ss, pi.item); + } + if ((Equal(ss, tname)) || (Equal(ss, rname))) { + Append(mpartials, pi.item); + } + Delete(ss); + } + } + } + + if (template_debug) { + Printf(stdout, " Matched partials: %s\n", mpartials); + } + + if (Len(mpartials)) { + String *s = Getitem(mpartials, 0); + n = Swig_symbol_clookup_local(s, 0); + if (Len(mpartials) > 1) { + 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' is used.\n", SwigType_namestr(Getattr(n, "name"))); + } + } + } + + if (!n) { + n = templ; + } + 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(rname); + Delete(mpartials); + if ((template_debug) && (n)) { + Printf(stdout, "Node: %p\n", n); + Swig_print_node(n); + } + Delete(parms); + 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")); + 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. Lets 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/Source/CParse/util.c b/Source/CParse/util.c new file mode 100644 index 0000000..de374c8 --- /dev/null +++ b/Source/CParse/util.c @@ -0,0 +1,88 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * util.c + * + * Parsing utilities. + * ----------------------------------------------------------------------------- */ + +char cvsroot_util_c[] = "$Id: util.c 9632 2007-01-03 20:58:19Z beazley $"; + +#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; + } + } +} + +/* ----------------------------------------------------------------------------- + * 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"); + } + } +} diff --git a/Source/DOH/README b/Source/DOH/README new file mode 100644 index 0000000..9a42e8b --- /dev/null +++ b/Source/DOH/README @@ -0,0 +1,118 @@ +DOH (Dave's Object Hack) + +Overview: +--------- +DOH is a small C library that provides a number of simple yet powerful +data structures. The data structures are built around a dynamic typing +model in which any given object is allowed to support one or more +classes of operations. Furthermore, a simple garbage collection +scheme and a variety of interesting library methods are available. +All and all, the operation of DOH makes massive abuse of the C type +system and would probably make the language purists scream and +performance addicts run away in horror. However, I really don't +care--so there! However, for the rest of us, DOH is actually kind of +fun to use. This is only a short description of the methods and is no +way meant to be exhaustive. + +Common Operations (for all types) +--------------------------------- +Delete(obj) Decrease the reference count and destroy if zero +Copy(obj) Make a copy of an object. +Clear(obj) Clear an object. +Setscope(obj) Set scope of an object (guru's only) +Str(obj) Create a string representation of obj. +Data(obj) Return pointer to raw data in an object +Char(obj) Convert to a char * +Len(obj) Length of an object +Hash(obj) Hash value (used for mapping) +Cmp(obj1,obj2) Compare two objects. +Name(obj) Return the object name +First(obj) Return first object (iterator) +Next(obj) Return next object +Dump(obj,out) Serialize on out +Load(in) Unserialize from in +First(obj) Iterator +Next(iter) Next iterator + +Mapping Operations (for hash table behavior) +-------------------------------------------- +Getattr(hash,key) Get an attribute +Setattr(hash,key,value) Set an attribute +Delattr(hash,key) Delete an attribute +First(hash) Get first object (iterator) +Next(hash) Get next object +GetInt(hash,key) Get attribute as an 'int' +SetInt(hash,key,ivalue) Set attribute as an 'int' +GetDouble(hash,key) Get attribute as a 'double' +SetDouble(hash,key,dvalue) Set Attribute as a 'double' +GetChar(hash,key) Get attribute as a 'char *' + +Sequence Operations +------------------- +Getitem(list,index) Get an item +Setitem(list,index,val) Set an item +Delitem(list,index,val) Delete an item +Insert(list,index,val) Insert an item +Append(list,val) Append to end +Push(list,val) Insert at beginning + +File Operations +--------------- +Read(obj,buffer,len) Read data +Write(obj,buffer,len) Write data +Getc(obj) Get a character +Putc(ch,obj) Put a character +Ungetc(ch,obj) Put character back on input stream +Seek(obj,offset,whence) Seek +Tell(obj) Return file pointer +Close(obj) Close + +String Operations +----------------- +Replace(obj, orig, rep, flags) Replace occurences of orig with rep. +Chop(obj) Remove trailing whitespace + +flags is one of the following: + DOH_REPLACE_ANY + DOH_REPLACE_NOQUOTE + DOH_REPLACE_ID + DOH_REPLACE_FIRST + +Callable Operations +------------------- +Call(obj, args) Perform a function call with arguments args. + +Miscellaneous library functions +------------------------------- +NewScope() Create a new scope +DelScope(s) Delete scope s +Readline(in) Read a line of input from in +Printf(out,fmt,...) Formatted output +DohEncoding(name, fn) Register a format encoding for Printf + +Currently Available datatypes +------------------------------ +NewString(char *initial) Strings +NewHash() Hash +NewList() List +NewVoid(void *ptr, void (*del)(void *)) Void +NewFile(char *filename, char *mode, List *newfiles) File +NewCallable(DOH *(*func)(DOH *, DOH *)) Callable object + + +Odds and ends: + + 1. All objects are of type 'DOH *' + 2. When in doubt, see rule (1) + 3. In certain cases, DOH performs implicit conversions + of 'char *' to an appropriate DOH string representation. + For operations involving files, DOH works with many + kinds of objects including FILE *, DOH File objects, + and DOH strings. Don't even ask how this works. + + 4. More complete documentation is forthcoming. + + + + + diff --git a/Source/DOH/base.c b/Source/DOH/base.c new file mode 100644 index 0000000..4262e70 --- /dev/null +++ b/Source/DOH/base.c @@ -0,0 +1,943 @@ +/* ----------------------------------------------------------------------------- + * base.c + * + * This file contains the function entry points for dispatching methods on + * DOH objects. A number of small utility functions are also included. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_base_c[] = "$Id: base.c 11097 2009-01-30 10:27:37Z bhy $"; + +#include "dohint.h" + +/* ----------------------------------------------------------------------------- + * DohDelete() + * ----------------------------------------------------------------------------- */ + +#ifndef SWIG_DEBUG_DELETE +#define SWIG_DEBUG_DELETE 0 +#endif + +void DohDelete(DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + + if (!obj) + return; +#if SWIG_DEBUG_DELETE + if (!DohCheck(b)) { + fputs("DOH: Fatal error. Attempt to delete a non-doh object.\n", stderr); + abort(); + } +#endif + if (b->flag_intern) + return; + assert(b->refcount > 0); + b->refcount--; + if (b->refcount <= 0) { + objinfo = b->type; + if (objinfo->doh_del) { + (objinfo->doh_del) (b); + } else { + if (b->data) + DohFree(b->data); + } + DohObjFree(b); + } +} + +/* ----------------------------------------------------------------------------- + * DohCopy() + * ----------------------------------------------------------------------------- */ + +DOH *DohCopy(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + + if (!obj) + return 0; + objinfo = b->type; + if (objinfo->doh_copy) { + DohBase *bc = (DohBase *) (objinfo->doh_copy) (b); + if ((bc) && b->meta) { + bc->meta = Copy(b->meta); + } + return (DOH *) bc; + } + return 0; +} + +void DohIncref(DOH *obj) { + Incref(obj); +} + +/* ----------------------------------------------------------------------------- + * DohClear() + * ----------------------------------------------------------------------------- */ + +void DohClear(DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_clear) + (objinfo->doh_clear) (b); +} + +/* ----------------------------------------------------------------------------- + * DohStr() + * ----------------------------------------------------------------------------- */ + +DOH *DohStr(const DOH *obj) { + char buffer[512]; + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(b)) { + objinfo = b->type; + if (objinfo->doh_str) { + return (objinfo->doh_str) (b); + } + sprintf(buffer, "<Object '%s' at %p>", objinfo->objname, (void *) b); + return NewString(buffer); + } else { + return NewString(obj); + } +} + +/* ----------------------------------------------------------------------------- + * DohDump() + * ----------------------------------------------------------------------------- */ + +int DohDump(const DOH *obj, DOH *out) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_dump) { + return (objinfo->doh_dump) (b, out); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohLen() - Defaults to strlen() if not a DOH object + * ----------------------------------------------------------------------------- */ +int DohLen(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (!b) + return 0; + if (DohCheck(b)) { + objinfo = b->type; + if (objinfo->doh_len) { + return (objinfo->doh_len) (b); + } + return 0; + } else { + return strlen((char *) obj); + } +} + +/* ----------------------------------------------------------------------------- + * DohHashVal() + * ----------------------------------------------------------------------------- */ + +int DohHashval(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + /* obj is already checked and/or converted into DohBase* */ + /* if (DohCheck(b)) */ + { + objinfo = b->type; + if (objinfo->doh_hashval) { + return (objinfo->doh_hashval) (b); + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohData() + * ----------------------------------------------------------------------------- */ + +void *DohData(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if (objinfo->doh_data) { + return (objinfo->doh_data) (b); + } + return 0; + } + return (void *) obj; +} + +/* ----------------------------------------------------------------------------- + * RawData() + * ----------------------------------------------------------------------------- */ + +static void *RawData(DohBase *b) { + DohObjInfo *objinfo = b->type; + return (objinfo->doh_data) ? (objinfo->doh_data) (b) : 0; +} + + +/* ----------------------------------------------------------------------------- + * DohCmp() + * ----------------------------------------------------------------------------- */ + +int DohCmp(const DOH *obj1, const DOH *obj2) { + DohBase *b1, *b2; + DohObjInfo *b1info, *b2info; + int c1, c2; + b1 = (DohBase *) obj1; + b2 = (DohBase *) obj2; + c1 = DohCheck(b1); + c2 = DohCheck(b2); + /* most of the times, obj2 is a plain c string */ + if (!c1 || !c2) { + if ((b1 == 0) && (b2 == 0)) + return 0; + if (b1 && !b2) + return 1; + if (!b1 && b2) + return -1; + return strcmp((char *) (c1 ? RawData(b1) : (void *) obj1), (char *) (c2 ? RawData(b2) : (void *) obj2)); + } + b1info = b1->type; + b2info = b2->type; + if ((b1info == b2info) && (b1info->doh_cmp)) + return (b1info->doh_cmp) (b1, b2); + return 1; +} + +/* ----------------------------------------------------------------------------- + * DohEqual() + * ----------------------------------------------------------------------------- */ + +int DohEqual(const DOH *obj1, const DOH *obj2) { + DohBase *b1 = (DohBase *) obj1; + DohBase *b2 = (DohBase *) obj2; + if (!b1) { + return !b2; + } else if (!b2) { + return 0; + } else { + DohObjInfo *b1info = 0; + DohObjInfo *b2info = 0; + if (DohCheck(b1)) { + b1info = b1->type; + if (DohCheck(b2)) { + b2info = b2->type; + } else { + int len = (b1info->doh_len) (b1); + char *cobj = (char *) obj2; + return len == (int) strlen(cobj) ? (memcmp(RawData(b1), cobj, len) == 0) : 0; + } + } else if (DohCheck(b2)) { + int len = (b2->type->doh_len) (b2); + char *cobj = (char *) obj1; + return len == (int) strlen(cobj) ? (memcmp(RawData(b2), cobj, len) == 0) : 0; + } else { + return strcmp((char *) obj1, (char *) obj2) == 0; + } + + if (!b1info) { + return obj1 == obj2; + } else if ((b1info == b2info)) { + return b1info->doh_equal ? (b1info->doh_equal) (b1, b2) : (b1info->doh_cmp ? (b1info->doh_cmp) (b1, b2) == 0 : (b1 == b2)); + } else { + return 0; + } + } +} + +/* ----------------------------------------------------------------------------- + * DohFirst() + * ----------------------------------------------------------------------------- */ + +DohIterator DohFirst(DOH *obj) { + DohIterator iter; + DohBase *b; + DohObjInfo *binfo; + + b = (DohBase *) obj; + if (DohCheck(b)) { + binfo = b->type; + if (binfo->doh_first) { + return (binfo->doh_first) (b); + } + } + iter.object = 0; + iter.item = 0; + iter.key = 0; + iter._current = 0; + iter._index = 0; + return iter; +} + +/* ----------------------------------------------------------------------------- + * DohNext() + * ----------------------------------------------------------------------------- */ + +DohIterator DohNext(DohIterator iter) { + DohIterator niter; + + if (iter.object) { + DohBase *b; + DohObjInfo *binfo; + + b = (DohBase *) iter.object; + binfo = b->type; + if (binfo->doh_next) { + return (binfo->doh_next) (iter); + } + } + niter = iter; + return niter; +} + +/* ----------------------------------------------------------------------------- + * DohIsMapping() + * ----------------------------------------------------------------------------- */ +int DohIsMapping(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (!DohCheck(b)) + return 0; + objinfo = b->type; + if (objinfo->doh_hash) + return 1; + else + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetattr() + * ----------------------------------------------------------------------------- */ + +DOH *DohGetattr(DOH *obj, const DOH *name) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_hash && objinfo->doh_hash->doh_getattr) { + DOH *r = (objinfo->doh_hash->doh_getattr) (b, (DOH *) name); + return (r == DohNone) ? 0 : r; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohSetattr() + * ----------------------------------------------------------------------------- */ + +int DohSetattr(DOH *obj, const DOH *name, const DOH *value) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_hash && objinfo->doh_hash->doh_setattr) { + return (objinfo->doh_hash->doh_setattr) (b, (DOH *) name, (DOH *) value); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohDelattr() + * ----------------------------------------------------------------------------- */ + +int DohDelattr(DOH *obj, const DOH *name) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_hash && objinfo->doh_hash->doh_delattr) { + return (objinfo->doh_hash->doh_delattr) (b, (DOH *) name); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohCheckattr() + * ----------------------------------------------------------------------------- */ + +int DohCheckattr(DOH *obj, const DOH *name, const DOH *value) { + DOH *attr = Getattr(obj,name); + if (!attr) return 0; + return DohEqual(attr,value); +} + +/* ----------------------------------------------------------------------------- + * DohKeys() + * ----------------------------------------------------------------------------- */ + +DOH *DohKeys(DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo && objinfo->doh_hash->doh_keys) { + return (objinfo->doh_hash->doh_keys) (b); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetInt() + * ----------------------------------------------------------------------------- */ + +int DohGetInt(DOH *obj, const DOH *name) { + DOH *val; + val = Getattr(obj, (DOH *) name); + if (!val) + return 0; + if (DohIsString(val)) { + return atoi((char *) Data(val)); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetDouble() + * ----------------------------------------------------------------------------- */ + +double DohGetDouble(DOH *obj, const DOH *name) { + DOH *val; + val = Getattr(obj, (DOH *) name); + if (!val) + return 0; + if (DohIsString(val)) { + return atof((char *) Data(val)); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetChar() + * ----------------------------------------------------------------------------- */ + +char *DohGetChar(DOH *obj, const DOH *name) { + DOH *val; + val = Getattr(obj, (DOH *) name); + if (!val) + return 0; + if (DohIsString(val)) { + return (char *) Data(val); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetFlagAttr() / DohGetFlag() + * A flag is unset if the attribute (name) does not exist on the node (obj), + * or it is set to "0". If the attribute is set to any other value, + * the flag is set. + * + * DohGetFlag() returns if the flag is set or not + * DohGetFlagAttr() returns the flag value if is set, NULL otherwise + * ----------------------------------------------------------------------------- */ + + +DOH *DohGetFlagAttr(DOH *obj, const DOH *name) { + DOH *val = Getattr(obj, (DOH *) name); + if (!val) { + return NULL; + } else { + const char *cval = Char(val); + if (!cval) + return val; + return (strcmp(cval, "0") != 0) ? val : NULL; + } +} + +int DohGetFlag(DOH *obj, const DOH *name) { + return DohGetFlagAttr(obj, name) ? 1 : 0; +} + + +/* ----------------------------------------------------------------------------- + * DohGetVoid() + * ----------------------------------------------------------------------------- */ + +void *DohGetVoid(DOH *obj, const DOH *name) { + DOH *val; + val = Getattr(obj, (DOH *) name); + if (!val) + return 0; + return (void *) Data(val); +} + +/* ----------------------------------------------------------------------------- + * DohSetInt() + * ----------------------------------------------------------------------------- */ + +void DohSetInt(DOH *obj, const DOH *name, int value) { + DOH *temp; + temp = NewStringEmpty(); + Printf(temp, "%d", value); + Setattr(obj, (DOH *) name, temp); +} + +/* ----------------------------------------------------------------------------- + * DohSetDouble() + * ----------------------------------------------------------------------------- */ + +void DohSetDouble(DOH *obj, const DOH *name, double value) { + DOH *temp; + temp = NewStringEmpty(); + Printf(temp, "%0.17f", value); + Setattr(obj, (DOH *) name, temp); +} + +/* ----------------------------------------------------------------------------- + * DohSetChar() + * ----------------------------------------------------------------------------- */ + +void DohSetChar(DOH *obj, const DOH *name, char *value) { + Setattr(obj, (DOH *) name, NewString(value)); +} + +/* ----------------------------------------------------------------------------- + * DohSetFlag() + * ----------------------------------------------------------------------------- */ + +void DohSetFlagAttr(DOH *obj, const DOH *name, const DOH *attr) { + Setattr(obj, (DOH *) name, attr ? attr : NewString("0")); +} + +void DohSetFlag(DOH *obj, const DOH *name) { + Setattr(obj, (DOH *) name, NewString("1")); +} + +/* ----------------------------------------------------------------------------- + * DohSetVoid() + * ----------------------------------------------------------------------------- */ + +void DohSetVoid(DOH *obj, const DOH *name, void *value) { + Setattr(obj, (DOH *) name, NewVoid(value, 0)); +} + +/* ----------------------------------------------------------------------------- + * DohIsSequence() + * ----------------------------------------------------------------------------- */ + +int DohIsSequence(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (!DohCheck(b)) + return 0; + objinfo = b->type; + if (objinfo->doh_list) + return 1; + else + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetitem() + * ----------------------------------------------------------------------------- */ + +DOH *DohGetitem(DOH *obj, int index) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_list && objinfo->doh_list->doh_getitem) { + return (objinfo->doh_list->doh_getitem) (b, index); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohSetitem() + * ----------------------------------------------------------------------------- */ + +int DohSetitem(DOH *obj, int index, const DOH *value) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_list && objinfo->doh_list->doh_setitem) { + return (objinfo->doh_list->doh_setitem) (b, index, (DOH *) value); + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * DohDelitem() + * ----------------------------------------------------------------------------- */ + +int DohDelitem(DOH *obj, int index) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_list && objinfo->doh_list->doh_delitem) { + return (objinfo->doh_list->doh_delitem) (b, index); + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * DohInsertitem() + * ----------------------------------------------------------------------------- */ + +int DohInsertitem(DOH *obj, int index, const DOH *value) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_list && objinfo->doh_list->doh_insitem) { + return (objinfo->doh_list->doh_insitem) (b, index, (DOH *) value); + } + return -1; +} + + +/* ----------------------------------------------------------------------------- + * DohDelslice() + * ----------------------------------------------------------------------------- */ + +int DohDelslice(DOH *obj, int sindex, int eindex) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo = b->type; + if (objinfo->doh_list && objinfo->doh_list->doh_delslice) { + return (objinfo->doh_list->doh_delslice) (b, sindex, eindex); + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * DohIsFile() + * ----------------------------------------------------------------------------- */ + +int DohIsFile(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (!DohCheck(b)) + return 0; + objinfo = b->type; + if (objinfo->doh_file) + return 1; + else + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohRead() + * ----------------------------------------------------------------------------- */ + +int DohRead(DOH *obj, void *buffer, int length) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if ((objinfo->doh_file) && (objinfo->doh_file->doh_read)) { + return (objinfo->doh_file->doh_read) (b, buffer, length); + } + return -1; + } + /* Hmmm. Not a file. Maybe it's a real FILE */ + return fread(buffer, 1, length, (FILE *) b); +} + +/* ----------------------------------------------------------------------------- + * DohWrite() + * ----------------------------------------------------------------------------- */ + +int DohWrite(DOH *obj, void *buffer, int length) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if ((objinfo->doh_file) && (objinfo->doh_file->doh_write)) { + return (objinfo->doh_file->doh_write) (b, buffer, length); + } + return -1; + } + /* Hmmm. Not a file. Maybe it's a real FILE */ + return fwrite(buffer, 1, length, (FILE *) b); +} + +/* ----------------------------------------------------------------------------- + * DohSeek() + * ----------------------------------------------------------------------------- */ + +int DohSeek(DOH *obj, long offset, int whence) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if ((objinfo->doh_file) && (objinfo->doh_file->doh_seek)) { + return (objinfo->doh_file->doh_seek) (b, offset, whence); + } + return -1; + } + return fseek((FILE *) b, offset, whence); +} + +/* ----------------------------------------------------------------------------- + * DohTell() + * ----------------------------------------------------------------------------- */ + +long DohTell(DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if ((objinfo->doh_file) && (objinfo->doh_file->doh_tell)) { + return (objinfo->doh_file->doh_tell) (b); + } + return -1; + } + return ftell((FILE *) b); +} + +/* ----------------------------------------------------------------------------- + * DohGetc() + * ----------------------------------------------------------------------------- */ + +int DohGetc(DOH *obj) { + static DOH *lastdoh = 0; + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (obj == lastdoh) { + objinfo = b->type; + return (objinfo->doh_file->doh_getc) (b); + } + if (DohCheck(obj)) { + objinfo = b->type; + if (objinfo->doh_file->doh_getc) { + lastdoh = obj; + return (objinfo->doh_file->doh_getc) (b); + } + return EOF; + } + return fgetc((FILE *) b); +} + +/* ----------------------------------------------------------------------------- + * DohPutc() + * ----------------------------------------------------------------------------- */ + +int DohPutc(int ch, DOH *obj) { + static DOH *lastdoh = 0; + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + + if (obj == lastdoh) { + objinfo = b->type; + return (objinfo->doh_file->doh_putc) (b, ch); + } + if (DohCheck(obj)) { + objinfo = b->type; + if (objinfo->doh_file->doh_putc) { + lastdoh = obj; + return (objinfo->doh_file->doh_putc) (b, ch); + } + return EOF; + } + return fputc(ch, (FILE *) b); +} + +/* ----------------------------------------------------------------------------- + * DohUngetc() + * ----------------------------------------------------------------------------- */ + +int DohUngetc(int ch, DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if (objinfo->doh_file->doh_ungetc) { + return (objinfo->doh_file->doh_ungetc) (b, ch); + } + return EOF; + } + return ungetc(ch, (FILE *) b); +} + +/* ----------------------------------------------------------------------------- + * DohClose() + * ----------------------------------------------------------------------------- */ + +int DohClose(DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (DohCheck(obj)) { + objinfo = b->type; + if (objinfo->doh_file->doh_close) { + return (objinfo->doh_file->doh_close) (b); + } + return 0; + } + return fclose((FILE *) obj); +} + +/* ----------------------------------------------------------------------------- + * DohIsString() + * ----------------------------------------------------------------------------- */ + +int DohIsString(const DOH *obj) { + DohBase *b = (DohBase *) obj; + DohObjInfo *objinfo; + if (!DohCheck(b)) + return 0; + objinfo = b->type; + if (objinfo->doh_string) + return 1; + else + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohReplace() + * ----------------------------------------------------------------------------- */ + +int DohReplace(DOH *src, const DOH *token, const DOH *rep, int flags) { + DohBase *b = (DohBase *) src; + DohObjInfo *objinfo; + if (!token) + return 0; + if (!rep) + rep = ""; + if (DohIsString(src)) { + objinfo = b->type; + if (objinfo->doh_string->doh_replace) { + return (objinfo->doh_string->doh_replace) (b, (DOH *) token, (DOH *) rep, flags); + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohChop() + * ----------------------------------------------------------------------------- */ + +void DohChop(DOH *src) { + DohBase *b = (DohBase *) src; + DohObjInfo *objinfo; + if (DohIsString(src)) { + objinfo = b->type; + if (objinfo->doh_string->doh_chop) { + (objinfo->doh_string->doh_chop) (b); + } + } +} + +/* ----------------------------------------------------------------------------- + * DohSetFile() + * ----------------------------------------------------------------------------- */ +void DohSetfile(DOH *ho, DOH *file) { + DohBase *h = (DohBase *) ho; + DohObjInfo *objinfo; + if (!h) + return; + objinfo = h->type; + if (objinfo->doh_setfile) + (objinfo->doh_setfile) (h, file); +} + +/* ----------------------------------------------------------------------------- + * DohGetFile() + * ----------------------------------------------------------------------------- */ +DOH *DohGetfile(const DOH *ho) { + DohBase *h = (DohBase *) ho; + DohObjInfo *objinfo; + if (!h) + return 0; + objinfo = h->type; + if (objinfo->doh_getfile) + return (objinfo->doh_getfile) (h); + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohSetLine() + * ----------------------------------------------------------------------------- */ +void DohSetline(DOH *ho, int l) { + DohBase *h = (DohBase *) ho; + DohObjInfo *objinfo; + if (!h) + return; + objinfo = h->type; + if (objinfo->doh_setline) + (objinfo->doh_setline) (h, l); +} + +/* ----------------------------------------------------------------------------- + * DohGetLine() + * ----------------------------------------------------------------------------- */ +int DohGetline(const DOH *ho) { + DohBase *h = (DohBase *) ho; + DohObjInfo *objinfo; + if (!h) + return 0; + objinfo = h->type; + if (objinfo->doh_getline) + return (objinfo->doh_getline) (h); + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohGetmeta() + * ----------------------------------------------------------------------------- */ + +DOH *DohGetmeta(DOH *ho, const DOH *name) { + DohBase *h = (DohBase *) ho; + if (!DohCheck(ho)) + return 0; + if (!h->meta) + return 0; + return DohGetattr(h->meta, name); +} + +/* ----------------------------------------------------------------------------- + * DohGetmeta() + * ----------------------------------------------------------------------------- */ + +int DohSetmeta(DOH *ho, const DOH *name, const DOH *value) { + DohBase *h = (DohBase *) ho; + if (!DohCheck(ho)) + return 0; + if (!h->meta) + h->meta = NewHash(); + return DohSetattr(h->meta, name, value); +} + +/* ----------------------------------------------------------------------------- + * DohDelmeta() + * ----------------------------------------------------------------------------- */ + +int DohDelmeta(DOH *ho, const DOH *name) { + DohBase *h = (DohBase *) ho; + if (!DohCheck(ho)) + return 0; + if (!h->meta) + return 0; + return DohDelattr(h->meta, name); +} + +/* ----------------------------------------------------------------------------- + * DohSetmark() + * ----------------------------------------------------------------------------- */ + +void DohSetmark(DOH *ho, int x) { + DohBase *h = (DohBase *) ho; + h->flag_usermark = x; +} + +int DohGetmark(DOH *ho) { + DohBase *h = (DohBase *) ho; + return h->flag_usermark; +} + +/* ----------------------------------------------------------------------------- + * DohCall() + * + * Invokes a function via DOH. A Function is represented by a hash table with + * the following attributes: + * + * "builtin" - Pointer to built-in function (if any) + * + * (Additional attributes may be added later) + * + * Returns a DOH object with result on success. Returns NULL on error + * ----------------------------------------------------------------------------- */ + +DOH *DohCall(DOH *func, DOH *args) { + DOH *result; + DOH *(*builtin) (DOH *); + + builtin = (DOH *(*)(DOH *)) GetVoid(func, "builtin"); + if (!builtin) + return 0; + result = (*builtin) (args); + return result; +} diff --git a/Source/DOH/doh.h b/Source/DOH/doh.h new file mode 100644 index 0000000..b731e95 --- /dev/null +++ b/Source/DOH/doh.h @@ -0,0 +1,442 @@ +/* ----------------------------------------------------------------------------- + * doh.h + * + * This file describes of the externally visible functions in DOH. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * + * $Id: doh.h 11097 2009-01-30 10:27:37Z bhy $ + * ----------------------------------------------------------------------------- */ + +#ifndef _DOH_H +#define _DOH_H + +#ifndef MACSWIG +#include "swigconfig.h" +#endif + +#include <stdio.h> +#include <stdarg.h> + +/* Set the namespace prefix for DOH API functions. This can be used to control + visibility of the functions in libraries */ + +/* Set this macro if you want to change DOH linkage. You would do this if you + wanted to hide DOH in a library using a different set of names. Note: simply + change "Doh" to a new name. */ + +/* +#define DOH_NAMESPACE(x) Doh ## x +*/ + +#ifdef DOH_NAMESPACE + +/* Namespace control. These macros define all of the public API names in DOH */ + +#define DohCheck DOH_NAMESPACE(Check) +#define DohIntern DOH_NAMESPACE(Intern) +#define DohDelete DOH_NAMESPACE(Delete) +#define DohCopy DOH_NAMESPACE(Copy) +#define DohClear DOH_NAMESPACE(Clear) +#define DohStr DOH_NAMESPACE(Str) +#define DohData DOH_NAMESPACE(Data) +#define DohDump DOH_NAMESPACE(Dump) +#define DohLen DOH_NAMESPACE(Len) +#define DohHashval DOH_NAMESPACE(Hashval) +#define DohCmp DOH_NAMESPACE(Cmp) +#define DohEqual DOH_NAMESPACE(Equal) +#define DohIncref DOH_NAMESPACE(Incref) +#define DohCheckattr DOH_NAMESPACE(Checkattr) +#define DohSetattr DOH_NAMESPACE(Setattr) +#define DohDelattr DOH_NAMESPACE(Delattr) +#define DohKeys DOH_NAMESPACE(Keys) +#define DohGetInt DOH_NAMESPACE(GetInt) +#define DohGetDouble DOH_NAMESPACE(GetDouble) +#define DohGetChar DOH_NAMESPACE(GetChar) +#define DohSetChar DOH_NAMESPACE(SetChar) +#define DohSetInt DOH_NAMESPACE(SetInt) +#define DohSetDouble DOH_NAMESPACE(SetDouble) +#define DohSetVoid DOH_NAMESPACE(SetVoid) +#define DohGetVoid DOH_NAMESPACE(GetVoid) +#define DohGetitem DOH_NAMESPACE(Getitem) +#define DohSetitem DOH_NAMESPACE(Setitem) +#define DohDelitem DOH_NAMESPACE(Delitem) +#define DohInsertitem DOH_NAMESPACE(Insertitem) +#define DohDelslice DOH_NAMESPACE(Delslice) +#define DohWrite DOH_NAMESPACE(Write) +#define DohRead DOH_NAMESPACE(Read) +#define DohSeek DOH_NAMESPACE(Seek) +#define DohTell DOH_NAMESPACE(Tell) +#define DohGetc DOH_NAMESPACE(Getc) +#define DohPutc DOH_NAMESPACE(Putc) +#define DohUngetc DOH_NAMESPACE(Ungetc) +#define DohGetline DOH_NAMESPACE(Getline) +#define DohSetline DOH_NAMESPACE(Setline) +#define DohGetfile DOH_NAMESPACE(Getfile) +#define DohSetfile DOH_NAMESPACE(Setfile) +#define DohReplace DOH_NAMESPACE(Replace) +#define DohChop DOH_NAMESPACE(Chop) +#define DohGetmeta DOH_NAMESPACE(Getmeta) +#define DohSetmeta DOH_NAMESPACE(Setmeta) +#define DohDelmeta DOH_NAMESPACE(Delmeta) +#define DohEncoding DOH_NAMESPACE(Encoding) +#define DohPrintf DOH_NAMESPACE(Printf) +#define DohvPrintf DOH_NAMESPACE(vPrintf) +#define DohPrintv DOH_NAMESPACE(Printv) +#define DohReadline DOH_NAMESPACE(Readline) +#define DohIsMapping DOH_NAMESPACE(IsMapping) +#define DohIsSequence DOH_NAMESPACE(IsSequence) +#define DohIsString DOH_NAMESPACE(IsString) +#define DohIsFile DOH_NAMESPACE(IsFile) +#define DohNewString DOH_NAMESPACE(NewString) +#define DohNewStringEmpty DOH_NAMESPACE(NewStringEmpty) +#define DohNewStringWithSize DOH_NAMESPACE(NewStringWithSize) +#define DohNewStringf DOH_NAMESPACE(NewStringf) +#define DohStrcmp DOH_NAMESPACE(Strcmp) +#define DohStrncmp DOH_NAMESPACE(Strncmp) +#define DohStrstr DOH_NAMESPACE(Strstr) +#define DohStrchr DOH_NAMESPACE(Strchr) +#define DohNewFile DOH_NAMESPACE(NewFile) +#define DohNewFileFromFile DOH_NAMESPACE(NewFileFromFile) +#define DohNewFileFromFd DOH_NAMESPACE(NewFileFromFd) +#define DohFileErrorDisplay DOH_NAMESPACE(FileErrorDisplay) +#define DohClose DOH_NAMESPACE(Close) +#define DohCopyto DOH_NAMESPACE(Copyto) +#define DohNewList DOH_NAMESPACE(NewList) +#define DohNewHash DOH_NAMESPACE(NewHash) +#define DohNewVoid DOH_NAMESPACE(NewVoid) +#define DohSplit DOH_NAMESPACE(Split) +#define DohSplitLines DOH_NAMESPACE(SplitLines) +#define DohNone DOH_NAMESPACE(None) +#define DohCall DOH_NAMESPACE(Call) +#define DohObjMalloc DOH_NAMESPACE(ObjMalloc) +#define DohObjFree DOH_NAMESPACE(ObjFree) +#define DohMemoryDebug DOH_NAMESPACE(MemoryDebug) +#define DohStringType DOH_NAMESPACE(StringType) +#define DohListType DOH_NAMESPACE(ListType) +#define DohHashType DOH_NAMESPACE(HashType) +#define DohFileType DOH_NAMESPACE(FileType) +#define DohVoidType DOH_NAMESPACE(VoidType) +#define DohIterator DOH_NAMESPACE(Iterator) +#define DohFirst DOH_NAMESPACE(First) +#define DohNext DOH_NAMESPACE(Next) +#endif + +#define DOH_MAJOR_VERSION 0 +#define DOH_MINOR_VERSION 1 + +typedef void DOH; + +/* + * With dynamic typing, all DOH objects are technically of type 'void *'. + * However, to clarify the reading of source code, the following symbolic + * names are used. + */ + +#define DOHString DOH +#define DOHList DOH +#define DOHHash DOH +#define DOHFile DOH +#define DOHVoid DOH +#define DOHString_or_char DOH +#define DOHObj_or_char DOH + +typedef const DOHString_or_char * const_String_or_char_ptr; +typedef const DOHString_or_char * DOHconst_String_or_char_ptr; + +#define DOH_BEGIN -1 +#define DOH_END -2 +#define DOH_CUR -3 +#define DOH_CURRENT -3 + +/* Iterator objects */ + +typedef struct { + void *key; /* Current key (if any) */ + void *item; /* Current item */ + void *object; /* Object being iterated over */ + void *_current; /* Internal use */ + int _index; /* Internal use */ +} DohIterator; + +/* Memory management */ + +#ifndef DohMalloc +#define DohMalloc malloc +#endif +#ifndef DohRealloc +#define DohRealloc realloc +#endif +#ifndef DohFree +#define DohFree free +#endif + +extern int DohCheck(const DOH *ptr); /* Check if a DOH object */ +extern void DohIntern(DOH *); /* Intern an object */ + +/* Basic object methods. Common to most objects */ + +extern void DohDelete(DOH *obj); /* Delete an object */ +extern DOH *DohCopy(const DOH *obj); +extern void DohClear(DOH *obj); +extern DOHString *DohStr(const DOH *obj); +extern void *DohData(const DOH *obj); +extern int DohDump(const DOH *obj, DOHFile * out); +extern int DohLen(const DOH *obj); +extern int DohHashval(const DOH *obj); +extern int DohCmp(const DOH *obj1, const DOH *obj2); +extern int DohEqual(const DOH *obj1, const DOH *obj2); +extern void DohIncref(DOH *obj); + +/* Mapping methods */ + +extern DOH *DohGetattr(DOH *obj, const DOHString_or_char *name); +extern int DohSetattr(DOH *obj, const DOHString_or_char *name, const DOHObj_or_char * value); +extern int DohDelattr(DOH *obj, const DOHString_or_char *name); +extern int DohCheckattr(DOH *obj, const DOHString_or_char *name, const DOHString_or_char *value); +extern DOH *DohKeys(DOH *obj); +extern int DohGetInt(DOH *obj, const DOHString_or_char *name); +extern void DohSetInt(DOH *obj, const DOHString_or_char *name, int); +extern double DohGetDouble(DOH *obj, const DOHString_or_char *name); +extern void DohSetDouble(DOH *obj, const DOHString_or_char *name, double); +extern char *DohGetChar(DOH *obj, const DOHString_or_char *name); +extern void DohSetChar(DOH *obj, const DOH *name, char *value); +extern void *DohGetFlagAttr(DOH *obj, const DOHString_or_char *name); +extern int DohGetFlag(DOH *obj, const DOHString_or_char *name); +extern void DohSetFlagAttr(DOH *obj, const DOHString_or_char *name, const DOHString_or_char *attr); +extern void DohSetFlag(DOH *obj, const DOHString_or_char *name); +extern void *DohGetVoid(DOH *obj, const DOHString_or_char *name); +extern void DohSetVoid(DOH *obj, const DOHString_or_char *name, void *value); + +/* Sequence methods */ + +extern DOH *DohGetitem(DOH *obj, int index); +extern int DohSetitem(DOH *obj, int index, const DOHObj_or_char * value); +extern int DohDelitem(DOH *obj, int index); +extern int DohInsertitem(DOH *obj, int index, const DOHObj_or_char * value); +extern int DohDelslice(DOH *obj, int sindex, int eindex); + +/* File methods */ + +extern int DohWrite(DOHFile * obj, void *buffer, int length); +extern int DohRead(DOHFile * obj, void *buffer, int length); +extern int DohSeek(DOHFile * obj, long offset, int whence); +extern long DohTell(DOHFile * obj); +extern int DohGetc(DOHFile * obj); +extern int DohPutc(int ch, DOHFile * obj); +extern int DohUngetc(int ch, DOHFile * obj); + + + +/* Iterators */ +extern DohIterator DohFirst(DOH *obj); +extern DohIterator DohNext(DohIterator x); + +/* Positional */ + +extern int DohGetline(const DOH *obj); +extern void DohSetline(DOH *obj, int line); +extern DOH *DohGetfile(const DOH *obj); +extern void DohSetfile(DOH *obj, DOH *file); + + /* String Methods */ + +extern int DohReplace(DOHString * src, const DOHString_or_char *token, const DOHString_or_char *rep, int flags); +extern void DohChop(DOHString * src); + +/* Meta-variables */ +extern DOH *DohGetmeta(DOH *, const DOH *); +extern int DohSetmeta(DOH *, const DOH *, const DOH *value); +extern int DohDelmeta(DOH *, const DOH *); + + /* Utility functions */ + +extern void DohEncoding(char *name, DOH *(*fn) (DOH *s)); +extern int DohPrintf(DOHFile * obj, const char *format, ...); +extern int DohvPrintf(DOHFile * obj, const char *format, va_list ap); +extern int DohPrintv(DOHFile * obj, ...); +extern DOH *DohReadline(DOHFile * in); + + /* Miscellaneous */ + +extern int DohIsMapping(const DOH *obj); +extern int DohIsSequence(const DOH *obj); +extern int DohIsString(const DOH *obj); +extern int DohIsFile(const DOH *obj); + +extern void DohSetmark(DOH *obj, int x); +extern int DohGetmark(DOH *obj); + +/* ----------------------------------------------------------------------------- + * Strings. + * ----------------------------------------------------------------------------- */ + +extern DOHString *DohNewStringEmpty(void); +extern DOHString *DohNewString(const DOH *c); +extern DOHString *DohNewStringWithSize(const DOH *c, int len); +extern DOHString *DohNewStringf(const DOH *fmt, ...); + +extern int DohStrcmp(const DOHString_or_char *s1, const DOHString_or_char *s2); +extern int DohStrncmp(const DOHString_or_char *s1, const DOHString_or_char *s2, int n); +extern char *DohStrstr(const DOHString_or_char *s1, const DOHString_or_char *s2); +extern char *DohStrchr(const DOHString_or_char *s1, int ch); + +/* String replacement flags */ + +#define DOH_REPLACE_ANY 0x01 +#define DOH_REPLACE_NOQUOTE 0x02 +#define DOH_REPLACE_ID 0x04 +#define DOH_REPLACE_FIRST 0x08 +#define DOH_REPLACE_ID_BEGIN 0x10 +#define DOH_REPLACE_ID_END 0x20 + +#define Replaceall(s,t,r) DohReplace(s,t,r,DOH_REPLACE_ANY) +#define Replaceid(s,t,r) DohReplace(s,t,r,DOH_REPLACE_ID) + +/* ----------------------------------------------------------------------------- + * Files + * ----------------------------------------------------------------------------- */ + +extern DOHFile *DohNewFile(DOH *filename, const char *mode, DOHList *outfiles); +extern DOHFile *DohNewFileFromFile(FILE *f); +extern DOHFile *DohNewFileFromFd(int fd); +extern void DohFileErrorDisplay(DOHString * filename); +extern int DohClose(DOH *file); +extern int DohCopyto(DOHFile * input, DOHFile * output); + + +/* ----------------------------------------------------------------------------- + * List + * ----------------------------------------------------------------------------- */ + +extern DOHList *DohNewList(void); +extern void DohSortList(DOH *lo, int (*cmp) (const DOH *, const DOH *)); + +/* ----------------------------------------------------------------------------- + * Hash + * ----------------------------------------------------------------------------- */ + +extern DOHHash *DohNewHash(void); + +/* ----------------------------------------------------------------------------- + * Void + * ----------------------------------------------------------------------------- */ + +extern DOHVoid *DohNewVoid(void *ptr, void (*del) (void *)); +extern DOHList *DohSplit(DOHFile * input, char ch, int nsplits); +extern DOHList *DohSplitLines(DOHFile * input); +extern DOH *DohNone; + +extern void DohMemoryDebug(void); + +#ifndef DOH_LONG_NAMES +/* Macros to invoke the above functions. Includes the location of + the caller to simplify debugging if something goes wrong */ + +#define Delete DohDelete +#define Copy DohCopy +#define Clear DohClear +#define Str DohStr +#define Dump DohDump +#define Getattr DohGetattr +#define Setattr DohSetattr +#define Delattr DohDelattr +#define Checkattr DohCheckattr +#define Hashval DohHashval +#define Getitem DohGetitem +#define Setitem DohSetitem +#define Delitem DohDelitem +#define Insert DohInsertitem +#define Delslice DohDelslice +#define Append(s,x) DohInsertitem(s,DOH_END,x) +#define Push(s,x) DohInsertitem(s,DOH_BEGIN,x) +#define Len DohLen +#define Data DohData +#define Char (char *) Data +#define Cmp DohCmp +#define Equal DohEqual +#define Setline DohSetline +#define Getline DohGetline +#define Setfile DohSetfile +#define Getfile DohGetfile +#define Write DohWrite +#define Read DohRead +#define Seek DohSeek +#define Tell DohTell +#define Printf DohPrintf +#define Printv DohPrintv +#define Getc DohGetc +#define Putc DohPutc +#define Ungetc DohUngetc + +/* #define StringPutc DohStringPutc */ +/* #define StringGetc DohStringGetc */ +/* #define StringUngetc DohStringUngetc */ +/* #define StringAppend Append */ +/* #define StringLen DohStringLen */ +/* #define StringChar DohStringChar */ +/* #define StringEqual DohStringEqual */ + +#define Close DohClose +#define vPrintf DohvPrintf +#define GetInt DohGetInt +#define GetDouble DohGetDouble +#define GetChar DohGetChar +#define GetVoid DohGetVoid +#define GetFlagAttr DohGetFlagAttr +#define GetFlag DohGetFlag +#define SetInt DohSetInt +#define SetDouble DohSetDouble +#define SetChar DohSetattr +#define SetVoid DohSetVoid +#define SetFlagAttr DohSetFlagAttr +#define SetFlag DohSetFlag +#define UnsetFlag(o,n) DohSetFlagAttr(o,n,NULL) +#define ClearFlag(o,n) DohSetFlagAttr(o,n,"") +#define Readline DohReadline +#define Replace DohReplace +#define Chop DohChop +#define Getmeta DohGetmeta +#define Setmeta DohSetmeta +#define Delmeta DohDelmeta +#define NewString DohNewString +#define NewStringEmpty DohNewStringEmpty +#define NewStringWithSize DohNewStringWithSize +#define NewStringf DohNewStringf +#define NewHash DohNewHash +#define NewList DohNewList +#define NewFile DohNewFile +#define NewFileFromFile DohNewFileFromFile +#define NewFileFromFd DohNewFileFromFd +#define FileErrorDisplay DohFileErrorDisplay +#define Close DohClose +#define NewVoid DohNewVoid +#define Keys DohKeys +#define Strcmp DohStrcmp +#define Strncmp DohStrncmp +#define Strstr DohStrstr +#define Strchr DohStrchr +#define Copyto DohCopyto +#define Split DohSplit +#define SplitLines DohSplitLines +#define Setmark DohSetmark +#define Getmark DohGetmark +#define None DohNone +#define Call DohCall +#define First DohFirst +#define Next DohNext +#define Iterator DohIterator +#define SortList DohSortList +#endif + +#ifdef NIL +#undef NIL +#endif + +#define NIL (char *) NULL + + +#endif /* DOH_H */ diff --git a/Source/DOH/dohint.h b/Source/DOH/dohint.h new file mode 100644 index 0000000..8f52d28 --- /dev/null +++ b/Source/DOH/dohint.h @@ -0,0 +1,133 @@ + +/* ----------------------------------------------------------------------------- + * dohint.h + * + * This file describes internally managed objects. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * + * $Id: dohint.h 9607 2006-12-05 22:11:40Z beazley $ + * ----------------------------------------------------------------------------- */ + +#ifndef _DOHINT_H +#define _DOHINT_H + +#include "doh.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> + +/* Hash objects */ +typedef struct { + DOH *(*doh_getattr) (DOH *obj, DOH *name); /* Get attribute */ + int (*doh_setattr) (DOH *obj, DOH *name, DOH *value); /* Set attribute */ + int (*doh_delattr) (DOH *obj, DOH *name); /* Del attribute */ + DOH *(*doh_keys) (DOH *obj); /* All keys as a list */ +} DohHashMethods; + +/* List objects */ +typedef struct { + DOH *(*doh_getitem) (DOH *obj, int index); /* Get item */ + int (*doh_setitem) (DOH *obj, int index, DOH *value); /* Set item */ + int (*doh_delitem) (DOH *obj, int index); /* Delete item */ + int (*doh_insitem) (DOH *obj, int index, DOH *value); /* Insert item */ + int (*doh_delslice) (DOH *obj, int sindex, int eindex); /* Delete slice */ +} DohListMethods; + +/* File methods */ +typedef struct { + int (*doh_read) (DOH *obj, void *buffer, int nbytes); /* Read bytes */ + int (*doh_write) (DOH *obj, void *buffer, int nbytes); /* Write bytes */ + int (*doh_putc) (DOH *obj, int ch); /* Put character */ + int (*doh_getc) (DOH *obj); /* Get character */ + int (*doh_ungetc) (DOH *obj, int ch); /* Unget character */ + int (*doh_seek) (DOH *obj, long offset, int whence); /* Seek */ + long (*doh_tell) (DOH *obj); /* Tell */ + int (*doh_close) (DOH *obj); /* Close */ +} DohFileMethods; + +/* String methods */ +typedef struct { + int (*doh_replace) (DOH *obj, DOH *old, DOH *rep, int flags); + void (*doh_chop) (DOH *obj); +} DohStringMethods; + +/* ----------------------------------------------------------------------------- + * DohObjInfo + * ----------------------------------------------------------------------------- */ + +typedef struct DohObjInfo { + char *objname; /* Object name */ + + /* Basic object methods */ + void (*doh_del) (DOH *obj); /* Delete object */ + DOH *(*doh_copy) (DOH *obj); /* Copy and object */ + void (*doh_clear) (DOH *obj); /* Clear an object */ + + /* I/O methods */ + DOH *(*doh_str) (DOH *obj); /* Make a full string */ + void *(*doh_data) (DOH *obj); /* Return raw data */ + int (*doh_dump) (DOH *obj, DOH *out); /* Serialize on out */ + + /* Length and hash values */ + int (*doh_len) (DOH *obj); + int (*doh_hashval) (DOH *obj); + + /* Compare */ + int (*doh_cmp) (DOH *obj1, DOH *obj2); + + /* Equal */ + int (*doh_equal) (DOH *obj1, DOH *obj2); + + /* Iterators */ + DohIterator (*doh_first) (DOH *obj); + DohIterator (*doh_next) (DohIterator); + + /* Positional */ + void (*doh_setfile) (DOH *obj, DOHString_or_char *file); + DOH *(*doh_getfile) (DOH *obj); + void (*doh_setline) (DOH *obj, int line); + int (*doh_getline) (DOH *obj); + + DohHashMethods *doh_hash; /* Hash methods */ + DohListMethods *doh_list; /* List methods */ + DohFileMethods *doh_file; /* File methods */ + DohStringMethods *doh_string; /* String methods */ + void *doh_reserved; /* Reserved */ + void *clientdata; /* User data */ +} DohObjInfo; + +typedef struct { + void *data; /* Data pointer */ + DohObjInfo *type; + void *meta; /* Meta data */ + unsigned int flag_intern:1; /* Interned object */ + unsigned int flag_marked:1; /* Mark flag. Used to avoid recursive loops in places */ + unsigned int flag_user:1; /* User flag */ + unsigned int flag_usermark:1; /* User marked */ + unsigned int refcount:28; /* Reference count (max 16 million) */ +} DohBase; + +/* Macros for decrefing and increfing (safe for null objects). */ + +#define Decref(a) if (a) ((DohBase *) a)->refcount-- +#define Incref(a) if (a) ((DohBase *) a)->refcount++ +#define Refcount(a) ((DohBase *) a)->refcount + +/* Macros for manipulating objects in a safe manner */ +#define ObjData(a) ((DohBase *)a)->data +#define ObjSetMark(a,x) ((DohBase *)a)->flag_marked = x +#define ObjGetMark(a) ((DohBase *)a)->flag_marked +#define ObjType(a) ((DohBase *)a)->type + +extern DOH *DohObjMalloc(DohObjInfo *type, void *data); /* Allocate a DOH object */ +extern void DohObjFree(DOH *ptr); /* Free a DOH object */ + +#endif /* DOHINT_H */ diff --git a/Source/DOH/file.c b/Source/DOH/file.c new file mode 100644 index 0000000..2384850 --- /dev/null +++ b/Source/DOH/file.c @@ -0,0 +1,299 @@ +/* ----------------------------------------------------------------------------- + * file.c + * + * This file implements a file-like object that can be built around an + * ordinary FILE * or integer file descriptor. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_file_c[] = "$Id: file.c 10898 2008-11-03 12:51:45Z wsfulton $"; + +#include "dohint.h" + +#ifdef DOH_INTFILE +#include <unistd.h> +#endif +#include <errno.h> + +typedef struct { + FILE *filep; + int fd; + int closeondel; +} DohFile; + +/* ----------------------------------------------------------------------------- + * DelFile() + * ----------------------------------------------------------------------------- */ + +static void DelFile(DOH *fo) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->closeondel) { + if (f->filep) { + fclose(f->filep); + } +#ifdef DOH_INTFILE + if (f->fd) { + close(f->fd); + } +#endif + } + DohFree(f); +} + +/* ----------------------------------------------------------------------------- + * File_read() + * ----------------------------------------------------------------------------- */ + +static int File_read(DOH *fo, void *buffer, int len) { + DohFile *f = (DohFile *) ObjData(fo); + + if (f->filep) { + return fread(buffer, 1, len, f->filep); + } else if (f->fd) { +#ifdef DOH_INTFILE + return read(f->fd, buffer, len); +#endif + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * File_write() + * ----------------------------------------------------------------------------- */ + +static int File_write(DOH *fo, void *buffer, int len) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + int ret = (int) fwrite(buffer, 1, len, f->filep); + int err = (ret != len) ? ferror(f->filep) : 0; + return err ? -1 : ret; + } else if (f->fd) { +#ifdef DOH_INTFILE + return write(f->fd, buffer, len); +#endif + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * File_seek() + * ----------------------------------------------------------------------------- */ + +static int File_seek(DOH *fo, long offset, int whence) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + return fseek(f->filep, offset, whence); + } else if (f->fd) { +#ifdef DOH_INTFILE + return lseek(f->fd, offset, whence); +#endif + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * File_tell() + * ----------------------------------------------------------------------------- */ + +static long File_tell(DOH *fo) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + return ftell(f->filep); + } else if (f->fd) { +#ifdef DOH_INTFILE + return lseek(f->fd, 0, SEEK_CUR); +#endif + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * File_putc() + * ----------------------------------------------------------------------------- */ + +static int File_putc(DOH *fo, int ch) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + return fputc(ch, f->filep); + } else if (f->fd) { +#ifdef DOH_INTFILE + char c; + c = (char) ch; + return write(f->fd, &c, 1); +#endif + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * File_getc() + * ----------------------------------------------------------------------------- */ + +static int File_getc(DOH *fo) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + return fgetc(f->filep); + } else if (f->fd) { +#ifdef DOH_INTFILE + unsigned char c; + if (read(f->fd, &c, 1) < 0) + return EOF; + return c; +#endif + } + return EOF; +} + +/* ----------------------------------------------------------------------------- + * File_ungetc() + * + * Put a character back onto the input + * ----------------------------------------------------------------------------- */ + +static int File_ungetc(DOH *fo, int ch) { + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + return ungetc(ch, f->filep); + } else if (f->fd) { +#ifdef DOH_INTFILE + /* Not implemented yet */ +#endif + } + return -1; +} + +/* ----------------------------------------------------------------------------- + * File_close() + * + * Close the file + * ----------------------------------------------------------------------------- */ + +static int File_close(DOH *fo) { + int ret = 0; + DohFile *f = (DohFile *) ObjData(fo); + if (f->filep) { + ret = fclose(f->filep); + f->filep = 0; + } else if (f->fd) { +#ifdef DOH_INTFILE + ret = close(f->fd); + f->fd = 0; +#endif + } + return ret; +} + +static DohFileMethods FileFileMethods = { + File_read, + File_write, + File_putc, + File_getc, + File_ungetc, + File_seek, + File_tell, + File_close, /* close */ +}; + +static DohObjInfo DohFileType = { + "DohFile", /* objname */ + DelFile, /* doh_del */ + 0, /* doh_copy */ + 0, /* doh_clear */ + 0, /* doh_str */ + 0, /* doh_data */ + 0, /* doh_dump */ + 0, /* doh_len */ + 0, /* doh_hash */ + 0, /* doh_cmp */ + 0, /* doh_equal */ + 0, /* doh_first */ + 0, /* doh_next */ + 0, /* doh_setfile */ + 0, /* doh_getfile */ + 0, /* doh_setline */ + 0, /* doh_getline */ + 0, /* doh_mapping */ + 0, /* doh_sequence */ + &FileFileMethods, /* doh_file */ + 0, /* doh_string */ + 0, /* doh_callable */ + 0, /* doh_position */ +}; + +/* ----------------------------------------------------------------------------- + * NewFile() + * + * Create a new file from a given filename and mode. + * If newfiles is non-zero, the filename is added to the list of new files. + * ----------------------------------------------------------------------------- */ + +DOH *DohNewFile(DOH *filename, const char *mode, DOHList *newfiles) { + DohFile *f; + FILE *file; + char *filen; + + filen = Char(filename); + file = fopen(filen, mode); + if (!file) + return 0; + + f = (DohFile *) DohMalloc(sizeof(DohFile)); + if (!f) { + fclose(file); + return 0; + } + if (newfiles) + Append(newfiles, filename); + f->filep = file; + f->fd = 0; + f->closeondel = 1; + return DohObjMalloc(&DohFileType, f); +} + +/* ----------------------------------------------------------------------------- + * NewFileFromFile() + * + * Create a file object from an already open FILE *. + * ----------------------------------------------------------------------------- */ + +DOH *DohNewFileFromFile(FILE *file) { + DohFile *f; + f = (DohFile *) DohMalloc(sizeof(DohFile)); + if (!f) + return 0; + f->filep = file; + f->fd = 0; + f->closeondel = 0; + return DohObjMalloc(&DohFileType, f); +} + +/* ----------------------------------------------------------------------------- + * NewFileFromFd() + * + * Create a file object from an already open FILE *. + * ----------------------------------------------------------------------------- */ + +DOH *DohNewFileFromFd(int fd) { + DohFile *f; + f = (DohFile *) DohMalloc(sizeof(DohFile)); + if (!f) + return 0; + f->filep = 0; + f->fd = fd; + f->closeondel = 0; + return DohObjMalloc(&DohFileType, f); +} + +/* ----------------------------------------------------------------------------- + * FileErrorDisplay() + * + * Display cause of one of the NewFile functions failing. + * ----------------------------------------------------------------------------- */ + +void DohFileErrorDisplay(DOHString * filename) { + Printf(stderr, "Unable to open file %s: %s\n", filename, strerror(errno)); +} diff --git a/Source/DOH/fio.c b/Source/DOH/fio.c new file mode 100644 index 0000000..7f3eb8b --- /dev/null +++ b/Source/DOH/fio.c @@ -0,0 +1,589 @@ +/* ----------------------------------------------------------------------------- + * fio.c + * + * This file implements a number of standard I/O operations included + * formatted output, readline, and splitting. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_fio_c[] = "$Id: fio.c 9607 2006-12-05 22:11:40Z beazley $"; + +#include "dohint.h" + +#define OBUFLEN 512 + +static DOH *encodings = 0; /* Encoding hash */ + +/* ----------------------------------------------------------------------------- + * Writen() + * + * Write's N characters of output and retries until all characters are + * written. This is useful should a write operation encounter a spurious signal. + * ----------------------------------------------------------------------------- */ + +static int Writen(DOH *out, void *buffer, int len) { + int nw = len, ret; + char *cb = (char *) buffer; + while (nw) { + ret = Write(out, cb, nw); + if (ret < 0) + return -1; + nw = nw - ret; + cb += ret; + } + return len; +} + +/* ----------------------------------------------------------------------------- + * DohEncoding() + * + * Registers a new printf encoding method. An encoder function should accept + * two file-like objects and operate as a filter. + * ----------------------------------------------------------------------------- */ + +void DohEncoding(char *name, DOH *(*fn) (DOH *s)) { + if (!encodings) + encodings = NewHash(); + Setattr(encodings, (void *) name, NewVoid((void *) fn, 0)); +} + +/* internal function for processing an encoding */ +static DOH *encode(char *name, DOH *s) { + DOH *handle, *ns; + DOH *(*fn) (DOH *); + long pos; + char *cfmt = strchr(name, ':'); + DOH *tmp = 0; + if (cfmt) { + tmp = NewString(cfmt + 1); + Append(tmp, s); + Setfile(tmp, Getfile((DOH *) s)); + Setline(tmp, Getline((DOH *) s)); + *cfmt = '\0'; + } + if (!encodings || !(handle = Getattr(encodings, name))) { + return Copy(s); + } + if (tmp) + s = tmp; + pos = Tell(s); + Seek(s, 0, SEEK_SET); + fn = (DOH *(*)(DOH *)) Data(handle); + ns = (*fn) (s); + Seek(s, pos, SEEK_SET); + if (tmp) + Delete(tmp); + return ns; +} + +/* ----------------------------------------------------------------------------- + * DohvPrintf() + * + * DOH implementation of printf. Output can be directed to any file-like object + * including bare FILE * objects. The same formatting codes as printf are + * recognized with two extensions: + * + * %s - Prints a "char *" or the string representation of any + * DOH object. This will implicitly result in a call to + * Str(obj). + * + * %(encoder)* - Filters the output through an encoding function registered + * with DohEncoder(). + * + * Note: This function is not particularly memory efficient with large strings. + * It's better to use Dump() or some other method instead. + * ----------------------------------------------------------------------------- */ + +int DohvPrintf(DOH *so, const char *format, va_list ap) { + static char *fmt_codes = "dioxXucsSfeEgGpn"; + int state = 0; + const char *p = format; + char newformat[256]; + char obuffer[OBUFLEN]; + char *fmt = 0; + char temp[64]; + int widthval = 0; + int precval = 0; + int maxwidth; + char *w = 0; + int ivalue; + double dvalue; + void *pvalue; + char *stemp; + int nbytes = 0; + char encoder[128], *ec = 0; + int plevel = 0; + + memset(newformat, 0, sizeof(newformat)); + + while (*p) { + switch (state) { + case 0: /* Ordinary text */ + if (*p != '%') { + Putc(*p, so); + nbytes++; + } else { + fmt = newformat; + widthval = 0; + precval = 0; + *(fmt++) = *p; + encoder[0] = 0; + state = 10; + } + break; + case 10: /* Look for a width and precision */ + if (isdigit((int) *p) && (*p != '0')) { + w = temp; + *(w++) = *p; + *(fmt++) = *p; + state = 20; + } else if (strchr(fmt_codes, *p)) { + /* Got one of the formatting codes */ + p--; + state = 100; + } else if (*p == '*') { + /* Width field is specified in the format list */ + widthval = va_arg(ap, int); + sprintf(temp, "%d", widthval); + for (w = temp; *w; w++) { + *(fmt++) = *w; + } + state = 30; + } else if (*p == '%') { + Putc(*p, so); + fmt = newformat; + nbytes++; + state = 0; + } else if (*p == '(') { + ++plevel; + ec = encoder; + state = 60; + } else { + *(fmt++) = *p; + } + break; + + case 20: /* Hmmm. At the start of a width field */ + if (isdigit((int) *p)) { + *(w++) = *p; + *(fmt++) = *p; + } else if (strchr(fmt_codes, *p)) { + /* Got one of the formatting codes */ + /* Figure out width */ + *w = 0; + widthval = atoi(temp); + p--; + state = 100; + } else if (*p == '.') { + *w = 0; + widthval = atoi(temp); + w = temp; + *(fmt++) = *p; + state = 40; + } else { + /* ??? */ + *w = 0; + widthval = atoi(temp); + state = 50; + } + break; + + case 30: /* Parsed a width from an argument. Look for a . */ + if (*p == '.') { + w = temp; + *(fmt++) = *p; + state = 40; + } else if (strchr(fmt_codes, *p)) { + /* Got one of the formatting codes */ + /* Figure out width */ + p--; + state = 100; + } else { + /* hmmm. Something else. */ + state = 50; + } + break; + + case 40: + /* Start of precision expected */ + if (isdigit((int) *p) && (*p != '0')) { + *(fmt++) = *p; + *(w++) = *p; + state = 41; + } else if (*p == '*') { + /* Precision field is specified in the format list */ + precval = va_arg(ap, int); + sprintf(temp, "%d", precval); + for (w = temp; *w; w++) { + *(fmt++) = *w; + } + state = 50; + } else if (strchr(fmt_codes, *p)) { + p--; + state = 100; + } else { + *(fmt++) = *p; + state = 50; + } + break; + case 41: + if (isdigit((int) *p)) { + *(fmt++) = *p; + *(w++) = *p; + } else if (strchr(fmt_codes, *p)) { + /* Got one of the formatting codes */ + /* Figure out width */ + *w = 0; + precval = atoi(temp); + p--; + state = 100; + } else { + *w = 0; + precval = atoi(temp); + *(fmt++) = *p; + state = 50; + } + break; + /* Hang out, wait for format specifier */ + case 50: + if (strchr(fmt_codes, *p)) { + p--; + state = 100; + } else { + *(fmt++) = *p; + } + break; + + /* Got an encoding header */ + case 60: + if (*p == '(') { + ++plevel; + *ec = *p; + ec++; + } else if (*p == ')') { + --plevel; + if (plevel <= 0) { + *ec = 0; + state = 10; + } else { + *ec = *p; + ec++; + } + } else { + *ec = *p; + ec++; + } + break; + case 100: + /* Got a formatting code */ + if (widthval < precval) + maxwidth = precval; + else + maxwidth = widthval; + if ((*p == 's') || (*p == 'S')) { /* Null-Terminated string */ + DOH *doh; + DOH *Sval; + DOH *enc = 0; + doh = va_arg(ap, DOH *); + if (DohCheck(doh)) { + /* Is a DOH object. */ + if (DohIsString(doh)) { + Sval = doh; + } else { + Sval = Str(doh); + } + if (strlen(encoder)) { + enc = encode(encoder, Sval); + maxwidth = maxwidth + strlen(newformat) + Len(enc); + } else { + maxwidth = maxwidth + strlen(newformat) + Len(Sval); + } + *(fmt++) = 's'; + *fmt = 0; + if ((maxwidth + 1) < OBUFLEN) { + stemp = obuffer; + } else { + stemp = (char *) DohMalloc(maxwidth + 1); + } + if (enc) { + nbytes += sprintf(stemp, newformat, Data(enc)); + } else { + nbytes += sprintf(stemp, newformat, Data(Sval)); + } + if (Writen(so, stemp, strlen(stemp)) < 0) + return -1; + if ((DOH *) Sval != doh) { + Delete(Sval); + } + if (enc) + Delete(enc); + if (*p == 'S') { + Delete(doh); + } + if (stemp != obuffer) { + DohFree(stemp); + } + } else { + if (!doh) + doh = (char *) ""; + + if (strlen(encoder)) { + DOH *s = NewString(doh); + Seek(s, 0, SEEK_SET); + enc = encode(encoder, s); + Delete(s); + doh = Char(enc); + } else { + enc = 0; + } + maxwidth = maxwidth + strlen(newformat) + strlen((char *) doh); + *(fmt++) = 's'; + *fmt = 0; + if ((maxwidth + 1) < OBUFLEN) { + stemp = obuffer; + } else { + stemp = (char *) DohMalloc(maxwidth + 1); + } + nbytes += sprintf(stemp, newformat, doh); + if (Writen(so, stemp, strlen(stemp)) < 0) + return -1; + if (stemp != obuffer) { + DohFree(stemp); + } + if (enc) + Delete(enc); + } + } else { + *(fmt++) = *p; + *fmt = 0; + maxwidth = maxwidth + strlen(newformat) + 64; + + /* Only allocate a buffer if it is too big to fit. Shouldn't have to do + this very often */ + + if (maxwidth < OBUFLEN) + stemp = obuffer; + else + stemp = (char *) DohMalloc(maxwidth + 1); + switch (*p) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + ivalue = va_arg(ap, int); + nbytes += sprintf(stemp, newformat, ivalue); + break; + case 'f': + case 'g': + case 'e': + case 'E': + case 'G': + dvalue = va_arg(ap, double); + nbytes += sprintf(stemp, newformat, dvalue); + break; + case 'p': + pvalue = va_arg(ap, void *); + nbytes += sprintf(stemp, newformat, pvalue); + break; + default: + break; + } + if (Writen(so, stemp, strlen(stemp)) < 0) + return -1; + if (stemp != obuffer) + DohFree(stemp); + } + state = 0; + break; + } + p++; + } + if (state) { + int r; + *fmt = 0; + r = Writen(so, fmt, strlen(fmt)); + if (r < 0) + return -1; + nbytes += r; + } + return nbytes; +} + +/* ----------------------------------------------------------------------------- + * DohPrintf() + * + * Variable length argument entry point to Printf + * ----------------------------------------------------------------------------- */ + +int DohPrintf(DOH *obj, const char *format, ...) { + va_list ap; + int ret; + va_start(ap, format); + ret = DohvPrintf(obj, format, ap); + va_end(ap); + return ret; +} + +/* ----------------------------------------------------------------------------- + * DohPrintv() + * + * Print a null-terminated variable length list of DOH objects + * ----------------------------------------------------------------------------- */ + +int DohPrintv(DOHFile * f, ...) { + va_list ap; + int ret = 0; + DOH *obj; + va_start(ap, f); + while (1) { + obj = va_arg(ap, void *); + if ((!obj) || (obj == DohNone)) + break; + if (DohCheck(obj)) { + ret += DohDump(obj, f); + } else { + ret += DohWrite(f, obj, strlen((char *) obj)); + } + } + va_end(ap); + return ret; +} + +/* ----------------------------------------------------------------------------- + * DohCopyto() + * + * Copies all of the input from an input stream to an output stream. Returns the + * number of bytes copied. + * ----------------------------------------------------------------------------- */ + +int DohCopyto(DOH *in, DOH *out) { + int nbytes = 0, ret; + int nwrite = 0, wret; + char *cw; + char buffer[16384]; + + if ((!in) || (!out)) + return 0; + while (1) { + ret = Read(in, buffer, 16384); + if (ret > 0) { + nwrite = ret; + cw = buffer; + while (nwrite) { + wret = Write(out, cw, nwrite); + if (wret < 0) + return -1; + nwrite = nwrite - wret; + cw += wret; + } + nbytes += ret; + } else { + return nbytes; + } + } +} + + +/* ----------------------------------------------------------------------------- + * DohSplit() + * + * Split an input stream into a list of strings delimited by the specified + * character. Optionally accepts a maximum number of splits to perform. + * ----------------------------------------------------------------------------- */ + +DOH *DohSplit(DOH *in, char ch, int nsplits) { + DOH *list; + DOH *str; + int c; + + list = NewList(); + + if (DohIsString(in)) { + Seek(in, 0, SEEK_SET); + } + + while (1) { + str = NewStringEmpty(); + do { + c = Getc(in); + } while ((c != EOF) && (c == ch)); + if (c != EOF) { + Putc(c, str); + while (1) { + c = Getc(in); + if ((c == EOF) || ((c == ch) && (nsplits != 0))) + break; + Putc(c, str); + } + nsplits--; + } + Append(list, str); + Delete(str); + if (c == EOF) + break; + } + return list; +} + +/* ----------------------------------------------------------------------------- + * DohSplitLines() + * + * Split an input stream into a list of strings delimited by newline characters. + * ----------------------------------------------------------------------------- */ + +DOH *DohSplitLines(DOH *in) { + DOH *list; + DOH *str; + int c = 0; + + list = NewList(); + + if (DohIsString(in)) { + Seek(in, 0, SEEK_SET); + } + + while (c != EOF) { + str = NewStringEmpty(); + while ((c = Getc(in)) != '\n' && c != EOF) { + Putc(c, str); + } + Append(list, str); + Delete(str); + } + return list; +} + + +/* ----------------------------------------------------------------------------- + * DohReadline() + * + * Read a single input line and return it as a string. + * ----------------------------------------------------------------------------- */ + +DOH *DohReadline(DOH *in) { + char c; + int n = 0; + DOH *s = NewStringEmpty(); + while (1) { + if (Read(in, &c, 1) < 0) { + if (n == 0) { + Delete(s); + return 0; + } + return s; + } + if (c == '\n') + return s; + if (c == '\r') + continue; + Putc(c, s); + n++; + } +} diff --git a/Source/DOH/hash.c b/Source/DOH/hash.c new file mode 100644 index 0000000..071a6a6 --- /dev/null +++ b/Source/DOH/hash.c @@ -0,0 +1,551 @@ +/* ----------------------------------------------------------------------------- + * hash.c + * + * Implements a simple hash table object. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_hash_c[] = "$Id: hash.c 10926 2008-11-11 22:17:40Z wsfulton $"; + +#include "dohint.h" + +extern DohObjInfo DohHashType; + +/* Hash node */ +typedef struct HashNode { + DOH *key; + DOH *object; + struct HashNode *next; +} HashNode; + +/* Hash object */ +typedef struct Hash { + DOH *file; + int line; + HashNode **hashtable; + int hashsize; + int nitems; +} Hash; + +/* Key interning structure */ +typedef struct KeyValue { + char *cstr; + DOH *sstr; + struct KeyValue *left; + struct KeyValue *right; +} KeyValue; + +static KeyValue *root = 0; + +/* Find or create a key in the interned key table */ +static DOH *find_key(DOH *doh_c) { + char *c = (char *) doh_c; + KeyValue *r, *s; + int d = 0; + /* OK, sure, we use a binary tree for maintaining interned + symbols. Then we use their hash values for accessing secondary + hash tables. */ + r = root; + s = 0; + while (r) { + s = r; + d = strcmp(r->cstr, c); + if (d == 0) + return r->sstr; + if (d < 0) + r = r->left; + else + r = r->right; + } + /* fprintf(stderr,"Interning '%s'\n", c); */ + r = (KeyValue *) DohMalloc(sizeof(KeyValue)); + r->cstr = (char *) DohMalloc(strlen(c) + 1); + strcpy(r->cstr, c); + r->sstr = NewString(c); + DohIntern(r->sstr); + r->left = 0; + r->right = 0; + if (!s) { + root = r; + } else { + if (d < 0) + s->left = r; + else + s->right = r; + } + return r->sstr; +} + +#define HASH_INIT_SIZE 7 + +/* Create a new hash node */ +static HashNode *NewNode(DOH *k, void *obj) { + HashNode *hn = (HashNode *) DohMalloc(sizeof(HashNode)); + hn->key = k; + Incref(hn->key); + hn->object = obj; + Incref(obj); + hn->next = 0; + return hn; +} + +/* Delete a hash node */ +static void DelNode(HashNode *hn) { + Delete(hn->key); + Delete(hn->object); + DohFree(hn); +} + +/* ----------------------------------------------------------------------------- + * DelHash() + * + * Delete a hash table. + * ----------------------------------------------------------------------------- */ + +static void DelHash(DOH *ho) { + Hash *h = (Hash *) ObjData(ho); + HashNode *n, *next; + int i; + + for (i = 0; i < h->hashsize; i++) { + n = h->hashtable[i]; + while (n) { + next = n->next; + DelNode(n); + n = next; + } + } + DohFree(h->hashtable); + h->hashtable = 0; + h->hashsize = 0; + DohFree(h); +} + +/* ----------------------------------------------------------------------------- + * Hash_clear() + * + * Clear all of the entries in the hash table. + * ----------------------------------------------------------------------------- */ + +static void Hash_clear(DOH *ho) { + Hash *h = (Hash *) ObjData(ho); + HashNode *n, *next; + int i; + + for (i = 0; i < h->hashsize; i++) { + n = h->hashtable[i]; + while (n) { + next = n->next; + DelNode(n); + n = next; + } + h->hashtable[i] = 0; + } + h->nitems = 0; +} + +/* resize the hash table */ +static void resize(Hash *h) { + HashNode *n, *next, **table; + int oldsize, newsize; + int i, p, hv; + + if (h->nitems < 2 * h->hashsize) + return; + + /* Too big. We have to rescale everything now */ + oldsize = h->hashsize; + + /* Calculate a new size */ + newsize = 2 * oldsize + 1; + p = 3; + while (p < (newsize >> 1)) { + if (((newsize / p) * p) == newsize) { + newsize += 2; + p = 3; + continue; + } + p = p + 2; + } + + table = (HashNode **) DohMalloc(newsize * sizeof(HashNode *)); + for (i = 0; i < newsize; i++) { + table[i] = 0; + } + + /* Walk down the old set of nodes and re-place */ + h->hashsize = newsize; + for (i = 0; i < oldsize; i++) { + n = h->hashtable[i]; + while (n) { + hv = Hashval(n->key) % newsize; + next = n->next; + n->next = table[hv]; + table[hv] = n; + n = next; + } + } + DohFree(h->hashtable); + h->hashtable = table; +} + +/* ----------------------------------------------------------------------------- + * Hash_setattr() + * + * Set an attribute in the hash table. Deletes the existing entry if it already + * exists. + * ----------------------------------------------------------------------------- */ + +static int Hash_setattr(DOH *ho, DOH *k, DOH *obj) { + int hv; + HashNode *n, *prev; + Hash *h = (Hash *) ObjData(ho); + + if (!obj) { + return DohDelattr(ho, k); + } + if (!DohCheck(k)) + k = find_key(k); + if (!DohCheck(obj)) { + obj = NewString((char *) obj); + Decref(obj); + } + hv = (Hashval(k)) % h->hashsize; + n = h->hashtable[hv]; + prev = 0; + while (n) { + if (Cmp(n->key, k) == 0) { + /* Node already exists. Just replace its contents */ + if (n->object == obj) { + /* Whoa. Same object. Do nothing */ + return 1; + } + Delete(n->object); + n->object = obj; + Incref(obj); + return 1; /* Return 1 to indicate a replacement */ + } else { + prev = n; + n = n->next; + } + } + /* Add this to the table */ + n = NewNode(k, obj); + if (prev) + prev->next = n; + else + h->hashtable[hv] = n; + h->nitems++; + resize(h); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Hash_getattr() + * + * Get an attribute from the hash table. Returns 0 if it doesn't exist. + * ----------------------------------------------------------------------------- */ +typedef int (*binop) (DOH *obj1, DOH *obj2); + + +static DOH *Hash_getattr(DOH *h, DOH *k) { + DOH *obj = 0; + Hash *ho = (Hash *) ObjData(h); + DOH *ko = DohCheck(k) ? k : find_key(k); + int hv = Hashval(ko) % ho->hashsize; + DohObjInfo *k_type = ((DohBase*)ko)->type; + HashNode *n = ho->hashtable[hv]; + if (k_type->doh_equal) { + binop equal = k_type->doh_equal; + while (n) { + DohBase *nk = (DohBase *)n->key; + if ((k_type == nk->type) && equal(ko, nk)) obj = n->object; + n = n->next; + } + } else { + binop cmp = k_type->doh_cmp; + while (n) { + DohBase *nk = (DohBase *)n->key; + if ((k_type == nk->type) && (cmp(ko, nk) == 0)) obj = n->object; + n = n->next; + } + } + return obj; +} + +/* ----------------------------------------------------------------------------- + * Hash_delattr() + * + * Delete an object from the hash table. + * ----------------------------------------------------------------------------- */ + +static int Hash_delattr(DOH *ho, DOH *k) { + HashNode *n, *prev; + int hv; + Hash *h = (Hash *) ObjData(ho); + + if (!DohCheck(k)) + k = find_key(k); + hv = Hashval(k) % h->hashsize; + n = h->hashtable[hv]; + prev = 0; + while (n) { + if (Cmp(n->key, k) == 0) { + /* Found it, kill it */ + + if (prev) { + prev->next = n->next; + } else { + h->hashtable[hv] = n->next; + } + DelNode(n); + h->nitems--; + return 1; + } + prev = n; + n = n->next; + } + return 0; +} + +static DohIterator Hash_firstiter(DOH *ho) { + DohIterator iter; + Hash *h = (Hash *) ObjData(ho); + iter.object = ho; + iter._current = 0; + iter.item = 0; + iter.key = 0; + iter._index = 0; /* Index in hash table */ + while ((iter._index < h->hashsize) && !h->hashtable[iter._index]) + iter._index++; + + if (iter._index >= h->hashsize) { + return iter; + } + iter._current = h->hashtable[iter._index]; + iter.item = ((HashNode *) iter._current)->object; + iter.key = ((HashNode *) iter._current)->key; + + /* Actually save the next slot in the hash. This makes it possible to + delete the item being iterated over without trashing the universe */ + iter._current = ((HashNode *) iter._current)->next; + return iter; +} + +static DohIterator Hash_nextiter(DohIterator iter) { + Hash *h = (Hash *) ObjData(iter.object); + if (!iter._current) { + iter._index++; + while ((iter._index < h->hashsize) && !h->hashtable[iter._index]) { + iter._index++; + } + if (iter._index >= h->hashsize) { + iter.item = 0; + iter.key = 0; + iter._current = 0; + return iter; + } + iter._current = h->hashtable[iter._index]; + } + iter.key = ((HashNode *) iter._current)->key; + iter.item = ((HashNode *) iter._current)->object; + + /* Store the next node to iterator on */ + iter._current = ((HashNode *) iter._current)->next; + return iter; +} + +/* ----------------------------------------------------------------------------- + * Hash_keys(DOH *) + * + * Return a list of keys + * ----------------------------------------------------------------------------- */ + +static DOH *Hash_keys(DOH *so) { + DOH *keys; + Iterator i; + + keys = NewList(); + for (i = First(so); i.key; i = Next(i)) { + Append(keys, i.key); + } + return keys; +} + +/* ----------------------------------------------------------------------------- + * Hash_str() + * + * Create a string representation of a hash table (mainly for debugging). + * ----------------------------------------------------------------------------- */ + +static DOH *Hash_str(DOH *ho) { + int i, j; + HashNode *n; + DOH *s; + static int indent = 4; + Hash *h = (Hash *) ObjData(ho); + + s = NewStringEmpty(); + if (ObjGetMark(ho)) { + Printf(s, "Hash(0x%x)", ho); + return s; + } + ObjSetMark(ho, 1); + Printf(s, "Hash {\n"); + for (i = 0; i < h->hashsize; i++) { + n = h->hashtable[i]; + while (n) { + for (j = 0; j < indent; j++) + Putc(' ', s); + indent += 4; + Printf(s, "'%s' : %s, \n", n->key, n->object); + indent -= 4; + n = n->next; + } + } + for (j = 0; j < (indent - 4); j++) + Putc(' ', s); + Printf(s, "}\n"); + ObjSetMark(ho, 0); + return s; +} + +/* ----------------------------------------------------------------------------- + * Hash_len() + * + * Return number of entries in the hash table. + * ----------------------------------------------------------------------------- */ + +static int Hash_len(DOH *ho) { + Hash *h = (Hash *) ObjData(ho); + return h->nitems; +} + +/* ----------------------------------------------------------------------------- + * CopyHash() + * + * Make a copy of a hash table. Note: this is a shallow copy. + * ----------------------------------------------------------------------------- */ + +static DOH *CopyHash(DOH *ho) { + Hash *h, *nh; + HashNode *n; + DOH *nho; + + int i; + h = (Hash *) ObjData(ho); + nh = (Hash *) DohMalloc(sizeof(Hash)); + nh->hashsize = h->hashsize; + nh->hashtable = (HashNode **) DohMalloc(nh->hashsize * sizeof(HashNode *)); + for (i = 0; i < nh->hashsize; i++) { + nh->hashtable[i] = 0; + } + nh->nitems = 0; + nh->line = h->line; + nh->file = h->file; + if (nh->file) + Incref(nh->file); + + nho = DohObjMalloc(&DohHashType, nh); + for (i = 0; i < h->hashsize; i++) { + n = h->hashtable[i]; + while (n) { + Hash_setattr(nho, n->key, n->object); + n = n->next; + } + } + return nho; +} + + + +static void Hash_setfile(DOH *ho, DOH *file) { + DOH *fo; + Hash *h = (Hash *) ObjData(ho); + + if (!DohCheck(file)) { + fo = NewString(file); + Decref(fo); + } else + fo = file; + Incref(fo); + Delete(h->file); + h->file = fo; +} + +static DOH *Hash_getfile(DOH *ho) { + Hash *h = (Hash *) ObjData(ho); + return h->file; +} + +static void Hash_setline(DOH *ho, int line) { + Hash *h = (Hash *) ObjData(ho); + h->line = line; +} + +static int Hash_getline(DOH *ho) { + Hash *h = (Hash *) ObjData(ho); + return h->line; +} + +/* ----------------------------------------------------------------------------- + * type information + * ----------------------------------------------------------------------------- */ + +static DohHashMethods HashHashMethods = { + Hash_getattr, + Hash_setattr, + Hash_delattr, + Hash_keys, +}; + +DohObjInfo DohHashType = { + "Hash", /* objname */ + DelHash, /* doh_del */ + CopyHash, /* doh_copy */ + Hash_clear, /* doh_clear */ + Hash_str, /* doh_str */ + 0, /* doh_data */ + 0, /* doh_dump */ + Hash_len, /* doh_len */ + 0, /* doh_hash */ + 0, /* doh_cmp */ + 0, /* doh_equal */ + Hash_firstiter, /* doh_first */ + Hash_nextiter, /* doh_next */ + Hash_setfile, /* doh_setfile */ + Hash_getfile, /* doh_getfile */ + Hash_setline, /* doh_setline */ + Hash_getline, /* doh_getline */ + &HashHashMethods, /* doh_mapping */ + 0, /* doh_sequence */ + 0, /* doh_file */ + 0, /* doh_string */ + 0, /* doh_positional */ + 0, +}; + +/* ----------------------------------------------------------------------------- + * NewHash() + * + * Create a new hash table. + * ----------------------------------------------------------------------------- */ + +DOH *DohNewHash(void) { + Hash *h; + int i; + h = (Hash *) DohMalloc(sizeof(Hash)); + h->hashsize = HASH_INIT_SIZE; + h->hashtable = (HashNode **) DohMalloc(h->hashsize * sizeof(HashNode *)); + for (i = 0; i < h->hashsize; i++) { + h->hashtable[i] = 0; + } + h->nitems = 0; + h->file = 0; + h->line = 0; + return DohObjMalloc(&DohHashType, h); +} diff --git a/Source/DOH/list.c b/Source/DOH/list.c new file mode 100644 index 0000000..b7e23ad --- /dev/null +++ b/Source/DOH/list.c @@ -0,0 +1,377 @@ +/* ----------------------------------------------------------------------------- + * list.c + * + * Implements a simple list object. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_list_c[] = "$Id: list.c 10926 2008-11-11 22:17:40Z wsfulton $"; + +#include "dohint.h" + +typedef struct List { + int maxitems; /* Max size */ + int nitems; /* Num items */ + DOH *file; + int line; + DOH **items; +} List; + +extern DohObjInfo DohListType; + +/* Doubles amount of memory in a list */ +static +void more(List *l) { + l->items = (void **) DohRealloc(l->items, l->maxitems * 2 * sizeof(void *)); + assert(l->items); + l->maxitems *= 2; +} + +/* ----------------------------------------------------------------------------- + * CopyList() + * + * Make a shallow copy of a list. + * ----------------------------------------------------------------------------- */ +static DOH *CopyList(DOH *lo) { + List *l, *nl; + int i; + l = (List *) ObjData(lo); + nl = (List *) DohMalloc(sizeof(List)); + nl->nitems = l->nitems; + nl->maxitems = l->maxitems; + nl->items = (void **) DohMalloc(l->maxitems * sizeof(void *)); + for (i = 0; i < l->nitems; i++) { + nl->items[i] = l->items[i]; + Incref(nl->items[i]); + } + nl->file = l->file; + if (nl->file) + Incref(nl->file); + nl->line = l->line; + return DohObjMalloc(&DohListType, nl); +} + +/* ----------------------------------------------------------------------------- + * DelList() + * + * Delete a list. + * ----------------------------------------------------------------------------- */ + +static void DelList(DOH *lo) { + List *l = (List *) ObjData(lo); + int i; + for (i = 0; i < l->nitems; i++) + Delete(l->items[i]); + DohFree(l->items); + DohFree(l); +} + +/* ----------------------------------------------------------------------------- + * List_clear() + * + * Remove all of the list entries, but keep the list object intact. + * ----------------------------------------------------------------------------- */ + +static void List_clear(DOH *lo) { + List *l = (List *) ObjData(lo); + int i; + for (i = 0; i < l->nitems; i++) { + Delete(l->items[i]); + } + l->nitems = 0; +} + +/* ----------------------------------------------------------------------------- + * List_insert() + * + * Insert an item into the list. If the item is not a DOH object, it is assumed + * to be a 'char *' and is used to construct an equivalent string object. + * ----------------------------------------------------------------------------- */ + +static int List_insert(DOH *lo, int pos, DOH *item) { + List *l = (List *) ObjData(lo); + int i; + + if (!item) + return -1; + if (!DohCheck(item)) { + item = NewString(item); + Decref(item); + } + if (pos == DOH_END) + pos = l->nitems; + if (pos < 0) + pos = 0; + if (pos > l->nitems) + pos = l->nitems; + if (l->nitems == l->maxitems) + more(l); + for (i = l->nitems; i > pos; i--) { + l->items[i] = l->items[i - 1]; + } + l->items[pos] = item; + Incref(item); + l->nitems++; + return 0; +} + +/* ----------------------------------------------------------------------------- + * List_remove() + * + * Remove an item from a list. + * ----------------------------------------------------------------------------- */ + +static int List_remove(DOH *lo, int pos) { + List *l = (List *) ObjData(lo); + int i; + if (pos == DOH_END) + pos = l->nitems - 1; + if (pos == DOH_BEGIN) + pos = 0; + assert(!((pos < 0) || (pos >= l->nitems))); + Delete(l->items[pos]); + for (i = pos; i < l->nitems - 1; i++) { + l->items[i] = l->items[i + 1]; + } + l->nitems--; + return 0; +} + +/* ----------------------------------------------------------------------------- + * List_len() + * + * Return the number of elements in the list + * ----------------------------------------------------------------------------- */ + +static int List_len(DOH *lo) { + List *l = (List *) ObjData(lo); + return l->nitems; +} + +/* ----------------------------------------------------------------------------- + * List_get() + * + * Get the nth item from the list. + * ----------------------------------------------------------------------------- */ + +static DOH *List_get(DOH *lo, int n) { + List *l = (List *) ObjData(lo); + if (n == DOH_END) + n = l->nitems - 1; + if (n == DOH_BEGIN) + n = 0; + assert(!((n < 0) || (n >= l->nitems))); + return l->items[n]; +} + +/* ----------------------------------------------------------------------------- + * List_set() + * + * Set the nth item in the list replacing any previous item. + * ----------------------------------------------------------------------------- */ + +static int List_set(DOH *lo, int n, DOH *val) { + List *l = (List *) ObjData(lo); + if (!val) + return -1; + assert(!((n < 0) || (n >= l->nitems))); + if (!DohCheck(val)) { + val = NewString(val); + Decref(val); + } + Delete(l->items[n]); + l->items[n] = val; + Incref(val); + Delete(val); + return 0; +} + +/* ----------------------------------------------------------------------------- + * List_first() + * + * Return the first item in the list. + * ----------------------------------------------------------------------------- */ + +static DohIterator List_first(DOH *lo) { + DohIterator iter; + List *l = (List *) ObjData(lo); + iter.object = lo; + iter._index = 0; + iter._current = 0; + iter.key = 0; + if (l->nitems > 0) { + iter.item = l->items[0]; + } else { + iter.item = 0; + } + return iter; +} + +/* ----------------------------------------------------------------------------- + * List_next() + * + * Return the next item in the list. + * ----------------------------------------------------------------------------- */ + +static DohIterator List_next(DohIterator iter) { + List *l = (List *) ObjData(iter.object); + iter._index = iter._index + 1; + if (iter._index >= l->nitems) { + iter.item = 0; + iter.key = 0; + } else { + iter.item = l->items[iter._index]; + } + return iter; +} + +/* ----------------------------------------------------------------------------- + * List_str() + * + * Create a string representation of the list. + * ----------------------------------------------------------------------------- */ +static DOH *List_str(DOH *lo) { + DOH *s; + int i; + List *l = (List *) ObjData(lo); + s = NewStringEmpty(); + if (ObjGetMark(lo)) { + Printf(s, "List(%x)", lo); + return s; + } + ObjSetMark(lo, 1); + Printf(s, "List[ "); + for (i = 0; i < l->nitems; i++) { + Printf(s, "%s", l->items[i]); + if ((i + 1) < l->nitems) + Printf(s, ", "); + } + Printf(s, " ]\n"); + ObjSetMark(lo, 0); + return s; +} + +/* ----------------------------------------------------------------------------- + * List_dump() + * + * Dump the items to an output stream. + * ----------------------------------------------------------------------------- */ + +static int List_dump(DOH *lo, DOH *out) { + int nsent = 0; + int i, ret; + List *l = (List *) ObjData(lo); + for (i = 0; i < l->nitems; i++) { + ret = Dump(l->items[i], out); + if (ret < 0) + return -1; + nsent += ret; + } + return nsent; +} + +static void List_setfile(DOH *lo, DOH *file) { + DOH *fo; + List *l = (List *) ObjData(lo); + + if (!DohCheck(file)) { + fo = NewString(file); + Decref(fo); + } else + fo = file; + Incref(fo); + Delete(l->file); + l->file = fo; +} + +static DOH *List_getfile(DOH *lo) { + List *l = (List *) ObjData(lo); + return l->file; +} + +static void List_setline(DOH *lo, int line) { + List *l = (List *) ObjData(lo); + l->line = line; +} + +static int List_getline(DOH *lo) { + List *l = (List *) ObjData(lo); + return l->line; +} + +static DohListMethods ListListMethods = { + List_get, + List_set, + List_remove, + List_insert, + 0, /* delslice */ +}; + +DohObjInfo DohListType = { + "List", /* objname */ + DelList, /* doh_del */ + CopyList, /* doh_copy */ + List_clear, /* doh_clear */ + List_str, /* doh_str */ + 0, /* doh_data */ + List_dump, /* doh_dump */ + List_len, /* doh_len */ + 0, /* doh_hash */ + 0, /* doh_cmp */ + 0, /* doh_equal */ + List_first, /* doh_first */ + List_next, /* doh_next */ + List_setfile, /* doh_setfile */ + List_getfile, /* doh_getfile */ + List_setline, /* doh_setline */ + List_getline, /* doh_getline */ + 0, /* doh_mapping */ + &ListListMethods, /* doh_sequence */ + 0, /* doh_file */ + 0, /* doh_string */ + 0, /* doh_callable */ + 0, /* doh_position */ +}; + +/* ----------------------------------------------------------------------------- + * NewList() + * + * Create a new list. + * ----------------------------------------------------------------------------- */ + +#define MAXLISTITEMS 8 + +DOH *DohNewList(void) { + List *l; + int i; + l = (List *) DohMalloc(sizeof(List)); + l->nitems = 0; + l->maxitems = MAXLISTITEMS; + l->items = (void **) DohMalloc(l->maxitems * sizeof(void *)); + for (i = 0; i < MAXLISTITEMS; i++) { + l->items[i] = 0; + } + l->file = 0; + l->line = 0; + return DohObjMalloc(&DohListType, l); +} + +static int (*List_sort_compare_func) (const DOH *, const DOH *); +static int List_qsort_compare(const void *a, const void *b) { + return List_sort_compare_func(*((DOH **) a), *((DOH **) b)); +} + +/* Sort a list */ +void DohSortList(DOH *lo, int (*cmp) (const DOH *, const DOH *)) { + List *l = (List *) ObjData(lo); + if (cmp) { + List_sort_compare_func = cmp; + } else { + List_sort_compare_func = DohCmp; + } + qsort(l->items, l->nitems, sizeof(DOH *), List_qsort_compare); +} diff --git a/Source/DOH/memory.c b/Source/DOH/memory.c new file mode 100644 index 0000000..79ff21c --- /dev/null +++ b/Source/DOH/memory.c @@ -0,0 +1,220 @@ +/* ----------------------------------------------------------------------------- + * memory.c + * + * This file implements all of DOH's memory management including allocation + * of objects and checking of objects. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_memory_c[] = "$Id: memory.c 9607 2006-12-05 22:11:40Z beazley $"; + +#include "dohint.h" + +#ifndef DOH_POOL_SIZE +#define DOH_POOL_SIZE 16384 +#endif + +static int PoolSize = DOH_POOL_SIZE; + +DOH *DohNone = 0; /* The DOH None object */ + +typedef struct pool { + DohBase *ptr; /* Start of pool */ + int len; /* Length of pool */ + int blen; /* Byte length of pool */ + int current; /* Current position for next allocation */ + char *pbeg; /* Beg of pool */ + char *pend; /* End of pool */ + struct pool *next; /* Next pool */ +} Pool; + +static DohBase *FreeList = 0; /* List of free objects */ +static Pool *Pools = 0; +static int pools_initialized = 0; + +/* ---------------------------------------------------------------------- + * CreatePool() - Create a new memory pool + * ---------------------------------------------------------------------- */ + +static void CreatePool() { + Pool *p = 0; + p = (Pool *) DohMalloc(sizeof(Pool)); + assert(p); + p->ptr = (DohBase *) DohMalloc(sizeof(DohBase) * PoolSize); + assert(p->ptr); + memset(p->ptr, 0, sizeof(DohBase) * PoolSize); + p->len = PoolSize; + p->blen = PoolSize * sizeof(DohBase); + p->current = 0; + p->pbeg = ((char *) p->ptr); + p->pend = p->pbeg + p->blen; + p->next = Pools; + Pools = p; +} + +/* ---------------------------------------------------------------------- + * InitPools() - Initialize the memory allocator + * ---------------------------------------------------------------------- */ + +static void InitPools() { + if (pools_initialized) + return; + CreatePool(); /* Create initial pool */ + pools_initialized = 1; + DohNone = NewVoid(0, 0); /* Create the None object */ + DohIntern(DohNone); +} + +/* ---------------------------------------------------------------------- + * DohCheck() + * + * Returns 1 if an arbitrary pointer is a DOH object. + * ---------------------------------------------------------------------- */ + +int DohCheck(const DOH *ptr) { + register Pool *p = Pools; + register char *cptr = (char *) ptr; + while (p) { + if ((cptr >= p->pbeg) && (cptr < p->pend)) + return 1; + /* + pptr = (char *) p->ptr; + if ((cptr >= pptr) && (cptr < (pptr+(p->current*sizeof(DohBase))))) return 1; */ + p = p->next; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * DohIntern() + * ----------------------------------------------------------------------------- */ + +void DohIntern(DOH *obj) { + DohBase *b = (DohBase *) obj; + b->flag_intern = 1; +} + +/* ---------------------------------------------------------------------- + * DohObjMalloc() + * + * Allocate memory for a new object. + * ---------------------------------------------------------------------- */ + +DOH *DohObjMalloc(DohObjInfo *type, void *data) { + DohBase *obj; + if (!pools_initialized) + InitPools(); + if (FreeList) { + obj = FreeList; + FreeList = (DohBase *) obj->data; + } else { + while (Pools->current == Pools->len) { + CreatePool(); + } + obj = Pools->ptr + Pools->current; + ++Pools->current; + } + obj->type = type; + obj->data = data; + obj->meta = 0; + obj->refcount = 1; + obj->flag_intern = 0; + obj->flag_marked = 0; + obj->flag_user = 0; + obj->flag_usermark = 0; + return (DOH *) obj; +} + +/* ---------------------------------------------------------------------- + * DohObjFree() - Free a DOH object + * ---------------------------------------------------------------------- */ + +void DohObjFree(DOH *ptr) { + DohBase *b, *meta; + b = (DohBase *) ptr; + if (b->flag_intern) + return; + meta = (DohBase *) b->meta; + b->data = (void *) FreeList; + b->meta = 0; + b->type = 0; + FreeList = b; + if (meta) { + Delete(meta); + } +} + +/* ---------------------------------------------------------------------- + * DohMemoryDebug() + * + * Display memory usage statistics + * ---------------------------------------------------------------------- */ + +void DohMemoryDebug(void) { + extern DohObjInfo DohStringType; + extern DohObjInfo DohListType; + extern DohObjInfo DohHashType; + + Pool *p; + int totsize = 0; + int totused = 0; + int totfree = 0; + + int numstring = 0; + int numlist = 0; + int numhash = 0; + + printf("Memory statistics:\n\n"); + printf("Pools:\n"); + + p = Pools; + while (p) { + /* Calculate number of used, free items */ + int i; + int nused = 0, nfree = 0; + for (i = 0; i < p->len; i++) { + if (p->ptr[i].refcount <= 0) + nfree++; + else { + nused++; + if (p->ptr[i].type == &DohStringType) + numstring++; + else if (p->ptr[i].type == &DohListType) + numlist++; + else if (p->ptr[i].type == &DohHashType) + numhash++; + } + } + printf(" Pool %8p: size = %10d. used = %10d. free = %10d\n", (void *) p, p->len, nused, nfree); + totsize += p->len; + totused += nused; + totfree += nfree; + p = p->next; + } + printf("\n Total: size = %10d, used = %10d, free = %10d\n", totsize, totused, totfree); + + printf("\nObject types\n"); + printf(" Strings : %d\n", numstring); + printf(" Lists : %d\n", numlist); + printf(" Hashes : %d\n", numhash); + +#if 0 + p = Pools; + while (p) { + int i; + for (i = 0; i < p->len; i++) { + if (p->ptr[i].refcount > 0) { + if (p->ptr[i].type == &DohStringType) { + Printf(stdout, "%s\n", p->ptr + i); + } + } + } + p = p->next; + } +#endif + +} diff --git a/Source/DOH/string.c b/Source/DOH/string.c new file mode 100644 index 0000000..425a39f --- /dev/null +++ b/Source/DOH/string.c @@ -0,0 +1,1158 @@ +/* ----------------------------------------------------------------------------- + * string.c + * + * Implements a string object that supports both sequence operations and + * file semantics. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_string_c[] = "$Id: string.c 10926 2008-11-11 22:17:40Z wsfulton $"; + +#include "dohint.h" + +extern DohObjInfo DohStringType; + +typedef struct String { + DOH *file; + int line; + int maxsize; /* Max size allocated */ + int len; /* Current length */ + int hashkey; /* Hash key value */ + int sp; /* Current position */ + char *str; /* String data */ +} String; + +/* ----------------------------------------------------------------------------- + * void *String_data() - Return as a 'void *' + * ----------------------------------------------------------------------------- */ + +static void *String_data(DOH *so) { + String *s = (String *) ObjData(so); + s->str[s->len] = 0; + return (void *) s->str; +} + +/* static char *String_char(DOH *so) { + return (char *) String_data(so); +} +*/ + +/* ----------------------------------------------------------------------------- + * int String_dump() - Serialize a string onto out + * ----------------------------------------------------------------------------- */ + +static int String_dump(DOH *so, DOH *out) { + int nsent; + int ret; + String *s = (String *) ObjData(so); + nsent = 0; + while (nsent < s->len) { + ret = Write(out, s->str + nsent, (s->len - nsent)); + if (ret < 0) + return ret; + nsent += ret; + } + return nsent; +} + +/* ----------------------------------------------------------------------------- + * CopyString() - Copy a string + * ----------------------------------------------------------------------------- */ + +static DOH *CopyString(DOH *so) { + String *str; + String *s = (String *) ObjData(so); + str = (String *) DohMalloc(sizeof(String)); + str->hashkey = s->hashkey; + str->sp = s->sp; + str->line = s->line; + str->file = s->file; + if (str->file) + Incref(str->file); + str->str = (char *) DohMalloc(s->len + 1); + memcpy(str->str, s->str, s->len); + str->maxsize = s->len; + str->len = s->len; + str->str[str->len] = 0; + + return DohObjMalloc(&DohStringType, str); +} + +/* ----------------------------------------------------------------------------- + * DelString() - Delete a string + * ----------------------------------------------------------------------------- */ + +static void DelString(DOH *so) { + String *s = (String *) ObjData(so); + DohFree(s->str); + DohFree(s); +} + +/* ----------------------------------------------------------------------------- + * DohString_len() - Length of a string + * ----------------------------------------------------------------------------- */ + +static int String_len(DOH *so) { + String *s = (String *) ObjData(so); + return s->len; +} + + +/* ----------------------------------------------------------------------------- + * int String_cmp() - Compare two strings + * ----------------------------------------------------------------------------- */ + +static int String_cmp(DOH *so1, DOH *so2) { + String *s1, *s2; + char *c1, *c2; + int maxlen, i; + s1 = (String *) ObjData(so1); + s2 = (String *) ObjData(so2); + maxlen = s1->len; + if (s2->len < maxlen) + maxlen = s2->len; + c1 = s1->str; + c2 = s2->str; + for (i = maxlen; i; --i, c1++, c2++) { + if (*c1 != *c2) + break; + } + if (i != 0) { + if (*c1 < *c2) + return -1; + else + return 1; + } + if (s1->len == s2->len) + return 0; + if (s1->len > s2->len) + return 1; + return -1; +} + +/* ----------------------------------------------------------------------------- + * int String_equal() - Say if two string are equal + * ----------------------------------------------------------------------------- */ + +static int String_equal(DOH *so1, DOH *so2) { + String *s1 = (String *) ObjData(so1); + String *s2 = (String *) ObjData(so2); + register int len = s1->len; + if (len != s2->len) { + return 0; + } else { + register char *c1 = s1->str; + register char *c2 = s2->str; +#if 0 + register int mlen = len >> 2; + register int i = mlen; + for (; i; --i) { + if (*(c1++) != *(c2++)) + return 0; + if (*(c1++) != *(c2++)) + return 0; + if (*(c1++) != *(c2++)) + return 0; + if (*(c1++) != *(c2++)) + return 0; + } + for (i = len - (mlen << 2); i; --i) { + if (*(c1++) != *(c2++)) + return 0; + } + return 1; +#else + return memcmp(c1, c2, len) == 0; +#endif + } +} + +/* ----------------------------------------------------------------------------- + * int String_hash() - Compute string hash value + * ----------------------------------------------------------------------------- */ + +static int String_hash(DOH *so) { + String *s = (String *) ObjData(so); + if (s->hashkey >= 0) { + return s->hashkey; + } else { + register char *c = s->str; + register int len = s->len > 50 ? 50 : s->len; + register int h = 0; + register int mlen = len >> 2; + register int i = mlen; + for (; i; --i) { + h = (h << 5) + *(c++); + h = (h << 5) + *(c++); + h = (h << 5) + *(c++); + h = (h << 5) + *(c++); + } + for (i = len - (mlen << 2); i; --i) { + h = (h << 5) + *(c++); + } + h &= 0x7fffffff; + s->hashkey = h; + return h; + } +} + +/* ----------------------------------------------------------------------------- + * DohString_append(String *s, const char *newstr) - Append to s + * ----------------------------------------------------------------------------- */ + +void DohString_append(DOH *so, DOH *str) { + int oldlen, newlen, newmaxsize, l, sp; + char *tc; + String *s = (String *) ObjData(so); + char *newstr = 0; + + if (DohCheck(str)) { + String *ss = (String *) ObjData(str); + newstr = (char *) String_data((DOH *) str); + l = ss->len; + } else { + newstr = (char *) (str); + l = (int) strlen(newstr); + } + if (!newstr) + return; + s->hashkey = -1; + + oldlen = s->len; + newlen = oldlen + l + 1; + if (newlen >= s->maxsize - 1) { + newmaxsize = 2 * s->maxsize; + if (newlen >= newmaxsize - 1) + newmaxsize = newlen + 1; + s->str = (char *) DohRealloc(s->str, newmaxsize); + assert(s->str); + s->maxsize = newmaxsize; + } + tc = s->str; + memcpy(tc + oldlen, newstr, l + 1); + sp = s->sp; + if (sp >= oldlen) { + int i = oldlen + l - sp; + tc += sp; + for (; i; --i) { + if (*(tc++) == '\n') + s->line++; + } + s->sp = oldlen + l; + } + s->len += l; +} + + +/* ----------------------------------------------------------------------------- + * void String_clear() - Clear a string + * ----------------------------------------------------------------------------- */ + +static void String_clear(DOH *so) { + String *s = (String *) ObjData(so); + s->hashkey = -1; + s->len = 0; + *(s->str) = 0; + s->sp = 0; + s->line = 1; +} + +/* ----------------------------------------------------------------------------- + * void String_insert() - Insert a string + * ----------------------------------------------------------------------------- */ + +static int String_insert(DOH *so, int pos, DOH *str) { + String *s; + char *nstr; + int len; + char *data; + + if (pos == DOH_END) { + DohString_append(so, str); + return 0; + } + + + s = (String *) ObjData(so); + s->hashkey = -1; + if (DohCheck(str)) { + String *ss = (String *) ObjData(str); + data = (char *) String_data(str); + len = ss->len; + } else { + data = (char *) (str); + len = (int) strlen(data); + } + nstr = s->str; + + if (pos < 0) + pos = 0; + else if (pos > s->len) + pos = s->len; + + /* See if there is room to insert the new data */ + while (s->maxsize <= s->len + len) { + int newsize = 2 * s->maxsize; + s->str = (char *) DohRealloc(s->str, newsize); + assert(s->str); + s->maxsize = newsize; + } + memmove(s->str + pos + len, s->str + pos, (s->len - pos)); + memcpy(s->str + pos, data, len); + if (s->sp >= pos) { + int i; + + for (i = 0; i < len; i++) { + if (data[i] == '\n') + s->line++; + } + s->sp += len; + } + s->len += len; + s->str[s->len] = 0; + return 0; +} + +/* ----------------------------------------------------------------------------- + * int String_delitem() - Delete a character + * ----------------------------------------------------------------------------- */ + +static int String_delitem(DOH *so, int pos) { + String *s = (String *) ObjData(so); + s->hashkey = -1; + if (pos == DOH_END) + pos = s->len - 1; + if (pos == DOH_BEGIN) + pos = 0; + if (s->len == 0) + return 0; + + if (s->sp > pos) { + s->sp--; + assert(s->sp >= 0); + if (s->str[pos] == '\n') + s->line--; + } + memmove(s->str + pos, s->str + pos + 1, ((s->len - 1) - pos)); + s->len--; + s->str[s->len] = 0; + return 0; +} + +/* ----------------------------------------------------------------------------- + * int String_delslice() - Delete a range + * ----------------------------------------------------------------------------- */ + +static int String_delslice(DOH *so, int sindex, int eindex) { + String *s = (String *) ObjData(so); + int size; + if (s->len == 0) + return 0; + s->hashkey = -1; + if (eindex == DOH_END) + eindex = s->len; + if (sindex == DOH_BEGIN) + sindex = 0; + + size = eindex - sindex; + if (s->sp > sindex) { + /* Adjust the file pointer and line count */ + int i, end; + if (s->sp > eindex) { + end = eindex; + s->sp -= size; + } else { + end = s->sp; + s->sp = sindex; + } + for (i = sindex; i < end; i++) { + if (s->str[i] == '\n') + s->line--; + } + assert(s->sp >= 0); + } + memmove(s->str + sindex, s->str + eindex, s->len - eindex); + s->len -= size; + s->str[s->len] = 0; + return 0; +} + +/* ----------------------------------------------------------------------------- + * DOH *String_str() - Returns a string (used by printing commands) + * ----------------------------------------------------------------------------- */ + +static DOH *String_str(DOH *so) { + String *s = (String *) ObjData(so); + s->str[s->len] = 0; + return NewString(s->str); +} + +/* ----------------------------------------------------------------------------- + * int String_read() - Read data from a string + * ----------------------------------------------------------------------------- */ + +static int String_read(DOH *so, void *buffer, int len) { + int reallen, retlen; + char *cb; + String *s = (String *) ObjData(so); + if ((s->sp + len) > s->len) + reallen = (s->len - s->sp); + else + reallen = len; + + cb = (char *) buffer; + retlen = reallen; + + if (reallen > 0) { + memmove(cb, s->str + s->sp, reallen); + s->sp += reallen; + } + return retlen; +} + +/* ----------------------------------------------------------------------------- + * int String_write() - Write data to a string + * ----------------------------------------------------------------------------- */ +static int String_write(DOH *so, void *buffer, int len) { + int newlen; + String *s = (String *) ObjData(so); + s->hashkey = -1; + if (s->sp > s->len) + s->sp = s->len; + newlen = s->sp + len + 1; + if (newlen > s->maxsize) { + s->str = (char *) DohRealloc(s->str, newlen); + assert(s->str); + s->maxsize = newlen; + s->len = s->sp + len; + } + if ((s->sp + len) > s->len) + s->len = s->sp + len; + memmove(s->str + s->sp, buffer, len); + s->sp += len; + s->str[s->len] = 0; + return len; +} + +/* ----------------------------------------------------------------------------- + * int String_seek() - Seek to a new position + * ----------------------------------------------------------------------------- */ + +static int String_seek(DOH *so, long offset, int whence) { + int pos, nsp, inc; + String *s = (String *) ObjData(so); + if (whence == SEEK_SET) + pos = 0; + else if (whence == SEEK_CUR) + pos = s->sp; + else if (whence == SEEK_END) { + pos = s->len; + offset = -offset; + } else + pos = s->sp; + + nsp = pos + offset; + if (nsp < 0) + nsp = 0; + if (s->len > 0 && nsp > s->len) + nsp = s->len; + + inc = (nsp > s->sp) ? 1 : -1; + + { +#if 0 + register int sp = s->sp; + register char *tc = s->str; + register int len = s->len; + while (sp != nsp) { + int prev = sp + inc; + if (prev >= 0 && prev <= len && tc[prev] == '\n') + s->line += inc; + sp += inc; + } +#else + register int sp = s->sp; + register char *tc = s->str; + if (inc > 0) { + while (sp != nsp) { + if (tc[++sp] == '\n') + ++s->line; + } + } else { + while (sp != nsp) { + if (tc[--sp] == '\n') + --s->line; + } + } +#endif + s->sp = sp; + } + assert(s->sp >= 0); + return 0; +} + +/* ----------------------------------------------------------------------------- + * long String_tell() - Return current position + * ----------------------------------------------------------------------------- */ + +static long String_tell(DOH *so) { + String *s = (String *) ObjData(so); + return (long) (s->sp); +} + +/* ----------------------------------------------------------------------------- + * int String_putc() + * ----------------------------------------------------------------------------- */ + +static int String_putc(DOH *so, int ch) { + String *s = (String *) ObjData(so); + register int len = s->len; + register int sp = s->sp; + s->hashkey = -1; + if (sp >= len) { + register int maxsize = s->maxsize; + register char *tc = s->str; + if (len > (maxsize - 2)) { + maxsize *= 2; + tc = (char *) DohRealloc(tc, maxsize); + assert(tc); + s->maxsize = (int) maxsize; + s->str = tc; + } + tc += sp; + *tc = (char) ch; + *(++tc) = 0; + s->len = s->sp = sp + 1; + } else { + s->str[s->sp++] = (char) ch; + } + if (ch == '\n') + s->line++; + return ch; +} + +/* ----------------------------------------------------------------------------- + * int String_getc() + * ----------------------------------------------------------------------------- */ + +static int String_getc(DOH *so) { + int c; + String *s = (String *) ObjData(so); + if (s->sp >= s->len) + c = EOF; + else + c = (int)(unsigned char) s->str[s->sp++]; + if (c == '\n') + s->line++; + return c; +} + +/* ----------------------------------------------------------------------------- + * int String_ungetc() + * ----------------------------------------------------------------------------- */ + +static int String_ungetc(DOH *so, int ch) { + String *s = (String *) ObjData(so); + if (ch == EOF) + return ch; + if (s->sp <= 0) + return EOF; + s->sp--; + if (ch == '\n') + s->line--; + return ch; +} + +/* ----------------------------------------------------------------------------- + * replace_simple(String *str, char *token, char *rep, int flags, int count) + * + * Replaces count non-overlapping occurrences of token with rep in a string. + * ----------------------------------------------------------------------------- */ + +static char *end_quote(char *s) { + char *qs; + char qc; + char *q; + char *nl; + qc = *s; + qs = s; + while (1) { + q = strpbrk(s + 1, "\"\'"); + nl = strchr(s + 1, '\n'); + if (nl && (nl < q)) { + /* A new line appears before the end of the string */ + if (*(nl - 1) == '\\') { + s = nl + 1; + continue; + } + /* String was terminated by a newline. Wing it */ + return qs; + } + if (!q && nl) { + return qs; + } + if (!q) + return 0; + if ((*q == qc) && (*(q - 1) != '\\')) + return q; + s = q; + } +} + +static char *match_simple(char *base, char *s, char *token, int tokenlen) { + (void) base; + (void) tokenlen; + return strstr(s, token); +} + +static char *match_identifier(char *base, char *s, char *token, int tokenlen) { + while (s) { + s = strstr(s, token); + if (!s) + return 0; + if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) { + s += tokenlen; + continue; + } + if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) { + s += tokenlen; + continue; + } + return s; + } + return 0; +} + + +static char *match_identifier_begin(char *base, char *s, char *token, int tokenlen) { + while (s) { + s = strstr(s, token); + if (!s) + return 0; + if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) { + s += tokenlen; + continue; + } + return s; + } + return 0; +} + +static char *match_identifier_end(char *base, char *s, char *token, int tokenlen) { + (void) base; + while (s) { + s = strstr(s, token); + if (!s) + return 0; + if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) { + s += tokenlen; + continue; + } + return s; + } + return 0; +} + +static int replace_simple(String *str, char *token, char *rep, int flags, int count, char *(*match) (char *, char *, char *, int)) { + int tokenlen; /* Length of the token */ + int replen; /* Length of the replacement */ + int delta, expand = 0; + int ic; + int rcount = 0; + int noquote = 0; + char *c, *s, *t, *first; + char *q, *q2; + register char *base; + int i; + + /* Figure out if anything gets replaced */ + if (!strlen(token)) + return 0; + + base = str->str; + tokenlen = strlen(token); + s = (*match) (base, base, token, tokenlen); + + if (!s) + return 0; /* No matches. Who cares */ + + str->hashkey = -1; + + if (flags & DOH_REPLACE_NOQUOTE) + noquote = 1; + + /* If we are not replacing inside quotes, we need to do a little extra work */ + if (noquote) { + q = strpbrk(base, "\"\'"); + if (!q) { + noquote = 0; /* Well, no quotes to worry about. Oh well */ + } else { + while (q && (q < s)) { + /* First match was found inside a quote. Try to find another match */ + q2 = end_quote(q); + if (!q2) { + return 0; + } + if (q2 > s) { + /* Find next match */ + s = (*match) (base, q2 + 1, token, tokenlen); + } + if (!s) + return 0; /* Oh well, no matches */ + q = strpbrk(q2 + 1, "\"\'"); + if (!q) + noquote = 0; /* No more quotes */ + } + } + } + + first = s; + replen = strlen(rep); + + delta = (replen - tokenlen); + + if (delta <= 0) { + /* String is either shrinking or staying the same size */ + /* In this case, we do the replacement in place without memory reallocation */ + ic = count; + t = s; /* Target of memory copies */ + while (ic && s) { + if (replen) { + memcpy(t, rep, replen); + t += replen; + } + rcount++; + expand += delta; + /* Find the next location */ + s += tokenlen; + if (ic == 1) + break; + c = (*match) (base, s, token, tokenlen); + + if (noquote) { + q = strpbrk(s, "\"\'"); + if (!q) { + noquote = 0; + } else { + while (q && (q < c)) { + /* First match was found inside a quote. Try to find another match */ + q2 = end_quote(q); + if (!q2) { + c = 0; + break; + } + if (q2 > c) + c = (*match) (base, q2 + 1, token, tokenlen); + if (!c) + break; + q = strpbrk(q2 + 1, "\"\'"); + if (!q) + noquote = 0; /* No more quotes */ + } + } + } + if (delta) { + if (c) { + memmove(t, s, c - s); + t += (c - s); + } else { + memmove(t, s, (str->str + str->len) - s + 1); + } + } else { + t += (c - s); + } + s = c; + ic--; + } + if (s && delta) { + memmove(t, s, (str->str + str->len) - s + 1); + } + str->len += expand; + str->str[str->len] = 0; + if (str->sp >= str->len) + str->sp += expand; /* Fix the end of file pointer */ + return rcount; + } + /* The string is expanding as a result of the replacement */ + /* Figure out how much expansion is going to occur and allocate a new string */ + { + char *ns; + int newsize; + + rcount++; + ic = count - 1; + s += tokenlen; + while (ic && (c = (*match) (base, s, token, tokenlen))) { + if (noquote) { + q = strpbrk(s, "\"\'"); + if (!q) { + break; + } else { + while (q && (q < c)) { + /* First match was found inside a quote. Try to find another match */ + q2 = end_quote(q); + if (!q2) { + c = 0; + break; + } + if (q2 > c) { + c = (*match) (base, q2 + 1, token, tokenlen); + if (!c) + break; + } + q = strpbrk(q2 + 1, "\"\'"); + if (!q) + noquote = 0; + } + } + } + if (c) { + rcount++; + ic--; + s = c + tokenlen; + } else { + break; + } + } + + expand = delta * rcount; /* Total amount of expansion for the replacement */ + newsize = str->maxsize; + while ((str->len + expand) >= newsize) + newsize *= 2; + + ns = (char *) DohMalloc(newsize); + assert(ns); + t = ns; + s = first; + + /* Copy the first part of the string */ + if (first > str->str) { + memcpy(t, str->str, (first - str->str)); + t += (first - str->str); + } + for (i = 0; i < rcount; i++) { + memcpy(t, rep, replen); + t += replen; + s += tokenlen; + c = (*match) (base, s, token, tokenlen); + if (noquote) { + q = strpbrk(s, "\"\'"); + if (!q) { + noquote = 0; + } else { + while (q && (q < c)) { + /* First match was found inside a quote. Try to find another match */ + q2 = end_quote(q); + if (!q2) { + c = 0; + break; + } + if (q2 > c) { + c = (*match) (base, q2 + 1, token, tokenlen); + if (!c) + break; + } + q = strpbrk(q2 + 1, "\"\'"); + if (!q) + noquote = 0; /* No more quotes */ + } + } + } + if (i < (rcount - 1)) { + memcpy(t, s, c - s); + t += (c - s); + } else { + memcpy(t, s, (str->str + str->len) - s + 1); + } + s = c; + } + c = str->str; + str->str = ns; + if (str->sp >= str->len) + str->sp += expand; + str->len += expand; + str->str[str->len] = 0; + str->maxsize = newsize; + DohFree(c); + return rcount; + } +} + +/* ----------------------------------------------------------------------------- + * int String_replace() + * ----------------------------------------------------------------------------- */ + +static int String_replace(DOH *stro, DOH *token, DOH *rep, int flags) { + int count = -1; + String *str = (String *) ObjData(stro); + + if (flags & DOH_REPLACE_FIRST) + count = 1; + + if (flags & DOH_REPLACE_ID_END) { + return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_end); + } else if (flags & DOH_REPLACE_ID_BEGIN) { + return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_begin); + } else if (flags & DOH_REPLACE_ID) { + return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier); + } else { + return replace_simple(str, Char(token), Char(rep), flags, count, match_simple); + } +} + +/* ----------------------------------------------------------------------------- + * void String_chop(DOH *str) + * ----------------------------------------------------------------------------- */ + +static void String_chop(DOH *so) { + char *c; + String *str = (String *) ObjData(so); + /* Replace trailing whitespace */ + c = str->str + str->len - 1; + while ((str->len > 0) && (isspace((int) *c))) { + if (str->sp >= str->len) { + str->sp--; + if (*c == '\n') + str->line--; + } + str->len--; + c--; + } + str->str[str->len] = 0; + assert(str->sp >= 0); + str->hashkey = -1; +} + +static void String_setfile(DOH *so, DOH *file) { + DOH *fo; + String *str = (String *) ObjData(so); + + if (!DohCheck(file)) { + fo = NewString(file); + Decref(fo); + } else + fo = file; + Incref(fo); + Delete(str->file); + str->file = fo; +} + +static DOH *String_getfile(DOH *so) { + String *str = (String *) ObjData(so); + return str->file; +} + +static void String_setline(DOH *so, int line) { + String *str = (String *) ObjData(so); + str->line = line; +} + +static int String_getline(DOH *so) { + String *str = (String *) ObjData(so); + return str->line; +} + +static DohListMethods StringListMethods = { + 0, /* doh_getitem */ + 0, /* doh_setitem */ + String_delitem, /* doh_delitem */ + String_insert, /* doh_insitem */ + String_delslice, /* doh_delslice */ +}; + +static DohFileMethods StringFileMethods = { + String_read, + String_write, + String_putc, + String_getc, + String_ungetc, + String_seek, + String_tell, + 0, /* close */ +}; + +static DohStringMethods StringStringMethods = { + String_replace, + String_chop, +}; + +DohObjInfo DohStringType = { + "String", /* objname */ + DelString, /* doh_del */ + CopyString, /* doh_copy */ + String_clear, /* doh_clear */ + String_str, /* doh_str */ + String_data, /* doh_data */ + String_dump, /* doh_dump */ + String_len, /* doh_len */ + String_hash, /* doh_hash */ + String_cmp, /* doh_cmp */ + String_equal, /* doh_equal */ + 0, /* doh_first */ + 0, /* doh_next */ + String_setfile, /* doh_setfile */ + String_getfile, /* doh_getfile */ + String_setline, /* doh_setline */ + String_getline, /* doh_getline */ + 0, /* doh_mapping */ + &StringListMethods, /* doh_sequence */ + &StringFileMethods, /* doh_file */ + &StringStringMethods, /* doh_string */ + 0, /* doh_position */ + 0 +}; + + +#define INIT_MAXSIZE 16 + +/* ----------------------------------------------------------------------------- + * NewString(const char *c) - Create a new string + * ----------------------------------------------------------------------------- */ + +DOHString *DohNewString(const DOH *so) { + int l = 0, max; + String *str; + char *s; + int hashkey = -1; + if (DohCheck(so)) { + str = (String *) ObjData(so); + s = (char *) String_data((String *) so); + l = s ? str->len : 0; + hashkey = str->hashkey; + } else { + s = (char *) so; + l = s ? (int) strlen(s) : 0; + } + + str = (String *) DohMalloc(sizeof(String)); + str->hashkey = hashkey; + str->sp = 0; + str->line = 1; + str->file = 0; + max = INIT_MAXSIZE; + if (s) { + if ((l + 1) > max) + max = l + 1; + } + str->str = (char *) DohMalloc(max); + str->maxsize = max; + if (s) { + strcpy(str->str, s); + str->len = l; + str->sp = l; + } else { + str->str[0] = 0; + str->len = 0; + } + return DohObjMalloc(&DohStringType, str); +} + + +/* ----------------------------------------------------------------------------- + * NewStringEmpty() - Create a new string + * ----------------------------------------------------------------------------- */ + +DOHString *DohNewStringEmpty(void) { + int max = INIT_MAXSIZE; + String *str = (String *) DohMalloc(sizeof(String)); + str->hashkey = 0; + str->sp = 0; + str->line = 1; + str->file = 0; + str->str = (char *) DohMalloc(max); + str->maxsize = max; + str->str[0] = 0; + str->len = 0; + return DohObjMalloc(&DohStringType, str); +} + +/* ----------------------------------------------------------------------------- + * NewStringWithSize(const char *c, int len) - Create a new string + * ----------------------------------------------------------------------------- */ + +DOHString *DohNewStringWithSize(const DOH *so, int len) { + int l = 0, max; + String *str; + char *s; + if (DohCheck(so)) { + s = (char *) String_data((String *) so); + } else { + s = (char *) so; + } + + str = (String *) DohMalloc(sizeof(String)); + str->hashkey = -1; + str->sp = 0; + str->line = 1; + str->file = 0; + max = INIT_MAXSIZE; + if (s) { + l = (int) len; + if ((l + 1) > max) + max = l + 1; + } + str->str = (char *) DohMalloc(max); + str->maxsize = max; + if (s) { + strncpy(str->str, s, len); + str->len = l; + str->sp = l; + } else { + str->str[0] = 0; + str->len = 0; + } + return DohObjMalloc(&DohStringType, str); +} + +/* ----------------------------------------------------------------------------- + * NewStringf(DOH *fmt, ...) + * + * Create a new string from a list of objects. + * ----------------------------------------------------------------------------- */ + +DOHString *DohNewStringf(const DOH *fmt, ...) { + va_list ap; + DOH *r; + va_start(ap, fmt); + r = NewStringEmpty(); + DohvPrintf(r, Char(fmt), ap); + va_end(ap); + return (DOHString *) r; +} + +/* ----------------------------------------------------------------------------- + * Strcmp() + * Strncmp() + * Strstr() + * Strchr() + * + * Some utility functions. + * ----------------------------------------------------------------------------- */ + +int DohStrcmp(const DOHString_or_char *s1, const DOHString_or_char *s2) { + const char *c1 = Char(s1); + const char *c2 = Char(s2); + if (c1 && c2) { + return strcmp(c1, c2); + } else { + return c1 < c2; + } +} + +int DohStrncmp(const DOHString_or_char *s1, const DOHString_or_char *s2, int n) { + return strncmp(Char(s1), Char(s2), n); +} + +char *DohStrstr(const DOHString_or_char *s1, const DOHString_or_char *s2) { + char *p1 = Char(s1); + char *p2 = Char(s2); + return p1 == 0 || p2 == 0 || *p2 == '\0' ? p1 : strstr(p1, p2); +} + +char *DohStrchr(const DOHString_or_char *s1, int ch) { + return strchr(Char(s1), ch); +} diff --git a/Source/DOH/void.c b/Source/DOH/void.c new file mode 100644 index 0000000..ed34da1 --- /dev/null +++ b/Source/DOH/void.c @@ -0,0 +1,96 @@ +/* ----------------------------------------------------------------------------- + * void.c + * + * Implements a "void" object that is really just a DOH container around + * an arbitrary C object represented as a void *. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 1999-2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +char cvsroot_void_c[] = "$Id: void.c 9607 2006-12-05 22:11:40Z beazley $"; + +#include "dohint.h" + +typedef struct { + void *ptr; + void (*del) (void *); +} VoidObj; + +/* ----------------------------------------------------------------------------- + * Void_delete() + * + * Delete a void object. Invokes the destructor supplied at the time of creation. + * ----------------------------------------------------------------------------- */ + +static void Void_delete(DOH *vo) { + VoidObj *v = (VoidObj *) ObjData(vo); + if (v->del) + (*v->del) (v->ptr); + DohFree(v); +} + +/* ----------------------------------------------------------------------------- + * Void_copy() + * + * Copies a void object. This is only a shallow copy. The object destruction + * function is not copied in order to avoid potential double-free problems. + * ----------------------------------------------------------------------------- */ + +static DOH *Void_copy(DOH *vo) { + VoidObj *v = (VoidObj *) ObjData(vo); + return NewVoid(v->ptr, 0); +} + +/* ----------------------------------------------------------------------------- + * Void_data() + * + * Returns the void * stored in the object. + * ----------------------------------------------------------------------------- */ + +static void *Void_data(DOH *vo) { + VoidObj *v = (VoidObj *) ObjData(vo); + return v->ptr; +} + +static DohObjInfo DohVoidType = { + "VoidObj", /* objname */ + Void_delete, /* doh_del */ + Void_copy, /* doh_copy */ + 0, /* doh_clear */ + 0, /* doh_str */ + Void_data, /* doh_data */ + 0, /* doh_dump */ + 0, /* doh_len */ + 0, /* doh_hash */ + 0, /* doh_cmp */ + 0, /* doh_equal */ + 0, /* doh_first */ + 0, /* doh_next */ + 0, /* doh_setfile */ + 0, /* doh_getfile */ + 0, /* doh_setline */ + 0, /* doh_getline */ + 0, /* doh_mapping */ + 0, /* doh_sequence */ + 0, /* doh_file */ + 0, /* doh_string */ + 0, /* doh_reserved */ + 0, /* clientdata */ +}; + +/* ----------------------------------------------------------------------------- + * NewVoid() + * + * Creates a new Void object given a void * and an optional destructor function. + * ----------------------------------------------------------------------------- */ + +DOH *DohNewVoid(void *obj, void (*del) (void *)) { + VoidObj *v; + v = (VoidObj *) DohMalloc(sizeof(VoidObj)); + v->ptr = obj; + v->del = del; + return DohObjMalloc(&DohVoidType, v); +} diff --git a/Source/Include/swigconfig.h.in b/Source/Include/swigconfig.h.in new file mode 100644 index 0000000..7b1a023 --- /dev/null +++ b/Source/Include/swigconfig.h.in @@ -0,0 +1,93 @@ +/* Source/Include/swigconfig.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the system has the type `bool'. */ +#undef HAVE_BOOL + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `dl' library (-ldl). */ +#undef HAVE_LIBDL + +/* Define to 1 if you have the `dld' library (-ldld). */ +#undef HAVE_LIBDLD + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if popen is available */ +#undef HAVE_POPEN + +/* Define if rxspencer is available */ +#undef HAVE_RXSPENCER + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Compiler that built SWIG */ +#undef SWIG_CXX + +/* Directory for SWIG system-independent libraries */ +#undef SWIG_LIB + +/* Directory for SWIG system-independent libraries (Unix install on native + Windows) */ +#undef SWIG_LIB_WIN_UNIX + +/* Platform that SWIG is built for */ +#undef SWIG_PLATFORM + +/* Version number of package */ +#undef VERSION + + +/* Default language */ +#define SWIG_LANG "-tcl" + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if defined(_MSC_VER) +# define _CRT_SECURE_NO_DEPRECATE +#endif + diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h new file mode 100644 index 0000000..194cf49 --- /dev/null +++ b/Source/Include/swigwarn.h @@ -0,0 +1,261 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigwarn.h + * + * SWIG warning message numbers + * This file serves as the main registry of warning message numbers. Some of these + * numbers are used internally in the C/C++ source code of SWIG. However, some + * of the numbers are used in SWIG configuration files (swig.swg and others). + * + * The numbers are roughly organized into a few different classes by functionality. + * + * Even though symbolic constants are used in the SWIG source, this is + * not always the case in SWIG interface files. Do not change the + * numbers in this file. + * ----------------------------------------------------------------------------- */ + +/* $Id: swigwarn.h 11459 2009-07-28 11:47:36Z vmiklos $ */ + +#ifndef SWIGWARN_H_ +#define SWIGWARN_H_ + +#define WARN_NONE 0 + +/* -- Deprecated features -- */ + +#define WARN_DEPRECATED_EXTERN 101 +#define WARN_DEPRECATED_VAL 102 +#define WARN_DEPRECATED_OUT 103 +#define WARN_DEPRECATED_DISABLEDOC 104 +#define WARN_DEPRECATED_ENABLEDOC 105 +#define WARN_DEPRECATED_DOCONLY 106 +#define WARN_DEPRECATED_STYLE 107 +#define WARN_DEPRECATED_LOCALSTYLE 108 +#define WARN_DEPRECATED_TITLE 109 +#define WARN_DEPRECATED_SECTION 110 +#define WARN_DEPRECATED_SUBSECTION 111 +#define WARN_DEPRECATED_SUBSUBSECTION 112 +#define WARN_DEPRECATED_ADDMETHODS 113 +#define WARN_DEPRECATED_READONLY 114 +#define WARN_DEPRECATED_READWRITE 115 +#define WARN_DEPRECATED_EXCEPT 116 +#define WARN_DEPRECATED_NEW 117 +#define WARN_DEPRECATED_EXCEPT_TM 118 +#define WARN_DEPRECATED_IGNORE_TM 119 +#define WARN_DEPRECATED_OPTC 120 +#define WARN_DEPRECATED_NAME 121 +#define WARN_DEPRECATED_NOEXTERN 122 +#define WARN_DEPRECATED_NODEFAULT 123 +#define WARN_DEPRECATED_TYPEMAP_LANG 124 +#define WARN_DEPRECATED_INPUT_FILE 125 + +/* -- Preprocessor -- */ + +#define WARN_PP_MISSING_FILE 201 +#define WARN_PP_EVALUATION 202 +#define WARN_PP_INCLUDEALL_IMPORTALL 203 +#define WARN_PP_CPP_WARNING 204 +#define WARN_PP_CPP_ERROR 205 + +/* -- C/C++ Parser -- */ + +#define WARN_PARSE_CLASS_KEYWORD 301 +#define WARN_PARSE_REDEFINED 302 +#define WARN_PARSE_EXTEND_UNDEF 303 +#define WARN_PARSE_UNSUPPORTED_VALUE 304 +#define WARN_PARSE_BAD_VALUE 305 +#define WARN_PARSE_PRIVATE 306 +#define WARN_PARSE_BAD_DEFAULT 307 +#define WARN_PARSE_NAMESPACE_ALIAS 308 +#define WARN_PARSE_PRIVATE_INHERIT 309 +#define WARN_PARSE_TEMPLATE_REPEAT 310 +#define WARN_PARSE_TEMPLATE_PARTIAL 311 +#define WARN_PARSE_NESTED_CLASS 312 +#define WARN_PARSE_UNDEFINED_EXTERN 313 +#define WARN_PARSE_KEYWORD 314 +#define WARN_PARSE_USING_UNDEF 315 +#define WARN_PARSE_MODULE_REPEAT 316 +#define WARN_PARSE_TEMPLATE_SP_UNDEF 317 +#define WARN_PARSE_TEMPLATE_AMBIG 318 +#define WARN_PARSE_NO_ACCESS 319 +#define WARN_PARSE_EXPLICIT_TEMPLATE 320 +#define WARN_PARSE_BUILTIN_NAME 321 +#define WARN_PARSE_REDUNDANT 322 +#define WARN_PARSE_REC_INHERITANCE 323 + +#define WARN_IGNORE_OPERATOR_NEW 350 /* new */ +#define WARN_IGNORE_OPERATOR_DELETE 351 /* delete */ +#define WARN_IGNORE_OPERATOR_PLUS 352 /* + */ +#define WARN_IGNORE_OPERATOR_MINUS 353 /* - */ +#define WARN_IGNORE_OPERATOR_MUL 354 /* * */ +#define WARN_IGNORE_OPERATOR_DIV 355 /* / */ +#define WARN_IGNORE_OPERATOR_MOD 356 /* % */ +#define WARN_IGNORE_OPERATOR_XOR 357 /* ^ */ +#define WARN_IGNORE_OPERATOR_AND 358 /* & */ +#define WARN_IGNORE_OPERATOR_OR 359 /* | */ +#define WARN_IGNORE_OPERATOR_NOT 360 /* ~ */ +#define WARN_IGNORE_OPERATOR_LNOT 361 /* ! */ +#define WARN_IGNORE_OPERATOR_EQ 362 /* = */ +#define WARN_IGNORE_OPERATOR_LT 363 /* < */ +#define WARN_IGNORE_OPERATOR_GT 364 /* > */ +#define WARN_IGNORE_OPERATOR_PLUSEQ 365 /* += */ +#define WARN_IGNORE_OPERATOR_MINUSEQ 366 /* -= */ +#define WARN_IGNORE_OPERATOR_MULEQ 367 /* *= */ +#define WARN_IGNORE_OPERATOR_DIVEQ 368 /* /= */ +#define WARN_IGNORE_OPERATOR_MODEQ 369 /* %= */ +#define WARN_IGNORE_OPERATOR_XOREQ 370 /* ^= */ +#define WARN_IGNORE_OPERATOR_ANDEQ 371 /* &= */ +#define WARN_IGNORE_OPERATOR_OREQ 372 /* |= */ +#define WARN_IGNORE_OPERATOR_LSHIFT 373 /* << */ +#define WARN_IGNORE_OPERATOR_RSHIFT 374 /* >> */ +#define WARN_IGNORE_OPERATOR_LSHIFTEQ 375 /* <<= */ +#define WARN_IGNORE_OPERATOR_RSHIFTEQ 376 /* >>= */ +#define WARN_IGNORE_OPERATOR_EQUALTO 377 /* == */ +#define WARN_IGNORE_OPERATOR_NOTEQUAL 378 /* != */ +#define WARN_IGNORE_OPERATOR_LTEQUAL 379 /* <= */ +#define WARN_IGNORE_OPERATOR_GTEQUAL 380 /* >= */ +#define WARN_IGNORE_OPERATOR_LAND 381 /* && */ +#define WARN_IGNORE_OPERATOR_LOR 382 /* || */ +#define WARN_IGNORE_OPERATOR_PLUSPLUS 383 /* ++ */ +#define WARN_IGNORE_OPERATOR_MINUSMINUS 384 /* -- */ +#define WARN_IGNORE_OPERATOR_COMMA 385 /* , */ +#define WARN_IGNORE_OPERATOR_ARROWSTAR 386 /* ->* */ +#define WARN_IGNORE_OPERATOR_ARROW 387 /* -> */ +#define WARN_IGNORE_OPERATOR_CALL 388 /* () */ +#define WARN_IGNORE_OPERATOR_INDEX 389 /* [] */ +#define WARN_IGNORE_OPERATOR_UPLUS 390 /* + */ +#define WARN_IGNORE_OPERATOR_UMINUS 391 /* - */ +#define WARN_IGNORE_OPERATOR_UMUL 392 /* * */ +#define WARN_IGNORE_OPERATOR_UAND 393 /* & */ +#define WARN_IGNORE_OPERATOR_NEWARR 394 /* new [] */ +#define WARN_IGNORE_OPERATOR_DELARR 395 /* delete [] */ +#define WARN_IGNORE_OPERATOR_REF 396 /* operator *() */ + +/* 394-399 are reserved */ + +/* -- Type system and typemaps -- */ + +#define WARN_TYPE_UNDEFINED_CLASS 401 +#define WARN_TYPE_INCOMPLETE 402 +#define WARN_TYPE_ABSTRACT 403 +#define WARN_TYPE_REDEFINED 404 + +#define WARN_TYPEMAP_SOURCETARGET 450 +#define WARN_TYPEMAP_CHARLEAK 451 +#define WARN_TYPEMAP_SWIGTYPE 452 +#define WARN_TYPEMAP_APPLY_UNDEF 453 +#define WARN_TYPEMAP_SWIGTYPELEAK 454 + +#define WARN_TYPEMAP_IN_UNDEF 460 +#define WARN_TYPEMAP_OUT_UNDEF 461 +#define WARN_TYPEMAP_VARIN_UNDEF 462 +#define WARN_TYPEMAP_VAROUT_UNDEF 463 +#define WARN_TYPEMAP_CONST_UNDEF 464 +#define WARN_TYPEMAP_UNDEF 465 +#define WARN_TYPEMAP_VAR_UNDEF 466 +#define WARN_TYPEMAP_TYPECHECK 467 +#define WARN_TYPEMAP_THROW 468 +#define WARN_TYPEMAP_DIRECTORIN_UNDEF 469 +#define WARN_TYPEMAP_THREAD_UNSAFE 470 /* mostly used in directorout typemaps */ +#define WARN_TYPEMAP_DIRECTOROUT_UNDEF 471 +#define WARN_TYPEMAP_TYPECHECK_UNDEF 472 +#define WARN_TYPEMAP_DIRECTOROUT_PTR 473 +#define WARN_TYPEMAP_OUT_OPTIMAL_IGNORED 474 +#define WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE 475 + +/* -- Fragments -- */ +#define WARN_FRAGMENT_NOT_FOUND 490 + +/* -- General code generation -- */ + +#define WARN_LANG_OVERLOAD_DECL 501 +#define WARN_LANG_OVERLOAD_CONSTRUCT 502 +#define WARN_LANG_IDENTIFIER 503 +#define WARN_LANG_RETURN_TYPE 504 +#define WARN_LANG_VARARGS 505 +#define WARN_LANG_VARARGS_KEYWORD 506 +#define WARN_LANG_NATIVE_UNIMPL 507 +#define WARN_LANG_DEREF_SHADOW 508 +#define WARN_LANG_OVERLOAD_SHADOW 509 +#define WARN_LANG_FRIEND_IGNORE 510 +#define WARN_LANG_OVERLOAD_KEYWORD 511 +#define WARN_LANG_OVERLOAD_CONST 512 +#define WARN_LANG_CLASS_UNNAMED 513 +#define WARN_LANG_DIRECTOR_VDESTRUCT 514 +#define WARN_LANG_DISCARD_CONST 515 +#define WARN_LANG_OVERLOAD_IGNORED 516 +#define WARN_LANG_DIRECTOR_ABSTRACT 517 +#define WARN_LANG_PORTABILITY_FILENAME 518 +#define WARN_LANG_TEMPLATE_METHOD_IGNORE 519 + +/* -- Reserved (600-799) -- */ + +/* -- Language module specific warnings (800 - 999) -- */ + +#define WARN_RUBY_WRONG_NAME 801 +#define WARN_RUBY_MULTIPLE_INHERITANCE 802 + +#define WARN_JAVA_TYPEMAP_JNI_UNDEF 810 +#define WARN_JAVA_TYPEMAP_JTYPE_UNDEF 811 +#define WARN_JAVA_TYPEMAP_JSTYPE_UNDEF 812 +#define WARN_JAVA_MULTIPLE_INHERITANCE 813 +#define WARN_JAVA_TYPEMAP_GETCPTR_UNDEF 814 +#define WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF 815 +#define WARN_JAVA_TYPEMAP_JAVABODY_UNDEF 816 +#define WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF 817 +#define WARN_JAVA_TYPEMAP_JAVAIN_UNDEF 818 +#define WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF 819 +#define WARN_JAVA_TYPEMAP_JAVADIRECTOROUT_UNDEF 820 +#define WARN_JAVA_COVARIANT_RET 822 +#define WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF 823 +#define WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC 824 +#define WARN_JAVA_NO_DIRECTORCONNECT_ATTR 825 + +/* please leave 810-829 free for Java */ + +#define WARN_CSHARP_TYPEMAP_CTYPE_UNDEF 830 +#define WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF 831 +#define WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF 832 +#define WARN_CSHARP_MULTIPLE_INHERITANCE 833 +#define WARN_CSHARP_TYPEMAP_GETCPTR_UNDEF 834 +#define WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF 835 +#define WARN_CSHARP_TYPEMAP_CSBODY_UNDEF 836 +#define WARN_CSHARP_TYPEMAP_CSOUT_UNDEF 837 +#define WARN_CSHARP_TYPEMAP_CSIN_UNDEF 838 +#define WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF 839 +#define WARN_CSHARP_TYPEMAP_CSDIRECTOROUT_UNDEF 840 +#define WARN_CSHARP_COVARIANT_RET 842 +#define WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF 843 +#define WARN_CSHARP_EXCODE 844 +#define WARN_CSHARP_CANTHROW 845 +#define WARN_CSHARP_NO_DIRECTORCONNECT_ATTR 846 + +/* please leave 830-849 free for C# */ + +#define WARN_MODULA3_TYPEMAP_TYPE_UNDEF 850 +#define WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF 851 +#define WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF 852 +#define WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF 853 +#define WARN_MODULA3_TYPEMAP_MULTIPLE_RETURN 854 +#define WARN_MODULA3_MULTIPLE_INHERITANCE 855 +#define WARN_MODULA3_TYPECONSTRUCTOR_UNKNOWN 856 +#define WARN_MODULA3_UNKNOWN_PRAGMA 857 +#define WARN_MODULA3_BAD_ENUMERATION 858 +#define WARN_MODULA3_DOUBLE_ID 859 +#define WARN_MODULA3_BAD_IMPORT 860 + +/* please leave 850-869 free for Modula 3 */ + +#define WARN_PHP_MULTIPLE_INHERITANCE 870 +#define WARN_PHP_UNKNOWN_PRAGMA 871 +#define WARN_PHP_PUBLIC_BASE 872 + +/* please leave 870-889 free for PHP */ + + +/* Feel free to claim any number in this space that's not currently being used. Just make sure you + add an entry here */ + +#endif diff --git a/Source/Makefile.am b/Source/Makefile.am new file mode 100644 index 0000000..aadf50d --- /dev/null +++ b/Source/Makefile.am @@ -0,0 +1,144 @@ +## Process this file with automake to produce Makefile.in + +# subdir-objects generates object files using the directory structure of the source files. +AUTOMAKE_OPTIONS = foreign nostdinc subdir-objects 1.7.2 + +SOURCE_DIR=$(top_srcdir)/Source +BUILD_SOURCE_DIR=$(top_builddir)/Source + +SWIG_CXX_DEFS = @SWILL@ + +AM_CPPFLAGS = -I$(BUILD_SOURCE_DIR)/Include \ + -I$(BUILD_SOURCE_DIR)/CParse \ + -I$(SOURCE_DIR)/Include \ + -I$(SOURCE_DIR)/DOH \ + -I$(SOURCE_DIR)/CParse \ + -I$(SOURCE_DIR)/Preprocessor \ + -I$(SOURCE_DIR)/Swig \ + -I$(SOURCE_DIR)/Modules + +AM_CXXFLAGS = $(SWIG_CXX_DEFS) + +AM_YFLAGS = -d + +BUILT_SOURCES = CParse/parser.h +eswig_SOURCES = CParse/cscanner.c \ + CParse/parser.y \ + CParse/templ.c \ + CParse/util.c \ + DOH/base.c \ + DOH/file.c \ + DOH/fio.c \ + DOH/hash.c \ + DOH/list.c \ + DOH/memory.c \ + DOH/string.c \ + DOH/void.c \ + Modules/allegrocl.cxx \ + Modules/allocate.cxx \ + Modules/browser.cxx \ + Modules/cffi.cxx \ + Modules/chicken.cxx \ + Modules/clisp.cxx \ + Modules/contract.cxx \ + Modules/csharp.cxx \ + Modules/directors.cxx \ + Modules/emit.cxx \ + Modules/guile.cxx \ + Modules/java.cxx \ + Modules/lang.cxx \ + Modules/lua.cxx \ + Modules/main.cxx \ + Modules/modula3.cxx \ + Modules/module.cxx \ + Modules/mzscheme.cxx \ + Modules/ocaml.cxx \ + Modules/octave.cxx \ + Modules/overload.cxx \ + Modules/perl5.cxx \ + Modules/php.cxx \ + Modules/pike.cxx \ + Modules/python.cxx \ + Modules/r.cxx \ + Modules/ruby.cxx \ + Modules/s-exp.cxx \ + Modules/swigmain.cxx \ + Modules/tcl8.cxx \ + Modules/typepass.cxx \ + Modules/uffi.cxx \ + Modules/utils.cxx \ + Modules/xml.cxx \ + Preprocessor/cpp.c \ + Preprocessor/expr.c \ + Swig/cwrap.c \ + Swig/deprecate.c \ + Swig/error.c \ + Swig/fragment.c \ + Swig/getopt.c \ + Swig/include.c \ + Swig/misc.c \ + Swig/naming.c \ + Swig/parms.c \ + Swig/scanner.c \ + Swig/stype.c \ + Swig/symbol.c \ + Swig/tree.c \ + Swig/typeobj.c \ + Swig/typemap.c \ + Swig/typesys.c \ + Swig/warn.c \ + Swig/wrapfunc.c + +bin_PROGRAMS = eswig +eswig_LDADD = @SWIGLIBS@ + +# Override the link stage to avoid using Libtool +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ + +# The executable is copied to the root directory for installation and running the test-suite. +# This occurs on each invocation of make and is a step towards providing support for multiple +# build directories. +all-local: eswig@EXEEXT@ + cp -f $(top_builddir)/Source/eswig@EXEEXT@ $(top_builddir)/swig@EXEEXT@ + +clean-local: + rm -f $(top_builddir)/swig@EXEEXT@ + rm -f core @EXTRA_CLEAN@ + + +# Beautify the code. +# Note that this works well on C code, but does some odd joining of lines for C++ code. +# Compiling with -DNDEBUG and no optimisations will allow one to do a binary diff of the +# swig executable as a way of checking before and after the 'beautifying'. +# Single files can be beautified with the beautify-file target, eg: 'make beautify-file INDENTFILE=chosenfile.c' + +SWIGTYPEDEFS=-T File -T DohObjInfo -T Parm -T Language -T List -T Typetab -T ModuleFactory -T ErrorMessageFormat -T Symtab -T Hash -T String -T DohBase -T Node -T String_or_char -T SwigType -T Dispatcher -T Wrapper -T DohStringMethods -T DohFileMethods -T DohListMethods -T DohHashMethods -T DOH -T DohIterator -T ParmList -T FILE -T HashNode -T DOHString_or_char +INDENTBAKSDIR=../IndentBaks + +beautify: + rm -rf $(INDENTBAKSDIR) + mkdir $(INDENTBAKSDIR) + mkdir $(INDENTBAKSDIR)/CParse + mkdir $(INDENTBAKSDIR)/DOH + mkdir $(INDENTBAKSDIR)/Modules + mkdir $(INDENTBAKSDIR)/Preprocessor + mkdir $(INDENTBAKSDIR)/Swig + mkdir $(INDENTBAKSDIR)/Include + (csources=`find . -name "*.c"` && \ + hsources=`find . -name "*.h"` && \ + cxxsources=`find . -name "*.cxx"` && \ + for file in $$csources $$hsources $$cxxsources; do \ + $(MAKE) beautify-file INDENTFILE=$$file; \ + done; ) + +beautify-file: + test -e $(INDENTBAKSDIR) || (echo $(INDENTBAKSDIR) directory does not exist && exit 1;) + test -n "$(INDENTFILE)" || (echo INDENTFILE not defined && exit 1;) + test -e $(INDENTFILE) || (echo File does not exist: $(INDENTFILE) && exit 1;) + cp $(INDENTFILE) $(INDENTBAKSDIR)/$(INDENTFILE); + unix2dos $(INDENTFILE) + dos2unix $(INDENTFILE) + indent -kr --honour-newlines --line-length160 --indent-level2 --braces-on-func-def-line --leave-optional-blank-lines $(SWIGTYPEDEFS) $(INDENTFILE) -o $(INDENTFILE).tmp; + cat $(INDENTFILE).tmp | sed -e 's/const const /const /' > $(INDENTFILE); + rm $(INDENTFILE).tmp; + diff --git a/Source/Makefile.in b/Source/Makefile.in new file mode 100644 index 0000000..d165ede --- /dev/null +++ b/Source/Makefile.in @@ -0,0 +1,1072 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = eswig$(EXEEXT) +subdir = Source +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + CParse/parser.c CParse/parser.h +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = \ + $(top_srcdir)/Tools/config/ac_compare_version.m4 \ + $(top_srcdir)/Tools/config/ac_compile_warnings.m4 \ + $(top_srcdir)/Tools/config/ac_define_dir.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/Source/Include/swigconfig.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am__dirstamp = $(am__leading_dot)dirstamp +am_eswig_OBJECTS = CParse/cscanner.$(OBJEXT) CParse/parser.$(OBJEXT) \ + CParse/templ.$(OBJEXT) CParse/util.$(OBJEXT) \ + DOH/base.$(OBJEXT) DOH/file.$(OBJEXT) DOH/fio.$(OBJEXT) \ + DOH/hash.$(OBJEXT) DOH/list.$(OBJEXT) DOH/memory.$(OBJEXT) \ + DOH/string.$(OBJEXT) DOH/void.$(OBJEXT) \ + Modules/allegrocl.$(OBJEXT) Modules/allocate.$(OBJEXT) \ + Modules/browser.$(OBJEXT) Modules/cffi.$(OBJEXT) \ + Modules/chicken.$(OBJEXT) Modules/clisp.$(OBJEXT) \ + Modules/contract.$(OBJEXT) Modules/csharp.$(OBJEXT) \ + Modules/directors.$(OBJEXT) Modules/emit.$(OBJEXT) \ + Modules/guile.$(OBJEXT) Modules/java.$(OBJEXT) \ + Modules/lang.$(OBJEXT) Modules/lua.$(OBJEXT) \ + Modules/main.$(OBJEXT) Modules/modula3.$(OBJEXT) \ + Modules/module.$(OBJEXT) Modules/mzscheme.$(OBJEXT) \ + Modules/ocaml.$(OBJEXT) Modules/octave.$(OBJEXT) \ + Modules/overload.$(OBJEXT) Modules/perl5.$(OBJEXT) \ + Modules/php.$(OBJEXT) Modules/pike.$(OBJEXT) \ + Modules/python.$(OBJEXT) Modules/r.$(OBJEXT) \ + Modules/ruby.$(OBJEXT) Modules/s-exp.$(OBJEXT) \ + Modules/swigmain.$(OBJEXT) Modules/tcl8.$(OBJEXT) \ + Modules/typepass.$(OBJEXT) Modules/uffi.$(OBJEXT) \ + Modules/utils.$(OBJEXT) Modules/xml.$(OBJEXT) \ + Preprocessor/cpp.$(OBJEXT) Preprocessor/expr.$(OBJEXT) \ + Swig/cwrap.$(OBJEXT) Swig/deprecate.$(OBJEXT) \ + Swig/error.$(OBJEXT) Swig/fragment.$(OBJEXT) \ + Swig/getopt.$(OBJEXT) Swig/include.$(OBJEXT) \ + Swig/misc.$(OBJEXT) Swig/naming.$(OBJEXT) Swig/parms.$(OBJEXT) \ + Swig/scanner.$(OBJEXT) Swig/stype.$(OBJEXT) \ + Swig/symbol.$(OBJEXT) Swig/tree.$(OBJEXT) \ + Swig/typeobj.$(OBJEXT) Swig/typemap.$(OBJEXT) \ + Swig/typesys.$(OBJEXT) Swig/warn.$(OBJEXT) \ + Swig/wrapfunc.$(OBJEXT) +eswig_OBJECTS = $(am_eswig_OBJECTS) +eswig_DEPENDENCIES = +DEFAULT_INCLUDES = +depcomp = $(SHELL) $(top_srcdir)/Tools/config/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +YLWRAP = $(top_srcdir)/Tools/config/ylwrap +SOURCES = $(eswig_SOURCES) +DIST_SOURCES = $(eswig_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLEGROCLBIN = @ALLEGROCLBIN@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CCSHARED = @CCSHARED@ +CFLAGS = @CFLAGS@ +CHICKEN = @CHICKEN@ +CHICKENLIB = @CHICKENLIB@ +CHICKENOPTS = @CHICKENOPTS@ +CHICKENSHAREDLIB = @CHICKENSHAREDLIB@ +CHICKEN_CSC = @CHICKEN_CSC@ +CHICKEN_CSI = @CHICKEN_CSI@ +CLISPBIN = @CLISPBIN@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CSHARPCFLAGS = @CSHARPCFLAGS@ +CSHARPCILINTERPRETER = @CSHARPCILINTERPRETER@ +CSHARPCOMPILER = @CSHARPCOMPILER@ +CSHARPCYGPATH_W = @CSHARPCYGPATH_W@ +CSHARPDYNAMICLINKING = @CSHARPDYNAMICLINKING@ +CSHARPLIBRARYPREFIX = @CSHARPLIBRARYPREFIX@ +CSHARPPATHSEPARATOR = @CSHARPPATHSEPARATOR@ +CSHARPSO = @CSHARPSO@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXSHARED = @CXXSHARED@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENABLE_CCACHE = @ENABLE_CCACHE@ +EXEEXT = @EXEEXT@ +EXTRA_CLEAN = @EXTRA_CLEAN@ +GCJ = @GCJ@ +GCJH = @GCJH@ +GREP = @GREP@ +GUILE = @GUILE@ +GUILEINCLUDE = @GUILEINCLUDE@ +GUILELIB = @GUILELIB@ +GUILELINK = @GUILELINK@ +GUILE_CONFIG = @GUILE_CONFIG@ +GUILE_GH_INTERFACE = @GUILE_GH_INTERFACE@ +GUILE_SCM_INTERFACE = @GUILE_SCM_INTERFACE@ +GUILE_SO = @GUILE_SO@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAVA = @JAVA@ +JAVAC = @JAVAC@ +JAVACFLAGS = @JAVACFLAGS@ +JAVACXXSHARED = @JAVACXXSHARED@ +JAVADYNAMICLINKING = @JAVADYNAMICLINKING@ +JAVAINC = @JAVAINC@ +JAVALDSHARED = @JAVALDSHARED@ +JAVALIBRARYPREFIX = @JAVALIBRARYPREFIX@ +JAVASO = @JAVASO@ +LDFLAGS = @LDFLAGS@ +LDSHARED = @LDSHARED@ +LIBC = @LIBC@ +LIBCRYPT = @LIBCRYPT@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LINKFORSHARED = @LINKFORSHARED@ +LTLIBOBJS = @LTLIBOBJS@ +LUABIN = @LUABIN@ +LUADYNAMICLINKING = @LUADYNAMICLINKING@ +LUAFLAGS = @LUAFLAGS@ +LUALINK = @LUALINK@ +LUA_SO = @LUA_SO@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MZC = @MZC@ +MZDYNOBJ = @MZDYNOBJ@ +MZSCHEME = @MZSCHEME@ +MZSCHEME_SO = @MZSCHEME_SO@ +OBJEXT = @OBJEXT@ +OCAMLBIN = @OCAMLBIN@ +OCAMLC = @OCAMLC@ +OCAMLDLGEN = @OCAMLDLGEN@ +OCAMLFIND = @OCAMLFIND@ +OCAMLINC = @OCAMLINC@ +OCAMLLOC = @OCAMLLOC@ +OCAMLMKTOP = @OCAMLMKTOP@ +OCAMLVER = @OCAMLVER@ +OCTAVE = @OCTAVE@ +OCTAVECCFLAGS = @OCTAVECCFLAGS@ +OCTAVEDYNAMICLINKING = @OCTAVEDYNAMICLINKING@ +OCTAVEEXT = @OCTAVEEXT@ +OCTAVELIB = @OCTAVELIB@ +OCTAVE_SO = @OCTAVE_SO@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL5CCFLAGS = @PERL5CCFLAGS@ +PERL5DYNAMICLINKING = @PERL5DYNAMICLINKING@ +PERL5EXT = @PERL5EXT@ +PERL5LIB = @PERL5LIB@ +PHP = @PHP@ +PHPINC = @PHPINC@ +PHP_SO = @PHP_SO@ +PIKE = @PIKE@ +PIKECCDLFLAGS = @PIKECCDLFLAGS@ +PIKECONFIG = @PIKECONFIG@ +PIKEDYNAMICLINKING = @PIKEDYNAMICLINKING@ +PIKEINCLUDE = @PIKEINCLUDE@ +PLATFLAGS = @PLATFLAGS@ +PY3CONFIG = @PY3CONFIG@ +PY3INCLUDE = @PY3INCLUDE@ +PY3LIB = @PY3LIB@ +PY3LINK = @PY3LINK@ +PYINCLUDE = @PYINCLUDE@ +PYLIB = @PYLIB@ +PYLINK = @PYLINK@ +PYTHON = @PYTHON@ +PYTHON3 = @PYTHON3@ +PYTHON3DYNAMICLINKING = @PYTHON3DYNAMICLINKING@ +PYTHONDYNAMICLINKING = @PYTHONDYNAMICLINKING@ +PYTHON_SO = @PYTHON_SO@ +RANLIB = @RANLIB@ +RBIN = @RBIN@ +ROOT_DIR = @ROOT_DIR@ +RPATH = @RPATH@ +RUBY = @RUBY@ +RUBYCCDLFLAGS = @RUBYCCDLFLAGS@ +RUBYDYNAMICLINKING = @RUBYDYNAMICLINKING@ +RUBYINCLUDE = @RUBYINCLUDE@ +RUBYLIB = @RUBYLIB@ +RUBYLINK = @RUBYLINK@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SKIP_ALLEGROCL = @SKIP_ALLEGROCL@ +SKIP_CFFI = @SKIP_CFFI@ +SKIP_CHICKEN = @SKIP_CHICKEN@ +SKIP_CLISP = @SKIP_CLISP@ +SKIP_CSHARP = @SKIP_CSHARP@ +SKIP_GCJ = @SKIP_GCJ@ +SKIP_GUILE = @SKIP_GUILE@ +SKIP_GUILESCM = @SKIP_GUILESCM@ +SKIP_JAVA = @SKIP_JAVA@ +SKIP_LUA = @SKIP_LUA@ +SKIP_MODULA3 = @SKIP_MODULA3@ +SKIP_MZSCHEME = @SKIP_MZSCHEME@ +SKIP_OCAML = @SKIP_OCAML@ +SKIP_OCTAVE = @SKIP_OCTAVE@ +SKIP_PERL5 = @SKIP_PERL5@ +SKIP_PHP = @SKIP_PHP@ +SKIP_PIKE = @SKIP_PIKE@ +SKIP_PYTHON = @SKIP_PYTHON@ +SKIP_PYTHON3 = @SKIP_PYTHON3@ +SKIP_R = @SKIP_R@ +SKIP_RUBY = @SKIP_RUBY@ +SKIP_TCL = @SKIP_TCL@ +SKIP_UFFI = @SKIP_UFFI@ +SO = @SO@ +STRIP = @STRIP@ +SWIGLIBS = @SWIGLIBS@ +SWIG_LIB = @SWIG_LIB@ +SWILL = @SWILL@ +TCLCXXSHARED = @TCLCXXSHARED@ +TCLDYNAMICLINKING = @TCLDYNAMICLINKING@ +TCLINCLUDE = @TCLINCLUDE@ +TCLLDSHARED = @TCLLDSHARED@ +TCLLIB = @TCLLIB@ +TCL_SO = @TCL_SO@ +TRYLINKINGWITHCXX = @TRYLINKINGWITHCXX@ +VERSION = @VERSION@ +XINCLUDES = @XINCLUDES@ +XLIBSW = @XLIBSW@ +XMKMF = @XMKMF@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +YODL2HTML = @YODL2HTML@ +YODL2MAN = @YODL2MAN@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_aux_dir = @ac_aux_dir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +swig_lib = @swig_lib@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# subdir-objects generates object files using the directory structure of the source files. +AUTOMAKE_OPTIONS = foreign nostdinc subdir-objects 1.7.2 +SOURCE_DIR = $(top_srcdir)/Source +BUILD_SOURCE_DIR = $(top_builddir)/Source +SWIG_CXX_DEFS = @SWILL@ +AM_CPPFLAGS = -I$(BUILD_SOURCE_DIR)/Include \ + -I$(BUILD_SOURCE_DIR)/CParse \ + -I$(SOURCE_DIR)/Include \ + -I$(SOURCE_DIR)/DOH \ + -I$(SOURCE_DIR)/CParse \ + -I$(SOURCE_DIR)/Preprocessor \ + -I$(SOURCE_DIR)/Swig \ + -I$(SOURCE_DIR)/Modules + +AM_CXXFLAGS = $(SWIG_CXX_DEFS) +AM_YFLAGS = -d +BUILT_SOURCES = CParse/parser.h +eswig_SOURCES = CParse/cscanner.c \ + CParse/parser.y \ + CParse/templ.c \ + CParse/util.c \ + DOH/base.c \ + DOH/file.c \ + DOH/fio.c \ + DOH/hash.c \ + DOH/list.c \ + DOH/memory.c \ + DOH/string.c \ + DOH/void.c \ + Modules/allegrocl.cxx \ + Modules/allocate.cxx \ + Modules/browser.cxx \ + Modules/cffi.cxx \ + Modules/chicken.cxx \ + Modules/clisp.cxx \ + Modules/contract.cxx \ + Modules/csharp.cxx \ + Modules/directors.cxx \ + Modules/emit.cxx \ + Modules/guile.cxx \ + Modules/java.cxx \ + Modules/lang.cxx \ + Modules/lua.cxx \ + Modules/main.cxx \ + Modules/modula3.cxx \ + Modules/module.cxx \ + Modules/mzscheme.cxx \ + Modules/ocaml.cxx \ + Modules/octave.cxx \ + Modules/overload.cxx \ + Modules/perl5.cxx \ + Modules/php.cxx \ + Modules/pike.cxx \ + Modules/python.cxx \ + Modules/r.cxx \ + Modules/ruby.cxx \ + Modules/s-exp.cxx \ + Modules/swigmain.cxx \ + Modules/tcl8.cxx \ + Modules/typepass.cxx \ + Modules/uffi.cxx \ + Modules/utils.cxx \ + Modules/xml.cxx \ + Preprocessor/cpp.c \ + Preprocessor/expr.c \ + Swig/cwrap.c \ + Swig/deprecate.c \ + Swig/error.c \ + Swig/fragment.c \ + Swig/getopt.c \ + Swig/include.c \ + Swig/misc.c \ + Swig/naming.c \ + Swig/parms.c \ + Swig/scanner.c \ + Swig/stype.c \ + Swig/symbol.c \ + Swig/tree.c \ + Swig/typeobj.c \ + Swig/typemap.c \ + Swig/typesys.c \ + Swig/warn.c \ + Swig/wrapfunc.c + +eswig_LDADD = @SWIGLIBS@ + +# Override the link stage to avoid using Libtool +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ + +# Beautify the code. +# Note that this works well on C code, but does some odd joining of lines for C++ code. +# Compiling with -DNDEBUG and no optimisations will allow one to do a binary diff of the +# swig executable as a way of checking before and after the 'beautifying'. +# Single files can be beautified with the beautify-file target, eg: 'make beautify-file INDENTFILE=chosenfile.c' +SWIGTYPEDEFS = -T File -T DohObjInfo -T Parm -T Language -T List -T Typetab -T ModuleFactory -T ErrorMessageFormat -T Symtab -T Hash -T String -T DohBase -T Node -T String_or_char -T SwigType -T Dispatcher -T Wrapper -T DohStringMethods -T DohFileMethods -T DohListMethods -T DohHashMethods -T DOH -T DohIterator -T ParmList -T FILE -T HashNode -T DOHString_or_char +INDENTBAKSDIR = ../IndentBaks +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .cxx .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Source/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Source/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +CParse/$(am__dirstamp): + @$(MKDIR_P) CParse + @: > CParse/$(am__dirstamp) +CParse/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) CParse/$(DEPDIR) + @: > CParse/$(DEPDIR)/$(am__dirstamp) +CParse/cscanner.$(OBJEXT): CParse/$(am__dirstamp) \ + CParse/$(DEPDIR)/$(am__dirstamp) +CParse/parser.h: CParse/parser.c + @if test ! -f $@; then \ + rm -f CParse/parser.c; \ + $(MAKE) $(AM_MAKEFLAGS) CParse/parser.c; \ + else :; fi +CParse/parser.$(OBJEXT): CParse/$(am__dirstamp) \ + CParse/$(DEPDIR)/$(am__dirstamp) +CParse/templ.$(OBJEXT): CParse/$(am__dirstamp) \ + CParse/$(DEPDIR)/$(am__dirstamp) +CParse/util.$(OBJEXT): CParse/$(am__dirstamp) \ + CParse/$(DEPDIR)/$(am__dirstamp) +DOH/$(am__dirstamp): + @$(MKDIR_P) DOH + @: > DOH/$(am__dirstamp) +DOH/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) DOH/$(DEPDIR) + @: > DOH/$(DEPDIR)/$(am__dirstamp) +DOH/base.$(OBJEXT): DOH/$(am__dirstamp) DOH/$(DEPDIR)/$(am__dirstamp) +DOH/file.$(OBJEXT): DOH/$(am__dirstamp) DOH/$(DEPDIR)/$(am__dirstamp) +DOH/fio.$(OBJEXT): DOH/$(am__dirstamp) DOH/$(DEPDIR)/$(am__dirstamp) +DOH/hash.$(OBJEXT): DOH/$(am__dirstamp) DOH/$(DEPDIR)/$(am__dirstamp) +DOH/list.$(OBJEXT): DOH/$(am__dirstamp) DOH/$(DEPDIR)/$(am__dirstamp) +DOH/memory.$(OBJEXT): DOH/$(am__dirstamp) \ + DOH/$(DEPDIR)/$(am__dirstamp) +DOH/string.$(OBJEXT): DOH/$(am__dirstamp) \ + DOH/$(DEPDIR)/$(am__dirstamp) +DOH/void.$(OBJEXT): DOH/$(am__dirstamp) DOH/$(DEPDIR)/$(am__dirstamp) +Modules/$(am__dirstamp): + @$(MKDIR_P) Modules + @: > Modules/$(am__dirstamp) +Modules/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) Modules/$(DEPDIR) + @: > Modules/$(DEPDIR)/$(am__dirstamp) +Modules/allegrocl.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/allocate.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/browser.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/cffi.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/chicken.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/clisp.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/contract.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/csharp.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/directors.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/emit.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/guile.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/java.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/lang.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/lua.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/main.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/modula3.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/module.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/mzscheme.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/ocaml.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/octave.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/overload.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/perl5.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/php.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/pike.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/python.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/r.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/ruby.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/s-exp.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/swigmain.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/tcl8.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/typepass.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/uffi.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/utils.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Modules/xml.$(OBJEXT): Modules/$(am__dirstamp) \ + Modules/$(DEPDIR)/$(am__dirstamp) +Preprocessor/$(am__dirstamp): + @$(MKDIR_P) Preprocessor + @: > Preprocessor/$(am__dirstamp) +Preprocessor/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) Preprocessor/$(DEPDIR) + @: > Preprocessor/$(DEPDIR)/$(am__dirstamp) +Preprocessor/cpp.$(OBJEXT): Preprocessor/$(am__dirstamp) \ + Preprocessor/$(DEPDIR)/$(am__dirstamp) +Preprocessor/expr.$(OBJEXT): Preprocessor/$(am__dirstamp) \ + Preprocessor/$(DEPDIR)/$(am__dirstamp) +Swig/$(am__dirstamp): + @$(MKDIR_P) Swig + @: > Swig/$(am__dirstamp) +Swig/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) Swig/$(DEPDIR) + @: > Swig/$(DEPDIR)/$(am__dirstamp) +Swig/cwrap.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/deprecate.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/error.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/fragment.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/getopt.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/include.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/misc.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/naming.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/parms.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/scanner.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/stype.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/symbol.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/tree.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/typeobj.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/typemap.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/typesys.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/warn.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +Swig/wrapfunc.$(OBJEXT): Swig/$(am__dirstamp) \ + Swig/$(DEPDIR)/$(am__dirstamp) +eswig$(EXEEXT): $(eswig_OBJECTS) $(eswig_DEPENDENCIES) + @rm -f eswig$(EXEEXT) + $(CXXLINK) $(eswig_OBJECTS) $(eswig_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f CParse/cscanner.$(OBJEXT) + -rm -f CParse/parser.$(OBJEXT) + -rm -f CParse/templ.$(OBJEXT) + -rm -f CParse/util.$(OBJEXT) + -rm -f DOH/base.$(OBJEXT) + -rm -f DOH/file.$(OBJEXT) + -rm -f DOH/fio.$(OBJEXT) + -rm -f DOH/hash.$(OBJEXT) + -rm -f DOH/list.$(OBJEXT) + -rm -f DOH/memory.$(OBJEXT) + -rm -f DOH/string.$(OBJEXT) + -rm -f DOH/void.$(OBJEXT) + -rm -f Modules/allegrocl.$(OBJEXT) + -rm -f Modules/allocate.$(OBJEXT) + -rm -f Modules/browser.$(OBJEXT) + -rm -f Modules/cffi.$(OBJEXT) + -rm -f Modules/chicken.$(OBJEXT) + -rm -f Modules/clisp.$(OBJEXT) + -rm -f Modules/contract.$(OBJEXT) + -rm -f Modules/csharp.$(OBJEXT) + -rm -f Modules/directors.$(OBJEXT) + -rm -f Modules/emit.$(OBJEXT) + -rm -f Modules/guile.$(OBJEXT) + -rm -f Modules/java.$(OBJEXT) + -rm -f Modules/lang.$(OBJEXT) + -rm -f Modules/lua.$(OBJEXT) + -rm -f Modules/main.$(OBJEXT) + -rm -f Modules/modula3.$(OBJEXT) + -rm -f Modules/module.$(OBJEXT) + -rm -f Modules/mzscheme.$(OBJEXT) + -rm -f Modules/ocaml.$(OBJEXT) + -rm -f Modules/octave.$(OBJEXT) + -rm -f Modules/overload.$(OBJEXT) + -rm -f Modules/perl5.$(OBJEXT) + -rm -f Modules/php.$(OBJEXT) + -rm -f Modules/pike.$(OBJEXT) + -rm -f Modules/python.$(OBJEXT) + -rm -f Modules/r.$(OBJEXT) + -rm -f Modules/ruby.$(OBJEXT) + -rm -f Modules/s-exp.$(OBJEXT) + -rm -f Modules/swigmain.$(OBJEXT) + -rm -f Modules/tcl8.$(OBJEXT) + -rm -f Modules/typepass.$(OBJEXT) + -rm -f Modules/uffi.$(OBJEXT) + -rm -f Modules/utils.$(OBJEXT) + -rm -f Modules/xml.$(OBJEXT) + -rm -f Preprocessor/cpp.$(OBJEXT) + -rm -f Preprocessor/expr.$(OBJEXT) + -rm -f Swig/cwrap.$(OBJEXT) + -rm -f Swig/deprecate.$(OBJEXT) + -rm -f Swig/error.$(OBJEXT) + -rm -f Swig/fragment.$(OBJEXT) + -rm -f Swig/getopt.$(OBJEXT) + -rm -f Swig/include.$(OBJEXT) + -rm -f Swig/misc.$(OBJEXT) + -rm -f Swig/naming.$(OBJEXT) + -rm -f Swig/parms.$(OBJEXT) + -rm -f Swig/scanner.$(OBJEXT) + -rm -f Swig/stype.$(OBJEXT) + -rm -f Swig/symbol.$(OBJEXT) + -rm -f Swig/tree.$(OBJEXT) + -rm -f Swig/typemap.$(OBJEXT) + -rm -f Swig/typeobj.$(OBJEXT) + -rm -f Swig/typesys.$(OBJEXT) + -rm -f Swig/warn.$(OBJEXT) + -rm -f Swig/wrapfunc.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@CParse/$(DEPDIR)/cscanner.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@CParse/$(DEPDIR)/parser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@CParse/$(DEPDIR)/templ.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@CParse/$(DEPDIR)/util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/base.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/fio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/string.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@DOH/$(DEPDIR)/void.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/allegrocl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/allocate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/browser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/cffi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/chicken.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/clisp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/contract.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/csharp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/directors.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/emit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/guile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/java.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/lang.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/lua.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/modula3.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/mzscheme.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/ocaml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/octave.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/overload.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/perl5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/php.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/pike.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/python.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/r.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/ruby.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/s-exp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/swigmain.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/tcl8.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/typepass.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/uffi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Modules/$(DEPDIR)/xml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Preprocessor/$(DEPDIR)/cpp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Preprocessor/$(DEPDIR)/expr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/cwrap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/deprecate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/fragment.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/getopt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/include.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/misc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/naming.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/parms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/scanner.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/stype.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/symbol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/tree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/typemap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/typeobj.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/typesys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/warn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@Swig/$(DEPDIR)/wrapfunc.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ mv -f $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ mv -f $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cxx.o: +@am__fastdepCXX_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ mv -f $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cxx.obj: +@am__fastdepCXX_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ mv -f $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.y.c: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) all-local +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -rm -f CParse/$(DEPDIR)/$(am__dirstamp) + -rm -f CParse/$(am__dirstamp) + -rm -f DOH/$(DEPDIR)/$(am__dirstamp) + -rm -f DOH/$(am__dirstamp) + -rm -f Modules/$(DEPDIR)/$(am__dirstamp) + -rm -f Modules/$(am__dirstamp) + -rm -f Preprocessor/$(DEPDIR)/$(am__dirstamp) + -rm -f Preprocessor/$(am__dirstamp) + -rm -f Swig/$(DEPDIR)/$(am__dirstamp) + -rm -f Swig/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f CParse/parser.c + -rm -f CParse/parser.h + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-local mostlyclean-am + +distclean: distclean-am + -rm -rf CParse/$(DEPDIR) DOH/$(DEPDIR) Modules/$(DEPDIR) Preprocessor/$(DEPDIR) Swig/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf CParse/$(DEPDIR) DOH/$(DEPDIR) Modules/$(DEPDIR) Preprocessor/$(DEPDIR) Swig/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-binPROGRAMS clean-generic clean-local ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS + + +# The executable is copied to the root directory for installation and running the test-suite. +# This occurs on each invocation of make and is a step towards providing support for multiple +# build directories. +all-local: eswig@EXEEXT@ + cp -f $(top_builddir)/Source/eswig@EXEEXT@ $(top_builddir)/swig@EXEEXT@ + +clean-local: + rm -f $(top_builddir)/swig@EXEEXT@ + rm -f core @EXTRA_CLEAN@ + +beautify: + rm -rf $(INDENTBAKSDIR) + mkdir $(INDENTBAKSDIR) + mkdir $(INDENTBAKSDIR)/CParse + mkdir $(INDENTBAKSDIR)/DOH + mkdir $(INDENTBAKSDIR)/Modules + mkdir $(INDENTBAKSDIR)/Preprocessor + mkdir $(INDENTBAKSDIR)/Swig + mkdir $(INDENTBAKSDIR)/Include + (csources=`find . -name "*.c"` && \ + hsources=`find . -name "*.h"` && \ + cxxsources=`find . -name "*.cxx"` && \ + for file in $$csources $$hsources $$cxxsources; do \ + $(MAKE) beautify-file INDENTFILE=$$file; \ + done; ) + +beautify-file: + test -e $(INDENTBAKSDIR) || (echo $(INDENTBAKSDIR) directory does not exist && exit 1;) + test -n "$(INDENTFILE)" || (echo INDENTFILE not defined && exit 1;) + test -e $(INDENTFILE) || (echo File does not exist: $(INDENTFILE) && exit 1;) + cp $(INDENTFILE) $(INDENTBAKSDIR)/$(INDENTFILE); + unix2dos $(INDENTFILE) + dos2unix $(INDENTFILE) + indent -kr --honour-newlines --line-length160 --indent-level2 --braces-on-func-def-line --leave-optional-blank-lines $(SWIGTYPEDEFS) $(INDENTFILE) -o $(INDENTFILE).tmp; + cat $(INDENTFILE).tmp | sed -e 's/const const /const /' > $(INDENTFILE); + rm $(INDENTFILE).tmp; +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Source/Modules/README b/Source/Modules/README new file mode 100644 index 0000000..058779d --- /dev/null +++ b/Source/Modules/README @@ -0,0 +1,9 @@ +06/25/2002 + +This directory contains all of the SWIG language modules. Many of these +modules contain code that dates back to SWIG1.0. The module API has changed +a lot in the development releases so this is fairly messy. We're working on +cleaning it up, but you'll have to bear with us until it's done. + +-- Dave + diff --git a/Source/Modules/allegrocl.cxx b/Source/Modules/allegrocl.cxx new file mode 100644 index 0000000..d40538d --- /dev/null +++ b/Source/Modules/allegrocl.cxx @@ -0,0 +1,3222 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * allegrocl.cxx + * + * ALLEGROCL language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_allegrocl_cxx[] = "$Id: allegrocl.cxx 11471 2009-07-29 20:52:29Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +// #define ALLEGROCL_DEBUG +// #define ALLEGROCL_WRAP_DEBUG +// #define ALLEGROCL_TYPE_DEBUG +// #define ALLEGROCL_CLASS_DEBUG + +static File *f_cl = 0; +String *f_clhead = NewString(""); +String *f_clwrap = NewString("(swig-in-package ())\n\n"); +static File *f_begin; +static File *f_runtime; +static File *f_cxx_header = 0; +static File *f_cxx_wrapper = 0; + +static String *module_name = 0; +static String *swig_package = 0; + +const char *identifier_converter = "identifier-convert-null"; + +static bool CWrap = true; // generate wrapper file for C code by default. most correct. +static bool Generate_Wrapper = false; +static bool unique_swig_package = false; + +static SwigType *fwdref_ffi_type = NewString("__SWIGACL_FwdReference"); + +static String *current_namespace = NewString(""); +static String *current_package = NewString(""); +static Hash *defined_namespace_packages = NewHash(); +static Node *in_class = 0; + +static Node *first_linked_type = 0; +static Hash *defined_foreign_types = NewHash(); +static Hash *defined_foreign_ltypes = NewHash(); + +static String *anon_type_name = NewString("anontype"); +static int anon_type_count = 0; + +// stub +String *convert_literal(String *num_param, String *type, bool try_to_split = true); + +class ALLEGROCL:public Language { +public: + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int namespaceDeclaration(Node *n); + virtual int constructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int globalvariableHandler(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int classHandler(Node *n); + virtual int emit_one(Node *n); + virtual int enumDeclaration(Node *n); + virtual int enumvalueDeclaration(Node *n); + virtual int typedefHandler(Node *n); + virtual int classforwardDeclaration(Node *n); + virtual int templateDeclaration(Node *n); + virtual int validIdentifier(String *s); +private: + int emit_defun(Node *n, File *f_cl); + int emit_dispatch_defun(Node *n); + int emit_buffered_defuns(Node *n); + int cClassHandler(Node *n); + int cppClassHandler(Node *n); +}; +static ALLEGROCL *allegrocl = 0; + +static String *trim(String *str) { + char *c = Char(str); + while (*c != '\0' && isspace((int) *c)) + ++c; + String *result = NewString(c); + Chop(result); + return result; +} + +int is_integer(String *s) { + char *c = Char(s); + if (c[0] == '#' && (c[1] == 'x' || c[1] == 'o')) + c += 2; + + while (*c) { + if (!isdigit(*c)) + return 0; + c++; + } + return 1; +} + +String *class_from_class_or_class_ref(String *type) { + SwigType *stripped = SwigType_strip_qualifiers(type); + if (SwigType_isclass(stripped)) + return stripped; + + if (SwigType_ispointer(stripped) || SwigType_isreference(stripped)) { + // Printf(stderr,"It is a pointer/reference. Is it a class?\n"); + SwigType_pop(stripped); + if (SwigType_isclass(stripped)) { + return stripped; + } + } + return 0; +} + +String *lookup_defined_foreign_type(String *k) { + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Looking up defined type '%s'.\n Found: '%s'\n", k, Getattr(defined_foreign_types, k)); +#endif + + return Getattr(defined_foreign_types, k); +} + +String *listify_namespace(String *namespaze) { + if (Len(namespaze) == 0) + return NewString("()"); + String *result = NewStringf("(\"%s\")", namespaze); + Replaceall(result, "::", "\" \""); + return result; +} + +String *namespaced_name(Node *n, String *ns = current_namespace) { + + return NewStringf("%s%s%s", ns, (Len(ns) != 0) ? "::" : "", Getattr(n, "sym:name")); +} + +// "Namespace::Nested::Class2::Baz" -> "Baz" +static String *strip_namespaces(String *str) { + char *result = Char(str); + String *stripped_one; + while ((stripped_one = Strstr(result, "::"))) + result = Char(stripped_one) + 2; + return NewString(result); +} + +static String *namespace_of(String *str) { + char *p = Char(str); + char *start = Char(str); + char *result = 0; + String *stripped_one; + + while ((stripped_one = Strstr(p, "::"))) { + p = Char(stripped_one) + 2; + } + if (p > start) { + int len = p - start - 1; + result = (char *) malloc(len); + strncpy(result, start, len - 1); + result[len - 1] = 0; + } + return Char(result); +} + +void add_linked_type(Node *n) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Adding linked node of type: %s(%s) %s(%x)\n\n", nodeType(n), Getattr(n, "storage"), Getattr(n, "name"), n); + // Swig_print_node(n); +#endif + if (!first_linked_type) { + first_linked_type = n; + Setattr(n, "allegrocl:last_linked_type", n); + } else { + Node *t = Getattr(first_linked_type, "allegrocl:last_linked_type"); + Setattr(t, "allegrocl:next_linked_type", n); + Setattr(first_linked_type, "allegrocl:last_linked_type", n); + } +} + +void replace_linked_type(Node *old, Node *new_node) { + Node *prev = Getattr(old, "allegrocl:prev_linked_type"); + + Setattr(new_node, "allegrocl:next_linked_type", Getattr(old, "allegrocl:next_linked_type")); + if (prev) + Setattr(prev, "allegrocl:next_linked_type", new_node); + Delattr(old, "allegrocl:next_linked_type"); + Delattr(old, "allegrocl:prev_linked_type"); + + // check if we're replacing the first link. + if (first_linked_type == old) { + first_linked_type = new_node; + Setattr(first_linked_type, "allegrocl:last_linked_type", Getattr(old, "allegrocl:last_linked_type")); + } + // check if we're replacing the last link. + if (Getattr(first_linked_type, "allegrocl:last_linked_type") == old) + Setattr(first_linked_type, "allegrocl:last_linked_type", new_node); +} + +void insert_linked_type_at(Node *old, Node *new_node, int before = 1) { + Node *p = 0; + + if (!first_linked_type) { + add_linked_type(new_node); + return; + } + + if (!before) { + Setattr(new_node, "allegrocl:next_linked_type", Getattr(old, "allegrocl:next_linked_type")); + Setattr(old, "allegrocl:next_linked_type", new_node); + if (Getattr(first_linked_type, "allegrocl:last_linked_type") == old) + Setattr(first_linked_type, "allegrocl:last_linked_type", new_node); + } else { + Node *c = first_linked_type; + while (c) { + if (c == old) { + break; + } else { + p = c; + c = Getattr(c, "allegrocl:next_linked_type"); + } + } + if (c == old) { + Setattr(new_node, "allegrocl:next_linked_type", c); + if (first_linked_type == c) { + first_linked_type = new_node; + Setattr(first_linked_type, "allegrocl:last_linked_type", Getattr(c, "allegrocl:last_linked_type")); + Delattr(c, "allegrocl:last_linked_type"); + } + if (p) + Setattr(p, "allegrocl:next_linked_type", new_node); + } + } +} + +Node *find_linked_type_by_name(String *name) { + Node *p = 0; + Node *c = first_linked_type; + + // Printf(stderr,"in find_linked_type_by_name '%s'...", name); + while (c) { + String *key = Getattr(c, "name"); + if (!Strcmp(key, name)) { + break; + } else { + p = c; + c = Getattr(c, "allegrocl:next_linked_type"); + } + } + // Printf(stderr,"exit find_linked_type_by_name.\n"); + + if (p && c) + Setattr(c, "allegrocl:prev_linked_type", p); + // Printf(stderr,"find_linked_type_by_name: DONE\n"); + return c; +} + +Node *get_primary_synonym_of(Node *n) { + Node *p = Getattr(n, "allegrocl:synonym-of"); + Node *prim = n; + + // Printf(stderr, "getting primary synonym of %x\n", n); + while (p) { + // Printf(stderr, " found one! %x\n", p); + prim = p; + p = Getattr(p, "allegrocl:synonym-of"); + } + // Printf(stderr,"get_primary_syn: DONE. returning %s(%x)\n", Getattr(prim,"name"),prim); + return prim; +} + +void add_forward_referenced_type(Node *n, int overwrite = 0) { + String *k = Getattr(n, "name"); + String *name = Getattr(n, "sym:name"); + String *ns = listify_namespace(current_namespace); + + String *val = Getattr(defined_foreign_types, k); + + if (!val || overwrite) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Adding forward reference for %s (overwrite=%d)\n", k, overwrite); +#endif + Setattr(defined_foreign_types, Copy(k), NewString("forward-reference")); + + String *mangled_lname_gen = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", name, ns); + + Setattr(defined_foreign_ltypes, Copy(k), mangled_lname_gen); + // Printf(f_cl, ";; forward reference stub\n" + // "(swig-def-foreign-class \"%s\" (ff:foreign-pointer) (:class ))\n\n" + // , name); + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Linking forward reference type = %s(%x)\n", k, n); +#endif + add_linked_type(n); + } +} + +void add_defined_foreign_type(Node *n, int overwrite = 0, String *k = 0, + String *name = 0, String *ns = current_namespace) { + + String *val; + String *ns_list = listify_namespace(ns); + String *templated = n ? Getattr(n, "template") : 0; + String *cDeclName = n ? Getattr(n, "classDeclaration:name") : 0; + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "IN A-D-F-T. (n=%x, ow=%d, k=%s, name=%s, ns=%s\n", n, overwrite, k, name, ns); + Printf(stderr, " templated = '%x', classDecl = '%x'\n", templated, cDeclName); +#endif + if (n) { + if (!name) + name = Getattr(n, "sym:name"); + if (!name) + name = strip_namespaces(Getattr(n, "name")); + if (templated) { + k = namespaced_name(n); + } else { + String *kind_of_type = Getattr(n, "kind"); + + /* + For typedefs of the form: + + typedef struct __xxx { ... } xxx; + + behavior differs between C mode and C++ mode. + + C Mode: + add_defined_foreign_type will be called once via classHandler + to define the type for 'struct __xxx' and add the mapping from + 'struct __xxx' -> 'xxx' + + It will also be called once via typedefHandler to add the + mapping 'xxx' -> 'xxx' + + C++ Mode: + add_defined_foreign_type will be called once via classHandler + to define the type for 'xxx'. it also adds the mapping from + 'xxx' -> 'xxx' and also for 'struct xxx' -> 'xxx' + + In typedefHandler, we again try to add the mapping from + 'xxx' -> 'xxx', which already exists. This second mapping + is ignored. + + Both modes: + + All references to this typedef'd struct will appear in + generated lisp code as an objectd of type 'xxx'. For + non-typedef'd structs, the classHand mapping will be + + struct __xxx -> (swig-insert-id "__xxx") + */ + // Swig_print_node(n); + String *unnamed = Getattr(n, "unnamed"); + if (kind_of_type && (!Strcmp(kind_of_type, "struct") + || !Strcmp(kind_of_type, "union")) && cDeclName && !unnamed) { + k = NewStringf("%s %s", kind_of_type, cDeclName); + } else { + if (!Strcmp(nodeType(n), "enum") && unnamed) { + name = NewStringf("%s%d", anon_type_name, anon_type_count++); + k = NewStringf("enum %s", name); + Setattr(n, "allegrocl:name", name); + + } else { + k = k ? k : Getattr(n, "name"); + } + } + } + // Swig_print_node(n); + } + + if (SwigType_istemplate(name)) { + String *temp = strip_namespaces(SwigType_templateprefix(name)); + name = NewStringf("%s%s%s", temp, SwigType_templateargs(name), SwigType_templatesuffix(name)); + } + + val = lookup_defined_foreign_type(k); + + int is_fwd_ref = 0; + if (val) + is_fwd_ref = !Strcmp(val, "forward-reference"); + + if (!val || overwrite || is_fwd_ref) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Adding defined type '%s' = '%s' '%s' (overwrite=%d, in-class=%d)\n", k, ns, name, overwrite, in_class); +#endif + String *mangled_name_gen = NewStringf("#.(swig-insert-id \"%s\" %s :type :type)", name, ns_list); + String *mangled_lname_gen = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", name, ns_list); + + Setattr(defined_foreign_types, Copy(k), Copy(mangled_name_gen)); + Setattr(defined_foreign_ltypes, Copy(k), Copy(mangled_lname_gen)); + + if (CPlusPlus) { + bool cpp_struct = Strstr(k, "struct ") ? true : false; + bool cpp_union = Strstr(k, "union ") ? true : false; + + String *cpp_type = 0; + if (cpp_struct) { + cpp_type = Copy(k); + Replaceall(cpp_type, "struct ", ""); + } else if (cpp_union) { + cpp_type = Copy(k); + Replaceall(cpp_type, "union ", ""); + } + + if (cpp_struct || cpp_union) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " Also adding defined type '%s' = '%s' '%s' (overwrite=%d)\n", cpp_type, ns, name, overwrite); +#endif + Setattr(defined_foreign_types, Copy(cpp_type), Copy(mangled_name_gen)); + Setattr(defined_foreign_ltypes, Copy(cpp_type), Copy(mangled_lname_gen)); + } + } +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "looking to add %s/%s(%x) to linked_type_list...\n", k, name, n); +#endif + if (is_fwd_ref) { + // Printf(stderr,"*** 1\n"); + add_linked_type(n); + } else { + // Printf(stderr,"*** 1-a\n"); + if (SwigType_istemplate(k)) { + SwigType *resolved = SwigType_typedef_resolve_all(k); + // Printf(stderr,"*** 1-b\n"); + Node *match = find_linked_type_by_name(resolved); + Node *new_node = 0; + // Printf(stderr, "*** temp-1\n"); + if (n) { + new_node = n; + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Creating a new templateInst:\n"); + Printf(stderr, " name = %s\n", resolved); + Printf(stderr, " sym:name = %s\n", name); + Printf(stderr, " real-name = %s\n", k); + Printf(stderr, " type = %s\n", resolved); + Printf(stderr, " ns = %s\n\n", ns); +#endif + new_node = NewHash(); + Setattr(new_node, "nodeType", "templateInst"); + Setattr(new_node, "name", Copy(resolved)); + Setattr(new_node, "sym:name", Copy(name)); + Setattr(new_node, "real-name", Copy(k)); + Setattr(new_node, "type", Copy(resolved)); + Setattr(new_node, "allegrocl:namespace", ns); + Setattr(new_node, "allegrocl:package", ns); + } + + if (!match) { + if (!Strcmp(nodeType(new_node), "templateInst") && in_class) { + /* this is an implicit template instantiation found while + walking a class. need to insert this into the + linked_type list before the current class definition */ +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "trying to insert a templateInst before a class\n"); +#endif + insert_linked_type_at(in_class, new_node); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "DID IT!\n"); +#endif + } else { + // Printf(stderr,"*** 3\n"); + add_linked_type(new_node); + } + Setattr(new_node, "allegrocl:synonym:is-primary", "1"); + } else { + // a synonym type was found (held in variable 'match') + // Printf(stderr, "setting primary synonym of %x to %x\n", new_node, match); + if (new_node == match) + Printf(stderr, "Hey-4 * - '%s' is a synonym of iteself!\n", Getattr(new_node, "name")); + Setattr(new_node, "allegrocl:synonym-of", match); + // Printf(stderr,"*** 4\n"); + add_linked_type(new_node); + } + } else { + Node *match; + + if (!Strcmp(nodeType(n), "cdecl") && !Strcmp(Getattr(n, "storage"), "typedef")) { + SwigType *type = SwigType_strip_qualifiers(Getattr(n, "type")); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Examining typedef '%s' for class references. (%d)\n", type, SwigType_isclass(type)); +#endif + if (SwigType_isclass(type)) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Found typedef of a class '%s'\n", type); +#endif + /* + For the following parsed expression: + + typedef struct __xxx { ... } xxx; + + if n is of kind "class" (defining the class 'struct __xxx' + then we add n to the linked type list. + + if n is "cdecl" node of storage "typedef" (to note + that xxx is equivalent to 'struct __xxx' then we don't + want to add this node to the linked type list. + */ + String *defined_type = lookup_defined_foreign_type(type); + String *defined_key_type = lookup_defined_foreign_type(k); + + if ((Strstr(type, "struct ") || Strstr(type, "union ")) + && defined_type && !Strcmp(defined_type, defined_key_type)) { + // mark as a synonym but don't add to linked_type list + // Printf(stderr,"*** 4.8\n"); + Setattr(n, "allegrocl:synonym", "1"); + } else { + SwigType *lookup_type = SwigType_istemplate(type) ? SwigType_typedef_resolve_all(type) : Copy(type); + match = find_linked_type_by_name(lookup_type); + if (match) { + Setattr(n, "allegrocl:synonym", "1"); + Setattr(n, "allegrocl:synonym-of", match); + Setattr(n, "real-name", Copy(lookup_type)); + + // Printf(stderr, "*** pre-5: found match of '%s'(%x)\n", Getattr(match,"name"),match); + // if(n == match) Printf(stderr, "Hey-5 *** setting synonym of %x to %x\n", n, match); + // Printf(stderr,"*** 5\n"); + add_linked_type(n); + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Creating classfoward node for struct stub in typedef.\n"); +#endif + Node *new_node = NewHash(); + String *symname = Copy(type); + Replaceall(symname, "struct ", ""); + Setattr(new_node, "nodeType", "classforward"); + Setattr(new_node, "name", Copy(type)); + Setattr(new_node, "sym:name", symname); + Setattr(new_node, "allegrocl:namespace", ns); + Setattr(new_node, "allegrocl:package", ns); + + String *mangled_new_name = NewStringf("#.(swig-insert-id \"%s\" %s)", symname, ns_list); + String *mangled_new_lname = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", symname, ns_list); + Setattr(defined_foreign_types, Copy(symname), Copy(mangled_new_name)); + Setattr(defined_foreign_ltypes, Copy(symname), Copy(mangled_new_lname)); + + // Printf(stderr,"Weird! Can't find the type!\n"); + add_forward_referenced_type(new_node); + add_linked_type(new_node); + + Setattr(n, "allegrocl:synonym", "1"); + Setattr(n, "allegrocl:synonym-of", new_node); + + add_linked_type(n); + } + Delete(lookup_type); + } + } else { + // check if it's a pointer or reference to a class. + // Printf(stderr,"Checking if '%s' is a p. or r. to a class\n", type); + String *class_ref = class_from_class_or_class_ref(type); + if (class_ref) { + match = find_linked_type_by_name(class_ref); + Setattr(n, "allegrocl:synonym", "1"); + Setattr(n, "allegrocl:synonym-of", match); + add_linked_type(n); + } + } + Delete(type); + // synonym types have already been added. + // Printf(stderr,"*** 10\n"); + if (!Getattr(n, "allegrocl:synonym")) + add_linked_type(n); + } else if (Getattr(n, "template")) { + // Printf(stderr, "this is a class template node(%s)\n", nodeType(n)); + String *resolved = SwigType_typedef_resolve_all(Getattr(n, "name")); + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " looking up %s for linked type match with %s...\n", Getattr(n, "sym:name"), resolved); +#endif + match = find_linked_type_by_name(resolved); + if (!match) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "found no implicit instantiation of %%template node %s(%x)\n", Getattr(n, "name"), n); +#endif + add_linked_type(n); + } else { + Node *primary = get_primary_synonym_of(match); + + Setattr(n, "allegrocl:synonym:is-primary", "1"); + Delattr(primary, "allegrocl:synonym:is-primary"); + if (n == match) + Printf(stderr, "Hey-7 * setting synonym of %x to %x\n (match = %x)", primary, n, match); + Setattr(primary, "allegrocl:synonym-of", n); + // Printf(stderr,"*** 7\n"); + add_linked_type(n); + } + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "linking type '%s'(%x)\n", k, n); +#endif + // Printf(stderr,"*** 8\n"); + add_linked_type(n); + } + } + } + Delete(mangled_name_gen); + Delete(mangled_lname_gen); + } else { + if (!CPlusPlus || Strcmp(Getattr(n,"kind"),"typedef")) { + Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), + "Attempting to store a foreign type that exists: %s (%s)\n", + k, val); + } + } + + Delete(ns_list); + +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "OUT A-D-F-T\n"); +#endif +} + +void note_implicit_template_instantiation(SwigType *t) { + // the namespace of the implicit instantiation is not necessarily + // current_namespace. Attempt to cull this from the type. +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "culling namespace of '%s' from '%s'\n", t, SwigType_templateprefix(t)); +#endif + String *implicit_ns = namespace_of(SwigType_templateprefix(t)); + add_defined_foreign_type(0, 0, t, t, implicit_ns ? implicit_ns : current_namespace); +} + +String *get_ffi_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + /* lookup defined foreign type. + if it exists, it will return a form suitable for placing + into lisp code to generate the def-foreign-type name */ + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "inside g_f_t: looking up '%s' '%s'\n", ty, name); +#endif + + String *found_type = lookup_defined_foreign_type(ty); + + if (found_type) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "found_type '%s'\n", found_type); +#endif + return (Strcmp(found_type, "forward-reference") ? Copy(found_type) : get_ffi_type(n, fwdref_ffi_type, "")); + } else { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("ffitype", node, name, 0); + Delete(node); + + if (tm) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "g-f-t: found ffitype typemap '%s'\n", tm); +#endif + return NewString(tm); + } + + if (SwigType_istemplate(ty)) { + note_implicit_template_instantiation(ty); + return Copy(lookup_defined_foreign_type(ty)); + } + } + return 0; +} + +String *lookup_defined_foreign_ltype(String *l) { + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Looking up defined ltype '%s'.\n Found: '%s'\n", l, Getattr(defined_foreign_ltypes, l)); +#endif + return Getattr(defined_foreign_ltypes, l); +} + +/* walk type and return string containing lisp version. + recursive. */ +String *internal_compose_foreign_type(Node *n, SwigType *ty) { + + SwigType *tok; + String *ffiType = NewString(""); + + // for a function type, need to walk the parm list. + while (Len(ty) != 0) { + tok = SwigType_pop(ty); + + if (SwigType_isfunction(tok)) { + // Generate Function wrapper + Printf(ffiType, "(:function "); + // walk parm list + List *pl = SwigType_parmlist(tok); + + Printf(ffiType, "("); // start parm list + for (Iterator i = First(pl); i.item; i = Next(i)) { + SwigType *f_arg = SwigType_strip_qualifiers(i.item); + Printf(ffiType, "%s ", internal_compose_foreign_type(n, f_arg)); + Delete(f_arg); + } + Printf(ffiType, ")"); // end parm list. + + // do function return type. + Printf(ffiType, " %s)", internal_compose_foreign_type(n, ty)); + break; + } else if (SwigType_ispointer(tok) || SwigType_isreference(tok)) { + Printf(ffiType, "(* %s)", internal_compose_foreign_type(n, ty)); + } else if (SwigType_isarray(tok)) { + Printf(ffiType, "(:array %s", internal_compose_foreign_type(n, ty)); + String *atype = NewString("int"); + String *dim = convert_literal(SwigType_array_getdim(tok, 0), atype); + Delete(atype); + if (is_integer(dim)) { + Printf(ffiType, " %s)", dim); + } else { + Printf(ffiType, " #| %s |#)", SwigType_array_getdim(tok, 0)); + } + } else if (SwigType_ismemberpointer(tok)) { + // temp + Printf(ffiType, "(* %s)", internal_compose_foreign_type(n, ty)); + } else { + String *res = get_ffi_type(n, tok, ""); + if (res) { + Printf(ffiType, "%s", res); + } else { + SwigType *resolved_type = SwigType_typedef_resolve(tok); + if (resolved_type) { + res = get_ffi_type(n, resolved_type, ""); + if (res) { + } else { + res = internal_compose_foreign_type(n, resolved_type); + } + if (res) + Printf(ffiType, "%s", res); + } + + if (!res) { + String *is_struct = 0; + String *tok_remove_text = 0; + String *tok_name = Copy(tok); + String *tok_key = SwigType_str(tok,0); + if ((is_struct = Strstr(tok_key, "struct ")) || Strstr(tok_key, "union ")) { + tok_remove_text = NewString(is_struct ? "struct " : "union "); + } + + /* be more permissive of opaque types. This is the swig way. + compiles will notice if these types are ultimately not + present. */ + + if(tok_remove_text) { + Replaceall(tok_name,tok_remove_text,""); + } + tok_name = strip_namespaces(tok_name); + Delete(tok_remove_text); + // Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(tok), Getline(tok), "Unable to find definition of '%s', assuming forward reference.\n", tok); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "i-c-f-t: adding forward reference for unknown type '%s'. mapping: %s -> %s\n", tok, tok_key, tok_name); +#endif + Node *nn = NewHash(); + Setattr(nn,"nodeType","classforward"); + Setattr(nn,"kind","class"); + Setattr(nn,"sym:name",tok_name); + Setattr(nn,"name",tok_key); + Setattr(nn,"allegrocl:package",current_namespace); + + add_forward_referenced_type(nn, 0); + // tok_name is dangling here, unused. ouch. why? + Printf(ffiType, "%s", get_ffi_type(n, tok, ""), tok_name); + } + } + } + } + return ffiType; +} + +String *compose_foreign_type(Node *n, SwigType *ty, String * /*id*/ = 0) { + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "compose_foreign_type: ENTER (%s)...\n ", ty); + // Printf(stderr, "compose_foreign_type: ENTER (%s)(%s)...\n ", ty, (id ? id : 0)); + /* String *id_ref = SwigType_str(ty, id); + Printf(stderr, "looking up typemap for %s, found '%s'(%x)\n", + id_ref, lookup_res ? Getattr(lookup_res, "code") : 0, lookup_res); + if (lookup_res) Swig_print_node(lookup_res); + */ +#endif + + /* should we allow named lookups in the typemap here? YES! */ + /* unnamed lookups should be found in get_ffi_type, called + by internal_compose_foreign_type(), below. */ + + /* I'm reverting to 'no' for the question above. I can no longer + remember why I needed it. If a user needed it, I'll find out + as soon as they upgrade. Sigh. -mutandiz 9/16/2008. */ + +/* + if(id && lookup_res) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "compose_foreign_type: EXIT-1 (%s)\n ", Getattr(lookup_res, "code")); +#endif + return NewString(Getattr(lookup_res, "code")); + } +*/ + + SwigType *temp = SwigType_strip_qualifiers(ty); + String *res = internal_compose_foreign_type(n, temp); + Delete(temp); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "compose_foreign_type: EXIT (%s)\n ", res); +#endif + + return res; +} + +void update_package_if_needed(Node *n, File *f = f_clwrap) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "update_package: ENTER... \n"); + Printf(stderr, " current_package = '%s'\n", current_package); + Printf(stderr, " node_package = '%s'\n", Getattr(n, "allegrocl:package")); + Printf(stderr, " node(%x) = '%s'\n", n, Getattr(n, "name")); +#endif + String *node_package = Getattr(n, "allegrocl:package"); + if (Strcmp(current_package, node_package)) { + String *lispy_package = listify_namespace(node_package); + + Delete(current_package); + current_package = Copy(node_package); + Printf(f, "\n(swig-in-package %s)\n", lispy_package); + Delete(lispy_package); + } +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "update_package: EXIT.\n"); +#endif +} + +static String *mangle_name(Node *n, char const *prefix = "ACL", String *ns = current_namespace) { + String *suffix = Getattr(n, "sym:overname"); + String *pre_mangled_name = NewStringf("%s_%s__%s%s", prefix, ns, Getattr(n, "sym:name"), suffix); + String *mangled_name = Swig_name_mangle(pre_mangled_name); + Delete(pre_mangled_name); + return mangled_name; +} + +/* utilities */ + +/* remove a pointer from ffitype. non-destructive. + (* :char) ==> :char + (* (:array :int 30)) ==> (:array :int 30) */ +String *dereference_ffitype(String *ffitype) { + char *start; + char *temp = Char(ffitype); + String *reduced_type = 0; + + if(temp && temp[0] == '(' && temp[1] == '*') { + temp += 2; + + // walk past start of pointer references + while(*temp == ' ') temp++; + start = temp; + // temp = Char(reduced_type); + reduced_type = NewString(start); + temp = Char(reduced_type); + // walk to end of string. remove closing paren + while(*temp != '\0') temp++; + *(--temp) = '\0'; + } + + return reduced_type ? reduced_type : Copy(ffitype); +} + +/* returns new string w/ parens stripped */ +String *strip_parens(String *string) { + string = Copy(string); + Replaceall(string, "(", ""); + Replaceall(string, ")", ""); + return string; +} + +int ALLEGROCL::validIdentifier(String *s) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "validIdentifier %s\n", s); +#endif + + char *c = Char(s); + + bool got_dot = false; + bool only_dots = true; + + /* Check that s is a valid common lisp symbol. There's a lot of leeway here. + A common lisp symbol is essentially any token that's not a number and + does not consist of only dots. + + We are expressly not allowing spaces in identifiers here, but spaces + could be added via the identifier converter. */ + while (*c) { + if (*c == '.') { + got_dot = true; + } else { + only_dots = false; + } + if (!isgraph(*c)) + return 0; + c++; + } + + return (got_dot && only_dots) ? 0 : 1; +} + +String *infix_to_prefix(String *val, char split_op, const String *op, String *type) { + List *ored = Split(val, split_op, -1); + + // some float hackery + if (((split_op == '+') || (split_op == '-')) && Len(ored) == 2 && + (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE)) { + // check that we're not splitting a float + String *possible_result = convert_literal(val, type, false); + if (possible_result) + return possible_result; + + } + // try parsing the split results. if any part fails, kick out. + bool part_failed = false; + if (Len(ored) > 1) { + String *result = NewStringf("(%s", op); + for (Iterator i = First(ored); i.item; i = Next(i)) { + String *converted = convert_literal(i.item, type); + if (converted) { + Printf(result, " %s", converted); + Delete(converted); + } else { + part_failed = true; + break; + } + } + Printf(result, ")"); + Delete(ored); + return part_failed ? 0 : result; + } + Delete(ored); + return 0; +} + +/* To be called by code generating the lisp interface + Will return a containing the literal based on type. + Will return null if there are problems. + + try_to_split defaults to true (see stub above). + */ +String *convert_literal(String *literal, String *type, bool try_to_split) { + String *num_param = Copy(literal); + String *trimmed = trim(num_param); + String *num = strip_parens(trimmed), *res = 0; + char *s = Char(num); + + String *ns = listify_namespace(current_namespace); + + // very basic parsing of infix expressions. + if (try_to_split && SwigType_type(type) != T_STRING) { + if ((res = infix_to_prefix(num, '|', "logior", type))) + return res; + if ((res = infix_to_prefix(num, '&', "logand", type))) + return res; + if ((res = infix_to_prefix(num, '^', "logxor", type))) + return res; + if ((res = infix_to_prefix(num, '*', "*", type))) + return res; + if ((res = infix_to_prefix(num, '/', "/", type))) + return res; + if ((res = infix_to_prefix(num, '+', "+", type))) + return res; + if ((res = infix_to_prefix(num, '-', "-", type))) + return res; + // if ((res = infix_to_prefix(num, '~', "lognot", type))) return res; + // if( (res = infix_to_prefix(num, '<<', "ash", type)) ) return res; + } + + // unary complement... + if (s[0] == '~' && Len(num) >= 2) { + String *id = NewString(++s); + String *id_conv = convert_literal(id, type, false); + Delete(id); + if (id_conv) + return NewStringf("(lognot %s)", id_conv); + s--; + } + + if (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE) { + // Use CL syntax for float literals + String *oldnum = Copy(num); + + // careful. may be a float identifier or float constant. + char *num_start = Char(num); + char *num_end = num_start + strlen(num_start) - 1; + + bool is_literal = isdigit(*num_start) || (*num_start == '.'); + + String *lisp_exp = 0; + if (is_literal) { + if (*num_end == 'f' || *num_end == 'F') { + lisp_exp = NewString("f"); + } else { + lisp_exp = NewString("d"); + } + + if (*num_end == 'l' || *num_end == 'L' || *num_end == 'f' || *num_end == 'F') { + *num_end = '\0'; + num_end--; + } + + int exponents = Replaceall(num, "e", lisp_exp) + Replaceall(num, "E", lisp_exp); + + if (!exponents) + Printf(num, "%s0", lisp_exp); + + if (exponents > 1 || (exponents + Replaceall(num, ".", ".") == 0)) { + // Printf(stderr, "Can't parse '%s' as type '%s'.\n", oldnum, type); + Delete(num); + num = 0; + } + Delete(lisp_exp); + } else { + String *id = NewStringf("#.(swig-insert-id \"%s\" %s :type :constant)", + num, ns); + Delete(num); + num = id; + } + + Delete(oldnum); + Delete(trimmed); + Delete(ns); + return num; + } else if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + Delete(num); + Delete(trimmed); + return NewStringf("#\\%s", num_param); + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + Delete(num); + Delete(trimmed); + return NewStringf("\"%s\"", num_param); + } else if (Len(num) >= 1 && (isdigit(s[0]) || s[0] == '+' || s[0] == '-')) { + /* use CL syntax for numbers */ + String *oldnum = Copy(num); + int usuffixes = Replaceall(num, "u", "") + Replaceall(num, "U", ""); + int lsuffixes = Replaceall(num, "l", "") + Replaceall(num, "L", ""); + if (usuffixes > 1 || lsuffixes > 1) { + Printf(stderr, "Weird!! number %s looks invalid.\n", oldnum); + SWIG_exit(EXIT_FAILURE); + } + s = Char(num); + if (s[0] == '0' && Len(num) >= 2) { + /*octal or hex */ + res = NewStringf("#%c%s", tolower(s[1]) == 'x' ? 'x' : 'o', s + 2); + Delete(num); + } else { + res = num; + } + Delete(oldnum); + Delete(trimmed); + return res; + } else if (allegrocl->validIdentifier(num)) { + /* convert C/C++ identifiers to CL symbols */ + res = NewStringf("#.(swig-insert-id \"%s\" %s :type :constant)", num, ns); + Delete(num); + Delete(trimmed); + Delete(ns); + return res; + } else { + Delete(trimmed); + return num; + } +} + + +void emit_stub_class(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_stub_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n); +#endif + + + String *name = Getattr(n, "sym:name"); + + if (Getattr(n, "allegrocl:synonym:already-been-stubbed")) + return; + + if (SwigType_istemplate(name)) { + String *temp = strip_namespaces(SwigType_templateprefix(name)); + name = NewStringf("%s%s%s", temp, SwigType_templateargs(name), SwigType_templatesuffix(name)); + + Delete(temp); + } else { + name = strip_namespaces(name); + } + + // Printf(f_clhead, ";; from emit-stub-class\n"); + update_package_if_needed(n, f_clhead); + Printf(f_clhead, ";; class template stub.\n"); + Printf(f_clhead, "(swig-def-foreign-stub \"%s\")\n", name); + + Setattr(n, "allegrocl:synonym:already-been-stubbed", "1"); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_stub_class: EXIT\n"); +#endif +} + +void emit_synonym(Node *synonym) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_synonym: ENTER... \n"); +#endif + + // Printf(stderr,"in emit_synonym for %s(%x)\n", Getattr(synonym,"name"),synonym); + int is_tempInst = !Strcmp(nodeType(synonym), "templateInst"); + String *synonym_type; + + Node *of = get_primary_synonym_of(synonym); + + if (is_tempInst) { + // Printf(stderr, "*** using real-name '%s'\n", Getattr(synonym,"real-name")); + synonym_type = Getattr(synonym, "real-name"); + } else { + // Printf(stderr, "*** using name '%s'\n", Getattr(synonym,"name")); + synonym_type = Getattr(synonym, "name"); + } + + String *synonym_ns = listify_namespace(Getattr(synonym, "allegrocl:namespace")); + String *syn_ltype, *syn_type, *of_ltype; + // String *of_cdeclname = Getattr(of,"allegrocl:classDeclarationName"); + String *of_ns = Getattr(of, "allegrocl:namespace"); + String *of_ns_list = listify_namespace(of_ns); + // String *of_name = of_cdeclname ? NewStringf("struct %s", Getattr(of,"name")) : NewStringf("%s::%s", of_ns, Getattr(of,"sym:name")); + // String *of_name = NewStringf("%s::%s", of_ns, Getattr(of,"sym:name")); + String *of_name = namespaced_name(of, of_ns); + + if (CPlusPlus && !Strcmp(nodeType(synonym), "cdecl")) { + syn_ltype = NewStringf("#.(swig-insert-id \"%s\" %s :type :class)", + strip_namespaces(Getattr(synonym, "real-name")), synonym_ns); + syn_type = NewStringf("#.(swig-insert-id \"%s\" %s :type :type)", + strip_namespaces(Getattr(synonym, "real-name")), synonym_ns); + } else { + syn_ltype = lookup_defined_foreign_ltype(synonym_type); + syn_type = lookup_defined_foreign_type(synonym_type); + } + + of_ltype = lookup_defined_foreign_ltype(of_name); + + // Printf(stderr,";; from emit-synonym syn='%s' of_ltype='%s'\n", syn_ltype, of_ltype); + if( of_ltype ) + Printf(f_clhead, "(swig-def-synonym-type %s\n %s\n %s)\n", syn_ltype, of_ltype, syn_type); + + Delete(synonym_ns); + Delete(of_ns_list); + Delete(of_name); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_synonym: EXIT\n"); +#endif +} + +void emit_full_class(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_full_class: ENTER... \n"); +#endif + + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + // Printf(stderr,"in emit_full_class: '%s'(%x).", Getattr(n,"name"),n); + if (Getattr(n, "allegrocl:synonym-of")) { + // Printf(stderr,"but it's a synonym of something.\n"); + update_package_if_needed(n, f_clhead); + emit_synonym(n); + return; + } + // collect superclasses + String *bases = Getattr(n, "bases"); + String *supers = NewString("("); + if (bases) { + int first = 1; + for (Iterator i = First(bases); i.item; i = Next(i)) { + if (!first) + Printf(supers, " "); + String *s = lookup_defined_foreign_ltype(Getattr(i.item, "name")); + // String *name = Getattr(i.item,"name"); + if (s) { + Printf(supers, "%s", s); + } else { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "emit_templ_inst: did not find ltype for base class %s (%s)", Getattr(i.item, "name"), Getattr(n, "allegrocl:namespace")); +#endif + } + } + } else { + Printf(supers, "ff:foreign-pointer"); + } + + Printf(supers, ")"); + + // Walk children to generate type definition. + String *slotdefs = NewString(" "); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, " walking children...\n"); +#endif + + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + String *storage_type = Getattr(c, "storage"); + if ((!Strcmp(nodeType(c), "cdecl") && (!storage_type || Strcmp(storage_type, "typedef")))) { + String *access = Getattr(c, "access"); + + // hack. why would decl have a value of "variableHandler" and now "0"? + String *childDecl = Getattr(c, "decl"); + // Printf(stderr,"childDecl = '%s' (%s)\n", childDecl, Getattr(c,"view")); + if (!Strcmp(childDecl, "0")) + childDecl = NewString(""); + + SwigType *childType; + String *cname; + + // don't include types for private slots (yet). spr33959. + if(access && Strcmp(access,"public")) { + childType = NewStringf("int"); + cname = NewString("nil"); + } else { + childType = NewStringf("%s%s", childDecl, Getattr(c, "type")); + cname = Copy(Getattr(c, "name")); + } + + if (!SwigType_isfunction(childType)) { + // Printf(slotdefs, ";;; member functions don't appear as slots.\n "); + // Printf(slotdefs, ";; "); + String *ns = listify_namespace(Getattr(n, "allegrocl:package")); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "slot name = '%s' ns = '%s' class-of '%s' and type = '%s'\n", cname, ns, name, childType); +#endif + Printf(slotdefs, "(#.(swig-insert-id \"%s\" %s :type :slot :class \"%s\") %s)", cname, ns, name, compose_foreign_type(n, childType)); + Delete(ns); + if (access && Strcmp(access, "public")) + Printf(slotdefs, " ;; %s member", access); + + Printf(slotdefs, "\n "); + } + Delete(childType); + Delete(cname); + } + } + + String *ns_list = listify_namespace(Getattr(n, "allegrocl:namespace")); + update_package_if_needed(n, f_clhead); + Printf(f_clhead, "(swig-def-foreign-class \"%s\"\n %s\n (:%s\n%s))\n\n", name, supers, kind, slotdefs); + + Delete(supers); + Delete(ns_list); + + Setattr(n, "allegrocl:synonym:already-been-stubbed", "1"); +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_full_class: EXIT\n"); +#endif + +} + +void emit_class(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n); +#endif + + int is_tempInst = !Strcmp(nodeType(n), "templateInst"); + + String *ns_list = listify_namespace(Getattr(n, "allegrocl:namespace")); + String *name = Getattr(n, is_tempInst ? "real-name" : "name"); + + if (SwigType_istemplate(name)) { + String *temp = strip_namespaces(SwigType_templateprefix(name)); + name = NewStringf("%s%s%s", temp, SwigType_templateargs(name), SwigType_templatesuffix(name)); + + Delete(temp); + } else { + name = strip_namespaces(name); + } + + if (Getattr(n, "allegrocl:synonym:is-primary")) { + // Printf(stderr," is primary... "); + if (is_tempInst) { + emit_stub_class(n); + } else { + emit_full_class(n); + } + } else { + // Node *primary = Getattr(n,"allegrocl:synonym-of"); + Node *primary = get_primary_synonym_of(n); + if (primary && (primary != n)) { + // Printf(stderr," emitting synonym... "); + emit_stub_class(primary); + update_package_if_needed(n, f_clhead); + emit_synonym(n); + } else { + emit_full_class(n); + } + } + // Printf(stderr,"DONE\n"); + Delete(name); + Delete(ns_list); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_class: EXIT\n"); +#endif +} + +void emit_typedef(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_typedef: ENTER... \n"); +#endif + + String *name; + String *sym_name = Getattr(n, "sym:name"); + String *type = NewStringf("%s%s", Getattr(n, "decl"), Getattr(n, "type")); + String *lisp_type = compose_foreign_type(n, type); + Delete(type); + Node *in_class = Getattr(n, "allegrocl:typedef:in-class"); + + // Printf(stderr,"in emit_typedef: '%s'(%x).",Getattr(n,"name"),n); + if (Getattr(n, "allegrocl:synonym-of")) { + // Printf(stderr," but it's a synonym of something.\n"); + emit_synonym(n); + return; + } + + if (in_class) { + String *class_name = Getattr(in_class, "name"); + if (SwigType_istemplate(class_name)) { + String *temp = strip_namespaces(SwigType_templateprefix(class_name)); + class_name = NewStringf("%s%s%s", temp, SwigType_templateargs(class_name), SwigType_templatesuffix(class_name)); + Delete(temp); + } + + name = NewStringf("%s__%s", class_name, sym_name); + Setattr(n, "allegrocl:in-class", in_class); + } else { + name = sym_name ? Copy(sym_name) : Copy(Getattr(n, "name")); + } + + // leave these in for now. might want to change these to def-foreign-class at some point. +// Printf(f_clhead, ";; %s\n", SwigType_typedef_resolve_all(lisp_type)); + Printf(f_clhead, "(swig-def-foreign-type \"%s\"\n %s)\n", name, lisp_type); + + Delete(name); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_typedef: EXIT\n"); +#endif +} + +void emit_enum_type_no_wrap(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type_no_wrap: ENTER... \n"); +#endif + + String *unnamed = Getattr(n, "unnamed"); + String *name; + // SwigType *enumtype; + + name = unnamed ? Getattr(n, "allegrocl:name") : Getattr(n, "sym:name"); + SwigType *tmp = NewStringf("enum %s", unnamed ? unnamed : name); + + Node *node = NewHash(); + Setattr(node, "type", tmp); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *enumtype = Swig_typemap_lookup("ffitype", node, "", 0); + Delete(node); + + Delete(tmp); + + if (name) { + String *ns = listify_namespace(current_namespace); + + Printf(f_clhead, "(swig-def-foreign-type \"%s\" %s)\n", name, enumtype); + Delete(ns); + + // walk children. + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + if (!Getattr(c, "error")) { + String *val = Getattr(c, "enumvalue"); + if (!val) + val = Getattr(c, "enumvalueex"); + String *converted_val = convert_literal(val, Getattr(c, "type")); + String *valname = Getattr(c, "sym:name"); + + if (converted_val) { + Printf(f_clhead, "(swig-defconstant \"%s\" %s)\n", valname, converted_val); + Delete(converted_val); + } else { + Swig_warning(WARN_LANG_DISCARD_CONST, Getfile(n), Getline(n), "Unable to parse enum value '%s'. Setting to NIL\n", val); + Printf(f_clhead, "(swig-defconstant \"%s\" nil #| %s |#)\n", valname, val); + } + } + } + } + Printf(f_clhead, "\n"); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type_no_wrap: EXIT\n"); +#endif + +} + +void emit_enum_type(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type: ENTER... \n"); +#endif + + if (!Generate_Wrapper) { + emit_enum_type_no_wrap(n); + return; + } + + String *unnamed = Getattr(n, "unnamed"); + String *name; + // SwigType *enumtype; + + name = unnamed ? Getattr(n, "allegrocl:name") : Getattr(n, "sym:name"); + SwigType *tmp = NewStringf("enum %s", unnamed ? unnamed : name); + + Node *node = NewHash(); + Setattr(node, "type", tmp); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *enumtype = Swig_typemap_lookup("ffitype", node, "", 0); + Delete(node); + + Delete(tmp); + + if (name) { + String *ns = listify_namespace(current_namespace); + + Printf(f_clhead, "(swig-def-foreign-type \"%s\" %s)\n", name, enumtype); + Delete(ns); + + // walk children. + Node *c; + for(c = firstChild(n); c; c=nextSibling(c)) { + String *mangled_name = mangle_name(c, "ACL_ENUM", Getattr(c,"allegrocl:package")); + Printf(f_clhead, "(swig-defvar \"%s\" \"%s\" :type :constant :ftype :signed-long)\n", Getattr(c, "sym:name"), mangled_name); + Delete(mangled_name); + } + } +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_enum_type: EXIT\n"); +#endif + +} + +void emit_default_linked_type(Node *n) { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_default_linked_type: ENTER... \n"); +#endif + + // catchall for non class types. + if (!Strcmp(nodeType(n), "classforward")) { + Printf(f_clhead, ";; forward referenced stub.\n"); + Printf(f_clhead, "(swig-def-foreign-class \"%s\" (ff:foreign-pointer) (:class ))\n\n", Getattr(n, "sym:name")); + } else if (!Strcmp(nodeType(n), "enum")) { + emit_enum_type(n); + } else { + Printf(stderr, "Don't know how to emit node type '%s' named '%s'\n", nodeType(n), Getattr(n, "name")); + } + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_default_linked_type: EXIT\n"); +#endif + +} + +void dump_linked_types(File *f) { + Node *n = first_linked_type; + int i = 0; + while (n) { + Printf(f, "%d: (%x) node '%s' name '%s'\n", i++, n, nodeType(n), Getattr(n, "sym:name")); + + Node *t = Getattr(n, "allegrocl:synonym-of"); + if (t) + Printf(f, " synonym-of %s(%x)\n", Getattr(t, "name"), t); + n = Getattr(n, "allegrocl:next_linked_type"); + } +} + +void emit_linked_types() { + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_linked_types: ENTER... "); +#endif + + Node *n = first_linked_type; + + while (n) { + String *node_type = nodeType(n); + + // Printf(stderr,"emitting node %s(%x) of type %s.", Getattr(n,"name"),n, nodeType(n)); + if (!Strcmp(node_type, "class") || !Strcmp(node_type, "templateInst")) { + // may need to emit a stub, so it will update the package itself. + // Printf(stderr," Passing to emit_class."); + emit_class(n); + } else if (!Strcmp(nodeType(n), "cdecl")) { + // Printf(stderr," Passing to emit_typedef."); + update_package_if_needed(n, f_clhead); + emit_typedef(n); + } else { + // Printf(stderr," Passing to default_emitter."); + update_package_if_needed(n, f_clhead); + emit_default_linked_type(n); + } + + n = Getattr(n, "allegrocl:next_linked_type"); + // Printf(stderr,"returned.\n"); + } + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_linked_types: EXIT\n"); +#endif +} + +extern "C" Language *swig_allegrocl(void) { + return (allegrocl = new ALLEGROCL()); +} + +void ALLEGROCL::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGALLEGROCL 1", 0); + SWIG_library_directory("allegrocl"); + SWIG_config_file("allegrocl.swg"); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-identifier-converter")) { + char *conv = argv[i + 1]; + + if (!conv) + Swig_arg_error(); + + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + + /* check for built-ins */ + if (!strcmp(conv, "lispify")) { + identifier_converter = "identifier-convert-lispify"; + } else if (!strcmp(conv, "null")) { + identifier_converter = "identifier-convert-null"; + } else { + /* Must be user defined */ + char *idconv = new char[strlen(conv) + 1]; + strcpy(idconv, conv); + identifier_converter = idconv; + } + } else if (!strcmp(argv[i], "-cwrap")) { + CWrap = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocwrap")) { + CWrap = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-isolate")) { + unique_swig_package = true; + Swig_mark_arg(i); + } + + if (!strcmp(argv[i], "-help")) { + fprintf(stdout, "Allegro CL Options (available with -allegrocl)\n"); + fprintf(stdout, + " -identifier-converter <type or funcname>\n" + "\tSpecifies the type of conversion to do on C identifiers to convert\n" + "\tthem to symbols. There are two built-in converters: 'null' and\n" + "\t 'lispify'. The default is 'null'. If you supply a name other\n" + "\tthan one of the built-ins, then a function by that name will be\n" + "\tcalled to convert identifiers to symbols.\n" + "\n" + " -[no]cwrap\n" + "\tTurn on or turn off generation of an intermediate C file when\n" "\tcreating a C interface. By default this is only done for C++ code.\n" + " -isolate\n" + "Define all SWIG helper functions in a package unique to this module. Avoids redefinition warnings when loading multiple SWIGged modules\n" + "into the same running Allegro CL image.\n"); + + } + + } + + allow_overloading(); +} + +int ALLEGROCL::top(Node *n) { + module_name = Getattr(n, "name"); + String *cxx_filename = Getattr(n, "outfile"); + String *cl_filename = NewString(""); + + swig_package = unique_swig_package ? NewStringf("swig.%s", module_name) : NewString("swig"); + + Printf(cl_filename, "%s%s.cl", SWIG_output_directory(), module_name); + + f_cl = NewFile(cl_filename, "w", SWIG_output_files()); + if (!f_cl) { + Printf(stderr, "Unable to open %s for writing\n", cl_filename); + SWIG_exit(EXIT_FAILURE); + } + + Generate_Wrapper = CPlusPlus || CWrap; + + if (Generate_Wrapper) { + f_begin = NewFile(cxx_filename, "w", SWIG_output_files()); + if (!f_begin) { + Close(f_cl); + Delete(f_cl); + Printf(stderr, "Unable to open %s for writing\n", cxx_filename); + SWIG_exit(EXIT_FAILURE); + } + } else + f_begin = NewString(""); + + f_runtime = NewString(""); + f_cxx_header = f_runtime; + f_cxx_wrapper = NewString(""); + + Swig_register_filebyname("header", f_cxx_header); + Swig_register_filebyname("wrapper", f_cxx_wrapper); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("lisp", f_clwrap); + Swig_register_filebyname("lisphead", f_cl); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGALLEGROCL\n"); + Printf(f_runtime, "\n"); + + Swig_banner_target_lang(f_cl, ";;"); + + Printf(f_cl, "\n" + "(defpackage :%s\n" + " (:use :common-lisp :ff :excl)\n" + " (:export #:*swig-identifier-converter* #:*swig-module-name*\n" + " #:*void* #:*swig-export-list*))\n" + "(in-package :%s)\n\n" + "(eval-when (:compile-toplevel :load-toplevel :execute)\n" + " (defparameter *swig-identifier-converter* '%s)\n" + " (defparameter *swig-module-name* :%s))\n\n", swig_package, swig_package, identifier_converter, module_name); + Printf(f_cl, "(defpackage :%s\n" " (:use :common-lisp :%s :ff :excl))\n\n", module_name, swig_package); + + Printf(f_clhead, "(in-package :%s)\n", module_name); + + // Swig_print_tree(n); + + Language::top(n); + + // SwigType_emit_type_table(f_runtime,f_cxx_wrapper); + + // Swig_print_tree(n); +#ifdef ALLEGROCL_TYPE_DEBUG + dump_linked_types(stderr); +#endif + emit_linked_types(); + + Printf(f_clwrap, "\n(cl::in-package :%s)\n", swig_package); + Printf(f_clwrap, "\n(macrolet ((swig-do-export ()\n"); + Printf(f_clwrap, " `(dolist (s ',*swig-export-list*)\n"); + Printf(f_clwrap, " (apply #'export s))))\n"); + Printf(f_clwrap, " (swig-do-export))\n"); + Printf(f_clwrap, "\n(setq *swig-export-list* nil)\n"); + + Printf(f_cl, "%s\n", f_clhead); + Printf(f_cl, "%s\n", f_clwrap); + + Close(f_cl); + Delete(f_cl); // Delete the handle, not the file + Delete(f_clhead); + Delete(f_clwrap); + + Dump(f_runtime, f_begin); + Printf(f_begin, "%s\n", f_cxx_wrapper); + + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + Delete(f_cxx_wrapper); + + // Swig_print_tree(n); + + return SWIG_OK; +} + +/* very shamelessly 'borrowed' from overload.cxx, which + keeps the below Swig_overload_rank() code to itself. + We don't need a dispatch function in the C++ wrapper + code; we want it over on the lisp side. */ + +#define MAX_OVERLOAD 256 + +/* Overload "argc" and "argv" */ +// String *argv_template_string; +// String *argc_template_string; + +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ +}; + +/* ----------------------------------------------------------------------------- + * Swig_overload_rank() + * + * This function takes an overloaded declaration and creates a list that ranks + * all overloaded methods in an order that can be used to generate a dispatch + * function. + * Slight difference in the way this function is used by scripting languages and + * statically typed languages. The script languages call this method via + * Swig_overload_dispatch() - where wrappers for all overloaded methods are generated, + * however sometimes the code can never be executed. The non-scripting languages + * call this method via Swig_overload_check() for each overloaded method in order + * to determine whether or not the method should be wrapped. Note the slight + * difference when overloading methods that differ by const only. The + * scripting languages will ignore the const method, whereas the non-scripting + * languages ignore the first method parsed. + * ----------------------------------------------------------------------------- */ + +static List *Swig_overload_rank(Node *n, bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n, "sym:overloaded"); + Node *c; + + if (!o) + return 0; + + c = o; + while (c) { + if (Getattr(c, "error")) { + c = Getattr(c, "sym:nextSibling"); + continue; + } + /* if (SmartPointer && Getattr(c,"cplus:staticbase")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } */ + + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + if (Getattr(c, "wrap:name")) { + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c, "wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nnodes++; + } + c = Getattr(c, "sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i, j; + for (i = 0; i < nnodes; i++) { + for (j = i + 1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i, j; + for (i = 0; i < nnodes - 1; i++) { + if (nodes[i].argc == nodes[i + 1].argc) { + for (j = i + 1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + // Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + if (checkAttribute(p1, "tmap:in:numinputs", "0")) { + p1 = Getattr(p1, "tmap:in:next"); + continue; + } + if (checkAttribute(p2, "tmap:in:numinputs", "0")) { + p2 = Getattr(p2, "tmap:in:next"); + continue; + } + String *t1 = Getattr(p1, "tmap:typecheck:precedence"); + String *t2 = Getattr(p2, "tmap:typecheck:precedence"); + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded method %s not supported (no type checking rule for '%s').\n", + Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s not supported (no type checking rule for '%s').\n", + Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v - t2v; + } else if (!t1 && t2) + differ = 1; + else if (t1 && !t2) + differ = -1; + else if (!t1 && !t2) + differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1, "0") == 0)) { + t1 = Getattr(p1, "ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1, "type")); + if (Getattr(p1, "tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1, "ltype", t1); + } + t2 = Getattr(p2, "ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2, "type")); + if (Getattr(p2, "tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2, "ltype", t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2, t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1, t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1, "tmap:in:next")) { + p1 = Getattr(p1, "tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2, "tmap:in:next")) { + p2 = Getattr(p2, "tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *d1 = Getattr(nodes[i].n, "decl"); + String *d2 = Getattr(nodes[j].n, "decl"); + if (d1 && d2) { + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1, dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s) ignored. Method %s(%s) const at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n, "name"), ParmList_errorstr(nodes[i].parms), Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s) const ignored. Method %s(%s) at %s:%d used.\n", + Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n, "name"), ParmList_errorstr(nodes[i].parms), Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s is shadowed by %s at %s:%d.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result, nodes[i].n); + // Printf(stdout,"[ %d ] %s\n", i, ParmList_errorstr(nodes[i].parms)); + // Swig_print_node(nodes[i].n); + } + } + return result; +} + +/* end shameless borrowing */ + +int any_varargs(ParmList *pl) { + Parm *p; + + for (p = pl; p; p = nextSibling(p)) { + if (SwigType_isvarargs(Getattr(p, "type"))) + return 1; + } + + return 0; +} + +String *get_lisp_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setattr(node, "name", name); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("lisptype", node, "", 0); + Delete(node); + + return tm ? NewString(tm) : NewString(""); +} + +Node *parent_node_skipping_extends(Node *n) { + Node *result = n; + do { + result = parentNode(result); + } + while (Cmp("extend", nodeType(result)) == 0); + return result; +} + +/* ----------------------------------------------------------------------------- + * emit_num_lin_arguments() + * + * Calculate the total number of arguments. This function is safe for use + * with multi-argument typemaps which may change the number of arguments in + * strange ways. + * ----------------------------------------------------------------------------- */ + +int emit_num_lin_arguments(ParmList *parms) { + Parm *p = parms; + int nargs = 0; + + while (p) { + // Printf(stderr,"enla: '%s' lin='%x'\n", Getattr(p,"name"), Getattr(p,"tmap:lin")); + if (Getattr(p, "tmap:lin")) { + nargs += GetInt(p, "tmap:lin:numinputs"); + p = Getattr(p, "tmap:lin:next"); + } else { + p = nextSibling(p); + } + } + + /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ + /* + if (parms && (p = Getattr(parms,"emit:varargs"))) { + if (!nextSibling(p)) { + nargs--; + } + } + */ + return nargs; +} + +String *id_converter_type(SwigType const *type) { + SwigType *t = Copy(type); + String *result = 0; + + if (SwigType_ispointer(t)) { + SwigType_pop(t); + String *pointee = id_converter_type(t); + result = NewStringf("(:* %s)", pointee); + Delete(pointee); + } else if (SwigType_ismemberpointer(t)) { + String *klass = SwigType_parm(t); + SwigType_pop(t); + String *member = id_converter_type(t); + result = NewStringf("(:member \"%s\" %s)", klass, member); + Delete(klass); + Delete(member); + } else if (SwigType_isreference(t)) { + SwigType_pop(t); + String *referencee = id_converter_type(t); + result = NewStringf("(:& %s)", referencee); + Delete(referencee); + } else if (SwigType_isarray(t)) { + String *size = SwigType_parm(t); + SwigType_pop(t); + String *element_type = id_converter_type(t); + result = NewStringf("(:array %s \"%s\")", element_type, size); + Delete(size); + Delete(element_type); + } else if (SwigType_isfunction(t)) { + result = NewString("(:function ("); + String *parmlist_str = SwigType_parm(t); + List *parms = SwigType_parmlist(parmlist_str); + + for (Iterator i = First(parms); i.item;) { + String *parm = id_converter_type((SwigType *) i.item); + Printf(result, "%s", parm); + i = Next(i); + if (i.item) + Printf(result, " "); + Delete(parm); + } + SwigType_pop(t); + String *ret = id_converter_type(t); + Printf(result, ") %s)", ret); + + Delete(parmlist_str); + Delete(parms); + Delete(ret); + } else if (SwigType_isqualifier(t)) { + result = NewString("(:qualified ("); + String *qualifiers_str = Copy(SwigType_parm(t)); // ?! + // Replaceall below SEGVs if we don't put the Copy here... + SwigType_pop(t); + String *qualifiee = id_converter_type(t); + + Replaceall(qualifiers_str, " ", " :"); + if (Len(qualifiers_str) > 0) + Printf(result, ":"); + Printf(result, "%s) %s)", qualifiers_str, qualifiee); + + Delete(qualifiers_str); + Delete(qualifiee); + } else if (SwigType_istemplate(t)) { + result = NewStringf("(:template \"%s\")", t); + } else { /* if (SwigType_issimple(t)) */ + + if (Strstr(Char(t), "::")) { + result = listify_namespace(t); + } else { + result = NewStringf("\"%s\"", t); + } + } + + Delete(t); + return result; +} + +static ParmList *parmlist_with_names(ParmList *pl) { + ParmList *pl2 = CopyParmList(pl); + for (Parm *p = pl, *p2 = pl2; p2; p = nextSibling(p), p2 = nextSibling(p2)) { + if (!Getattr(p2, "name")) + Setattr(p2, "name", Getattr(p2, "lname")); + Setattr(p2, "name", strip_namespaces(Getattr(p2, "name"))); + Setattr(p2, "tmap:ctype", Getattr(p, "tmap:ctype")); + + String *temp = Getattr(p, "tmap:lin"); + if (temp) { + Setattr(p2, "tmap:lin", temp); + Setattr(p2, "tmap:lin:next", Getattr(p, "tmap:lin:next")); + } + } + return pl2; +} + +static String *parmlist_str_id_converter(ParmList *pl) { + String *result = NewString(""); + for (Parm *p = pl; p;) { + String *lispy_type = id_converter_type(Getattr(p, "type")); + Printf(result, "(\"%s\" %s)", Getattr(p, "name"), lispy_type); + Delete(lispy_type); + if ((p = nextSibling(p))) + Printf(result, " "); + } + return result; +} + +String *collect_others_args(Node *overload) { + String *overloaded_from = Getattr(overload, "sym:overloaded"); + String *others_args = NewString(""); + int first_overload = 1; + + for (Node *overload2 = overloaded_from; overload2; overload2 = Getattr(overload2, "sym:nextSibling")) { + if (overload2 == overload || GetInt(overload2, "overload:ignore")) + continue; + + ParmList *opl = parmlist_with_names(Getattr(overload2, "wrap:parms")); + String *args = parmlist_str_id_converter(opl); + if (!first_overload) + Printf(others_args, "\n "); + Printf(others_args, "(%s)", args); + Delete(args); + Delete(opl); + first_overload = 0; + } + return others_args; +} + +struct IDargs { + String *name; + String *type; + String *klass; + String *arity; + + IDargs():name(0), type(0), klass(0), arity(0) { + } + + String *full_quoted_str() { + String *result = no_others_quoted_str(); + if (arity) + Printf(result, " :arity %s", arity); + return result; + } + + String *no_others_quoted_str() { + String *result = NewString(""); + Printf(result, "\"%s\" :type :%s", name, type); + if (klass) + Printf(result, " :class \"%s\"", klass); + return result; + } + + String *noname_str() { + String *result = NewString(""); + Printf(result, " :type :%s", type); + if (klass) + Printf(result, " :class \"%s\"", klass); + if (arity) + Printf(result, " :arity %s", arity); + return result; + } +}; +IDargs *id_converter_arguments(Node *n) { + IDargs *result = (IDargs *) GetVoid(n, "allegrocl:id-converter-args"); + if (!result) + result = new IDargs; + + // Base name + if (!result->name) { + result->name = Getattr(n, "allegrocl:old-sym:name"); + if (!result->name) + result->name = Getattr(n, "sym:name"); + result->name = Copy(result->name); + } + // :type + if (result->type) + Delete(result->type); + if (!Getattr(n, "allegrocl:kind")) + Setattr(n, "allegrocl:kind", "function"); + if (Strstr(Getattr(n, "name"), "operator ")) + Replaceall(Getattr(n, "allegrocl:kind"), "function", "operator"); + if (Strstr(Getattr(n, "allegrocl:kind"), "variable")) { + int name_end = Len(Getattr(n, "sym:name")) - 4; + char *str = Char(Getattr(n, "sym:name")); + String *get_set = NewString(str + name_end + 1); + result->type = Copy(Getattr(n, "allegrocl:kind")); + Replaceall(result->type, "variable", ""); + Printf(result->type, "%ster", get_set); + Delete(get_set); + } else { + result->type = Copy(Getattr(n, "allegrocl:kind")); + } + + // :class + if (Strstr(result->type, "member ")) { + Replaceall(result->type, "member ", ""); + if (!result->klass) + result->klass = Copy(Getattr(parent_node_skipping_extends(n), "sym:name")); + } + // :arity + if (Getattr(n, "sym:overloaded")) { + if (result->arity) + Delete(result->arity); + result->arity = NewStringf("%d", + // emit_num_arguments(Getattr(n, "wrap:parms"))); + emit_num_lin_arguments(Getattr(n, "wrap:parms"))); + // Printf(stderr, "got arity of '%s' node '%s' '%x'\n", result->arity, Getattr(n,"name"), Getattr(n,"wrap:parms")); + } + + SetVoid(n, "allegrocl:id-converter-args", result); + return result; +} + +int ALLEGROCL::emit_buffered_defuns(Node *n) { + + Node *overloaded_from = Getattr(n, "sym:overloaded"); + + String *wrap; + + if (!overloaded_from) { + wrap = Getattr(n, "allegrocl:lisp-wrap"); + + Printf(f_clwrap, "%s\n", wrap); + Delattr(n, "allegrocl:lisp-wrap"); + Delete(wrap); + } else { + for (Node *overload = overloaded_from; overload; overload = Getattr(overload, "sym:nextSibling")) { + String *others_args = collect_others_args(overload); + wrap = Getattr(overload, "allegrocl:lisp-wrap"); + + Replaceall(wrap, "@@OTHERS-ARGS-GO-HERE@@", others_args); +// IDargs* id_args = id_converter_arguments(overload); +// Replaceall(id_args->others_args, "@@OTHERS-ARGS-GO-HERE@@", others_args); + + if (!GetInt(overload, "overload:ignore")) + Printf(f_clwrap, "%s", wrap); + + Delattr(overload, "allegrocl:lisp-wrap"); + Delete(wrap); + } + } + return SWIG_OK; +} + +String *dispatching_type(Node *n, Parm *p) { + String *result = 0; + + String *parsed = Getattr(p, "type"); //Swig_cparse_type(Getattr(p,"tmap:ctype")); + String *cl_t = SwigType_typedef_resolve_all(parsed); + + Node *node = NewHash(); + Setattr(node, "type", parsed); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("lispclass", node, Getattr(p, "name"), 0); + Delete(node); + + if (tm) { + result = Copy(tm); + } else { + String *lookup_type = class_from_class_or_class_ref(parsed); + if (lookup_type) + result = lookup_defined_foreign_ltype(lookup_type); + } + + // if (!result && SwigType_ispointer(cl_t)) { + // SwigType_pop(cl_t); + // result = lookup_defined_foreign_ltype(cl_t); + // } + + if (!result) + result = NewStringf("ff:foreign-pointer"); + + // Delete(parsed); + Delete(cl_t); + return result; +} + +int ALLEGROCL::emit_dispatch_defun(Node *n) { +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_dispatch_defun: ENTER... "); +#endif + List *overloads = Swig_overload_rank(n, true); + + String *id_args = id_converter_arguments(n)->no_others_quoted_str(); + Printf(f_clwrap, "(swig-dispatcher (%s :arities (", id_args); + + int last_arity = -1; + for (Iterator i = First(overloads); i.item; i = Next(i)) { + int arity = emit_num_lin_arguments(Getattr(i.item, "wrap:parms")); + if (arity == last_arity) + continue; + + Printf(f_clwrap, "%s%d", last_arity == -1 ? "" : " ", arity); + + last_arity = arity; + } + Printf(f_clwrap, ")))\n"); + + Delete(id_args); + Delete(overloads); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_dispatch_defun: EXIT\n"); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::emit_defun(Node *n, File *fcl) { +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_defun: ENTER... "); +#endif + +#ifdef ALLEGROCL_DEBUG + int auto_generated = Cmp(Getattr(n, "view"), "globalfunctionHandler"); + Printf(stderr, "%s%sfunction %s%s%s\n", auto_generated ? "> " : "", Getattr(n, "sym:overloaded") + ? "overloaded " : "", current_namespace, (current_namespace) > 0 ? "::" : "", Getattr(n, "sym:name")); + Printf(stderr, " (view: %s)\n", Getattr(n, "view")); +#endif + + String *funcname = Getattr(n, "allegrocl:old-sym:name"); + if (!funcname) + funcname = Getattr(n, "sym:name"); + String *mangled_name = Getattr(n, "wrap:name"); + ParmList *pl = parmlist_with_names(Getattr(n, "wrap:parms")); + + // attach typemap info. + Wrapper *wrap = NewWrapper(); + Swig_typemap_attach_parms("lin", pl, wrap); + // Swig_typemap_attach_parms("ffitype", pl, wrap); + Swig_typemap_lookup("lout", n, "result", 0); + + SwigType *result_type = Swig_cparse_type(Getattr(n, "tmap:ctype")); + // prime the pump, with support for OUTPUT, INOUT typemaps. + Printf(wrap->code, + "(cl::let ((ACL_ffresult %s:*void*)\n ACL_result)\n $body\n (cl::if (cl::eq ACL_ffresult %s:*void*)\n (cl::values-list ACL_result)\n (cl::values-list (cl::cons ACL_ffresult ACL_result))))", + swig_package, swig_package); + + Parm *p; + int largnum = 0, argnum = 0, first = 1; + // int varargs=0; + if (Generate_Wrapper) { + String *extra_parms = id_converter_arguments(n)->noname_str(); + if (Getattr(n, "sym:overloaded")) + Printf(fcl, "(swig-defmethod (\"%s\" \"%s\"%s)\n", funcname, mangled_name, extra_parms); + else + Printf(fcl, "(swig-defun (\"%s\" \"%s\"%s)\n", funcname, mangled_name, extra_parms); + Delete(extra_parms); + } + // Just C + else { + Printf(fcl, "(swig-defun (\"%s\" \"%s\")\n", funcname, Generate_Wrapper ? mangled_name : funcname); + } + + ////////////////////////////////////// + // Lisp foreign call parameter list // + ////////////////////////////////////// + Printf(fcl, " ("); + + /* Special cases */ + + if (ParmList_len(pl) == 0) { + Printf(fcl, ":void"); +/* } else if (any_varargs(pl)) { + Printf(fcl, "#| varargs |#"); + varargs=1; */ + } else { + String *largs = NewString(""); + + for (p = pl; p; p = nextSibling(p), argnum++, largnum++) { + // SwigType *argtype=Getattr(p, "type"); + SwigType *argtype = Swig_cparse_type(Getattr(p, "tmap:ctype")); + SwigType *parmtype = Getattr(p,"type"); + + if (!first) { + Printf(fcl, "\n "); + } + + /* by default, skip varargs */ + if (!SwigType_isvarargs(parmtype)) { + String *argname = NewStringf("PARM%d_%s", largnum, Getattr(p, "name")); + + // Printf(stderr,"%s\n", Getattr(p,"tmap:lin")); + String *ffitype = compose_foreign_type(n, argtype, Getattr(p,"name")); + String *deref_ffitype = dereference_ffitype(ffitype); + String *lisptype = get_lisp_type(n, parmtype, Getattr(p, "name")); + +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "lisptype of '%s' '%s' = '%s'\n", parmtype, + Getattr(p, "name"), lisptype); +#endif + + // while we're walking the parameters, generating LIN + // wrapper code... + Setattr(p, "lname", NewStringf("SWIG_arg%d", largnum)); + + String *parm_code = Getattr(p, "tmap:lin"); + if (parm_code) { + String *lname = Getattr(p, "lname"); + + Printf(largs, " %s", lname); + Replaceall(parm_code, "$in_fftype", ffitype); // must come before $in + Replaceall(parm_code, "$in", argname); + Replaceall(parm_code, "$out", lname); + Replaceall(parm_code, "$*in_fftype", deref_ffitype); + Replaceall(wrap->code, "$body", parm_code); + } + + String *dispatchtype = Getattr(n, "sym:overloaded") ? dispatching_type(n, p) : NewString(""); + + // if this parameter has been removed from the C/++ wrapper + // it shouldn't be in the lisp wrapper either. + if (!checkAttribute(p, "tmap:in:numinputs", "0")) { + Printf(fcl, "(%s %s %s %s %s)", + // parms in the ff wrapper, but not in the lisp wrapper. + (checkAttribute(p, "tmap:lin:numinputs", "0") ? ":p-" : ":p+"), argname, dispatchtype, ffitype, lisptype); + + first = 0; + } + + Delete(argname); + Delete(ffitype); + Delete(deref_ffitype); + Delete(lisptype); + } + } + + Printf(wrap->locals, "%s", largs); + } + + String *lout = Getattr(n, "tmap:lout"); + Replaceall(lout, "$owner", GetFlag(n, "feature:new") ? "t" : "nil"); + + Replaceall(wrap->code, "$body", lout); + // $lclass handling. + String *lclass = (String *) 0; + SwigType *parsed = Swig_cparse_type(Getattr(n, "tmap:ctype")); + // SwigType *cl_t = SwigType_typedef_resolve_all(parsed); + SwigType *cl_t = class_from_class_or_class_ref(parsed); + String *out_ffitype = compose_foreign_type(n, parsed); + String *deref_out_ffitype; + String *out_temp = Copy(parsed); + + if (SwigType_ispointer(out_temp)) { + SwigType_pop(out_temp); + deref_out_ffitype = compose_foreign_type(n, out_temp); + } else { + deref_out_ffitype = Copy(out_ffitype); + } + + Delete(out_temp); + + Delete(parsed); + + int isPtrReturn = 0; + + if (cl_t) { + lclass = lookup_defined_foreign_ltype(cl_t); + isPtrReturn = 1; + } + + int ff_foreign_ptr = 0; + if (!lclass) { + ff_foreign_ptr = 1; + lclass = NewStringf("ff:foreign-pointer"); + } +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "for output wrapping %s: type=%s, ctype=%s\n", Getattr(n, "name"), + Getattr(n, "type"), Swig_cparse_type(Getattr(n, "tmap:ctype"))); +#endif + + if (lclass) + Replaceall(wrap->code, "$lclass", lclass); + if (out_ffitype) + Replaceall(wrap->code, "$out_fftype", out_ffitype); + if (deref_out_ffitype) + Replaceall(wrap->code, "$*out_fftype", deref_out_ffitype); + // if(Replaceall(wrap->code,"$lclass", lclass) && !isPtrReturn) { + // Swig_warning(WARN_LANG_RETURN_TYPE,Getfile(n), Getline(n), + // "While Wrapping %s, replaced a $lclass reference when return type is non-pointer %s!\n", + // Getattr(n,"name"), cl_t); + // } + + Replaceall(wrap->code, "$body", NewStringf("(swig-ff-call%s)", wrap->locals)); +// Replaceall(wrap->code,"$body", +// (!Strcmp(result_type,"void") ? +// NewStringf("(swig-ff-call%s)", wrap->locals) : +// NewStringf("(push (swig-ff-call%s) ACL_result)", wrap->locals))); + String *ldestructor = Copy(lclass); + if (ff_foreign_ptr) + Replaceall(ldestructor, ldestructor, "identity"); + else + Replaceall(ldestructor, ":type :class", ":type :destructor"); + Replaceall(wrap->code, "$ldestructor", ldestructor); + Delete(ldestructor); + + Printf(fcl, ")\n"); /* finish arg list */ + + ///////////////////////////////////////////////////// + // Lisp foreign call return type and optimizations // + ///////////////////////////////////////////////////// + Printf(fcl, " (:returning (%s %s)", compose_foreign_type(n, result_type), get_lisp_type(n, Getattr(n, "type"), "result")); + + for (Iterator option = First(n); option.item; option = Next(option)) { + if (Strncmp("feature:ffargs:", option.key, 15)) + continue; + String *option_val = option.item; + String *option_name = NewString(Char(option.key) + 14); + Replaceall(option_name, "_", "-"); + + // TODO: varargs vs call-direct ? + Printf(fcl, "\n %s %s", option_name, option_val); + + Delete(option_name); + } + + Printf(fcl, ")\n %s)\n\n", wrap->code); + // Wrapper_print(wrap, stderr); + + Delete(result_type); + Delete(mangled_name); + Delete(pl); + DelWrapper(wrap); + +#ifdef ALLEGROCL_WRAP_DEBUG + Printf(stderr, "emit_defun: EXIT\n"); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::functionWrapper(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "functionWrapper %s\n", Getattr(n,"name")); + Swig_print_node(n); +#endif + + + ParmList *parms = CopyParmList(Getattr(n, "parms")); + Wrapper *f = NewWrapper(); + SwigType *t = Getattr(n, "type"); + String *name = Getattr(n, "name"); + + String *raw_return_type = Swig_typemap_lookup("ctype", n, "", 0); + SwigType *return_type = Swig_cparse_type(raw_return_type); + SwigType *resolved = SwigType_typedef_resolve_all(return_type); + int is_void_return = (Cmp(resolved, "void") == 0); + + Delete(resolved); + + if (!is_void_return) { + String *lresult_init = + NewStringf("= (%s)0", + SwigType_str(SwigType_strip_qualifiers(return_type),0)); + Wrapper_add_localv(f, "lresult", + SwigType_lstr(SwigType_ltype(return_type), "lresult"), + lresult_init, NIL); + Delete(lresult_init); + } + // Emit all of the local variables for holding arguments. + emit_parameter_variables(parms, f); + + // Attach the standard typemaps + Swig_typemap_attach_parms("ctype", parms, f); + Swig_typemap_attach_parms("lin", parms, f); + emit_attach_parmmaps(parms, f); + + String *mangled = mangle_name(n); + Node *overloaded = Getattr(n, "sym:overloaded"); + + // Parameter overloading + Setattr(n, "wrap:parms", parms); + Setattr(n, "wrap:name", mangled); + + if (overloaded) { + // emit warnings when overloading is impossible on the lisp side. + // basically Swig_overload_check(n), but with script_lang_wrapping + // set to true. + Delete(Swig_overload_rank(n, true)); + if (Getattr(n, "overload:ignore")) { + // if we're the last overload, make sure to force the emit + // of the rest of the overloads before we leave. + Printf(stderr, "ignored overload %s(%x)\n", name, Getattr(n, "sym:nextSibling")); + if (!Getattr(n, "sym:nextSibling")) { + update_package_if_needed(n); + emit_buffered_defuns(n); + emit_dispatch_defun(n); + } + DelWrapper(f); + return SWIG_OK; + } + } + // Get number of required and total arguments + int num_arguments = emit_num_arguments(parms); + int gencomma = 0; + +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "Walking parameters for %s '%s'\n", Getattr(n, "allegrocl:kind"), name); +#endif + // Now walk the function parameter list and generate code to get arguments + String *name_and_parms = NewStringf("%s (", mangled); + int i; + Parm *p; + for (i = 0, p = parms; i < num_arguments; i++) { + + while (p && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + if (!p) + break; + + SwigType *c_parm_type = Swig_cparse_type(Getattr(p, "tmap:ctype")); + String *arg = NewStringf("l%s", Getattr(p, "lname")); + + // Emit parameter declaration + if (gencomma) + Printf(name_and_parms, ", "); + String *parm_decl = SwigType_str(c_parm_type, arg); + Printf(name_and_parms, "%s", parm_decl); +#ifdef ALLEGROCL_DEBUG + Printf(stderr, " param: %s\n", parm_decl); +#endif + Delete(parm_decl); + gencomma = 1; + + // Emit parameter conversion code + String *parm_code = Getattr(p, "tmap:in"); + //if (!parm_code) { + // Swig_warning(...); + // p = nextSibling(p); + /*} else */ { + // canThrow(n, "in", p); + Replaceall(parm_code, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", parm_code); + p = Getattr(p, "tmap:in:next"); + } + + Delete(arg); + } + Printf(name_and_parms, ")"); + + // Emit the function definition + String *signature = SwigType_str(return_type, name_and_parms); + Printf(f->def, "EXPORT %s {", signature); + if (CPlusPlus) + Printf(f->code, " try {\n"); + + String *actioncode = emit_action(n); + + String *tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode); + if (!is_void_return && tm) { + if (tm) { + Replaceall(tm, "$result", "lresult"); + Printf(f->code, "%s\n", tm); + Printf(f->code, " return lresult;\n"); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, + "Unable to use return type %s in function %s.\n", + SwigType_str(t, 0), name); + } + } + + emit_return_variable(n, t, f); + + if (CPlusPlus) { + Printf(f->code, " } catch (...) {\n"); + if (!is_void_return) + Printf(f->code, " return (%s)0;\n", + SwigType_str(SwigType_strip_qualifiers(return_type),0)); + Printf(f->code, " }\n"); + } + Printf(f->code, "}\n"); + + /* print this when in C mode? make this a command-line arg? */ + if (Generate_Wrapper) + Wrapper_print(f, f_cxx_wrapper); + + String *f_buffer = NewString(""); + + emit_defun(n, f_buffer); + Setattr(n, "allegrocl:lisp-wrap", f_buffer); + + if (!overloaded || !Getattr(n, "sym:nextSibling")) { + update_package_if_needed(n); + emit_buffered_defuns(n); + // this is the last overload. + if (overloaded) { + emit_dispatch_defun(n); + } + } + + DelWrapper(f); + + return SWIG_OK; +} + +int ALLEGROCL::namespaceDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "namespaceDecl: '%s'(0x%x) (fc=0x%x)\n", Getattr(n, "sym:name"), n, firstChild(n)); +#endif + + /* don't wrap a namespace with no contents. package bloat. + also, test-suite/namespace_class.i claims an unnamed namespace + is 'private' and should not be wrapped. Complying... + */ + if (Getattr(n,"unnamed") || !firstChild(n)) + return SWIG_OK; + + String *name = Getattr(n, "sym:name"); + + String *old_namespace = current_namespace; + if (Cmp(current_namespace, "") == 0) + current_namespace = NewStringf("%s", name); + else + current_namespace = NewStringf("%s::%s", current_namespace, name); + + if (!GetInt(defined_namespace_packages, current_namespace)) { + SetInt(defined_namespace_packages, current_namespace, 1); + String *lispy_namespace = listify_namespace(current_namespace); + Printf(f_clhead, "(swig-defpackage %s)\n", lispy_namespace); + Delete(lispy_namespace); + } + + emit_children(n); + + Delete(current_namespace); + current_namespace = old_namespace; + return SWIG_OK; +} + +int ALLEGROCL::constructorHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "constructorHandler %s\n", Getattr(n, "name")); +#endif + // Swig_print_node(n); + Setattr(n, "allegrocl:kind", "constructor"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a global forwarding function. + return Language::constructorHandler(n); +} + +int ALLEGROCL::destructorHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "destructorHandler %s\n", Getattr(n, "name")); +#endif + + Setattr(n, "allegrocl:kind", "destructor"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a global forwarding function. + return Language::destructorHandler(n); +} + +int ALLEGROCL::constantWrapper(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "constantWrapper %s\n", Getattr(n, "name")); +#endif + + if (Generate_Wrapper) { + // Setattr(n,"wrap:name",mangle_name(n, "ACLPP")); + String *const_type = Getattr(n, "type"); + + String *const_val = 0; + String *raw_const = Getattr(n, "value"); + + if (SwigType_type(const_type) == T_STRING) { + const_val = NewStringf("\"%s\"", raw_const); + } else if (SwigType_type(const_type) == T_CHAR) { + const_val = NewStringf("'%s'", raw_const); + } else { + const_val = Copy(raw_const); + } + + SwigType_add_qualifier(const_type, "const"); + + String *ppcname = NewStringf("ACLppc_%s", Getattr(n, "sym:name")); + // Printf(f_runtime, "static const %s = %s;\n", SwigType_lstr(const_type, ppcname), const_val); + Printf(f_runtime, "static %s = %s;\n", SwigType_lstr(const_type, ppcname), const_val); + + Setattr(n, "name", ppcname); + SetFlag(n, "feature:immutable"); + + Delete(const_val); + return variableWrapper(n); + } + + String *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *converted_value = convert_literal(value, type); + String *name = Getattr(n, "sym:name"); + + Setattr(n, "allegrocl:kind", "constant"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + +#if 0 + Printf(stdout, "constant %s is of type %s. value: %s\n", name, type, converted_value); +#endif + + if (converted_value) { + Printf(f_clwrap, "(swig-defconstant \"%s\" %s)\n", name, converted_value); + } else { + Swig_warning(WARN_LANG_DISCARD_CONST, Getfile(n), Getline(n), "Unable to parse constant value '%s'. Setting to NIL\n", value); + Printf(f_clwrap, "(swig-defconstant \"%s\" nil #| %s |#)\n", name, value); + } + + Delete(converted_value); + + return SWIG_OK; +} + +int ALLEGROCL::globalvariableHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "globalvariableHandler %s\n", Getattr(n, "name")); +#endif + + if (Generate_Wrapper) + return Language::globalvariableHandler(n); + + // String *name = Getattr(n, "name"); + SwigType *type = Getattr(n, "type"); + SwigType *ctype; + SwigType *rtype = SwigType_typedef_resolve_all(type); + + int pointer_added = 0; + + if (SwigType_isclass(rtype)) { + SwigType_add_pointer(type); + SwigType_add_pointer(rtype); + pointer_added = 1; + } + + ctype = SwigType_str(type, 0); + // EXPORT <SwigType_str> <mangled_name>; + // <SwigType_str> <mangled_name> = <name>; + // Printf(f_runtime, "EXPORT %s %s;\n%s %s = %s%s;\n", ctype, mangled_name, + // ctype, mangled_name, (pointer_added ? "&" : ""), name); + + Printf(f_clwrap, "(swig-defvar \"%s\" \"%s\" :type %s)\n", + Getattr(n, "sym:name"), Getattr(n, "sym:name"), ((SwigType_isconst(type)) ? ":constant" : ":variable")); + + return SWIG_OK; +} + +int ALLEGROCL::variableWrapper(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "variableWrapper %s\n", Getattr(n, "name")); +#endif + Setattr(n, "allegrocl:kind", "variable"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a get/set function pair. + if (Generate_Wrapper) + return Language::variableWrapper(n); + + String *name = Getattr(n, "name"); + SwigType *type = Getattr(n, "type"); + SwigType *ctype; + SwigType *rtype = SwigType_typedef_resolve_all(type); + + String *mangled_name = mangle_name(n); + + int pointer_added = 0; + + if (SwigType_isclass(rtype)) { + SwigType_add_pointer(type); + SwigType_add_pointer(rtype); + pointer_added = 1; + } + + ctype = SwigType_str(type, 0); + + // EXPORT <SwigType_str> <mangled_name>; + // <SwigType_str> <mangled_name> = <name>; + Printf(f_runtime, "EXPORT %s %s;\n%s %s = %s%s;\n", ctype, mangled_name, ctype, mangled_name, (pointer_added ? "&" : ""), name); + + Printf(f_cl, "(swig-defvar \"%s\" :type %s)\n", mangled_name, ((SwigType_isconst(type)) ? ":constant" : ":variable")); + + Printf(stderr,"***\n"); + Delete(mangled_name); + +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "DONE variable %s\n", Getattr(n, "name")); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::memberfunctionHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "memberfunctionHandler %s::%s\n", Getattr(parent_node_skipping_extends(n), "name"), Getattr(n, "name")); +#endif + Setattr(n, "allegrocl:kind", "member function"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a global forwarding function. + return Language::memberfunctionHandler(n); +} + +int ALLEGROCL::membervariableHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "membervariableHandler %s::%s\n", Getattr(parent_node_skipping_extends(n), "name"), Getattr(n, "name")); +#endif + Setattr(n, "allegrocl:kind", "member variable"); + Setattr(n, "allegrocl:old-sym:name", Getattr(n, "sym:name")); + + // Let SWIG generate a get/set function pair. + return Language::membervariableHandler(n); +} + +int ALLEGROCL::typedefHandler(Node *n) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "In typedefHandler\n"); +#endif + + SwigType *typedef_type = Getattr(n,"type"); + // has the side-effect of noting any implicit + // template instantiations in type. + String *ff_type = compose_foreign_type(n, typedef_type); + + String *sym_name = Getattr(n, "sym:name"); + + String *name; + String *type_ref; + + if (in_class) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, " typedef in class '%s'(%x)\n", Getattr(in_class, "sym:name"), in_class); +#endif + Setattr(n, "allegrocl:typedef:in-class", in_class); + + String *class_name = Getattr(in_class, "name"); + name = NewStringf("%s__%s", class_name, sym_name); + type_ref = NewStringf("%s::%s", class_name, sym_name); + Setattr(n, "allegrocl:in-class", in_class); + } else { + name = Copy(sym_name); + type_ref = Copy(Getattr(n, "name")); + } + + Setattr(n, "allegrocl:namespace", current_namespace); + + String *lookup = lookup_defined_foreign_type(typedef_type); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "** lookup='%s'(%x), typedef_type='%s', strcmp = '%d' strstr = '%d'\n", lookup, lookup, typedef_type, Strcmp(typedef_type,"void"), Strstr(ff_type,"__SWIGACL_FwdReference")); +#endif + + if(lookup || (!lookup && Strcmp(typedef_type,"void")) || + (!lookup && Strstr(ff_type,"__SWIGACL_FwdReference"))) { + add_defined_foreign_type(n, 0, type_ref, name); + } else { + add_forward_referenced_type(n); + } + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Out typedefHandler\n"); +#endif + + Delete(ff_type); + + return SWIG_OK; +} + +// forward referenced classes are added specially to defined_foreign_types +int ALLEGROCL::classforwardDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "classforwardDeclaration %s\n", Getattr(n, "name")); +#endif + + add_forward_referenced_type(n); + return SWIG_OK; +} + +int ALLEGROCL::classHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "classHandler %s::%s\n", current_namespace, Getattr(n, "sym:name")); +#endif + + int result; + + if (Generate_Wrapper) + result = cppClassHandler(n); + else + result = cClassHandler(n); + + return result; +} + +int ALLEGROCL::cClassHandler(Node *n) { +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "In cClassHandler\n"); +#endif + // String *cDeclName = Getattr(n,"classDeclaration:name"); + // String *name= Getattr(n, "sym:name"); + // String *kind = Getattr(n,"kind"); + // Node *c; + + /* Add this structure to the known lisp types */ + // Printf(stderr, "Adding %s foreign type\n", name); + String *ns = listify_namespace(current_namespace); + + add_defined_foreign_type(n); + + Delete(ns); + +#ifdef ALLEGROCL_TYPE_DEBUG + Printf(stderr, "Out cClassHandler\n"); +#endif + + return SWIG_OK; +} + +int ALLEGROCL::cppClassHandler(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "cppClassHandler %s\n", Getattr(n, "name")); +#endif + + // String *name=Getattr(n, "sym:name"); + // String *kind = Getattr(n,"kind"); + + /* Template instantiation. + Careful. + SWIG does not create instantiations of templated classes whenever + it sees a templated class reference (say, as a return type, or + in a parameter list). + + The %template directive results in a templated class instantiation + that will actually be seen by <LANG> :: classHandler(). + + In this case, we don't want to error if the type already exists; + the point is to force the creation of wrappers for the templated + class. + */ + String *templated = Getattr(n, "template"); + String *t_name; + // String *ns = listify_namespace(current_namespace); + + if (templated) { + t_name = namespaced_name(n); + } else { + t_name = Getattr(n, "name"); + } + + Setattr(n, "allegrocl:namespace", current_namespace); + + /* Add this structure to the known lisp types. + Class may contain references to the type currently being + defined */ + if (!templated || !lookup_defined_foreign_type(t_name)) { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "Adding %s foreign type\n", Getattr(n, "sym:name")); +#endif + add_defined_foreign_type(n); + } else { +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "cppClassHand: type %s already exists. Assuming %%template instantiation for wrapping purposes.\n", Getattr(n, "sym:name")); +#endif + add_defined_foreign_type(n, 1); + } + + // Generate slot accessors, constructor, and destructor. + Node *prev_class = in_class; + in_class = n; + + Node *c; + // walk all member variables. +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " MANUALLY walking class members... \n"); +#endif + for (c = firstChild(n); c; c = nextSibling(c)) { + // ping the types of all children--even protected and private + // so their types can be added to the linked_type_list. + SwigType *childType = NewStringf("%s%s", Getattr(c, "decl"), + Getattr(c, "type")); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, "looking at child '%x' of type '%s'\n", c, childType); +#endif + if (!SwigType_isfunction(childType)) + Delete(compose_foreign_type(n, childType)); + + Delete(childType); + } +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " MANUAL walk DONE.\n"); +#endif + + // this will walk all necessary methods. +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " LANGUAGE walk of children...\n"); +#endif + Language::classHandler(n); +#ifdef ALLEGROCL_CLASS_DEBUG + Printf(stderr, " LANGUAGE walk DONE\n"); +#endif + in_class = prev_class; + + return SWIG_OK; +} + +int ALLEGROCL::emit_one(Node *n) { + // When the current package does not correspond with the current + // namespace we need to generate an IN-PACKAGE form, unless the + // current node is another namespace node. + if (Cmp(nodeType(n), "namespace") != 0 && Cmp(current_package, current_namespace) != 0) { + String *lispy_namespace = listify_namespace(current_namespace); + Printf(f_clwrap, "(swig-in-package %s)\n", lispy_namespace); + Delete(lispy_namespace); + Delete(current_package); + current_package = NewStringf("%s", current_namespace); + } + + Setattr(n, "allegrocl:package", current_package); + + return Language::emit_one(n); +} + +int ALLEGROCL::enumDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "enumDeclaration %s\n", Getattr(n, "name")); +#endif + + if (Getattr(n, "sym:name")) { + add_defined_foreign_type(n); + } + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + ALLEGROCL::enumvalueDeclaration(c); + // since we walk our own children, we need to add + // the current package ourselves. + Setattr(c, "allegrocl:package", current_package); + } + return SWIG_OK; +} + + +int ALLEGROCL::enumvalueDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "enumvalueDeclaration %s\n", Getattr(n, "name")); +#endif + /* print this when in C mode? make this a command-line arg? */ + if (Generate_Wrapper) { + SwigType *enum_type = Copy(Getattr(n,"type")); + String *mangled_name = + mangle_name(n, "ACL_ENUM", + in_class ? Getattr(in_class,"name") : + current_namespace); + + SwigType_add_qualifier(enum_type,"const"); + + String *enum_decl = SwigType_str(enum_type, mangled_name); + Printf(f_cxx_wrapper, "EXPORT %s;\n", enum_decl); + Printf(f_cxx_wrapper, "%s = %s;\n", enum_decl, Getattr(n, "value")); + + Delete(mangled_name); + Delete(enum_type); + Delete(enum_decl); + } + return SWIG_OK; +} + +int ALLEGROCL::templateDeclaration(Node *n) { +#ifdef ALLEGROCL_DEBUG + Printf(stderr, "templateDeclaration %s\n", Getattr(n, "name")); +#endif + + String *type = Getattr(n, "templatetype"); + + // Printf(stderr, "tempDecl: %s %s\n", Getattr(n,"name"), + // type); + // Swig_print_node(n); + + if (!Strcmp(type, "cdecl")) { + SwigType *ty = NewStringf("%s%s", Getattr(n, "decl"), + Getattr(n, "type")); + Delete(ty); + } + + Delete(type); + + return SWIG_OK; +} diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx new file mode 100644 index 0000000..b52578b --- /dev/null +++ b/Source/Modules/allocate.cxx @@ -0,0 +1,955 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * allocate.cxx + * + * This module tries to figure out which classes and structures support + * default constructors and destructors in C++. There are several rules that + * define this behavior including pure abstract methods, private sections, + * and non-default constructors in base classes. See the ARM or + * Doc/Manual/SWIGPlus.html for details. + * ----------------------------------------------------------------------------- */ + +char cvsroot_allocate_cxx[] = "$Id: allocate.cxx 11583 2009-08-15 23:22:20Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" + +static int virtual_elimination_mode = 0; /* set to 0 on default */ + +/* Set virtual_elimination_mode */ +void Wrapper_virtual_elimination_mode_set(int flag) { + virtual_elimination_mode = flag; +} + +/* Helper function to assist with abstract class checking. + This is a major hack. Sorry. */ + +extern "C" { + static String *search_decl = 0; /* Declarator being searched */ + static int check_implemented(Node *n) { + String *decl; + if (!n) + return 0; + while (n) { + if (Strcmp(nodeType(n), "cdecl") == 0) { + decl = Getattr(n, "decl"); + if (SwigType_isfunction(decl)) { + SwigType *decl1 = SwigType_typedef_resolve_all(decl); + SwigType *decl2 = SwigType_pop_function(decl1); + if (Strcmp(decl2, search_decl) == 0) { + if (!Getattr(n, "abstract")) { + Delete(decl1); + Delete(decl2); + return 1; + } + } + Delete(decl1); + Delete(decl2); + } + } + n = Getattr(n, "csym:nextSibling"); + } + return 0; + } +} + +class Allocate:public Dispatcher { + Node *inclass; + int extendmode; + + /* Checks if a function, n, is the same as any in the base class, ie if the method is polymorphic. + * Also checks for methods which will be hidden (ie a base has an identical non-virtual method). + * Both methods must have public access for a match to occur. */ + int function_is_defined_in_bases(Node *n, Node *bases) { + + if (!bases) + return 0; + + String *this_decl = Getattr(n, "decl"); + if (!this_decl) + return 0; + + String *name = Getattr(n, "name"); + String *this_type = Getattr(n, "type"); + String *resolved_decl = SwigType_typedef_resolve_all(this_decl); + + // Search all base classes for methods with same signature + for (int i = 0; i < Len(bases); i++) { + Node *b = Getitem(bases, i); + Node *base = firstChild(b); + while (base) { + if (Strcmp(nodeType(base), "extend") == 0) { + // Loop through all the %extend methods + Node *extend = firstChild(base); + while (extend) { + if (function_is_defined_in_bases_seek(n, b, extend, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + extend = nextSibling(extend); + } + } else if (Strcmp(nodeType(base), "using") == 0) { + // Loop through all the using declaration methods + Node *usingdecl = firstChild(base); + while (usingdecl) { + if (function_is_defined_in_bases_seek(n, b, usingdecl, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + usingdecl = nextSibling(usingdecl); + } + } else { + // normal methods + if (function_is_defined_in_bases_seek(n, b, base, this_decl, name, this_type, resolved_decl)) { + Delete(resolved_decl); + return 1; + } + } + base = nextSibling(base); + } + } + Delete(resolved_decl); + resolved_decl = 0; + for (int j = 0; j < Len(bases); j++) { + Node *b = Getitem(bases, j); + if (function_is_defined_in_bases(n, Getattr(b, "allbases"))) + return 1; + } + return 0; + } + + /* Helper function for function_is_defined_in_bases */ + int function_is_defined_in_bases_seek(Node *n, Node *b, Node *base, String *this_decl, String *name, String *this_type, String *resolved_decl) { + + String *base_decl = Getattr(base, "decl"); + SwigType *base_type = Getattr(base, "type"); + if (base_decl && base_type) { + if (checkAttribute(base, "name", name) && !GetFlag(b, "feature:ignore") /* whole class is ignored */ ) { + if (SwigType_isfunction(resolved_decl) && SwigType_isfunction(base_decl)) { + // We have found a method that has the same name as one in a base class + bool covariant_returntype = false; + bool returntype_match = Strcmp(base_type, this_type) == 0 ? true : false; + bool decl_match = Strcmp(base_decl, this_decl) == 0 ? true : false; + if (returntype_match && decl_match) { + // Exact match - we have found a method with identical signature + // No typedef resolution was done, but skipping it speeds things up slightly + } else { + // Either we have: + // 1) matching methods but are one of them uses a different typedef (return type or parameter) to the one in base class' method + // 2) matching polymorphic methods with covariant return type + // 3) a non-matching method (ie an overloaded method of some sort) + // 4) a matching method which is not polymorphic, ie it hides the base class' method + + // Check if fully resolved return types match (including + // covariant return types) + if (!returntype_match) { + String *this_returntype = function_return_type(n); + String *base_returntype = function_return_type(base); + returntype_match = Strcmp(this_returntype, base_returntype) == 0 ? true : false; + if (!returntype_match) { + covariant_returntype = SwigType_issubtype(this_returntype, base_returntype) ? true : false; + returntype_match = covariant_returntype; + } + Delete(this_returntype); + Delete(base_returntype); + } + // The return types must match at this point, for the whole method to match + if (returntype_match && !decl_match) { + // Now need to check the parameter list + // First do an inexpensive parameter count + ParmList *this_parms = Getattr(n, "parms"); + ParmList *base_parms = Getattr(base, "parms"); + if (ParmList_len(this_parms) == ParmList_len(base_parms)) { + // Number of parameters are the same, now check that all the parameters match + SwigType *base_fn = NewString(""); + SwigType *this_fn = NewString(""); + SwigType_add_function(base_fn, base_parms); + SwigType_add_function(this_fn, this_parms); + base_fn = SwigType_typedef_resolve_all(base_fn); + this_fn = SwigType_typedef_resolve_all(this_fn); + if (Strcmp(base_fn, this_fn) == 0) { + // Finally check that the qualifiers match + int base_qualifier = SwigType_isqualifier(resolved_decl); + int this_qualifier = SwigType_isqualifier(base_decl); + if (base_qualifier == this_qualifier) { + decl_match = true; + } + } + Delete(base_fn); + Delete(this_fn); + } + } + } + //Printf(stderr,"look %s %s %d %d\n",base_decl, this_decl, returntype_match, decl_match); + + if (decl_match && returntype_match) { + // Found an identical method in the base class + bool this_wrapping_protected_members = is_member_director(n) ? true : false; // This should really check for dirprot rather than just being a director method + bool base_wrapping_protected_members = is_member_director(base) ? true : false; // This should really check for dirprot rather than just being a director method + bool both_have_public_access = is_public(n) && is_public(base); + bool both_have_protected_access = (is_protected(n) && this_wrapping_protected_members) && (is_protected(base) && base_wrapping_protected_members); + bool both_have_private_access = is_private(n) && is_private(base); + if (checkAttribute(base, "storage", "virtual")) { + // Found a polymorphic method. + // Mark the polymorphic method, in case the virtual keyword was not used. + Setattr(n, "storage", "virtual"); + + if (both_have_public_access || both_have_protected_access) { + if (!is_non_public_base(inclass, b)) + Setattr(n, "override", base); // Note C# definition of override, ie access must be the same + } else if (!both_have_private_access) { + // Different access + if (this_wrapping_protected_members || base_wrapping_protected_members) + if (!is_non_public_base(inclass, b)) + Setattr(n, "hides", base); // Note C# definition of hiding, ie hidden if access is different + } + // Try and find the most base's covariant return type + SwigType *most_base_covariant_type = Getattr(base, "covariant"); + if (!most_base_covariant_type && covariant_returntype) + most_base_covariant_type = function_return_type(base, false); + + if (!most_base_covariant_type) { + // Eliminate the derived virtual method. + if (virtual_elimination_mode) + if (both_have_public_access) + if (!is_non_public_base(inclass, b)) + if (!Swig_symbol_isoverloaded(n)) { + // Don't eliminate if an overloaded method as this hides the method + // in the scripting languages: the dispatch function will hide the base method if ignored. + SetFlag(n, "feature:ignore"); + } + } else { + // Some languages need to know about covariant return types + Setattr(n, "covariant", most_base_covariant_type); + } + + } else { + // Found an identical method in the base class, but it is not polymorphic. + if (both_have_public_access || both_have_protected_access) + if (!is_non_public_base(inclass, b)) + Setattr(n, "hides", base); + } + if (both_have_public_access || both_have_protected_access) + return 1; + } + } + } + } + return 0; + } + + /* Determines whether the base class, b, is in the list of private + * or protected base classes for class n. */ + bool is_non_public_base(Node *n, Node *b) { + bool non_public_base = false; + Node *bases = Getattr(n, "privatebases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *base = Getitem(bases, i); + if (base == b) + non_public_base = true; + } + } + bases = Getattr(n, "protectedbases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *base = Getitem(bases, i); + if (base == b) + non_public_base = true; + } + } + return non_public_base; + } + + /* Returns the return type for a function. The node n should be a function. + If resolve is true the fully returned type is fully resolved. + Caller is responsible for deleting returned string. */ + String *function_return_type(Node *n, bool resolve = true) { + String *decl = Getattr(n, "decl"); + SwigType *type = Getattr(n, "type"); + String *ty = NewString(type); + SwigType_push(ty, decl); + if (SwigType_isqualifier(ty)) + Delete(SwigType_pop(ty)); + Delete(SwigType_pop_function(ty)); + if (resolve) { + String *unresolved = ty; + ty = SwigType_typedef_resolve_all(unresolved); + Delete(unresolved); + } + return ty; + } + + /* Checks if a class member is the same as inherited from the class bases */ + int class_member_is_defined_in_bases(Node *member, Node *classnode) { + Node *bases; /* bases is the closest ancestors of classnode */ + int defined = 0; + + bases = Getattr(classnode, "allbases"); + if (!bases) + return 0; + + { + int old_mode = virtual_elimination_mode; + if (is_member_director(classnode, member)) + virtual_elimination_mode = 0; + + if (function_is_defined_in_bases(member, bases)) { + defined = 1; + } + + virtual_elimination_mode = old_mode; + } + + if (defined) + return 1; + else + return 0; + } + + /* Checks to see if a class is abstract through inheritance, + and saves the first node that seems to be abstract. + */ + int is_abstract_inherit(Node *n, Node *base = 0, int first = 0) { + if (!first && (base == n)) + return 0; + if (!base) { + /* Root node */ + Symtab *stab = Getattr(n, "symtab"); /* Get symbol table for node */ + Symtab *oldtab = Swig_symbol_setscope(stab); + int ret = is_abstract_inherit(n, n, 1); + Swig_symbol_setscope(oldtab); + return ret; + } + List *abstract = Getattr(base, "abstract"); + if (abstract) { + int dabstract = 0; + int len = Len(abstract); + for (int i = 0; i < len; i++) { + Node *nn = Getitem(abstract, i); + String *name = Getattr(nn, "name"); + if (!name) + continue; + String *base_decl = Getattr(nn, "decl"); + if (base_decl) + base_decl = SwigType_typedef_resolve_all(base_decl); + if (Strchr(name, '~')) + continue; /* Don't care about destructors */ + + if (SwigType_isfunction(base_decl)) { + search_decl = SwigType_pop_function(base_decl); + } + Node *dn = Swig_symbol_clookup_local_check(name, 0, check_implemented); + Delete(search_decl); + Delete(base_decl); + + if (!dn) { + List *nabstract = Getattr(n, "abstract"); + if (!nabstract) { + nabstract = NewList(); + Setattr(n, "abstract", nabstract); + Delete(nabstract); + } + Append(nabstract, nn); + if (!Getattr(n, "abstract:firstnode")) { + Setattr(n, "abstract:firstnode", nn); + } + dabstract = base != n; + } + } + if (dabstract) + return 1; + } + List *bases = Getattr(base, "allbases"); + if (!bases) + return 0; + for (int i = 0; i < Len(bases); i++) { + if (is_abstract_inherit(n, Getitem(bases, i))) { + return 1; + } + } + return 0; + } + + + /* Grab methods used by smart pointers */ + + List *smart_pointer_methods(Node *cls, List *methods, int isconst, String *classname = 0) { + if (!methods) { + methods = NewList(); + } + + Node *c = firstChild(cls); + String *kind = Getattr(cls, "kind"); + int mode = PUBLIC; + if (kind && (Strcmp(kind, "class") == 0)) + mode = PRIVATE; + + while (c) { + if (Getattr(c, "error") || GetFlag(c, "feature:ignore")) { + c = nextSibling(c); + continue; + } + if (!isconst && (Strcmp(nodeType(c), "extend") == 0)) { + methods = smart_pointer_methods(c, methods, isconst, Getattr(cls, "name")); + } else if (Strcmp(nodeType(c), "cdecl") == 0) { + if (!GetFlag(c, "feature:ignore")) { + String *storage = Getattr(c, "storage"); + if (!((Cmp(storage, "typedef") == 0)) + && !((Cmp(storage, "friend") == 0))) { + String *name = Getattr(c, "name"); + String *symname = Getattr(c, "sym:name"); + Node *e = Swig_symbol_clookup_local(name, 0); + if (e && is_public(e) && !GetFlag(e, "feature:ignore") && (Cmp(symname, Getattr(e, "sym:name")) == 0)) { + Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(e), Getline(e), "Declaration of '%s' shadows declaration accessible via operator->(),\n", name); + Swig_warning(WARN_LANG_DEREF_SHADOW, Getfile(c), Getline(c), "previous declaration of '%s'.\n", name); + } else { + /* Make sure node with same name doesn't already exist */ + int k; + int match = 0; + for (k = 0; k < Len(methods); k++) { + e = Getitem(methods, k); + if (Cmp(symname, Getattr(e, "sym:name")) == 0) { + match = 1; + break; + } + if ((!symname || (!Getattr(e, "sym:name"))) && (Cmp(name, Getattr(e, "name")) == 0)) { + match = 1; + break; + } + } + if (!match) { + Node *cc = c; + while (cc) { + Node *cp = cc; + if (classname) { + Setattr(cp, "classname", classname); + } + Setattr(cp, "allocate:smartpointeraccess", "1"); + /* If constant, we have to be careful */ + if (isconst) { + SwigType *decl = Getattr(cp, "decl"); + if (decl) { + if (SwigType_isfunction(decl)) { /* If method, we only add if it's a const method */ + if (SwigType_isconst(decl)) { + Append(methods, cp); + } + } else { + Append(methods, cp); + } + } else { + Append(methods, cp); + } + } else { + Append(methods, cp); + } + cc = Getattr(cc, "sym:nextSibling"); + } + } + } + } + } + } + + if (Strcmp(nodeType(c), "access") == 0) { + kind = Getattr(c, "kind"); + if (Strcmp(kind, "public") == 0) + mode = PUBLIC; + else + mode = PRIVATE; + } + c = nextSibling(c); + } + /* Look for methods in base classes */ + { + Node *bases = Getattr(cls, "bases"); + int k; + for (k = 0; k < Len(bases); k++) { + smart_pointer_methods(Getitem(bases, k), methods, isconst); + } + } + /* Remove protected/private members */ + { + for (int i = 0; i < Len(methods);) { + Node *n = Getitem(methods, i); + if (!is_public(n)) { + Delitem(methods, i); + continue; + } + i++; + } + } + return methods; + } + + void mark_exception_classes(ParmList *p) { + while (p) { + SwigType *ty = Getattr(p, "type"); + SwigType *t = SwigType_typedef_resolve_all(ty); + if (SwigType_isreference(t) || SwigType_ispointer(t) || SwigType_isarray(t)) { + Delete(SwigType_pop(t)); + } + Node *c = Swig_symbol_clookup(t, 0); + if (c) { + if (!GetFlag(c, "feature:exceptionclass")) { + SetFlag(c, "feature:exceptionclass"); + } + } + p = nextSibling(p); + Delete(t); + } + } + + + void process_exceptions(Node *n) { + ParmList *catchlist = 0; + /* + the "catchlist" attribute is used to emit the block + + try {$action;} + catch <list of catches>; + + in emit.cxx + + and is either constructued from the "feature:catches" feature + or copied from the node "throws" list. + */ + String *scatchlist = Getattr(n, "feature:catches"); + if (scatchlist) { + catchlist = Swig_cparse_parms(scatchlist); + if (catchlist) { + Setattr(n, "catchlist", catchlist); + mark_exception_classes(catchlist); + Delete(catchlist); + } + } + ParmList *throws = Getattr(n, "throws"); + if (throws) { + /* if there is no explicit catchlist, we catch everything in the throws list */ + if (!catchlist) { + Setattr(n, "catchlist", throws); + } + mark_exception_classes(throws); + } + } + +public: +Allocate(): + inclass(NULL), extendmode(0) { + } + + virtual int top(Node *n) { + cplus_mode = PUBLIC; + inclass = 0; + extendmode = 0; + emit_children(n); + return SWIG_OK; + } + + virtual int importDirective(Node *n) { + return emit_children(n); + } + virtual int includeDirective(Node *n) { + return emit_children(n); + } + virtual int externDeclaration(Node *n) { + return emit_children(n); + } + virtual int namespaceDeclaration(Node *n) { + return emit_children(n); + } + virtual int extendDirective(Node *n) { + extendmode = 1; + emit_children(n); + extendmode = 0; + return SWIG_OK; + } + + virtual int classDeclaration(Node *n) { + Symtab *symtab = Swig_symbol_current(); + Swig_symbol_setscope(Getattr(n, "symtab")); + + if (!CPlusPlus) { + /* Always have default constructors/destructors in C */ + Setattr(n, "allocate:default_constructor", "1"); + Setattr(n, "allocate:default_destructor", "1"); + } + + if (Getattr(n, "allocate:visit")) + return SWIG_OK; + Setattr(n, "allocate:visit", "1"); + + /* Always visit base classes first */ + { + List *bases = Getattr(n, "bases"); + if (bases) { + for (int i = 0; i < Len(bases); i++) { + Node *b = Getitem(bases, i); + classDeclaration(b); + } + } + } + + inclass = n; + String *kind = Getattr(n, "kind"); + if (Strcmp(kind, "class") == 0) { + cplus_mode = PRIVATE; + } else { + cplus_mode = PUBLIC; + } + + emit_children(n); + + /* Check if the class is abstract via inheritance. This might occur if a class didn't have + any pure virtual methods of its own, but it didn't implement all of the pure methods in + a base class */ + if (!Getattr(n, "abstract") && is_abstract_inherit(n)) { + if (((Getattr(n, "allocate:public_constructor") || (!GetFlag(n, "feature:nodefault") && !Getattr(n, "allocate:has_constructor"))))) { + if (!GetFlag(n, "feature:notabstract")) { + Node *na = Getattr(n, "abstract:firstnode"); + if (na) { + Swig_warning(WARN_TYPE_ABSTRACT, Getfile(n), Getline(n), + "Class '%s' might be abstract, " "no constructors generated,\n", SwigType_namestr(Getattr(n, "name"))); + Swig_warning(WARN_TYPE_ABSTRACT, Getfile(na), Getline(na), "Method %s might not be implemented.\n", Swig_name_decl(na)); + if (!Getattr(n, "abstract")) { + List *abstract = NewList(); + Append(abstract, na); + Setattr(n, "abstract", abstract); + Delete(abstract); + } + } + } + } + } + + if (!Getattr(n, "allocate:has_constructor")) { + /* No constructor is defined. We need to check a few things */ + /* If class is abstract. No default constructor. Sorry */ + if (Getattr(n, "abstract")) { + Delattr(n, "allocate:default_constructor"); + } + if (!Getattr(n, "allocate:default_constructor")) { + /* Check base classes */ + List *bases = Getattr(n, "allbases"); + int allows_default = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow default constructor, we don't allow it either */ + if (!Getattr(n, "allocate:default_constructor") && (!Getattr(n, "allocate:default_base_constructor"))) { + allows_default = 0; + } + } + if (allows_default) { + Setattr(n, "allocate:default_constructor", "1"); + } + } + } + if (!Getattr(n, "allocate:has_copy_constructor")) { + if (Getattr(n, "abstract")) { + Delattr(n, "allocate:copy_constructor"); + } + if (!Getattr(n, "allocate:copy_constructor")) { + /* Check base classes */ + List *bases = Getattr(n, "allbases"); + int allows_copy = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow copy constructor, we don't allow it either */ + if (!Getattr(n, "allocate:copy_constructor") && (!Getattr(n, "allocate:copy_base_constructor"))) { + allows_copy = 0; + } + } + if (allows_copy) { + Setattr(n, "allocate:copy_constructor", "1"); + } + } + } + + if (!Getattr(n, "allocate:has_destructor")) { + /* No destructor was defined. We need to check a few things here too */ + List *bases = Getattr(n, "allbases"); + int allows_destruct = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow default destructor, we don't allow it either */ + if (!Getattr(n, "allocate:default_destructor") && (!Getattr(n, "allocate:default_base_destructor"))) { + allows_destruct = 0; + } + } + if (allows_destruct) { + Setattr(n, "allocate:default_destructor", "1"); + } + } + + if (!Getattr(n, "allocate:has_assign")) { + /* No destructor was defined. We need to check a few things here too */ + List *bases = Getattr(n, "allbases"); + int allows_assign = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow default destructor, we don't allow it either */ + if (Getattr(n, "allocate:has_assign")) { + allows_assign = !Getattr(n, "allocate:noassign"); + } + } + if (!allows_assign) { + Setattr(n, "allocate:noassign", "1"); + } + } + + if (!Getattr(n, "allocate:has_new")) { + /* No destructor was defined. We need to check a few things here too */ + List *bases = Getattr(n, "allbases"); + int allows_new = 1; + + for (int i = 0; i < Len(bases); i++) { + Node *n = Getitem(bases, i); + /* If base class does not allow default destructor, we don't allow it either */ + if (Getattr(n, "allocate:has_new")) { + allows_new = !Getattr(n, "allocate:nonew"); + } + } + if (!allows_new) { + Setattr(n, "allocate:nonew", "1"); + } + } + + /* Check if base classes allow smart pointers, but might be hidden */ + if (!Getattr(n, "allocate:smartpointer")) { + Node *sp = Swig_symbol_clookup((char *) "operator ->", 0); + if (sp) { + /* Look for parent */ + Node *p = parentNode(sp); + if (Strcmp(nodeType(p), "extend") == 0) { + p = parentNode(p); + } + if (Strcmp(nodeType(p), "class") == 0) { + if (GetFlag(p, "feature:ignore")) { + Setattr(n, "allocate:smartpointer", Getattr(p, "allocate:smartpointer")); + } + } + } + } + + /* Only care about default behavior. Remove temporary values */ + Setattr(n, "allocate:visit", "1"); + inclass = 0; + Swig_symbol_setscope(symtab); + return SWIG_OK; + } + + virtual int accessDeclaration(Node *n) { + String *kind = Getattr(n, "kind"); + if (Cmp(kind, "public") == 0) { + cplus_mode = PUBLIC; + } else if (Cmp(kind, "private") == 0) { + cplus_mode = PRIVATE; + } else if (Cmp(kind, "protected") == 0) { + cplus_mode = PROTECTED; + } + return SWIG_OK; + } + + virtual int usingDeclaration(Node *n) { + + Node *c = 0; + for (c = firstChild(n); c; c = nextSibling(c)) { + if (Strcmp(nodeType(c), "cdecl") == 0) { + process_exceptions(c); + + if (inclass) + class_member_is_defined_in_bases(c, inclass); + } + } + + return SWIG_OK; + } + + virtual int cDeclaration(Node *n) { + + process_exceptions(n); + + if (inclass) { + /* check whether the member node n is defined in class node in class's bases */ + class_member_is_defined_in_bases(n, inclass); + + /* Check to see if this is a static member or not. If so, we add an attribute + cplus:staticbase that saves the current class */ + + if (checkAttribute(n, "storage", "static")) { + Setattr(n, "cplus:staticbase", inclass); + } + + String *name = Getattr(n, "name"); + if (cplus_mode != PUBLIC) { + if (Strcmp(name, "operator =") == 0) { + /* Look for a private assignment operator */ + Setattr(inclass, "allocate:has_assign", "1"); + Setattr(inclass, "allocate:noassign", "1"); + } else if (Strcmp(name, "operator new") == 0) { + /* Look for a private new operator */ + Setattr(inclass, "allocate:has_new", "1"); + Setattr(inclass, "allocate:nonew", "1"); + } + } else { + if (Strcmp(name, "operator =") == 0) { + Setattr(inclass, "allocate:has_assign", "1"); + } else if (Strcmp(name, "operator new") == 0) { + Setattr(inclass, "allocate:has_new", "1"); + } + /* Look for smart pointer operator */ + if ((Strcmp(name, "operator ->") == 0) && (!GetFlag(n, "feature:ignore"))) { + /* Look for version with no parameters */ + Node *sn = n; + while (sn) { + if (!Getattr(sn, "parms")) { + SwigType *type = SwigType_typedef_resolve_all(Getattr(sn, "type")); + SwigType_push(type, Getattr(sn, "decl")); + Delete(SwigType_pop_function(type)); + SwigType *base = SwigType_base(type); + Node *sc = Swig_symbol_clookup(base, 0); + if ((sc) && (Strcmp(nodeType(sc), "class") == 0)) { + if (SwigType_check_decl(type, "p.")) { + /* Need to check if type is a const pointer */ + int isconst = 0; + Delete(SwigType_pop(type)); + if (SwigType_isconst(type)) { + isconst = 1; + Setattr(inclass, "allocate:smartpointerconst", "1"); + } + List *methods = smart_pointer_methods(sc, 0, isconst); + Setattr(inclass, "allocate:smartpointer", methods); + Setattr(inclass, "allocate:smartpointerbase", base); + } else { + /* Hmmm. The return value is not a pointer. If the type is a value + or reference. We're going to chase it to see if another operator->() + can be found */ + + if ((SwigType_check_decl(type, "")) || (SwigType_check_decl(type, "r."))) { + Node *nn = Swig_symbol_clookup((char *) "operator ->", Getattr(sc, "symtab")); + if (nn) { + Delete(base); + Delete(type); + sn = nn; + continue; + } + } + } + } + Delete(base); + Delete(type); + break; + } + } + } + } + } + return SWIG_OK; + } + + virtual int constructorDeclaration(Node *n) { + if (!inclass) + return SWIG_OK; + Parm *parms = Getattr(n, "parms"); + + process_exceptions(n); + if (!extendmode) { + if (!ParmList_numrequired(parms)) { + /* Class does define a default constructor */ + /* However, we had better see where it is defined */ + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:default_constructor", "1"); + } else if (cplus_mode == PROTECTED) { + Setattr(inclass, "allocate:default_base_constructor", "1"); + } + } + /* Class defines some kind of constructor. May or may not be public */ + Setattr(inclass, "allocate:has_constructor", "1"); + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:public_constructor", "1"); + } + } else { + Setattr(inclass, "allocate:has_constructor", "1"); + Setattr(inclass, "allocate:public_constructor", "1"); + } + + + /* See if this is a copy constructor */ + if (parms && (ParmList_numrequired(parms) == 1)) { + /* Look for a few cases. X(const X &), X(X &), X(X *) */ + int copy_constructor = 0; + SwigType *type = Getattr(inclass, "name"); + String *tn = NewStringf("r.q(const).%s", type); + String *cc = SwigType_typedef_resolve_all(tn); + SwigType *rt = SwigType_typedef_resolve_all(Getattr(parms, "type")); + if (SwigType_istemplate(type)) { + String *tmp = Swig_symbol_template_deftype(cc, 0); + Delete(cc); + cc = tmp; + tmp = Swig_symbol_template_deftype(rt, 0); + Delete(rt); + rt = tmp; + } + if (Strcmp(cc, rt) == 0) { + copy_constructor = 1; + } else { + Delete(cc); + cc = NewStringf("r.%s", Getattr(inclass, "name")); + if (Strcmp(cc, Getattr(parms, "type")) == 0) { + copy_constructor = 1; + } else { + Delete(cc); + cc = NewStringf("p.%s", Getattr(inclass, "name")); + String *ty = SwigType_strip_qualifiers(Getattr(parms, "type")); + if (Strcmp(cc, ty) == 0) { + copy_constructor = 1; + } + Delete(ty); + } + } + Delete(cc); + Delete(rt); + Delete(tn); + + if (copy_constructor) { + Setattr(n, "copy_constructor", "1"); + Setattr(inclass, "allocate:has_copy_constructor", "1"); + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:copy_constructor", "1"); + } else if (cplus_mode == PROTECTED) { + Setattr(inclass, "allocate:copy_base_constructor", "1"); + } + } + } + return SWIG_OK; + } + + virtual int destructorDeclaration(Node *n) { + (void) n; + if (!inclass) + return SWIG_OK; + if (!extendmode) { + Setattr(inclass, "allocate:has_destructor", "1"); + if (cplus_mode == PUBLIC) { + Setattr(inclass, "allocate:default_destructor", "1"); + } else if (cplus_mode == PROTECTED) { + Setattr(inclass, "allocate:default_base_destructor", "1"); + } + } + return SWIG_OK; + } +}; + +void Swig_default_allocators(Node *n) { + if (!n) + return; + Allocate *a = new Allocate; + a->top(n); + delete a; +} diff --git a/Source/Modules/browser.cxx b/Source/Modules/browser.cxx new file mode 100644 index 0000000..dd1679a --- /dev/null +++ b/Source/Modules/browser.cxx @@ -0,0 +1,413 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * browser.cxx + * + * A web-base parse tree browser using SWILL. This is an optional + * feature that's normally disabled. + * ----------------------------------------------------------------------------- */ + +char cvsroot_browser_cxx[] = "$Id: browser.cxx 10003 2007-10-17 21:42:11Z wsfulton $"; + +#include "swigmod.h" + +#ifdef SWIG_SWILL +extern "C" { +#include "swill.h" +} static FILE *out = 0; +static Node *view_top = 0; + +class Browser:public Dispatcher { + void show_checkbox(Node *t, Node *n) { + int v = 0; + if (Getmeta(n, "visible")) { + v = 1; + } + if (v) { + Printf(out, "<a name=\"n%x\"></a>[<a href=\"hide.html?node=0x%x&hn=0x%x#n%x\">-</a>] ", n, t, n, n); + } else { + Printf(out, "<a name=\"n%x\"></a>[<a href=\"show.html?node=0x%x&hn=0x%x#n%x\">+</a>] ", n, t, n, n); + } + } + void show_attributes(Node *obj) { + if (!Getmeta(obj, "visible")) + return; + String *os = NewString(""); + String *k; + Iterator ki; + ki = First(obj); + while (ki.key) { + k = ki.key; + if ((Cmp(k, "nodeType") == 0) || (Cmp(k, "firstChild") == 0) || (Cmp(k, "lastChild") == 0) || + (Cmp(k, "parentNode") == 0) || (Cmp(k, "nextSibling") == 0) || (Cmp(k, "previousSibling") == 0) || (*(Char(k)) == '$')) { + /* Do nothing */ + } else if (Cmp(k, "parms") == 0) { + String *o = NewString(""); + Printf(o, "%s", ParmList_protostr(Getattr(obj, k))); + Replaceall(o, "&", "&"); + Replaceall(o, "<", "<"); + Replaceall(o, ">", ">"); + Printf(os, "<a href=\"data.html?n=0x%x\">?</a> %-12s - %s\n", Getattr(obj, k), k, o); + Delete(o); + } else { + DOH *o; + char *trunc = ""; + if (DohIsString(Getattr(obj, k))) { + o = Str(Getattr(obj, k)); + if (Len(o) > 70) { + trunc = "..."; + } + Replaceall(o, "&", "&"); + Replaceall(o, "<", "<"); + Printf(os, "<a href=\"data.html?n=0x%x\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj, k), k, o, trunc); + Delete(o); + } else { + Printf(os, "<a href=\"data.html?n=0x%x\">?</a> %-12s - 0x%x\n", Getattr(obj, k), k, Getattr(obj, k)); + } + } + ki = Next(ki); + } + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os)); + Delete(os); + } + +public: + virtual int emit_one(Node *n) { + char *tag = Char(nodeType(n)); + char *file = Char(Getfile(n)); + int line = Getline(n); + char *name = GetChar(n, "name"); + + show_checkbox(view_top, n); + Printf(out, "<b><a href=\"index.html?node=0x%x\">%s</a></b>", n, tag); + if (name) { + Printf(out, " (%s)", name); + } + Printf(out, ". %s:%d\n", file, line); + Printf(out, "<br>"); + Dispatcher::emit_one(n); + return SWIG_OK; + } + virtual int emit_children(Node *n) { + if (Getmeta(n, "visible")) { + Printf(out, "<blockquote>\n"); + Dispatcher::emit_children(n); + Printf(out, "</blockquote>\n"); + } + return SWIG_OK; + } + virtual int defaultHandler(Node *n) { + show_attributes(n); + return SWIG_OK; + } + virtual int top(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int includeDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int importDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int extendDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int classDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int templateDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + + virtual int enumDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int typemapDirective(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int namespaceDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + virtual int usingDeclaration(Node *n) { + show_attributes(n); + emit_children(n); + return SWIG_OK; + } + +}; + +static int browser_exit = 0; +static Node *tree_top = 0; +static Browser *browse = 0; + +/* ---------------------------------------------------------------------- + * exit_handler() - Force the browser to exit + * ---------------------------------------------------------------------- */ + +void exit_handler(FILE *f) { + browser_exit = 1; + Printf(f, "Terminated.\n"); +} + +/* ---------------------------------------------------------------------- + * node_handler() - Generate information about a specific node + * ---------------------------------------------------------------------- */ + +static void display(FILE *f, Node *n) { + /* Print standard HTML header */ + + Printf(f, "<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", Swig_package_version()); + Printf(f, "<b>SWIG-%s</b><br>\n", Swig_package_version()); + Printf(f, "[ <a href=\"exit.html\">Exit</a> ]"); + Printf(f, " [ <a href=\"index.html?node=0x%x\">Top</a> ]", tree_top); + if (n != tree_top) { + Printf(f, " [ <a href=\"index.html?node=0x%x\">Up</a> ]", parentNode(n)); + } + Printf(f, " [ <a href=\"symbol.html\">Symbols</a> ]"); + Printf(f, "<br><hr><p>\n"); + + out = f; + + browse->emit_one(n); + + /* Print standard footer */ + Printf(f, "<br><hr></BODY></HTML>\n"); + +} + +void node_handler(FILE *f) { + Node *n = 0; + if (!swill_getargs("p(node)", &n)) { + n = tree_top; + } + view_top = n; + display(f, n); +} + + +/* ---------------------------------------------------------------------- + * hide_handler() - Hide a node + * ---------------------------------------------------------------------- */ + +void hide_handler(FILE *f) { + Node *n = 0; + if (!swill_getargs("p(hn)", &n)) { + n = 0; + } + if (n) { + Delmeta(n, "visible"); + } + node_handler(f); +} + +void show_handler(FILE *f) { + Node *n = 0; + if (!swill_getargs("p(hn)", &n)) { + n = 0; + } + if (n) { + Setmeta(n, "visible", "1"); + } + node_handler(f); +} + +void raw_data(FILE *out, Node *obj) { + if (!obj) + return; + if (DohIsMapping(obj)) { + String *k; + Iterator ki; + String *os = NewString(""); + Printf(os, "Hash {\n"); + ki = First(obj); + while (ki.key) { + k = ki.key; + DOH *o; + const char *trunc = ""; + if (DohIsString(Getattr(obj, k))) { + o = Str(Getattr(obj, k)); + if (Len(o) > 70) { + trunc = "..."; + } + Replaceall(o, "<", "<"); + Printf(os, " <a href=\"data.html?n=0x%x\">?</a> %-12s - \"%(escape)-0.70s%s\"\n", Getattr(obj, k), k, o, trunc); + Delete(o); + } else { + Printf(os, " <a href=\"data.html?n=0x%x\">?</a> %-12s - 0x%x\n", Getattr(obj, k), k, Getattr(obj, k)); + } + ki = Next(ki); + } + Printf(os, "}\n"); + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os)); + Delete(os); + } else if (DohIsString(obj)) { + String *o = Str(obj); + Replaceall(o, "<", "<"); + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(o)); + Delete(o); + } else if (DohIsSequence(obj)) { + int i; + String *os = NewString(""); + Printf(os, "List [\n"); + for (i = 0; i < Len(obj); i++) { + DOH *o = Getitem(obj, i); + const char *trunc = ""; + if (DohIsString(o)) { + String *s = Str(o); + if (Len(s) > 70) { + trunc = "..."; + } + Replaceall(o, "<", "<"); + Printf(os, " <a href=\"data.html?n=0x%x\">?</a> [%d] - \"%(escape)-0.70s%s\"\n", o, i, s, trunc); + Delete(s); + } else { + Printf(os, " <a href=\"data.html?n=0x%x\">?</a> [%d] - 0x%x\n", o, i, o); + } + } + Printf(os, "\n]\n"); + Printf(out, "<FONT color=\"#660000\"><pre>\n%s</pre></FONT>\n", Char(os)); + Delete(os); + } +} + +void data_handler(FILE *f) { + DOH *n = 0; + if (!swill_getargs("p(n)", &n)) { + n = 0; + } + Printf(f, "<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", Swig_package_version()); + Printf(f, "<b>SWIG-%s</b><br>\n", Swig_package_version()); + Printf(f, "[ <a href=\"exit.html\">Exit</a> ]"); + Printf(f, " [ <a href=\"index.html?node=0x%x\">Top</a> ]", tree_top); + Printf(f, "<br><hr><p>\n"); + if (n) { + raw_data(f, n); + } + /* Print standard footer */ + Printf(f, "<br><hr></BODY></HTML>\n"); +} + +void symbol_handler(FILE *f) { + Symtab *sym; + char *name = 0; + + Printf(f, "<HTML><HEAD><TITLE>SWIG-%s</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n", Swig_package_version()); + Printf(f, "<b>SWIG-%s</b><br>\n", Swig_package_version()); + Printf(f, "[ <a href=\"exit.html\">Exit</a> ]"); + Printf(f, " [ <a href=\"index.html?node=0x%x\">Top</a> ]", tree_top); + Printf(f, " [ <a href=\"symbol.html\">Symbols</a> ]"); + Printf(f, "<br><hr><p>\n"); + + if (!swill_getargs("p(sym)|s(name)", &sym, &name)) { + sym = Swig_symbol_getscope(""); + name = 0; + } + if (!sym) { + Printf(f, "No symbol table specified!\n"); + return; + } + { + String *q = Swig_symbol_qualifiedscopename(sym); + if (!Len(q)) { + Printf(f, "<b>Symbol table: :: (global)</b><br>\n"); + } else { + Printf(f, "<b>Symbol table: %s</b><br>\n", q); + } + Delete(q); + } + + fprintf(f, "<p><form action=\"symbol.html\" method=GET>\n"); + fprintf(f, "Symbol lookup: <input type=text name=name size=40></input><br>\n"); + fprintf(f, "<input type=hidden name=sym value=\"0x%x\">\n", sym); + fprintf(f, "Submit : <input type=submit></input>\n"); + fprintf(f, "</form>"); + + if (name) { + Node *n = Swig_symbol_clookup(name, sym); + Printf(f, "Symbol '%s':\n", name); + Printf(f, "<blockquote>\n"); + if (!n) { + Printf(f, "Not defined!\n"); + } else { + raw_data(f, n); + } + Printf(f, "</blockquote>\n"); + } + + Printf(f, "<p><b>Nested scopes</b><br>\n"); + Printf(f, "<blockquote><pre>\n"); + { + Hash *h; + h = firstChild(sym); + while (h) { + Printf(f, "<a href=\"symbol.html?sym=0x%x\">%s</a>\n", h, Getattr(h, "name")); + h = nextSibling(h); + } + } + Printf(f, "</pre></blockquote>\n"); + + Printf(f, "<p><b>Symbol table contents</b></br>\n"); + raw_data(f, Getattr(sym, "symtab")); + Printf(f, "<br><hr></BODY></HTML>\n"); + +} +#endif + +void Swig_browser(Node *top, int port) { +#ifdef SWIG_SWILL + int sport; + browser_exit = 0; + + /* Initialize the server */ + sport = swill_init(port); + if (sport < 0) { + Printf(stderr, "Couldn't open socket on port %d. Sorry.\n", port); + return; + } + browse = new Browser(); + Setmeta(top, "visible", "1"); + tree_top = top; + + Printf(stderr, "SWIG: Tree browser listening on port %d\n", sport); + + swill_handle("exit.html", exit_handler, 0); + swill_handle("index.html", node_handler, 0); + swill_handle("hide.html", hide_handler, 0); + swill_handle("show.html", show_handler, 0); + swill_handle("data.html", data_handler, 0); + swill_handle("symbol.html", symbol_handler, 0); + swill_netscape("index.html"); + + while (!browser_exit) { + swill_serve(); + } + Printf(stderr, "Browser terminated.\n"); + swill_close(); + delete browse; + return; +#else + (void) top; + (void) port; +#endif +} diff --git a/Source/Modules/cffi.cxx b/Source/Modules/cffi.cxx new file mode 100644 index 0000000..053bab7 --- /dev/null +++ b/Source/Modules/cffi.cxx @@ -0,0 +1,1081 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * cffi.cxx + * + * cffi language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_cffi_cxx[] = "$Id: cffi.cxx 11380 2009-07-08 12:17:45Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +//#define CFFI_DEBUG +//#define CFFI_WRAP_DEBUG + +class CFFI:public Language { +public: + String *f_cl; + String *f_clhead; + String *f_clwrap; + bool CWrap; // generate wrapper file for C code? + File *f_begin; + File *f_runtime; + File *f_cxx_header; + File *f_cxx_wrapper; + File *f_clos; + + String *module; + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + // virtual int classDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int typedefHandler(Node *n); + + //c++ specific code + virtual int constructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int classHandler(Node *n); + +private: + void emit_defun(Node *n, String *name); + void emit_defmethod(Node *n); + void emit_initialize_instance(Node *n); + void emit_getter(Node *n); + void emit_setter(Node *n); + void emit_class(Node *n); + void emit_struct_union(Node *n, bool un); + void emit_export(Node *n, String *name); + void emit_inline(Node *n, String *name); + String *lispy_name(char *name); + String *lispify_name(Node *n, String *ty, const char *flag, bool kw = false); + String *convert_literal(String *num_param, String *type, bool try_to_split = true); + String *infix_to_prefix(String *val, char split_op, const String *op, String *type); + String *strip_parens(String *string); + String *trim(String *string); + int generate_typedef_flag; + bool no_swig_lisp; +}; + +void CFFI::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGCFFI 1", 0); + SWIG_library_directory("cffi"); + SWIG_config_file("cffi.swg"); + generate_typedef_flag = 0; + no_swig_lisp = false; + CWrap = false; + for (i = 1; i < argc; i++) { + if (!Strcmp(argv[i], "-help")) { + Printf(stdout, "cffi Options (available with -cffi)\n"); + Printf(stdout, + " -generate-typedef\n" + "\tIf this option is given then defctype will be used to generate\n" + "\tshortcuts according to the typedefs in the input.\n" + " -[no]cwrap\n" + "\tTurn on or turn off generation of an intermediate C file when\n" + "\tcreating a C interface. By default this is only done for C++ code.\n" + " -[no]swig-lisp\n" + "\tTurns on or off generation of code for helper lisp macro, functions,\n" + "\tetc. which SWIG uses while generating wrappers. These macros, functions\n" "\tmay still be used by generated wrapper code.\n"); + } else if (!strcmp(argv[i], "-cwrap")) { + CWrap = true; + Swig_mark_arg(i); + } else if ((Strcmp(argv[i], "-generate-typedef") == 0)) { + generate_typedef_flag = 1; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocwrap")) { + CWrap = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-swig-lisp")) { + no_swig_lisp = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-noswig-lisp")) { + no_swig_lisp = true; + Swig_mark_arg(i); + } + + } + f_clhead = NewString(""); + f_clwrap = NewString(""); + f_cl = NewString(""); + + allow_overloading(); +} + +int CFFI::top(Node *n) { + File *f_null = NewString(""); + module = Getattr(n, "name"); + + String *cxx_filename = Getattr(n, "outfile"); + String *lisp_filename = NewString(""); + + Printf(lisp_filename, "%s%s.lisp", SWIG_output_directory(), module); + + File *f_lisp = NewFile(lisp_filename, "w", SWIG_output_files()); + if (!f_lisp) { + FileErrorDisplay(lisp_filename); + SWIG_exit(EXIT_FAILURE); + } + + if (CPlusPlus || CWrap) { + f_begin = NewFile(cxx_filename, "w", SWIG_output_files()); + if (!f_begin) { + Close(f_lisp); + Delete(f_lisp); + Printf(stderr, "Unable to open %s for writing\n", cxx_filename); + SWIG_exit(EXIT_FAILURE); + } + + String *clos_filename = NewString(""); + Printf(clos_filename, "%s%s-clos.lisp", SWIG_output_directory(), module); + f_clos = NewFile(clos_filename, "w", SWIG_output_files()); + if (!f_clos) { + Close(f_lisp); + Delete(f_lisp); + Printf(stderr, "Unable to open %s for writing\n", cxx_filename); + SWIG_exit(EXIT_FAILURE); + } + } else { + f_begin = NewString(""); + f_clos = NewString(""); + } + + f_runtime = NewString(""); + f_cxx_header = f_runtime; + f_cxx_wrapper = NewString(""); + + Swig_register_filebyname("header", f_cxx_header); + Swig_register_filebyname("wrapper", f_cxx_wrapper); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("lisphead", f_clhead); + if (!no_swig_lisp) + Swig_register_filebyname("swiglisp", f_cl); + else + Swig_register_filebyname("swiglisp", f_null); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCFFI\n"); + Printf(f_runtime, "\n"); + + Swig_banner_target_lang(f_lisp, ";;;"); + + Language::top(n); + Printf(f_lisp, "%s\n", f_clhead); + Printf(f_lisp, "%s\n", f_cl); + Printf(f_lisp, "%s\n", f_clwrap); + + Close(f_lisp); + Delete(f_lisp); // Deletes the handle, not the file + Delete(f_cl); + Delete(f_clhead); + Delete(f_clwrap); + Dump(f_runtime, f_begin); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + Delete(f_cxx_wrapper); + Delete(f_null); + + return SWIG_OK; +} + +int CFFI::classHandler(Node *n) { +#ifdef CFFI_DEBUG + Printf(stderr, "class %s::%s\n", "some namespace", //current_namespace, + Getattr(n, "sym:name")); +#endif + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + // maybe just remove this check and get rid of the else clause below. + if (Strcmp(kind, "struct") == 0) { + emit_struct_union(n, false); + return SWIG_OK; + } else if (Strcmp(kind, "union") == 0) { + emit_struct_union(n, true); + return SWIG_OK; + } else if (Strcmp(kind, "class") == 0) { + emit_class(n); + Language::classHandler(n); + } else { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + return SWIG_OK; + } + + return SWIG_OK; +} + +int CFFI::constructorHandler(Node *n) { +#ifdef CFFI_DEBUG + Printf(stderr, "constructor %s\n", Getattr(n, "name")); + Printf(stderr, "constructor %s\n and %s and %s", Getattr(n, "kind"), Getattr(n, "sym:name"), Getattr(n, "allegrocl:old-sym:name")); +#endif + Setattr(n, "cffi:constructorfunction", "1"); + // Let SWIG generate a global forwarding function. + return Language::constructorHandler(n); +} + +int CFFI::destructorHandler(Node *n) { +#ifdef CFFI_DEBUG + Printf(stderr, "destructor %s\n", Getattr(n, "name")); +#endif + + // Let SWIG generate a global forwarding function. + return Language::destructorHandler(n); +} + +void CFFI::emit_defmethod(Node *n) { + String *args_placeholder = NewStringf(""); + String *args_call = NewStringf(""); + + ParmList *pl = Getattr(n, "parms"); + int argnum = 0; + Node *parent = getCurrentClass(); + bool first = 0; + + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + String *ffitype = Swig_typemap_lookup("lispclass", p, "", 0); + + int tempargname = 0; + + if(!first) + first = true; + else + Printf(args_placeholder, " "); + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) { + argname = NewStringf("t-arg%d", argnum); + tempargname = 1; + } + if (Len(ffitype) > 0) + Printf(args_placeholder, "(%s %s)", argname, ffitype); + else + Printf(args_placeholder, "%s", argname); + + if (ffitype && Strcmp(ffitype, lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'classname")) == 0) + Printf(args_call, " (ff-pointer %s)", argname); + else + Printf(args_call, " %s", argname); + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + + String *method_name = Getattr(n, "name"); + int x = Replace(method_name, "operator ", "", DOH_REPLACE_FIRST); // + + if (x == 1) + Printf(f_clos, "(cl:shadow \"%s\")\n", method_name); + + Printf(f_clos, "(cl:defmethod %s (%s)\n (%s%s))\n\n", + lispify_name(n, lispy_name(Char(method_name)), "'method"), args_placeholder, + lispify_name(n, Getattr(n, "sym:name"), "'function"), args_call); + +} + +void CFFI::emit_initialize_instance(Node *n) { + String *args_placeholder = NewStringf(""); + String *args_call = NewStringf(""); + + ParmList *pl = Getattr(n, "parms"); + int argnum = 0; + Node *parent = getCurrentClass(); + + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + String *ffitype = Swig_typemap_lookup("lispclass", p, "", 0); + + int tempargname = 0; + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) { + argname = NewStringf("t-arg%d", argnum); + tempargname = 1; + } + if (Len(ffitype) > 0) + Printf(args_placeholder, " (%s %s)", argname, ffitype); + else + Printf(args_placeholder, " %s", argname); + + if (Strcmp(ffitype, lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'classname")) == 0) + Printf(args_call, " (ff-pointer %s)", argname); + else + Printf(args_call, " %s", argname); + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + + Printf(f_clos, "(cl:defmethod initialize-instance :after ((obj %s) &key%s)\n (setf (slot-value obj 'ff-pointer) (%s%s)))\n\n", + lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), args_placeholder, + lispify_name(n, Getattr(n, "sym:name"), "'function"), args_call); + +} + +void CFFI::emit_setter(Node *n) { + Node *parent = getCurrentClass(); + Printf(f_clos, "(cl:defmethod (cl:setf %s) (arg0 (obj %s))\n (%s (ff-pointer obj) arg0))\n\n", + lispify_name(n, Getattr(n, "name"), "'method"), + lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), lispify_name(n, Getattr(n, "sym:name"), "'function")); +} + + +void CFFI::emit_getter(Node *n) { + Node *parent = getCurrentClass(); + Printf(f_clos, "(cl:defmethod %s ((obj %s))\n (%s (ff-pointer obj)))\n\n", + lispify_name(n, Getattr(n, "name"), "'method"), + lispify_name(parent, lispy_name(Char(Getattr(parent, "sym:name"))), "'class"), lispify_name(n, Getattr(n, "sym:name"), "'function")); +} + +int CFFI::memberfunctionHandler(Node *n) { + // Let SWIG generate a global forwarding function. + Setattr(n, "cffi:memberfunction", "1"); + return Language::memberfunctionHandler(n); +} + +int CFFI::membervariableHandler(Node *n) { + // Let SWIG generate a get/set function pair. + Setattr(n, "cffi:membervariable", "1"); + return Language::membervariableHandler(n); +} + +int CFFI::functionWrapper(Node *n) { + + ParmList *parms = Getattr(n, "parms"); + String *iname = Getattr(n, "sym:name"); + Wrapper *f = NewWrapper(); + + String *raw_return_type = Swig_typemap_lookup("ctype", n, "", 0); + SwigType *return_type = Swig_cparse_type(raw_return_type); + SwigType *resolved = SwigType_typedef_resolve_all(return_type); + int is_void_return = (Cmp(resolved, "void") == 0); + Delete(resolved); + + if (!is_void_return) { + String *lresult_init = NewStringf("lresult = (%s)0", raw_return_type); + Wrapper_add_localv(f, "lresult", raw_return_type, lresult_init, NIL); + Delete(lresult_init); + } + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(parms, f); + + // Attach the standard typemaps + Swig_typemap_attach_parms("ctype", parms, f); + emit_attach_parmmaps(parms, f); + + int num_arguments = emit_num_arguments(parms); + String *name_and_parms = NewStringf("%s (", wname); + int i; + Parm *p; + int gencomma = 0; + +#ifdef CFFI_DEBUG + Printf(stderr, "function - %s - %d\n", Getattr(n, "name"), num_arguments); +#endif + + for (i = 0, p = parms; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *c_parm_type = Swig_cparse_type(Getattr(p, "tmap:ctype")); + String *arg = NewStringf("l%s", Getattr(p, "lname")); + + // Emit parameter declaration + if (gencomma) + Printf(name_and_parms, ", "); + String *parm_decl = SwigType_str(c_parm_type, arg); + Printf(name_and_parms, "%s", parm_decl); +#ifdef CFFI_DEBUG + Printf(stderr, " param: %s\n", parm_decl); +#endif + Delete(parm_decl); + gencomma = 1; + + // Emit parameter conversion code + String *parm_code = Getattr(p, "tmap:in"); + { + Replaceall(parm_code, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", parm_code); + p = Getattr(p, "tmap:in:next"); + } + + Delete(arg); + } + Printf(name_and_parms, ")"); + + // Emit the function definition + String *signature = SwigType_str(return_type, name_and_parms); + Printf(f->def, "EXPORT %s {", signature); + Printf(f->code, " try {\n"); + + String *actioncode = emit_action(n); + + String *result_convert = Swig_typemap_lookup_out("out", n, "result", f, actioncode); + Replaceall(result_convert, "$result", "lresult"); + Printf(f->code, "%s\n", result_convert); + if(!is_void_return) Printf(f->code, " return lresult;\n"); + Delete(result_convert); + emit_return_variable(n, Getattr(n, "type"), f); + + Printf(f->code, " } catch (...) {\n"); + if (!is_void_return) + Printf(f->code, " return (%s)0;\n", raw_return_type); + Printf(f->code, " }\n"); + Printf(f->code, "}\n"); + + if (CPlusPlus) + Wrapper_print(f, f_runtime); + + if (CPlusPlus) { + emit_defun(n, wname); + if (Getattr(n, "cffi:memberfunction")) + emit_defmethod(n); + else if (Getattr(n, "cffi:membervariable")) { + if (Getattr(n, "memberget")) + emit_getter(n); + else if (Getattr(n, "memberset")) + emit_setter(n); + } + else if (Getattr(n, "cffi:constructorfunction")) { + emit_initialize_instance(n); + } + } else + emit_defun(n, iname); + + // if (!overloaded || !Getattr(n, "sym:nextSibling")) { + // update_package_if_needed(n); + // emit_buffered_defuns(n); + // // this is the last overload. + // if (overloaded) { + // emit_dispatch_defun(n); + // } + // } + + Delete(wname); + DelWrapper(f); + + return SWIG_OK; +} + + +void CFFI::emit_defun(Node *n, String *name) { + + // String *storage=Getattr(n,"storage"); + // if(!storage || (Strcmp(storage,"extern") && Strcmp(storage,"externc"))) + // return SWIG_OK; + + String *func_name = Getattr(n, "sym:name"); + + ParmList *pl = Getattr(n, "parms"); + + int argnum = 0; + + func_name = lispify_name(n, func_name, "'function"); + + emit_inline(n, func_name); + + Printf(f_cl, "\n(cffi:defcfun (\"%s\" %s)", name, func_name); + String *ffitype = Swig_typemap_lookup("cout", n, ":pointer", 0); + + Printf(f_cl, " %s", ffitype); + Delete(ffitype); + + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + + if (SwigType_isvarargs(Getattr(p, "type"))) { + Printf(f_cl, "\n %s", NewString("&rest")); + continue; + } + + String *argname = Getattr(p, "name"); + + ffitype = Swig_typemap_lookup("cin", p, "", 0); + + int tempargname = 0; + if (!argname) { + + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } else if (Strcmp(argname, "t") == 0 || Strcmp(argname, "T") == 0) { + argname = NewStringf("t_arg%d", argnum); + tempargname = 1; + } + + Printf(f_cl, "\n (%s %s)", argname, ffitype); + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + Printf(f_cl, ")\n"); /* finish arg list */ + + emit_export(n, func_name); +} + + +int CFFI::constantWrapper(Node *n) { + String *type = Getattr(n, "type"); + String *converted_value = convert_literal(Getattr(n, "value"), type); + String *name = lispify_name(n, Getattr(n, "sym:name"), "'constant"); + + if (Strcmp(name, "t") == 0 || Strcmp(name, "T") == 0) + name = NewStringf("t_var"); + + Printf(f_cl, "\n(cl:defconstant %s %s)\n", name, converted_value); + Delete(converted_value); + + emit_export(n, name); + return SWIG_OK; +} + +int CFFI::variableWrapper(Node *n) { + // String *storage=Getattr(n,"storage"); + // Printf(stdout,"\"%s\" %s)\n",storage,Getattr(n, "sym:name")); + + // if(!storage || (Strcmp(storage,"extern") && Strcmp(storage,"externc"))) + // return SWIG_OK; + + String *var_name = Getattr(n, "sym:name"); + String *lisp_type = Swig_typemap_lookup("cin", n, "", 0); + String *lisp_name = lispify_name(n, var_name, "'variable"); + + if (Strcmp(lisp_name, "t") == 0 || Strcmp(lisp_name, "T") == 0) + lisp_name = NewStringf("t_var"); + + Printf(f_cl, "\n(cffi:defcvar (\"%s\" %s)\n %s)\n", var_name, lisp_name, lisp_type); + + Delete(lisp_type); + + emit_export(n, lisp_name); + return SWIG_OK; +} + +int CFFI::typedefHandler(Node *n) { + if (generate_typedef_flag && strncmp(Char(Getattr(n, "type")), "enum", 4)) { + String *lisp_name = lispify_name(n, Getattr(n, "name"), "'typename"); + Printf(f_cl, "\n(cffi:defctype %s %s)\n", lisp_name, Swig_typemap_lookup("cin", n, "", 0)); + emit_export(n, lisp_name); + } + return Language::typedefHandler(n); +} + +int CFFI::enumDeclaration(Node *n) { + String *name = Getattr(n, "sym:name"); + bool slot_name_keywords; + String *lisp_name = 0; + if (name && Len(name) != 0) { + lisp_name = lispify_name(n, name, "'enumname"); + if (GetFlag(n, "feature:bitfield")) { + Printf(f_cl, "\n(cffi:defbitfield %s", lisp_name); + } else { + Printf(f_cl, "\n(cffi:defcenum %s", lisp_name); + } + slot_name_keywords = true; + + //Registering the enum name to the cin and cout typemaps + Parm *pattern = NewParm(name, NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + //Registering with the kind, i.e., enum + pattern = NewParm(NewStringf("enum %s", name), NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + + } else { + Printf(f_cl, "\n(defanonenum %s", name); + slot_name_keywords = false; + } + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + + String *slot_name = lispify_name(c, Getattr(c, "name"), "'enumvalue", slot_name_keywords); + String *value = Getattr(c, "enumvalue"); + + if (!value || GetFlag(n, "feature:bitfield:ignore_values")) + Printf(f_cl, "\n\t%s", slot_name); + else { + String *type = Getattr(c, "type"); + String *converted_value = convert_literal(value, type); + Printf(f_cl, "\n\t(%s #.%s)", slot_name, converted_value); + Delete(converted_value); + } + Delete(value); + } + + Printf(f_cl, ")\n"); + + // No need to export keywords + if (lisp_name && Len(lisp_name) != 0) { + emit_export(n, lisp_name); + } else { + for (Node *c = firstChild(n); c; c = nextSibling(c)) + emit_export(c, lispify_name(c, Getattr(c, "name"), "'enumvalue")); + } + + return SWIG_OK; +} +void CFFI::emit_class(Node *n) { + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, "emit_class: ENTER... '%s'(%x)\n", Getattr(n, "sym:name"), n); +#endif + + String *name = Getattr(n, "sym:name"); + String *lisp_name = lispify_name(n, lispy_name(Char(name)), "'classname"); + + String *bases = Getattr(n, "bases"); + String *supers = NewString("("); + if (bases) { + int first = 1; + for (Iterator i = First(bases); i.item; i = Next(i)) { + if (!first) + Printf(supers, " "); + String *s = Getattr(i.item, "name"); + Printf(supers, "%s", lispify_name(i.item, s, "'classname")); + } + } else { + // Printf(supers,"ff:foreign-pointer"); + } + + Printf(supers, ")"); + Printf(f_clos, "\n(cl:defclass %s%s", lisp_name, supers); + Printf(f_clos, "\n ((ff-pointer :reader ff-pointer)))\n\n"); + + Parm *pattern = NewParm(Getattr(n, "name"), NULL); + + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + SwigType_add_pointer(Getattr(pattern, "type")); + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + SwigType_add_qualifier(Getattr(pattern, "type"), "const"); + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + SwigType_del_pointer(Getattr(pattern, "type")); + SwigType_add_reference(Getattr(pattern, "type")); + Swig_typemap_register("lispclass", pattern, lisp_name, NULL, NULL); + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, " pattern %s name %s .. ... %s .\n", pattern, lisp_name); +#endif + + Delete(pattern); + + // Walk children to generate type definition. + String *slotdefs = NewString(" "); + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, " walking children...\n"); +#endif + + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + String *storage_type = Getattr(c, "storage"); + if ((!Strcmp(nodeType(c), "cdecl") && (!storage_type || Strcmp(storage_type, "typedef")))) { + String *access = Getattr(c, "access"); + + // hack. why would decl have a value of "variableHandler" and now "0"? + String *childDecl = Getattr(c, "decl"); + // Printf(stderr,"childDecl = '%s' (%s)\n", childDecl, Getattr(c,"view")); + if (!Strcmp(childDecl, "0")) + childDecl = NewString(""); + + SwigType *childType = NewStringf("%s%s", childDecl, + Getattr(c, "type")); + String *cname = (access && Strcmp(access, "public")) ? NewString("nil") : Copy(Getattr(c, "name")); + + if (!SwigType_isfunction(childType)) { + // Printf(slotdefs, ";;; member functions don't appear as slots.\n "); + // Printf(slotdefs, ";; "); + // String *ns = listify_namespace(Getattr(n, "cffi:package")); + String *ns = NewString(""); +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, "slot name = '%s' ns = '%s' class-of '%s' and type = '%s'\n", cname, ns, name, childType); +#endif + Printf(slotdefs, "(#.(swig-insert-id \"%s\" %s :type :slot :class \"%s\") %s)", cname, ns, name, childType); //compose_foreign_type(childType) + Delete(ns); + if (access && Strcmp(access, "public")) + Printf(slotdefs, " ;; %s member", access); + + Printf(slotdefs, "\n "); + } + Delete(childType); + Delete(cname); + } + } + + + // String *ns_list = listify_namespace(Getattr(n,"cffi:namespace")); + // update_package_if_needed(n,f_clhead); + // Printf(f_clos, + // "(swig-def-foreign-class \"%s\"\n %s\n (:%s\n%s))\n\n", + // name, supers, kind, slotdefs); + + Delete(supers); + // Delete(ns_list); + + // Parm *pattern = NewParm(name,NULL); + // Swig_typemap_register("cin",pattern,lisp_name,NULL,NULL); + //Swig_typemap_register("cout",pattern,lisp_name,NULL,NULL); + //Delete(pattern); + +#ifdef CFFI_WRAP_DEBUG + Printf(stderr, "emit_class: EXIT\n"); +#endif +} + +// Includes structs +void CFFI::emit_struct_union(Node *n, bool un = false) { +#ifdef CFFI_DEBUG + Printf(stderr, "struct/union %s\n", Getattr(n, "name")); + Printf(stderr, "struct/union %s\n and %s", Getattr(n, "kind"), Getattr(n, "sym:name")); +#endif + + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + if (Strcmp(kind, "struct") != 0 && Strcmp(kind, "union") != 0) { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + } + String *lisp_name = lispify_name(n, name, "'classname"); + + //Register the struct/union name to the cin and cout typemaps + + Parm *pattern = NewParm(name, NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + //Registering with the kind, i.e., struct or union + pattern = NewParm(NewStringf("%s %s", kind, name), NULL); + Swig_typemap_register("cin", pattern, lisp_name, NULL, NULL); + Swig_typemap_register("cout", pattern, lisp_name, NULL, NULL); + Delete(pattern); + + if (un) { + Printf(f_cl, "\n(cffi:defcunion %s", lisp_name); + } else + Printf(f_cl, "\n(cffi:defcstruct %s", lisp_name); + + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { +#ifdef CFFI_DEBUG + Printf(stderr, "struct/union %s\n", Getattr(c, "name")); + Printf(stderr, "struct/union %s and %s \n", Getattr(c, "kind"), Getattr(c, "sym:name")); +#endif + + if (Strcmp(nodeType(c), "cdecl")) { + //C declaration ignore + // Printf(stderr, "Structure %s has a slot that we can't deal with.\n", + // name); + // Printf(stderr, "nodeType: %s, name: %s, type: %s\n", + // nodeType(c), + // Getattr(c, "name"), + // Getattr(c, "type")); + // SWIG_exit(EXIT_FAILURE); + } else { + SwigType *childType = NewStringf("%s%s", Getattr(c, "decl"), Getattr(c, "type")); + + Node *node = NewHash(); + Setattr(node, "type", childType); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("cin", node, "", 0); + + String *typespec = tm ? NewString(tm) : NewString(""); + + String *slot_name = lispify_name(c, Getattr(c, "sym:name"), "'slotname"); + if (Strcmp(slot_name, "t") == 0 || Strcmp(slot_name, "T") == 0) + slot_name = NewStringf("t_var"); + + Printf(f_cl, "\n\t(%s %s)", slot_name, typespec); + + Delete(node); + Delete(childType); + Delete(typespec); + } + } + + Printf(f_cl, ")\n"); + + emit_export(n, lisp_name); + for (Node *child = firstChild(n); child; child = nextSibling(child)) { + if (!Strcmp(nodeType(child), "cdecl")) { + emit_export(child, lispify_name(child, Getattr(child, "sym:name"), "'slotname")); + } + } + + /* Add this structure to the known lisp types */ + //Printf(stdout, "Adding %s foreign type\n", name); + // add_defined_foreign_type(name); + +} + +void CFFI::emit_export(Node *n, String *name) { + if (GetInt(n, "feature:export")) + Printf(f_cl, "\n(cl:export '%s)\n", name); +} + +void CFFI::emit_inline(Node *n, String *name) { + if (GetInt(n, "feature:inline")) + Printf(f_cl, "\n(cl:declaim (cl:inline %s))\n", name); +} + +String *CFFI::lispify_name(Node *n, String *ty, const char *flag, bool kw) { + String *intern_func = Getattr(n, "feature:intern_function"); + if (intern_func) { + if (Strcmp(intern_func, "1") == 0) + intern_func = NewStringf("swig-lispify"); + return NewStringf("#.(%s \"%s\" %s%s)", intern_func, ty, flag, kw ? " :keyword" : ""); + } else if (kw) + return NewStringf(":%s", ty); + else + return ty; +} + +/* utilities */ +/* returns new string w/ parens stripped */ +String *CFFI::strip_parens(String *string) { + char *s = Char(string), *p; + int len = Len(string); + String *res; + + if (len == 0 || s[0] != '(' || s[len - 1] != ')') { + return NewString(string); + } + + p = (char *) malloc(len - 2 + 1); + if (!p) { + Printf(stderr, "Malloc failed\n"); + SWIG_exit(EXIT_FAILURE); + } + + strncpy(p, s + 1, len - 1); + p[len - 2] = 0; /* null terminate */ + + res = NewString(p); + free(p); + + return res; +} + +String *CFFI::trim(String *str) { + char *c = Char(str); + while (*c != '\0' && isspace((int) *c)) + ++c; + String *result = NewString(c); + Chop(result); + return result; +} + +String *CFFI::infix_to_prefix(String *val, char split_op, const String *op, String *type) { + List *ored = Split(val, split_op, -1); + + // some float hackery + //i don't understand it, if you do then please explain + // if ( ((split_op == '+') || (split_op == '-')) && Len(ored) == 2 && + // (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || + // SwigType_type(type) == T_LONGDOUBLE) ) { + // // check that we're not splitting a float + // String *possible_result = convert_literal(val, type, false); + // if (possible_result) return possible_result; + + // } + + // try parsing the split results. if any part fails, kick out. + bool part_failed = false; + if (Len(ored) > 1) { + String *result = NewStringf("(%s", op); + for (Iterator i = First(ored); i.item; i = Next(i)) { + String *converted = convert_literal(i.item, type); + if (converted) { + Printf(result, " %s", converted); + Delete(converted); + } else { + part_failed = true; + break; + } + } + Printf(result, ")"); + Delete(ored); + return part_failed ? 0 : result; + } else { + Delete(ored); + } + return 0; +} + +/* To be called by code generating the lisp interface + Will return a String containing the literal based on type. + Will return null if there are problems. + + try_to_split defaults to true (see stub above). +*/ +String *CFFI::convert_literal(String *literal, String *type, bool try_to_split) { + String *num_param = Copy(literal); + String *trimmed = trim(num_param); + String *num = strip_parens(trimmed), *res = 0; + Delete(trimmed); + char *s = Char(num); + + // very basic parsing of infix expressions. + if (try_to_split) { + if ((res = infix_to_prefix(num, '|', "cl:logior", type))) + return res; + if ((res = infix_to_prefix(num, '&', "cl:logand", type))) + return res; + if ((res = infix_to_prefix(num, '^', "cl:logxor", type))) + return res; + if ((res = infix_to_prefix(num, '*', "cl:*", type))) + return res; + if ((res = infix_to_prefix(num, '/', "cl:/", type))) + return res; + if ((res = infix_to_prefix(num, '+', "cl:+", type))) + return res; + if ((res = infix_to_prefix(num, '-', "cl:-", type))) + return res; + } + + if (SwigType_type(type) == T_FLOAT || SwigType_type(type) == T_DOUBLE || SwigType_type(type) == T_LONGDOUBLE) { + // Use CL syntax for float literals + + // careful. may be a float identifier or float constant. + char *num_start = Char(num); + char *num_end = num_start + strlen(num_start) - 1; + + bool is_literal = isdigit(*num_start) || (*num_start == '.') || (*num_start == '+') || (*num_start == '-'); + + String *lisp_exp = 0; + if (is_literal) { + if (*num_end == 'f' || *num_end == 'F') { + lisp_exp = NewString("f"); + } else { + lisp_exp = NewString("d"); + } + + if (*num_end == 'l' || *num_end == 'L' || *num_end == 'f' || *num_end == 'F') { + *num_end = '\0'; + num_end--; + } + + int exponents = Replaceall(num, "e", lisp_exp) + Replaceall(num, "E", lisp_exp); + + if (!exponents) + Printf(num, "%s0", lisp_exp); + + if (exponents > 1 || (exponents + Replaceall(num, ".", ".") == 0)) { + Delete(num); + num = 0; + } + } + return num; + } else if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + String* result = NewStringf("#\\%c", s[2]); + Delete(num); + // Printf(stderr, "%s %c %d", s, s[2], s); + return result; + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + String* result = NewStringf("\"%s\"", num_param); + Delete(num); + return result; + } else if (SwigType_type(type) == T_INT || SwigType_type(type) == T_UINT) { + // Printf(stderr, "Is a T_INT or T_UINT %s, before replaceall\n", s); + Replaceall(num, "u", ""); + Replaceall(num, "U", ""); + Replaceall(num, "l", ""); + Replaceall(num, "L", ""); + + int i, j; + if (sscanf(s, "%d >> %d", &i, &j) == 2) { + String* result = NewStringf("(cl:ash %d -%d)", i, j); + Delete(num); + return result; + } else if (sscanf(s, "%d << %d", &i, &j) == 2) { + String* result = NewStringf("(cl:ash %d %d)", i, j); + Delete(num); + return result; + } + } + + if (Len(num) >= 2 && s[0] == '0') { /* octal or hex */ + if (s[1] == 'x'){ + DohReplace(num,"0","#",DOH_REPLACE_FIRST); + } + else{ + DohReplace(num,"0","#o",DOH_REPLACE_FIRST); + } + } + return num; +} + +//less flexible as it does the conversion in C, the lispify name does the conversion in lisp +String *CFFI::lispy_name(char *name) { + bool helper = false; + String *new_name = NewString(""); + for (unsigned int i = 0; i < strlen(name); i++) { + if (name[i] == '_' || name[i] == '-') { + Printf(new_name, "%c", '-'); + helper = false; + } else if (name[i] >= 'A' && name[i] <= 'Z') { + if (helper) + Printf(new_name, "%c", '-'); + Printf(new_name, "%c", ('a' + (name[i] - 'A'))); + helper = false; + } else { + helper = true; + Printf(new_name, "%c", name[i]); + } + } + return new_name; +} + +extern "C" Language *swig_cffi(void) { + return new CFFI(); +} diff --git a/Source/Modules/chicken.cxx b/Source/Modules/chicken.cxx new file mode 100644 index 0000000..3bf6602 --- /dev/null +++ b/Source/Modules/chicken.cxx @@ -0,0 +1,1552 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * chicken.cxx + * + * CHICKEN language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_chicken_cxx[] = "$Id: chicken.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +static const char *chicken_usage = (char *) "\ +\ +CHICKEN Options (available with -chicken)\n\ + -proxy - Export TinyCLOS class definitions\n\ + -closprefix <prefix> - Prepend <prefix> to all clos identifiers\n\ + -useclassprefix - Prepend the class name to all clos identifiers\n\ + -unhideprimitive - Unhide the primitive: symbols\n\ + -nounit - Do not (declare (unit ...)) in scheme file\n\ + -noclosuses - Do not (declare (uses ...)) in scheme file\n\ + -nocollection - Do not register pointers with chicken garbage\n\ + collector and export destructors\n\ +\n"; + +static char *module = 0; +static char *chicken_path = (char *) "chicken"; +static int num_methods = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; +static String *chickentext = 0; +static String *closprefix = 0; +static String *swigtype_ptr = 0; + + +static String *f_sym_size = 0; + +/* some options */ +static int declare_unit = 1; +static int no_collection = 0; +static int clos_uses = 1; + +/* C++ Support + Clos Classes */ +static int clos = 0; +static String *c_class_name = 0; +static String *class_name = 0; +static String *short_class_name = 0; + +static int in_class = 0; +static int have_constructor = 0; +static bool exporting_destructor = false; +static bool exporting_constructor = false; +static String *constructor_name = 0; +static String *member_name = 0; + +/* sections of the .scm code */ +static String *scm_const_defs = 0; +static String *clos_class_defines = 0; +static String *clos_methods = 0; + +/* Some clos options */ +static int useclassprefix = 0; +static String *clossymnameprefix = 0; +static int hide_primitive = 1; +static Hash *primitive_names = 0; + +/* Used for overloading constructors */ +static int has_constructor_args = 0; +static List *constructor_arg_types = 0; +static String *constructor_dispatch = 0; + +static Hash *overload_parameter_lists = 0; + +class CHICKEN:public Language { +public: + + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int classHandler(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int constructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int validIdentifier(String *s); + virtual int staticmembervariableHandler(Node *n); + virtual int staticmemberfunctionHandler(Node *n); + virtual int importDirective(Node *n); + +protected: + void addMethod(String *scheme_name, String *function); + /* Return true iff T is a pointer type */ + int isPointer(SwigType *t); + void dispatchFunction(Node *n); + + String *chickenNameMapping(String *, const_String_or_char_ptr ); + String *chickenPrimitiveName(String *); + + String *runtimeCode(); + String *defaultExternalRuntimeFilename(); + String *buildClosFunctionCall(List *types, const_String_or_char_ptr closname, const_String_or_char_ptr funcname); +}; + +/* ----------------------------------------------------------------------- + * swig_chicken() - Instantiate module + * ----------------------------------------------------------------------- */ + +static Language *new_swig_chicken() { + return new CHICKEN(); +} + +extern "C" { + Language *swig_chicken(void) { + return new_swig_chicken(); + } +} + +void CHICKEN::main(int argc, char *argv[]) { + int i; + + SWIG_library_directory(chicken_path); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(chicken_usage, stdout); + SWIG_exit(0); + } else if (strcmp(argv[i], "-proxy") == 0) { + clos = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-closprefix") == 0) { + if (argv[i + 1]) { + clossymnameprefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-useclassprefix") == 0) { + useclassprefix = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-unhideprimitive") == 0) { + hide_primitive = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nounit") == 0) { + declare_unit = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noclosuses") == 0) { + clos_uses = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocollection") == 0) { + no_collection = 1; + Swig_mark_arg(i); + } + } + } + + if (!clos) + hide_primitive = 0; + + // Add a symbol for this module + Preprocessor_define("SWIGCHICKEN 1", 0); + + // Set name of typemaps + + SWIG_typemap_lang("chicken"); + + // Read in default typemaps */ + SWIG_config_file("chicken.swg"); + allow_overloading(); +} + +int CHICKEN::top(Node *n) { + String *chicken_filename = NewString(""); + File *f_scm; + String *scmmodule; + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + chickentext = NewString(""); + closprefix = NewString(""); + f_sym_size = NewString(""); + primitive_names = NewHash(); + overload_parameter_lists = NewHash(); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + + Swig_register_filebyname("chicken", chickentext); + Swig_register_filebyname("closprefix", closprefix); + + clos_class_defines = NewString(""); + clos_methods = NewString(""); + scm_const_defs = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCHICKEN\n"); + + if (no_collection) + Printf(f_runtime, "#define SWIG_CHICKEN_NO_COLLECTION 1\n"); + + Printf(f_runtime, "\n"); + + /* Set module name */ + module = Swig_copy_string(Char(Getattr(n, "name"))); + scmmodule = NewString(module); + Replaceall(scmmodule, "_", "-"); + + Printf(f_header, "#define SWIG_init swig_%s_init\n", module); + Printf(f_header, "#define SWIG_name \"%s\"\n", scmmodule); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + Language::top(n); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + Printf(f_init, "C_kontinue (continuation, ret);\n"); + Printf(f_init, "}\n\n"); + + Printf(f_init, "#ifdef __cplusplus\n"); + Printf(f_init, "}\n"); + Printf(f_init, "#endif\n"); + + Printf(chicken_filename, "%s%s.scm", SWIG_output_directory(), module); + if ((f_scm = NewFile(chicken_filename, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(chicken_filename); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner_target_lang(f_scm, ";;"); + Printf(f_scm, "\n"); + + if (declare_unit) + Printv(f_scm, "(declare (unit ", scmmodule, "))\n\n", NIL); + Printv(f_scm, "(declare \n", + tab4, "(hide swig-init swig-init-return)\n", + tab4, "(foreign-declare \"C_extern void swig_", module, "_init(C_word,C_word,C_word) C_noret;\"))\n", NIL); + Printv(f_scm, "(define swig-init (##core#primitive \"swig_", module, "_init\"))\n", NIL); + Printv(f_scm, "(define swig-init-return (swig-init))\n\n", NIL); + + if (clos) { + //Printf (f_scm, "(declare (uses tinyclos))\n"); + //New chicken versions have tinyclos as an egg + Printf(f_scm, "(require-extension tinyclos)\n"); + Replaceall(closprefix, "$module", scmmodule); + Printf(f_scm, "%s\n", closprefix); + Printf(f_scm, "%s\n", clos_class_defines); + Printf(f_scm, "%s\n", clos_methods); + } else { + Printf(f_scm, "%s\n", scm_const_defs); + } + + Printf(f_scm, "%s\n", chickentext); + + + Close(f_scm); + Delete(f_scm); + + char buftmp[20]; + sprintf(buftmp, "%d", num_methods); + Replaceall(f_init, "$nummethods", buftmp); + Replaceall(f_init, "$symsize", f_sym_size); + + if (hide_primitive) + Replaceall(f_init, "$veclength", buftmp); + else + Replaceall(f_init, "$veclength", "0"); + + Delete(chicken_filename); + Delete(chickentext); + Delete(closprefix); + Delete(overload_parameter_lists); + + Delete(clos_class_defines); + Delete(clos_methods); + Delete(scm_const_defs); + + /* Close all of the files */ + Delete(primitive_names); + Delete(scmmodule); + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_sym_size); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; +} + +int CHICKEN::functionWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + Parm *p; + int i; + String *wname; + Wrapper *f; + String *mangle = NewString(""); + String *get_pointers; + String *cleanup; + String *argout; + String *tm; + String *overname = 0; + String *declfunc = 0; + String *scmname; + bool any_specialized_arg = false; + List *function_arg_types = NewList(); + + int num_required; + int num_arguments; + int have_argout; + + Printf(mangle, "\"%s\"", SwigType_manglestr(d)); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + wname = NewString(""); + get_pointers = NewString(""); + cleanup = NewString(""); + argout = NewString(""); + declfunc = NewString(""); + scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + /* Local vars */ + Wrapper_add_local(f, "resultobj", "C_word resultobj"); + + /* Write code to extract function parameters. */ + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + Append(wname, Swig_name_wrapper(iname)); + if (overname) { + Append(wname, overname); + } + // Check for interrupts + Printv(f->code, "C_trace(\"", scmname, "\");\n", NIL); + + Printv(f->def, "static ", "void ", wname, " (C_word argc, C_word closure, C_word continuation", NIL); + Printv(declfunc, "void ", wname, "(C_word,C_word,C_word", NIL); + + /* Generate code for argument marshalling */ + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + Printf(f->def, ", C_word scm%d", i + 1); + Printf(declfunc, ",C_word"); + + /* Look for an input typemap */ + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + String *source = NewStringf("scm%d", i + 1); + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); /* Save the location of + the object */ + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + if (i >= num_required) + Printf(get_pointers, "if (argc-2>%i && (%s)) {\n", i, source); + Printv(get_pointers, tm, "\n", NIL); + if (i >= num_required) + Printv(get_pointers, "}\n", NIL); + + if (clos) { + if (i < num_required) { + if (strcmp("void", Char(pt)) != 0) { + Node *class_node = 0; + String *clos_code = Getattr(p, "tmap:in:closcode"); + class_node = classLookup(pt); + if (clos_code && class_node) { + String *class_name = NewStringf("<%s>", Getattr(class_node, "sym:name")); + Replaceall(class_name, "_", "-"); + Append(function_arg_types, class_name); + Append(function_arg_types, Copy(clos_code)); + any_specialized_arg = true; + Delete(class_name); + } else { + Append(function_arg_types, "<top>"); + Append(function_arg_types, "$input"); + } + } + } + } + Delete(source); + } + + p = Getattr(p, "tmap:in:next"); + continue; + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + + /* finish argument marshalling */ + + Printf(f->def, ") {"); + Printf(declfunc, ")"); + + if (num_required != num_arguments) { + Append(function_arg_types, "^^##optional$$"); + } + + /* First check the number of arguments is correct */ + if (num_arguments != num_required) + Printf(f->code, "if (argc-2<%i || argc-2>%i) C_bad_argc(argc,%i);\n", num_required, num_arguments, num_required + 2); + else + Printf(f->code, "if (argc!=%i) C_bad_argc(argc,%i);\n", num_arguments + 2, num_arguments + 2); + + /* Now piece together the first part of the wrapper function */ + Printv(f->code, get_pointers, NIL); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + have_argout = 0; + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + + if (!have_argout) { + have_argout = 1; + // Print initial argument output code + Printf(argout, "SWIG_Chicken_SetupArgout\n"); + } + + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printf(argout, "%s", tm); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + Setattr(n, "wrap:name", wname); + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* Return the function value */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + + Printf(f->code, "%s", tm); + + if (have_argout) + Printf(f->code, "\nSWIG_APPEND_VALUE(resultobj);\n"); + + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* Insert the argumetn output code */ + Printv(f->code, argout, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + + if (have_argout) { + Printf(f->code, "C_kontinue(continuation,C_SCHEME_END_OF_LIST);\n"); + } else { + if (exporting_constructor && clos && hide_primitive) { + /* Don't return a proxy, the wrapped CLOS class is the proxy */ + Printf(f->code, "C_kontinue(continuation,resultobj);\n"); + } else { + // make the continuation the proxy creation function, if one exists + Printv(f->code, "{\n", + "C_word func;\n", + "SWIG_Chicken_FindCreateProxy(func, resultobj)\n", + "if (C_swig_is_closurep(func))\n", + " ((C_proc4)(void *)C_block_item(func, 0))(4,func,continuation,resultobj,C_SCHEME_FALSE);\n", + "else\n", " C_kontinue(continuation, resultobj);\n", "}\n", NIL); + } + } + + /* Error handling code */ +#ifdef USE_FAIL + Printf(f->code, "fail:\n"); + Printv(f->code, cleanup, NIL); + Printf(f->code, "swig_panic (\"failure in " "'$symname' SWIG function wrapper\");\n"); +#endif + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", "resultobj"); + + /* Dump the function out */ + Printv(f_wrappers, "static ", declfunc, " C_noret;\n", NIL); + Wrapper_print(f, f_wrappers); + + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + if (exporting_destructor && !no_collection) { + Printf(f_init, "((swig_chicken_clientdata *)(SWIGTYPE%s->clientdata))->destroy = (swig_chicken_destructor) %s;\n", swigtype_ptr, wname); + } else { + addMethod(scmname, wname); + } + + /* Only export if we are not in a class, or if in a class memberfunction */ + if (!in_class || member_name) { + String *method_def; + String *clos_name; + if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + + if (!any_specialized_arg) { + method_def = NewString(""); + Printv(method_def, "(define ", clos_name, " ", chickenPrimitiveName(scmname), ")", NIL); + } else { + method_def = buildClosFunctionCall(function_arg_types, clos_name, chickenPrimitiveName(scmname)); + } + Printv(clos_methods, method_def, "\n", NIL); + Delete(clos_name); + Delete(method_def); + } + + if (have_constructor && !has_constructor_args && any_specialized_arg) { + has_constructor_args = 1; + constructor_arg_types = Copy(function_arg_types); + } + } else { + /* add function_arg_types to overload hash */ + List *flist = Getattr(overload_parameter_lists, scmname); + if (!flist) { + flist = NewList(); + Setattr(overload_parameter_lists, scmname, flist); + } + + Append(flist, Copy(function_arg_types)); + + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + + Delete(wname); + Delete(get_pointers); + Delete(cleanup); + Delete(declfunc); + Delete(mangle); + Delete(function_arg_types); + DelWrapper(f); + return SWIG_OK; +} + +int CHICKEN::variableWrapper(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + String *wname = NewString(""); + String *mangle = NewString(""); + String *tm; + String *tm2 = NewString("");; + String *argnum = NewString("0"); + String *arg = NewString("argv[0]"); + Wrapper *f; + String *overname = 0; + String *scmname; + + int num_required; + int num_arguments; + + scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + Printf(mangle, "\"%s\"", SwigType_manglestr(t)); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + // evaluation function names + Append(wname, Swig_name_wrapper(iname)); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Check for interrupts + Printv(f->code, "C_trace(\"", scmname, "\");\n", NIL); + + if (1 || (SwigType_type(t) != T_USER) || (isPointer(t))) { + + Printv(f->def, "static ", "void ", wname, "(C_word, C_word, C_word, C_word) C_noret;\n", NIL); + Printv(f->def, "static " "void ", wname, "(C_word argc, C_word closure, " "C_word continuation, C_word value) {\n", NIL); + + Wrapper_add_local(f, "resultobj", "C_word resultobj"); + + Printf(f->code, "if (argc!=2 && argc!=3) C_bad_argc(argc,2);\n"); + + /* Check for a setting of the variable value */ + if (!GetFlag(n, "feature:immutable")) { + Printf(f->code, "if (argc > 2) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "value"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "value"); + /* Printv(f->code, tm, "\n",NIL); */ + emit_action_code(n, f->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + } + Printf(f->code, "}\n"); + } + + String *varname; + if (SwigType_istemplate((char *) name)) { + varname = SwigType_namestr((char *) name); + } else { + varname = name; + } + + // Now return the value of the variable - regardless + // of evaluating or setting. + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", varname); + Replaceall(tm, "$varname", varname); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + /* Printf(f->code, "%s\n", tm); */ + emit_action_code(n, f->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + + Printv(f->code, "{\n", + "C_word func;\n", + "SWIG_Chicken_FindCreateProxy(func, resultobj)\n", + "if (C_swig_is_closurep(func))\n", + " ((C_proc4)(void *)C_block_item(func, 0))(4,func,continuation,resultobj,C_SCHEME_FALSE);\n", + "else\n", " C_kontinue(continuation, resultobj);\n", "}\n", NIL); + + /* Error handling code */ +#ifdef USE_FAIL + Printf(f->code, "fail:\n"); + Printf(f->code, "swig_panic (\"failure in " "'%s' SWIG wrapper\");\n", proc_name); +#endif + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + /* Now register the variable with the interpreter. */ + addMethod(scmname, wname); + + if (!in_class || member_name) { + String *clos_name; + if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + + Node *class_node = classLookup(t); + String *clos_code = Getattr(n, "tmap:varin:closcode"); + if (class_node && clos_code && !GetFlag(n, "feature:immutable")) { + Replaceall(clos_code, "$input", "(car lst)"); + Printv(clos_methods, "(define (", clos_name, " . lst) (if (null? lst) (", chickenPrimitiveName(scmname), ") (", + chickenPrimitiveName(scmname), " ", clos_code, ")))\n", NIL); + } else { + /* Simply re-export the procedure */ + if (GetFlag(n, "feature:immutable") && GetFlag(n, "feature:constasvar")) { + Printv(clos_methods, "(define ", clos_name, " (", chickenPrimitiveName(scmname), "))\n", NIL); + Printv(scm_const_defs, "(set! ", scmname, " (", scmname, "))\n", NIL); + } else { + Printv(clos_methods, "(define ", clos_name, " ", chickenPrimitiveName(scmname), ")\n", NIL); + } + } + Delete(clos_name); + } + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + + Delete(wname); + Delete(argnum); + Delete(arg); + Delete(tm2); + Delete(mangle); + DelWrapper(f); + return SWIG_OK; +} + +/* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + +int CHICKEN::constantWrapper(Node *n) { + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *value = Getattr(n, "value"); + + String *proc_name = NewString(""); + String *wname = NewString(""); + String *mangle = NewString(""); + String *tm; + String *tm2 = NewString(""); + String *source = NewString(""); + String *argnum = NewString("0"); + String *arg = NewString("argv[0]"); + Wrapper *f; + String *overname = 0; + String *scmname; + String *rvalue; + SwigType *nctype; + + int num_required; + int num_arguments; + + scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + Printf(source, "swig_const_%s", iname); + Replaceall(source, "::", "__"); + + Printf(mangle, "\"%s\"", SwigType_manglestr(t)); + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + Append(wname, Swig_name_wrapper(iname)); + if (overname) { + Append(wname, overname); + } + + nctype = NewString(t); + if (SwigType_isconst(nctype)) { + Delete(SwigType_pop(nctype)); + } + + if (SwigType_type(nctype) == T_STRING) { + rvalue = NewStringf("\"%s\"", value); + } else if (SwigType_type(nctype) == T_CHAR) { + rvalue = NewStringf("\'%s\'", value); + } else { + rvalue = NewString(value); + } + + /* Special hook for member pointer */ + if (SwigType_type(t) == T_MPOINTER) { + Printf(f_header, "static %s = %s;\n", SwigType_str(t, source), rvalue); + } else { + if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", rvalue); + Replaceall(tm, "$target", source); + Replaceall(tm, "$result", source); + Replaceall(tm, "$value", rvalue); + Printf(f_header, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + } + + f = NewWrapper(); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + // evaluation function names + + // Check for interrupts + Printv(f->code, "C_trace(\"", scmname, "\");\n", NIL); + + if (1 || (SwigType_type(t) != T_USER) || (isPointer(t))) { + + Setattr(n, "wrap:name", wname); + Printv(f->def, "static ", "void ", wname, "(C_word, C_word, C_word) C_noret;\n", NIL); + + Printv(f->def, "static ", "void ", wname, "(C_word argc, C_word closure, " "C_word continuation) {\n", NIL); + + Wrapper_add_local(f, "resultobj", "C_word resultobj"); + + Printf(f->code, "if (argc!=2) C_bad_argc(argc,2);\n"); + + // Return the value of the variable + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + + Replaceall(tm, "$source", source); + Replaceall(tm, "$varname", source); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + /* Printf(f->code, "%s\n", tm); */ + emit_action_code(n, f->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + + Printv(f->code, "{\n", + "C_word func;\n", + "SWIG_Chicken_FindCreateProxy(func, resultobj)\n", + "if (C_swig_is_closurep(func))\n", + " ((C_proc4)(void *)C_block_item(func, 0))(4,func,continuation,resultobj,C_SCHEME_FALSE);\n", + "else\n", " C_kontinue(continuation, resultobj);\n", "}\n", NIL); + + /* Error handling code */ +#ifdef USE_FAIL + Printf(f->code, "fail:\n"); + Printf(f->code, "swig_panic (\"failure in " "'%s' SWIG wrapper\");\n", proc_name); +#endif + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + /* Now register the variable with the interpreter. */ + addMethod(scmname, wname); + + if (!in_class || member_name) { + String *clos_name; + if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + if (GetFlag(n, "feature:constasvar")) { + Printv(clos_methods, "(define ", clos_name, " (", chickenPrimitiveName(scmname), "))\n", NIL); + Printv(scm_const_defs, "(set! ", scmname, " (", scmname, "))\n", NIL); + } else { + Printv(clos_methods, "(define ", clos_name, " ", chickenPrimitiveName(scmname), ")\n", NIL); + } + Delete(clos_name); + } + + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + + Delete(wname); + Delete(nctype); + Delete(proc_name); + Delete(argnum); + Delete(arg); + Delete(tm2); + Delete(mangle); + Delete(source); + Delete(rvalue); + DelWrapper(f); + return SWIG_OK; +} + +int CHICKEN::classHandler(Node *n) { + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + constructor_dispatch = 0; + constructor_name = 0; + + c_class_name = NewString(Getattr(n, "sym:name")); + class_name = NewString(""); + short_class_name = NewString(""); + Printv(class_name, "<", c_class_name, ">", NIL); + Printv(short_class_name, c_class_name, NIL); + Replaceall(class_name, "_", "-"); + Replaceall(short_class_name, "_", "-"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + /* Handle inheritance */ + String *base_class = NewString(""); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator base = First(baselist); + while (base.item) { + if (!Getattr(base.item, "feature:ignore")) + Printv(base_class, "<", Getattr(base.item, "sym:name"), "> ", NIL); + base = Next(base); + } + } + + Replaceall(base_class, "_", "-"); + + String *scmmod = NewString(module); + Replaceall(scmmod, "_", "-"); + + Printv(clos_class_defines, "(define ", class_name, "\n", " (make <swig-metaclass-", scmmod, "> 'name \"", short_class_name, "\"\n", NIL); + Delete(scmmod); + + if (Len(base_class)) { + Printv(clos_class_defines, " 'direct-supers (list ", base_class, ")\n", NIL); + } else { + Printv(clos_class_defines, " 'direct-supers (list <object>)\n", NIL); + } + + Printf(clos_class_defines, " 'direct-slots (list 'swig-this\n"); + + String *mangled_classname = Swig_name_mangle(Getattr(n, "sym:name")); + + SwigType *ct = NewStringf("p.%s", Getattr(n, "name")); + swigtype_ptr = SwigType_manglestr(ct); + + Printf(f_runtime, "static swig_chicken_clientdata _swig_chicken_clientdata%s = { 0 };\n", mangled_classname); + Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", swigtype_ptr, ", (void *) &_swig_chicken_clientdata", mangled_classname, ");\n", NIL); + SwigType_remember(ct); + + /* Emit all of the members */ + + in_class = 1; + Language::classHandler(n); + in_class = 0; + + Printf(clos_class_defines, ")))\n\n"); + + if (have_constructor) { + Printv(clos_methods, "(define-method (initialize (obj ", class_name, ") initargs)\n", " (swig-initialize obj initargs ", NIL); + if (constructor_arg_types) { + String *initfunc_name = NewStringf("%s@@SWIG@initmethod", class_name); + String *func_call = buildClosFunctionCall(constructor_arg_types, initfunc_name, chickenPrimitiveName(constructor_name)); + Printf(clos_methods, "%s)\n)\n", initfunc_name); + Printf(clos_methods, "(declare (hide %s))\n", initfunc_name); + Printf(clos_methods, "%s\n", func_call); + Delete(func_call); + Delete(initfunc_name); + Delete(constructor_arg_types); + constructor_arg_types = 0; + } else if (constructor_dispatch) { + Printf(clos_methods, "%s)\n)\n", constructor_dispatch); + Delete(constructor_dispatch); + constructor_dispatch = 0; + } else { + Printf(clos_methods, "%s)\n)\n", chickenPrimitiveName(constructor_name)); + } + Delete(constructor_name); + constructor_name = 0; + } else { + Printv(clos_methods, "(define-method (initialize (obj ", class_name, ") initargs)\n", " (swig-initialize obj initargs (lambda x #f)))\n", NIL); + } + + /* export class initialization function */ + if (clos) { + String *funcname = NewString(mangled_classname); + Printf(funcname, "_swig_chicken_setclosclass"); + String *closfuncname = NewString(funcname); + Replaceall(closfuncname, "_", "-"); + + Printv(f_wrappers, "static void ", funcname, "(C_word,C_word,C_word,C_word) C_noret;\n", + "static void ", funcname, "(C_word argc, C_word closure, C_word continuation, C_word cl) {\n", + " C_trace(\"", funcname, "\");\n", + " if (argc!=3) C_bad_argc(argc,3);\n", + " swig_chicken_clientdata *cdata = (swig_chicken_clientdata *) SWIGTYPE", swigtype_ptr, "->clientdata;\n", + " cdata->gc_proxy_create = CHICKEN_new_gc_root();\n", + " CHICKEN_gc_root_set(cdata->gc_proxy_create, cl);\n", " C_kontinue(continuation, C_SCHEME_UNDEFINED);\n", "}\n", NIL); + addMethod(closfuncname, funcname); + + Printv(clos_methods, "(", chickenPrimitiveName(closfuncname), " (lambda (x lst) (if lst ", + "(cons (make ", class_name, " 'swig-this x) lst) ", "(make ", class_name, " 'swig-this x))))\n\n", NIL); + Delete(closfuncname); + Delete(funcname); + } + + Delete(mangled_classname); + Delete(swigtype_ptr); + swigtype_ptr = 0; + + Delete(class_name); + Delete(short_class_name); + Delete(c_class_name); + class_name = 0; + short_class_name = 0; + c_class_name = 0; + + return SWIG_OK; +} + +int CHICKEN::memberfunctionHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + member_name = chickenNameMapping(proc, short_class_name); + Language::memberfunctionHandler(n); + Delete(member_name); + member_name = NULL; + Delete(proc); + + return SWIG_OK; +} + +int CHICKEN::staticmemberfunctionHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + member_name = NewStringf("%s-%s", short_class_name, proc); + Language::staticmemberfunctionHandler(n); + Delete(member_name); + member_name = NULL; + Delete(proc); + + return SWIG_OK; +} + +int CHICKEN::membervariableHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + //String *pb = SwigType_typedef_resolve_all(SwigType_base(Getattr(n, "type"))); + + Language::membervariableHandler(n); + + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + //Node *class_node = Swig_symbol_clookup(pb, Getattr(n, "sym:symtab")); + Node *class_node = classLookup(Getattr(n, "type")); + + //String *getfunc = NewStringf("%s-%s-get", short_class_name, proc); + //String *setfunc = NewStringf("%s-%s-set", short_class_name, proc); + String *getfunc = Swig_name_get(Swig_name_member(c_class_name, iname)); + Replaceall(getfunc, "_", "-"); + String *setfunc = Swig_name_set(Swig_name_member(c_class_name, iname)); + Replaceall(setfunc, "_", "-"); + + Printv(clos_class_defines, " (list '", proc, " ':swig-virtual ':swig-get ", chickenPrimitiveName(getfunc), NIL); + + if (!GetFlag(n, "feature:immutable")) { + if (class_node) { + Printv(clos_class_defines, " ':swig-set (lambda (x y) (", chickenPrimitiveName(setfunc), " x (slot-ref y 'swig-this))))\n", NIL); + } else { + Printv(clos_class_defines, " ':swig-set ", chickenPrimitiveName(setfunc), ")\n", NIL); + } + } else { + Printf(clos_class_defines, ")\n"); + } + + Delete(proc); + Delete(setfunc); + Delete(getfunc); + return SWIG_OK; +} + +int CHICKEN::staticmembervariableHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + member_name = NewStringf("%s-%s", short_class_name, proc); + Language::staticmembervariableHandler(n); + Delete(member_name); + member_name = NULL; + Delete(proc); + + return SWIG_OK; +} + +int CHICKEN::constructorHandler(Node *n) { + have_constructor = 1; + has_constructor_args = 0; + + + exporting_constructor = true; + Language::constructorHandler(n); + exporting_constructor = false; + + has_constructor_args = 1; + + String *iname = Getattr(n, "sym:name"); + constructor_name = Swig_name_construct(iname); + Replaceall(constructor_name, "_", "-"); + return SWIG_OK; +} + +int CHICKEN::destructorHandler(Node *n) { + + if (no_collection) + member_name = NewStringf("delete-%s", short_class_name); + + exporting_destructor = true; + Language::destructorHandler(n); + exporting_destructor = false; + + if (no_collection) { + Delete(member_name); + member_name = NULL; + } + + return SWIG_OK; +} + +int CHICKEN::importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname && clos_uses) { + + // Find the module node for this imported module. It should be the + // first child but search just in case. + Node *mod = firstChild(n); + while (mod && Strcmp(nodeType(mod), "module") != 0) + mod = nextSibling(mod); + + if (mod) { + String *name = Getattr(mod, "name"); + if (name) { + Printf(closprefix, "(declare (uses %s))\n", name); + } + } + } + + return Language::importDirective(n); +} + +String *CHICKEN::buildClosFunctionCall(List *types, const_String_or_char_ptr closname, const_String_or_char_ptr funcname) { + String *method_signature = NewString(""); + String *func_args = NewString(""); + String *func_call = NewString(""); + + Iterator arg_type; + int arg_count = 0; + int optional_arguments = 0; + + for (arg_type = First(types); arg_type.item; arg_type = Next(arg_type)) { + if (Strcmp(arg_type.item, "^^##optional$$") == 0) { + optional_arguments = 1; + } else { + Printf(method_signature, " (arg%i %s)", arg_count, arg_type.item); + arg_type = Next(arg_type); + if (!arg_type.item) + break; + + String *arg = NewStringf("arg%i", arg_count); + String *access_arg = Copy(arg_type.item); + + Replaceall(access_arg, "$input", arg); + Printf(func_args, " %s", access_arg); + + Delete(arg); + Delete(access_arg); + } + arg_count++; + } + + if (optional_arguments) { + Printf(func_call, "(define-method (%s %s . args) (apply %s %s args))", closname, method_signature, funcname, func_args); + } else { + Printf(func_call, "(define-method (%s %s) (%s %s))", closname, method_signature, funcname, func_args); + } + + Delete(method_signature); + Delete(func_args); + + return func_call; +} + +extern "C" { + + /* compares based on non-primitive names */ + static int compareTypeListsHelper(const DOH *a, const DOH *b, int opt_equal) { + List *la = (List *) a; + List *lb = (List *) b; + + Iterator ia = First(la); + Iterator ib = First(lb); + + while (ia.item && ib.item) { + int ret = Strcmp(ia.item, ib.item); + if (ret) + return ret; + ia = Next(Next(ia)); + ib = Next(Next(ib)); + } if (opt_equal && ia.item && Strcmp(ia.item, "^^##optional$$") == 0) + return 0; + if (ia.item) + return -1; + if (opt_equal && ib.item && Strcmp(ib.item, "^^##optional$$") == 0) + return 0; + if (ib.item) + return 1; + + return 0; + } + + static int compareTypeLists(const DOH *a, const DOH *b) { + return compareTypeListsHelper(a, b, 0); + } +} + +void CHICKEN::dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "%s (2+$numargs,closure," "continuation$commaargs);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *iname = Getattr(n, "sym:name"); + String *wname = NewString(""); + String *scmname = NewString(iname); + Replaceall(scmname, "_", "-"); + + Append(wname, Swig_name_wrapper(iname)); + + Printv(f->def, "static void real_", wname, "(C_word, C_word, C_word, C_word) C_noret;\n", NIL); + + Printv(f->def, "static void real_", wname, "(C_word oldargc, C_word closure, C_word continuation, C_word args) {", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "C_word argv[%d]", maxargs + 1); + Wrapper_add_local(f, "argv", tmp); + Wrapper_add_local(f, "ii", "int ii"); + Wrapper_add_local(f, "t", "C_word t = args"); + Printf(f->code, "if (!C_swig_is_list (args)) {\n"); + Printf(f->code, " swig_barf (SWIG_BARF1_BAD_ARGUMENT_TYPE, " "\"Argument #1 must be a list of overloaded arguments\");\n"); + Printf(f->code, "}\n"); + Printf(f->code, "argc = C_unfix (C_i_length (args));\n"); + Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++, t = C_block_item (t, 1)) {\n", maxargs); + Printf(f->code, "argv[ii] = C_block_item (t, 0);\n"); + Printf(f->code, "}\n"); + + Printv(f->code, dispatch, "\n", NIL); + Printf(f->code, "swig_barf (SWIG_BARF1_BAD_ARGUMENT_TYPE," "\"No matching function for overloaded '%s'\");\n", iname); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + addMethod(scmname, wname); + + DelWrapper(f); + f = NewWrapper(); + + /* varargs */ + Printv(f->def, "void ", wname, "(C_word, C_word, C_word, ...) C_noret;\n", NIL); + Printv(f->def, "void ", wname, "(C_word c, C_word t0, C_word t1, ...) {", NIL); + Printv(f->code, + "C_word t2;\n", + "va_list v;\n", + "C_word *a, c2 = c;\n", + "C_save_rest (t1, c2, 2);\n", "a = C_alloc((c-2)*3);\n", "t2 = C_restore_rest (a, C_rest_count (0));\n", "real_", wname, " (3, t0, t1, t2);\n", NIL); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + + /* Now deal with overloaded function when exporting clos */ + if (clos) { + List *flist = Getattr(overload_parameter_lists, scmname); + if (flist) { + Delattr(overload_parameter_lists, scmname); + + SortList(flist, compareTypeLists); + + String *clos_name; + int construct = 0; + if (have_constructor && !has_constructor_args) { + has_constructor_args = 1; + constructor_dispatch = NewStringf("%s@SWIG@new@dispatch", short_class_name); + clos_name = Copy(constructor_dispatch); + construct = 1; + Printf(clos_methods, "(declare (hide %s))\n", clos_name); + } else if (in_class) + clos_name = NewString(member_name); + else + clos_name = chickenNameMapping(scmname, (char *) ""); + + Iterator f; + List *prev = 0; + int all_primitive = 1; + + /* first check for duplicates and an empty call */ + String *newlist = NewList(); + for (f = First(flist); f.item; f = Next(f)) { + /* check if cur is a duplicate of prev */ + if (prev && compareTypeListsHelper(f.item, prev, 1) == 0) { + Delete(f.item); + } else { + Append(newlist, f.item); + prev = f.item; + Iterator j; + for (j = First(f.item); j.item; j = Next(j)) { + if (Strcmp(j.item, "^^##optional$$") != 0 && Strcmp(j.item, "<top>") != 0) + all_primitive = 0; + } + } + } + Delete(flist); + flist = newlist; + + if (all_primitive) { + Printf(clos_methods, "(define %s %s)\n", clos_name, chickenPrimitiveName(scmname)); + } else { + for (f = First(flist); f.item; f = Next(f)) { + /* now export clos code for argument */ + String *func_call = buildClosFunctionCall(f.item, clos_name, chickenPrimitiveName(scmname)); + Printf(clos_methods, "%s\n", func_call); + Delete(f.item); + Delete(func_call); + } + } + + Delete(clos_name); + Delete(flist); + } + } + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); +} + +int CHICKEN::isPointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); +} + +void CHICKEN::addMethod(String *scheme_name, String *function) { + String *sym = NewString(""); + if (clos) { + Append(sym, "primitive:"); + } + Append(sym, scheme_name); + + /* add symbol to Chicken internal symbol table */ + if (hide_primitive) { + Printv(f_init, "{\n", + " C_word *p0 = a;\n", " *(a++)=C_CLOSURE_TYPE|1;\n", " *(a++)=(C_word)", function, ";\n", " C_mutate(return_vec++, (C_word)p0);\n", "}\n", NIL); + } else { + Printf(f_sym_size, "+C_SIZEOF_INTERNED_SYMBOL(%d)", Len(sym)); + Printf(f_init, "sym = C_intern (&a, %d, \"%s\");\n", Len(sym), sym); + Printv(f_init, "C_mutate ((C_word*)sym+1, (*a=C_CLOSURE_TYPE|1, a[1]=(C_word)", function, ", tmp=(C_word)a, a+=2, tmp));\n", NIL); + } + + if (hide_primitive) { + Setattr(primitive_names, scheme_name, NewStringf("(vector-ref swig-init-return %i)", num_methods)); + } else { + Setattr(primitive_names, scheme_name, Copy(sym)); + } + + num_methods++; + + Delete(sym); +} + +String *CHICKEN::chickenPrimitiveName(String *name) { + String *value = Getattr(primitive_names, name); + if (value) + return value; + else { + Swig_error(input_file, line_number, "Internal Error: attempting to reference non-existant primitive name %s\n", name); + return NewString("#f"); + } +} + +int CHICKEN::validIdentifier(String *s) { + char *c = Char(s); + /* Check whether we have an R5RS identifier. */ + /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ + /* <initial> --> <letter> | <special initial> */ + if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~'))) { + /* <peculiar identifier> --> + | - | ... */ + if ((strcmp(c, "+") == 0) + || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) + return 1; + else + return 0; + } + /* <subsequent> --> <initial> | <digit> | <special subsequent> */ + while (*c) { + if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') + || (*c == '-') || (*c == '.') || (*c == '@'))) + return 0; + c++; + } + return 1; +} + + /* ------------------------------------------------------------ + * closNameMapping() + * Maps the identifier from C++ to the CLOS based on command + * line parameters and such. + * If class_name = "" that means the mapping is for a function or + * variable not attached to any class. + * ------------------------------------------------------------ */ +String *CHICKEN::chickenNameMapping(String *name, const_String_or_char_ptr class_name) { + String *n = NewString(""); + + if (Strcmp(class_name, "") == 0) { + // not part of a class, so no class name to prefix + if (clossymnameprefix) { + Printf(n, "%s%s", clossymnameprefix, name); + } else { + Printf(n, "%s", name); + } + } else { + if (useclassprefix) { + Printf(n, "%s-%s", class_name, name); + } else { + if (clossymnameprefix) { + Printf(n, "%s%s", clossymnameprefix, name); + } else { + Printf(n, "%s", name); + } + } + } + return n; +} + +String *CHICKEN::runtimeCode() { + String *s = Swig_include_sys("chickenrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'chickenrun.swg'\n"); + s = NewString(""); + } + return s; +} + +String *CHICKEN::defaultExternalRuntimeFilename() { + return NewString("swigchickenrun.h"); +} diff --git a/Source/Modules/clisp.cxx b/Source/Modules/clisp.cxx new file mode 100644 index 0000000..665a8c2 --- /dev/null +++ b/Source/Modules/clisp.cxx @@ -0,0 +1,509 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * clisp.cxx + * + * clisp language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_clisp_cxx[] = "$Id: clisp.cxx 11380 2009-07-08 12:17:45Z wsfulton $"; + +#include "swigmod.h" + +class CLISP:public Language { +public: + File *f_cl; + String *module; + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int classDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int typedefHandler(Node *n); + List *entries; +private: + String *get_ffi_type(Node *n, SwigType *ty); + String *convert_literal(String *num_param, String *type); + String *strip_parens(String *string); + int extern_all_flag; + int generate_typedef_flag; + int is_function; +}; + +void CLISP::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGCLISP 1", 0); + SWIG_library_directory("clisp"); + SWIG_config_file("clisp.swg"); + generate_typedef_flag = 0; + extern_all_flag = 0; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-help")) { + Printf(stdout, "clisp Options (available with -clisp)\n"); + Printf(stdout, + " -extern-all\n" + "\t If this option is given then clisp definitions for all the functions\n" + "and global variables will be created otherwise only definitions for \n" + "externed functions and variables are created.\n" + " -generate-typedef\n" + "\t If this option is given then def-c-type will be used to generate shortcuts\n" + "according to the typedefs in the input.\n"); + } else if ((Strcmp(argv[i], "-extern-all") == 0)) { + extern_all_flag = 1; + Swig_mark_arg(i); + } else if ((Strcmp(argv[i], "-generate-typedef") == 0)) { + generate_typedef_flag = 1; + Swig_mark_arg(i); + } + } +} + +int CLISP::top(Node *n) { + + File *f_null = NewString(""); + module = Getattr(n, "name"); + String *output_filename; + entries = NewList(); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + if (!outfile) + output_filename = outfile; + else { + output_filename = NewString(""); + Printf(output_filename, "%s%s.lisp", SWIG_output_directory(), module); + } + + f_cl = NewFile(output_filename, "w+", SWIG_output_files()); + if (!f_cl) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + + Swig_register_filebyname("header", f_null); + Swig_register_filebyname("begin", f_null); + Swig_register_filebyname("runtime", f_null); + Swig_register_filebyname("wrapper", f_null); + + String *header = NewString(""); + + Swig_banner_target_lang(header, ";;"); + + Printf(header, "\n(defpackage :%s\n (:use :common-lisp :ffi)", module); + + Language::top(n); + + Iterator i; + + long len = Len(entries); + if (len > 0) { + Printf(header, "\n (:export"); + } + //else nothing to export + + for (i = First(entries); i.item; i = Next(i)) { + Printf(header, "\n\t:%s", i.item); + } + + if (len > 0) { + Printf(header, ")"); + } + + Printf(header, ")\n"); + Printf(header, "\n(in-package :%s)\n", module); + Printf(header, "\n(default-foreign-language :stdc)\n"); + + len = Tell(f_cl); + + Printf(f_cl, "%s", header); + + long end = Tell(f_cl); + + for (len--; len >= 0; len--) { + end--; + Seek(f_cl, len, SEEK_SET); + int ch = Getc(f_cl); + Seek(f_cl, end, SEEK_SET); + Putc(ch, f_cl); + } + + Seek(f_cl, 0, SEEK_SET); + Write(f_cl, Char(header), Len(header)); + + Close(f_cl); + Delete(f_cl); // Deletes the handle, not the file + + return SWIG_OK; +} + + +int CLISP::functionWrapper(Node *n) { + is_function = 1; + String *storage = Getattr(n, "storage"); + if (!extern_all_flag && (!storage || (Strcmp(storage, "extern") && Strcmp(storage, "externc")))) + return SWIG_OK; + + String *func_name = Getattr(n, "sym:name"); + + ParmList *pl = Getattr(n, "parms"); + + int argnum = 0, first = 1; + + Printf(f_cl, "\n(ffi:def-call-out %s\n\t(:name \"%s\")\n", func_name, func_name); + + Append(entries, func_name); + + if (ParmList_len(pl) != 0) { + Printf(f_cl, "\t(:arguments "); + } + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + + String *argname = Getattr(p, "name"); + // SwigType *argtype; + + String *ffitype = get_ffi_type(n, Getattr(p, "type")); + + int tempargname = 0; + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } + + if (!first) { + Printf(f_cl, "\n\t\t"); + } + Printf(f_cl, "(%s %s)", argname, ffitype); + first = 0; + + Delete(ffitype); + + if (tempargname) + Delete(argname); + } + if (ParmList_len(pl) != 0) { + Printf(f_cl, ")\n"); /* finish arg list */ + } + String *ffitype = get_ffi_type(n, Getattr(n, "type")); + if (Strcmp(ffitype, "NIL")) { //when return type is not nil + Printf(f_cl, "\t(:return-type %s)\n", ffitype); + } + Printf(f_cl, "\t(:library +library-name+))\n"); + + return SWIG_OK; +} + + +int CLISP::constantWrapper(Node *n) { + is_function = 0; + String *type = Getattr(n, "type"); + String *converted_value = convert_literal(Getattr(n, "value"), type); + String *name = Getattr(n, "sym:name"); + + Printf(f_cl, "\n(defconstant %s %s)\n", name, converted_value); + Append(entries, name); + Delete(converted_value); + + return SWIG_OK; +} + +int CLISP::variableWrapper(Node *n) { + is_function = 0; + // SwigType *type=; + String *storage = Getattr(n, "storage"); + + if (!extern_all_flag && (!storage || (Strcmp(storage, "extern") && Strcmp(storage, "externc")))) + return SWIG_OK; + + String *var_name = Getattr(n, "sym:name"); + String *lisp_type = get_ffi_type(n, Getattr(n, "type")); + Printf(f_cl, "\n(ffi:def-c-var %s\n (:name \"%s\")\n (:type %s)\n", var_name, var_name, lisp_type); + Printf(f_cl, "\t(:library +library-name+))\n"); + Append(entries, var_name); + + Delete(lisp_type); + return SWIG_OK; +} + +int CLISP::typedefHandler(Node *n) { + if (generate_typedef_flag) { + is_function = 0; + Printf(f_cl, "\n(ffi:def-c-type %s %s)\n", Getattr(n, "name"), get_ffi_type(n, Getattr(n, "type"))); + } + + return Language::typedefHandler(n); +} + +int CLISP::enumDeclaration(Node *n) { + is_function = 0; + String *name = Getattr(n, "sym:name"); + + Printf(f_cl, "\n(ffi:def-c-enum %s ", name); + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + + String *slot_name = Getattr(c, "name"); + String *value = Getattr(c, "enumvalue"); + + Printf(f_cl, "(%s %s)", slot_name, value); + + Append(entries, slot_name); + + Delete(value); + } + + Printf(f_cl, ")\n"); + return SWIG_OK; +} + + +// Includes structs +int CLISP::classDeclaration(Node *n) { + is_function = 0; + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + + if (Strcmp(kind, "struct")) { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + } + + + Printf(f_cl, "\n(ffi:def-c-struct %s", name); + + Append(entries, NewStringf("make-%s", name)); + + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + + if (Strcmp(nodeType(c), "cdecl")) { + Printf(stderr, "Structure %s has a slot that we can't deal with.\n", name); + Printf(stderr, "nodeType: %s, name: %s, type: %s\n", nodeType(c), Getattr(c, "name"), Getattr(c, "type")); + SWIG_exit(EXIT_FAILURE); + } + + String *temp = Copy(Getattr(c, "decl")); + Append(temp, Getattr(c, "type")); //appending type to the end, otherwise wrong type + String *lisp_type = get_ffi_type(n, temp); + Delete(temp); + + String *slot_name = Getattr(c, "sym:name"); + Printf(f_cl, "\n\t(%s %s)", slot_name, lisp_type); + + Append(entries, NewStringf("%s-%s", name, slot_name)); + + Delete(lisp_type); + } + + Printf(f_cl, ")\n"); + + /* Add this structure to the known lisp types */ + //Printf(stdout, "Adding %s foreign type\n", name); + // add_defined_foreign_type(name); + + return SWIG_OK; +} + +/* utilities */ +/* returns new string w/ parens stripped */ +String *CLISP::strip_parens(String *string) { + char *s = Char(string), *p; + int len = Len(string); + String *res; + + if (len == 0 || s[0] != '(' || s[len - 1] != ')') { + return NewString(string); + } + + p = (char *) malloc(len - 2 + 1); + if (!p) { + Printf(stderr, "Malloc failed\n"); + SWIG_exit(EXIT_FAILURE); + } + + strncpy(p, s + 1, len - 1); + p[len - 2] = 0; /* null terminate */ + + res = NewString(p); + free(p); + + return res; +} + +String *CLISP::convert_literal(String *num_param, String *type) { + String *num = strip_parens(num_param), *res; + char *s = Char(num); + + /* Make sure doubles use 'd' instead of 'e' */ + if (!Strcmp(type, "double")) { + String *updated = Copy(num); + if (Replace(updated, "e", "d", DOH_REPLACE_ANY) > 1) { + Printf(stderr, "Weird!! number %s looks invalid.\n", num); + SWIG_exit(EXIT_FAILURE); + } + Delete(num); + return updated; + } + + if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + return NewStringf("#\\%s", num_param); + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + return NewStringf("\"%s\"", num_param); + } + + if (Len(num) < 2 || s[0] != '0') { + return num; + } + + /* octal or hex */ + + res = NewStringf("#%c%s", s[1] == 'x' ? 'x' : 'o', s + 2); + Delete(num); + + return res; +} + +String *CLISP::get_ffi_type(Node *n, SwigType *ty) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("in", node, "", 0); + Delete(node); + + if (tm) { + return NewString(tm); + } else if (SwigType_ispointer(ty)) { + SwigType *cp = Copy(ty); + SwigType_del_pointer(cp); + String *inner_type = get_ffi_type(n, cp); + + if (SwigType_isfunction(cp)) { + return inner_type; + } + + SwigType *base = SwigType_base(ty); + String *base_name = SwigType_str(base, 0); + + String *str; + if (!Strcmp(base_name, "int") || !Strcmp(base_name, "float") || !Strcmp(base_name, "short") + || !Strcmp(base_name, "double") || !Strcmp(base_name, "long") || !Strcmp(base_name, "char")) { + + str = NewStringf("(ffi:c-ptr %s)", inner_type); + } else { + str = NewStringf("(ffi:c-pointer %s)", inner_type); + } + Delete(base_name); + Delete(base); + Delete(cp); + Delete(inner_type); + return str; + } else if (SwigType_isarray(ty)) { + SwigType *cp = Copy(ty); + String *array_dim = SwigType_array_getdim(ty, 0); + + if (!Strcmp(array_dim, "")) { //dimension less array convert to pointer + Delete(array_dim); + SwigType_del_array(cp); + SwigType_add_pointer(cp); + String *str = get_ffi_type(n, cp); + Delete(cp); + return str; + } else { + SwigType_pop_arrays(cp); + String *inner_type = get_ffi_type(n, cp); + Delete(cp); + + int ndim = SwigType_array_ndim(ty); + String *dimension; + if (ndim == 1) { + dimension = array_dim; + } else { + dimension = array_dim; + for (int i = 1; i < ndim; i++) { + array_dim = SwigType_array_getdim(ty, i); + Append(dimension, " "); + Append(dimension, array_dim); + Delete(array_dim); + } + String *temp = dimension; + dimension = NewStringf("(%s)", dimension); + Delete(temp); + } + String *str; + if (is_function) + str = NewStringf("(ffi:c-ptr (ffi:c-array %s %s))", inner_type, dimension); + else + str = NewStringf("(ffi:c-array %s %s)", inner_type, dimension); + + Delete(inner_type); + Delete(dimension); + return str; + } + } else if (SwigType_isfunction(ty)) { + SwigType *cp = Copy(ty); + SwigType *fn = SwigType_pop_function(cp); + String *args = NewString(""); + ParmList *pl = SwigType_function_parms(fn); + if (ParmList_len(pl) != 0) { + Printf(args, "(:arguments "); + } + int argnum = 0, first = 1; + for (Parm *p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + SwigType *argtype = Getattr(p, "type"); + String *ffitype = get_ffi_type(n, argtype); + + int tempargname = 0; + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } + if (!first) { + Printf(args, "\n\t\t"); + } + Printf(args, "(%s %s)", argname, ffitype); + first = 0; + Delete(ffitype); + if (tempargname) + Delete(argname); + } + if (ParmList_len(pl) != 0) { + Printf(args, ")\n"); /* finish arg list */ + } + String *ffitype = get_ffi_type(n, cp); + String *str = NewStringf("(ffi:c-function %s \t\t\t\t(:return-type %s))", args, ffitype); + Delete(fn); + Delete(args); + Delete(cp); + Delete(ffitype); + return str; + } + String *str = SwigType_str(ty, 0); + if (str) { + char *st = Strstr(str, "struct"); + if (st) { + st += 7; + return NewString(st); + } + char *cl = Strstr(str, "class"); + if (cl) { + cl += 6; + return NewString(cl); + } + } + return str; +} + +extern "C" Language *swig_clisp(void) { + return new CLISP(); +} diff --git a/Source/Modules/contract.cxx b/Source/Modules/contract.cxx new file mode 100644 index 0000000..89e3150 --- /dev/null +++ b/Source/Modules/contract.cxx @@ -0,0 +1,354 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * contract.cxx + * + * Support for Wrap by Contract in SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_contract_cxx[] = "$Id: contract.cxx 11049 2009-01-10 01:15:03Z wsfulton $"; + +#include "swigmod.h" + +/* Contract structure. This holds rules about the different kinds of contract sections + and their combination rules */ + +struct contract { + const char *section; + const char *combiner; +}; +/* Contract rules. This table defines what contract sections are recognized as well as + how contracts are to combined via inheritance */ + +static contract Rules[] = { + {"require:", "&&"}, + {"ensure:", "||"}, + {NULL, NULL} +}; + +/* ---------------------------------------------------------------------------- + * class Contracts: + * + * This class defines the functions that need to be used in + * "wrap by contract" module. + * ------------------------------------------------------------------------- */ + +class Contracts:public Dispatcher { + String *make_expression(String *s, Node *n); + void substitute_parms(String *s, ParmList *p, int method); +public: + Hash *ContractSplit(Node *n); + int emit_contract(Node *n, int method); + int cDeclaration(Node *n); + int constructorDeclaration(Node *n); + int externDeclaration(Node *n); + int extendDirective(Node *n); + int importDirective(Node *n); + int includeDirective(Node *n); + int namespaceDeclaration(Node *n); + int classDeclaration(Node *n); + virtual int top(Node *n); +}; + +static int Contract_Mode = 0; /* contract option */ +static int InClass = 0; /* Parsing C++ or not */ +static int InConstructor = 0; +static Node *CurrentClass = 0; + +/* Set the contract mode, default is 0 (not open) */ +/* Normally set in main.cxx, when get the "-contracts" option */ +void Swig_contract_mode_set(int flag) { + Contract_Mode = flag; +} + +/* Get the contract mode */ +int Swig_contract_mode_get() { + return Contract_Mode; +} + +/* Apply contracts */ +void Swig_contracts(Node *n) { + + Contracts *a = new Contracts; + a->top(n); + delete a; +} + +/* Split the whole contract into preassertion, postassertion and others */ +Hash *Contracts::ContractSplit(Node *n) { + + String *contract = Getattr(n, "feature:contract"); + Hash *result; + if (!contract) + return NULL; + + result = NewHash(); + String *current_section = NewString(""); + const char *current_section_name = Rules[0].section; + List *l = SplitLines(contract); + + Iterator i; + for (i = First(l); i.item; i = Next(i)) { + int found = 0; + if (Strchr(i.item, '{')) + continue; + if (Strchr(i.item, '}')) + continue; + for (int j = 0; Rules[j].section; j++) { + if (Strstr(i.item, Rules[j].section)) { + if (Len(current_section)) { + Setattr(result, current_section_name, current_section); + current_section = Getattr(result, Rules[j].section); + if (!current_section) + current_section = NewString(""); + } + current_section_name = Rules[j].section; + found = 1; + break; + } + } + if (!found) + Append(current_section, i.item); + } + if (Len(current_section)) + Setattr(result, current_section_name, current_section); + return result; +} + +/* This function looks in base classes and collects contracts found */ +void inherit_contracts(Node *c, Node *n, Hash *contracts, Hash *messages) { + + Node *b, *temp; + String *name, *type, *local_decl, *base_decl; + List *bases; + int found = 0; + + bases = Getattr(c, "bases"); + if (!bases) + return; + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + local_decl = Getattr(n, "decl"); + if (local_decl) { + local_decl = SwigType_typedef_resolve_all(local_decl); + } else { + return; + } + /* Width first search */ + for (int i = 0; i < Len(bases); i++) { + b = Getitem(bases, i); + temp = firstChild(b); + while (temp) { + base_decl = Getattr(temp, "decl"); + if (base_decl) { + base_decl = SwigType_typedef_resolve_all(base_decl); + if ((checkAttribute(temp, "storage", "virtual")) && + (checkAttribute(temp, "name", name)) && (checkAttribute(temp, "type", type)) && (!Strcmp(local_decl, base_decl))) { + /* Yes, match found. */ + Hash *icontracts = Getattr(temp, "contract:rules"); + Hash *imessages = Getattr(temp, "contract:messages"); + found = 1; + if (icontracts && imessages) { + /* Add inherited contracts and messages to the contract rules above */ + int j = 0; + for (j = 0; Rules[j].section; j++) { + String *t = Getattr(contracts, Rules[j].section); + String *s = Getattr(icontracts, Rules[j].section); + if (s) { + if (t) { + Insert(t, 0, "("); + Printf(t, ") %s (%s)", Rules[j].combiner, s); + String *m = Getattr(messages, Rules[j].section); + Printf(m, " %s [%s from %s]", Rules[j].combiner, Getattr(imessages, Rules[j].section), Getattr(b, "name")); + } else { + Setattr(contracts, Rules[j].section, NewString(s)); + Setattr(messages, Rules[j].section, NewStringf("[%s from %s]", Getattr(imessages, Rules[j].section), Getattr(b, "name"))); + } + } + } + } + } + Delete(base_decl); + } + temp = nextSibling(temp); + } + } + Delete(local_decl); + if (!found) { + for (int j = 0; j < Len(bases); j++) { + b = Getitem(bases, j); + inherit_contracts(b, n, contracts, messages); + } + } +} + +/* This function cleans up the assertion string by removing some extraneous characters. + Splitting the assertion into pieces */ + +String *Contracts::make_expression(String *s, Node *n) { + String *str_assert, *expr = 0; + List *list_assert; + + str_assert = NewString(s); + /* Omit all useless characters and split by ; */ + Replaceall(str_assert, "\n", ""); + Replaceall(str_assert, "{", ""); + Replaceall(str_assert, "}", ""); + Replace(str_assert, " ", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE); + Replace(str_assert, "\t", "", DOH_REPLACE_ANY | DOH_REPLACE_NOQUOTE); + + list_assert = Split(str_assert, ';', -1); + Delete(str_assert); + + /* build up new assertion */ + str_assert = NewString(""); + Iterator ei; + + for (ei = First(list_assert); ei.item; ei = Next(ei)) { + expr = ei.item; + if (Len(expr)) { + Replaceid(expr, Getattr(n, "name"), "result"); + if (Len(str_assert)) + Append(str_assert, "&&"); + Printf(str_assert, "(%s)", expr); + } + } + Delete(list_assert); + return str_assert; +} + +/* This function substitutes parameter names for argument names in the + contract specification. Note: it is assumed that the wrapper code + uses arg1 for self and arg2..argn for arguments. */ + +void Contracts::substitute_parms(String *s, ParmList *p, int method) { + int argnum = 1; + char argname[32]; + + if (method) { + Replaceid(s, "$self", "arg1"); + argnum++; + } + while (p) { + sprintf(argname, "arg%d", argnum); + String *name = Getattr(p, "name"); + if (name) { + Replaceid(s, name, argname); + } + argnum++; + p = nextSibling(p); + } +} + +int Contracts::emit_contract(Node *n, int method) { + Hash *contracts; + Hash *messages; + String *c; + + ParmList *cparms; + + if (!Getattr(n, "feature:contract")) + return SWIG_ERROR; + + /* Get contract parameters */ + cparms = Getmeta(Getattr(n, "feature:contract"), "parms"); + + /* Split contract into preassert & postassert */ + contracts = ContractSplit(n); + if (!contracts) + return SWIG_ERROR; + + /* This messages hash is used to hold the error messages that will be displayed on + failed contract. */ + + messages = NewHash(); + + /* Take the different contract expressions and clean them up a bit */ + Iterator i; + for (i = First(contracts); i.item; i = Next(i)) { + String *e = make_expression(i.item, n); + substitute_parms(e, cparms, method); + Setattr(contracts, i.key, e); + + /* Make a string containing error messages */ + Setattr(messages, i.key, NewString(e)); + } + + /* If we're in a class. We need to inherit other assertions. */ + if (InClass) { + inherit_contracts(CurrentClass, n, contracts, messages); + } + + /* Save information */ + Setattr(n, "contract:rules", contracts); + Setattr(n, "contract:messages", messages); + + /* Okay. Generate the contract runtime code. */ + + if ((c = Getattr(contracts, "require:"))) { + Setattr(n, "contract:preassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: require: %s\");\n", c, Getattr(messages, "require:"))); + } + if ((c = Getattr(contracts, "ensure:"))) { + Setattr(n, "contract:postassert", NewStringf("SWIG_contract_assert(%s, \"Contract violation: ensure: %s\");\n", c, Getattr(messages, "ensure:"))); + } + return SWIG_OK; +} + +int Contracts::cDeclaration(Node *n) { + int ret = SWIG_OK; + String *decl = Getattr(n, "decl"); + + /* Not a function. Don't even bother with it (for now) */ + if (!SwigType_isfunction(decl)) + return SWIG_OK; + + if (Getattr(n, "feature:contract")) + ret = emit_contract(n, (InClass && !checkAttribute(n, "storage", "static"))); + return ret; +} + +int Contracts::constructorDeclaration(Node *n) { + int ret = SWIG_OK; + InConstructor = 1; + if (Getattr(n, "feature:contract")) + ret = emit_contract(n, 0); + InConstructor = 0; + return ret; +} + +int Contracts::externDeclaration(Node *n) { + return emit_children(n); +} + +int Contracts::extendDirective(Node *n) { + return emit_children(n); +} + +int Contracts::importDirective(Node *n) { + return emit_children(n); +} + +int Contracts::includeDirective(Node *n) { + return emit_children(n); +} + +int Contracts::namespaceDeclaration(Node *n) { + return emit_children(n); +} + +int Contracts::classDeclaration(Node *n) { + int ret = SWIG_OK; + InClass = 1; + CurrentClass = n; + emit_children(n); + InClass = 0; + CurrentClass = 0; + return ret; +} + +int Contracts::top(Node *n) { + emit_children(n); + return SWIG_OK; +} diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx new file mode 100644 index 0000000..5713257 --- /dev/null +++ b/Source/Modules/csharp.cxx @@ -0,0 +1,3960 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * csharp.cxx + * + * C# language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_csharp_cxx[] = "$Id: csharp.cxx 11583 2009-08-15 23:22:20Z wsfulton $"; + +#include "swigmod.h" +#include <limits.h> // for INT_MAX +#include "cparse.h" +#include <ctype.h> + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class CSHARP:public Language { + static const char *usage; + const String *empty_string; + const String *public_string; + const String *protected_string; + + Hash *swig_types_hash; + File *f_begin; + File *f_runtime; + File *f_runtime_h; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_directors; + File *f_directors_h; + List *filenames_list; + + bool proxy_flag; // Flag for generating proxy classes + bool native_function_flag; // Flag for when wrapping a native function + bool enum_constant_flag; // Flag for when wrapping an enum or constant + bool static_flag; // Flag for when wrapping a static functions or member variables + bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable + bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const + bool global_variable_flag; // Flag for when wrapping a global variable + bool old_variable_names; // Flag for old style variable names in the intermediary class + bool generate_property_declaration_flag; // Flag for generating properties + + String *imclass_name; // intermediary class name + String *module_class_name; // module class name + String *imclass_class_code; // intermediary class code + String *proxy_class_def; + String *proxy_class_code; + String *module_class_code; + String *proxy_class_name; + String *variable_name; //Name of a variable being wrapped + String *proxy_class_constants_code; + String *module_class_constants_code; + String *enum_code; + String *dllimport; // DllImport attribute name + String *namespce; // Optional namespace name + String *imclass_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *imclass_baseclass; //inheritance for intermediary class class from %pragma + String *module_baseclass; //inheritance for module class from %pragma + String *imclass_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *imclass_class_modifiers; //class modifiers for intermediary class overriden by %pragma + String *module_class_modifiers; //class modifiers for module class overriden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *imclass_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *director_callback_typedefs; // Director function pointer typedefs for callbacks + String *director_callbacks; // Director callback function pointer member variables + String *director_delegate_callback; // Director callback method that delegates are set to call + String *director_delegate_definitions; // Director delegates definitions in proxy class + String *director_delegate_instances; // Director delegates member variables in proxy class + String *director_method_types; // Director method types + String *director_connect_parms; // Director delegates parameter list for director connect call + String *destructor_call; //C++ destructor call if any + + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + int first_class_dmethod; + int curr_class_dmethod; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + + static Parm *NewParmFromNode(SwigType *type, const_String_or_char_ptr name, Node *n) { + Parm *p = NewParm(type, name); + Setfile(p, Getfile(n)); + Setline(p, Getline(n)); + return p; + } + +public: + + /* ----------------------------------------------------------------------------- + * CSHARP() + * ----------------------------------------------------------------------------- */ + + CSHARP():empty_string(NewString("")), + public_string(NewString("public")), + protected_string(NewString("protected")), + swig_types_hash(NULL), + f_begin(NULL), + f_runtime(NULL), + f_runtime_h(NULL), + f_header(NULL), + f_wrappers(NULL), + f_init(NULL), + f_directors(NULL), + f_directors_h(NULL), + filenames_list(NULL), + proxy_flag(true), + native_function_flag(false), + enum_constant_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + old_variable_names(false), + generate_property_declaration_flag(false), + imclass_name(NULL), + module_class_name(NULL), + imclass_class_code(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + module_class_code(NULL), + proxy_class_name(NULL), + variable_name(NULL), + proxy_class_constants_code(NULL), + module_class_constants_code(NULL), + enum_code(NULL), + dllimport(NULL), + namespce(NULL), + imclass_imports(NULL), + module_imports(NULL), + imclass_baseclass(NULL), + module_baseclass(NULL), + imclass_interfaces(NULL), + module_interfaces(NULL), + imclass_class_modifiers(NULL), + module_class_modifiers(NULL), + upcasts_code(NULL), + imclass_cppcasts_code(NULL), + director_callback_typedefs(NULL), + director_callbacks(NULL), + director_delegate_callback(NULL), + director_delegate_definitions(NULL), + director_delegate_instances(NULL), + director_method_types(NULL), + director_connect_parms(NULL), + destructor_call(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(0) { + /* for now, multiple inheritance in directors is disabled, this + should be easy to implement though */ + director_multiple_inheritance = 0; + director_language = 1; + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class + * Return NULL if not otherwise the proxy class name + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *directorClassName(Node *n) { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = Getattr(n, "sym:name"); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + + return dirclassname; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("csharp"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-dllimport") == 0) { + if (argv[i + 1]) { + dllimport = NewString(""); + Printf(dllimport, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-namespace") == 0) { + if (argv[i + 1]) { + namespce = NewString(""); + Printf(namespce, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + Swig_mark_arg(i); + proxy_flag = false; + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGCSHARP 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("csharp"); + SWIG_config_file("csharp.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + + // Get any options set in the module directive + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + + if (optionsnode) { + if (Getattr(optionsnode, "imclassname")) + imclass_name = Copy(Getattr(optionsnode, "imclassname")); + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + if (Getattr(optionsnode, "directors")) { + allow_directors(); + } + if (Getattr(optionsnode, "dirprot")) { + allow_dirprot(); + } + allow_allprotected(GetFlag(optionsnode, "allprotected")); + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + if (!outfile) { + Printf(stderr, "Unable to determine outfile\n"); + SWIG_exit(EXIT_FAILURE); + } + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + if (directorsEnabled()) { + if (!outfile_h) { + Printf(stderr, "Unable to determine outfile_h\n"); + SWIG_exit(EXIT_FAILURE); + } + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + swig_types_hash = NewHash(); + filenames_list = NewList(); + + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + if (!imclass_name) { + imclass_name = NewStringf("%sPINVOKE", Getattr(n, "name")); + module_class_name = Copy(Getattr(n, "name")); + } else { + // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution + if (Cmp(imclass_name, Getattr(n, "name")) == 0) + module_class_name = NewStringf("%sModule", Getattr(n, "name")); + else + module_class_name = Copy(Getattr(n, "name")); + } + + imclass_class_code = NewString(""); + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + module_class_constants_code = NewString(""); + imclass_baseclass = NewString(""); + imclass_interfaces = NewString(""); + imclass_class_modifiers = NewString(""); + module_class_code = NewString(""); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + module_class_modifiers = NewString(""); + imclass_imports = NewString(""); + imclass_cppcasts_code = NewString(""); + director_connect_parms = NewString(""); + upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + if (!namespce) + namespce = NewString(""); + if (!dllimport) + dllimport = Copy(module_class_name); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCSHARP\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + + /* Emit initial director header and director code: */ + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_class_name); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_name); + + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + if (outfile_h) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + Printf(f_runtime, "\n"); + + Swig_name_register((char *) "wrapper", (char *) "CSharp_%f"); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%v"); + } + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + /* Emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director.swg", f_runtime); + } + // Generate the intermediary class + { + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), imclass_name); + File *f_im = NewFile(filen, "w", SWIG_output_files()); + if (!f_im) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the intermediary class file + emitBanner(f_im); + + addOpenNamespace(namespce, f_im); + + if (imclass_imports) + Printf(f_im, "%s\n", imclass_imports); + + if (Len(imclass_class_modifiers) > 0) + Printf(f_im, "%s ", imclass_class_modifiers); + Printf(f_im, "%s ", imclass_name); + + if (imclass_baseclass && *Char(imclass_baseclass)) + Printf(f_im, ": %s ", imclass_baseclass); + if (Len(imclass_interfaces) > 0) + Printv(f_im, "implements ", imclass_interfaces, " ", NIL); + Printf(f_im, "{\n"); + + // Add the intermediary class methods + Replaceall(imclass_class_code, "$module", module_class_name); + Replaceall(imclass_class_code, "$imclassname", imclass_name); + Replaceall(imclass_class_code, "$dllimport", dllimport); + Printv(f_im, imclass_class_code, NIL); + Printv(f_im, imclass_cppcasts_code, NIL); + + // Finish off the class + Printf(f_im, "}\n"); + addCloseNamespace(namespce, f_im); + + Close(f_im); + } + + // Generate the C# module class + { + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), module_class_name); + File *f_module = NewFile(filen, "w", SWIG_output_files()); + if (!f_module) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the module class file + emitBanner(f_module); + + addOpenNamespace(namespce, f_module); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + if (Len(module_class_modifiers) > 0) + Printf(f_module, "%s ", module_class_modifiers); + Printf(f_module, "%s ", module_class_name); + + if (module_baseclass && *Char(module_baseclass)) + Printf(f_module, ": %s ", module_baseclass); + if (Len(module_interfaces) > 0) + Printv(f_module, "implements ", module_interfaces, " ", NIL); + Printf(f_module, "{\n"); + + Replaceall(module_class_code, "$module", module_class_name); + Replaceall(module_class_constants_code, "$module", module_class_name); + + Replaceall(module_class_code, "$imclassname", imclass_name); + Replaceall(module_class_constants_code, "$imclassname", imclass_name); + + Replaceall(module_class_code, "$dllimport", dllimport); + Replaceall(module_class_constants_code, "$dllimport", dllimport); + + // Add the wrapper methods + Printv(f_module, module_class_code, NIL); + + // Write out all the global constants + Printv(f_module, module_class_constants_code, NIL); + + // Finish off the class + Printf(f_module, "}\n"); + addCloseNamespace(namespce, f_module); + + Close(f_module); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a C# type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + // Check for overwriting file problems on filesystems that are case insensitive + Iterator it1; + Iterator it2; + for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { + String *item1_lower = Swig_string_lower(it1.item); + for (it2 = Next(it1); it2.item; it2 = Next(it2)) { + String *item2_lower = Swig_string_lower(it2.item); + if (it1.item && it2.item) { + if (Strcmp(item1_lower, item2_lower) == 0) { + Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, + "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " + "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); + } + } + Delete(item2_lower); + } + Delete(item1_lower); + } + + Delete(swig_types_hash); + swig_types_hash = NULL; + Delete(filenames_list); + filenames_list = NULL; + Delete(imclass_name); + imclass_name = NULL; + Delete(imclass_class_code); + imclass_class_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(module_class_constants_code); + module_class_constants_code = NULL; + Delete(imclass_baseclass); + imclass_baseclass = NULL; + Delete(imclass_interfaces); + imclass_interfaces = NULL; + Delete(imclass_class_modifiers); + imclass_class_modifiers = NULL; + Delete(module_class_name); + module_class_name = NULL; + Delete(module_class_code); + module_class_code = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(module_class_modifiers); + module_class_modifiers = NULL; + Delete(imclass_imports); + imclass_imports = NULL; + Delete(imclass_cppcasts_code); + imclass_cppcasts_code = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(dmethods_seq); + dmethods_seq = NULL; + Delete(dmethods_table); + dmethods_table = NULL; + Delete(namespce); + namespce = NULL; + n_dmethods = 0; + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors, f_begin); + Dump(f_directors_h, f_runtime_h); + + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + + Close(f_runtime_h); + Delete(f_runtime_h); + f_runtime_h = NULL; + Delete(f_directors); + f_directors = NULL; + Delete(f_directors_h); + f_directors_h = NULL; + } + + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * emitBanner() + * ----------------------------------------------------------------------------- */ + + void emitBanner(File *f) { + Printf(f, "/* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); + } + + /*----------------------------------------------------------------------- + * Add new director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *decl, String *overloaded_name) { + UpcallData *udata; + String *imclass_methodidx; + String *class_methodidx; + Hash *new_udata; + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, key))) { + Delete(key); + return Getattr(udata, "methodoff"); + } + + imclass_methodidx = NewStringf("%d", n_dmethods); + class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); + n_dmethods++; + + new_udata = NewHash(); + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, key, new_udata); + + Setattr(new_udata, "method", Copy(class_method)); + // TODO: remove fdesc +// Setattr(new_udata, "fdesc", Copy(class_desc)); +// Setattr(new_udata, "imclass_method", Copy(imclass_method)); +// Setattr(new_udata, "imclass_methodidx", imclass_methodidx); + Setattr(new_udata, "class_methodidx", class_methodidx); + Setattr(new_udata, "decl", Copy(decl)); + Setattr(new_udata, "overname", Copy(overloaded_name)); + + Delete(key); + return new_udata; + } + + /*----------------------------------------------------------------------- + * Get director upcall signature + *----------------------------------------------------------------------*/ + + /* + UpcallData * getUpcallMethodData(String *director_class, String *decl) { + String *key = NewStringf("%s|%s", director_class, decl); + UpcallData *udata = Getattr(dmethods_table, key); + + Delete(key); + return udata; + } + */ + + /* ---------------------------------------------------------------------- + * nativeWrapper() + * ---------------------------------------------------------------------- */ + + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + if (Getattr(n, "type")) { + Swig_save("nativeWrapper", n, "name", NIL); + Setattr(n, "name", wrapname); + native_function_flag = true; + functionWrapper(n); + Swig_restore(n); + native_function_flag = false; + } else { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, Getattr(n, "wrap:name")); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *c_return_type = NewString(""); + String *im_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + String *im_outattributes = 0; + int num_arguments = 0; + int num_required = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(Getattr(n, "sym:name"), n)) + return SWIG_ERROR; + } + + /* + The rest of this function deals with generating the intermediary class wrapper function (that wraps + a c/c++ function) and generating the PInvoke c code. Each C# wrapper function has a + matching PInvoke c function call. + */ + + // A new wrapper function object + Wrapper *f = NewWrapper(); + + // Make a wrapper name for this function + String *wname = Swig_name_wrapper(overloaded_name); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("ctype", l, f); + Swig_typemap_attach_parms("imtype", l, f); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("ctype", n, "", 0))) { + String *ctypeout = Getattr(n, "tmap:ctype:out"); // the type in the ctype typemap's out attribute overrides the type in the typemap + if (ctypeout) + tm = ctypeout; + Printf(c_return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if ((tm = Swig_typemap_lookup("imtype", n, "", 0))) { + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + Printf(im_return_type, "%s", tm); + im_outattributes = Getattr(n, "tmap:imtype:outattributes"); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + is_void_return = (Cmp(c_return_type, "void") == 0); + if (!is_void_return) + Wrapper_add_localv(f, "jresult", c_return_type, "jresult", NIL); + + Printv(f->def, " SWIGEXPORT ", c_return_type, " SWIGSTDCALL ", wname, "(", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + + // Parameter overloading + Setattr(n, "wrap:parms", l); + Setattr(n, "wrap:name", wname); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "sym:overloaded")) { + // Emit warnings for the few cases that can't be overloaded in C# and give up on generating wrapper + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + } + + Printv(imclass_class_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", overloaded_name, "\")]\n", NIL); + + if (im_outattributes) + Printf(imclass_class_code, " %s\n", im_outattributes); + + Printf(imclass_class_code, " public static extern %s %s(", im_return_type, overloaded_name); + + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + int gencomma = 0; + + // Now walk the function parameter list and generate code to get arguments + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + String *im_param_type = NewString(""); + String *c_param_type = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* Get the ctype types of the parameter */ + if ((tm = Getattr(p, "tmap:ctype"))) { + Printv(c_param_type, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Get the intermediary class parameter types of the parameter */ + if ((tm = Getattr(p, "tmap:imtype"))) { + const String *inattributes = Getattr(p, "tmap:imtype:inattributes"); + Printf(im_param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to intermediary class method */ + if (gencomma) + Printf(imclass_class_code, ", "); + Printf(imclass_class_code, "%s %s", im_param_type, arg); + + // Add parameter to C function + Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + + gencomma = 1; + + // Get typemap for this argument + if ((tm = Getattr(p, "tmap:in"))) { + canThrow(n, "in", p); + Replaceall(tm, "$source", arg); /* deprecated */ + Replaceall(tm, "$target", ln); /* deprecated */ + Replaceall(tm, "$arg", arg); /* deprecated? */ + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + Delete(im_param_type); + Delete(c_param_type); + Delete(arg); + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + canThrow(n, "check", p); + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + canThrow(n, "freearg", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + canThrow(n, "argout", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Look for usage of throws typemap and the canthrow flag + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "catchlist"))) { + Swig_typemap_attach_parms("throws", throw_parm_list, f); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + canThrow(n, "throws", p); + } + } + } + + String *null_attribute = 0; + // Now write code to make the function call + if (!native_function_flag) { + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) + Swig_restore(n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + canThrow(n, "out", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Replaceall(tm, "$target", "jresult"); /* deprecated */ + Replaceall(tm, "$result", "jresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s", tm); + null_attribute = Getattr(n, "tmap:out:null"); + if (Len(tm)) + Printf(f->code, "\n"); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); + } + emit_return_variable(n, t, f); + } + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + canThrow(n, "newfree", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if (!native_function_flag) { + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + canThrow(n, "ret", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C function and intermediary class function definitions */ + Printf(imclass_class_code, ")"); + Printf(imclass_class_code, ";\n"); + + Printf(f->def, ") {"); + + if (!is_void_return) + Printv(f->code, " return jresult;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + /* Contract macro modification */ + if (Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, ") > 0) { + Setattr(n, "csharp:canthrow", "1"); + } + + if (!null_attribute) + Replaceall(f->code, "$null", "0"); + else + Replaceall(f->code, "$null", null_attribute); + + /* Dump the function out */ + if (!native_function_flag) { + Wrapper_print(f, f_wrappers); + + // Handle %csexception which sets the canthrow attribute + if (Getattr(n, "feature:except:canthrow")) + Setattr(n, "csharp:canthrow", "1"); + + // A very simple check (it is not foolproof) to help typemap/feature writers for + // throwing C# exceptions from unmanaged code. It checks for the common methods which + // set a pending C# exception... the 'canthrow' typemap/feature attribute must be set + // so that code which checks for pending exceptions is added in the C# proxy method. + if (!Getattr(n, "csharp:canthrow")) { + if (Strstr(f->code, "SWIG_exception")) { + Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, + "Unmanaged code contains a call to SWIG_exception and C# code does not handle pending exceptions via the canthrow attribute.\n"); + } else if (Strstr(f->code, "SWIG_CSharpSetPendingException")) { + Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, + "Unmanaged code contains a call to a SWIG_CSharpSetPendingException method and C# code does not handle pending exceptions via the canthrow attribute.\n"); + } + } + } + + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + moduleClassFunctionHandler(n); + } + + /* + * Generate the proxy class properties for public member variables. + * Not for enums and constants. + */ + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Capitalize the first letter in the variable in the getter/setter function name + bool getter_flag = Cmp(symname, Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) != 0; + + String *getter_setter_name = NewString(""); + if (!getter_flag) + Printf(getter_setter_name, "set"); + else + Printf(getter_setter_name, "get"); + Putc(toupper((int) *Char(variable_name)), getter_setter_name); + Printf(getter_setter_name, "%s", Char(variable_name) + 1); + + Setattr(n, "proxyfuncname", getter_setter_name); + Setattr(n, "imfuncname", symname); + + proxyClassFunctionHandler(n); + Delete(getter_setter_name); + } + + Delete(c_return_type); + Delete(im_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(overloaded_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + Language::variableWrapper(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * globalvariableHandler() + * ------------------------------------------------------------------------ */ + + virtual int globalvariableHandler(Node *n) { + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + generate_property_declaration_flag = false; + + if (proxy_flag) { + Printf(module_class_code, "\n }\n\n"); + } + + return ret; + } + + /* ---------------------------------------------------------------------- + * enumDeclaration() + * + * C/C++ enums can be mapped in one of 4 ways, depending on the cs:enum feature specified: + * 1) Simple enums - simple constant within the proxy class or module class + * 2) Typeunsafe enums - simple constant in a C# class (class named after the c++ enum name) + * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) + * 4) Proper enums - proper C# enum + * Anonymous enums always default to 1) + * ---------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + enum_code = NewString(""); + String *symname = Getattr(n, "sym:name"); + String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; + EnumFeature enum_feature = decodeEnumFeature(n); + String *typemap_lookup_type = Getattr(n, "name"); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + + // Pure C# baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "csinterfaces", typemap_lookup_type, WARN_NONE); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(enum_code, "%s\n", csattributes); + + // Emit the enum + Printv(enum_code, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers (enum modifiers really) + " ", symname, (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {\n", NIL); + } else { + // Wrap C++ enum with integers - just indicate start of enum with a comment, no comment for anonymous enums of any sort + if (symname && !Getattr(n, "unnamedinstance")) + Printf(constants_code, " // %s \n", symname); + } + + // Emit each enum item + Language::enumDeclaration(n); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + // Finish the enum declaration + // Typemaps are used to generate the enum definition in a similar manner to proxy classes. + Printv(enum_code, (enum_feature == ProperEnum) ? "\n" : typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "}", NIL); + + Replaceall(enum_code, "$csclassname", symname); + + // Substitute $enumvalues - intended usage is for typesafe enums + if (Getattr(n, "enumvalues")) + Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); + else + Replaceall(enum_code, "$enumvalues", ""); + + if (proxy_flag && is_wrapping_class()) { + // Enums defined within the C++ class are defined within the proxy class + + // Add extra indentation + Replaceall(enum_code, "\n", "\n "); + Replaceall(enum_code, " \n", "\n"); + + Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL); + } else { + // Global enums are defined in their own file + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), symname); + File *f_enum = NewFile(filen, "w", SWIG_output_files()); + if (!f_enum) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the enum file + emitBanner(f_enum); + + addOpenNamespace(namespce, f_enum); + + Printv(f_enum, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + addCloseNamespace(namespce, f_enum); + + Close(f_enum); + } + } else { + // Wrap C++ enum with simple constant + Printf(enum_code, "\n"); + if (proxy_flag && is_wrapping_class()) + Printv(proxy_class_constants_code, enum_code, NIL); + else + Printv(module_class_constants_code, enum_code, NIL); + } + + Delete(enum_code); + enum_code = NULL; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + + // Strange hack from parent method + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + // Note that this is used in enumValue() amongst other places + Setattr(n, "value", tmpValue); + + { + EnumFeature enum_feature = decodeEnumFeature(parentNode(n)); + + if ((enum_feature == ProperEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymous) C/C++ enum with a proper C# enum + // Emit the enum item. + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + Printf(enum_code, " %s", symname); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + // Note that the enum value must be a true constant and cannot be set from a PINVOKE call, thus no support for %csconst(0) + value = value ? value : Getattr(n, "enumvalue"); + if (value) { + Printf(enum_code, " = %s", value); + } + } else { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + const String *parent_name = Getattr(parentNode(n), "name"); + String *typemap_lookup_type = parent_name ? Copy(parent_name) : NewString("int"); + const String *tm = typemapLookup(n, "cstype", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF); + String *return_type = Copy(tm); + Delete(typemap_lookup_type); + typemap_lookup_type = NULL; + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if ((enum_feature == TypesafeEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymouse) enum using the typesafe enum pattern + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, " %s static readonly %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); + Delete(value); + } else { + Printf(enum_code, " %s static readonly %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); + } + } else { + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + const char *const_readonly = const_feature_flag ? "const" : "static readonly"; + String *value = enumValue(n); + Printf(enum_code, " %s %s %s %s = %s;\n", methodmods, const_readonly, return_type, symname, value); + Delete(value); + } + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parentNode(n), "enumvalues"); + if (!enumvalues) + Setattr(parentNode(n), "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + } + + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * Used for wrapping constants - #define or %constant. + * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). + * C# static const variables are generated for these. + * If the %csconst(1) feature is used then the C constant value is used to initialise the C# const variable. + * If not, a PINVOKE method is generated to get the C constant value for initialisation of the C# const variable. + * However, if the %csconstvalue feature is used, it overrides all other ways to generate the initialisation. + * Also note that this method might be called for wrapping enum items (when the enum is using %csconst(0)). + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + /* Adjust the enum type for the Swig_typemap_lookup. + * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ + if (is_enum_item) { + t = Getattr(parentNode(n), "enumtype"); + Setattr(n, "type", t); + } + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("cstype", l, NULL); + + /* Get C# return types */ + bool classname_substituted_flag = false; + + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + classname_substituted_flag = substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + // Add the stripped quotes back in + String *new_value = NewString(""); + Swig_save("constantWrapper", n, "value", NIL); + if (SwigType_type(t) == T_STRING) { + Printf(new_value, "\"%s\"", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } else if (SwigType_type(t) == T_CHAR) { + Printf(new_value, "\'%s\'", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } + + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(constants_code, " %s\n", outattributes); + const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + Printf(constants_code, " %s %s %s %s = ", methodmods, (const_feature_flag ? "const" : "static readonly"), return_type, itemname); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + if (value) { + Printf(constants_code, "%s;\n", value); + } else if (!const_feature_flag) { + // Default enum and constant handling will work with any type of C constant and initialises the C# variable from C through a PINVOKE call. + + if (classname_substituted_flag) { + if (SwigType_isenum(t)) { + // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) + Printf(constants_code, "(%s)%s.%s();\n", return_type, imclass_name, Swig_name_get(symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(symname)); + } + } else + Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(symname)); + + // Each constant and enum value is wrapped with a separate PInvoke function call + SetFlag(n, "feature:immutable"); + enum_constant_flag = true; + variableWrapper(n); + enum_constant_flag = false; + } else { + // Alternative constant handling will use the C syntax to make a true C# constant and hope that it compiles as C# code + Printf(constants_code, "%s;\n", Getattr(n, "value")); + } + + // Emit the generated code to appropriate place + // Enums only emit the intermediate and PINVOKE methods, so no proxy or module class wrapper methods needed + if (!is_enum_item) { + if (proxy_flag && wrapping_member_flag) + Printv(proxy_class_constants_code, constants_code, NIL); + else + Printv(module_class_constants_code, constants_code, NIL); + } + // Cleanup + Swig_restore(n); + Delete(new_value); + Delete(return_type); + Delete(constants_code); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * insertDirective() + * ----------------------------------------------------------------------------- */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + Replaceall(code, "$dllimport", dllimport); + return Language::insertDirective(n); + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * imclassbase - base (extends) for the intermediary class + * imclassclassmodifiers - class modifiers for the intermediary class + * imclasscode - text (C# code) is copied verbatim to the intermediary class + * imclassimports - import statements for the intermediary class + * imclassinterfaces - interface (implements) for the intermediary class + * + * modulebase - base (extends) for the module class + * moduleclassmodifiers - class modifiers for the module class + * modulecode - text (C# code) is copied verbatim to the module class + * moduleimports - import statements for the module class + * moduleinterfaces - interface (implements) for the module class + * + * ----------------------------------------------------------------------------- */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *code = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "csharp") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); + + if (Strcmp(code, "imclassbase") == 0) { + Delete(imclass_baseclass); + imclass_baseclass = Copy(strvalue); + } else if (Strcmp(code, "imclassclassmodifiers") == 0) { + Delete(imclass_class_modifiers); + imclass_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "imclasscode") == 0) { + Printf(imclass_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "imclassimports") == 0) { + Delete(imclass_imports); + imclass_imports = Copy(strvalue); + } else if (Strcmp(code, "imclassinterfaces") == 0) { + Delete(imclass_interfaces); + imclass_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(module_class_modifiers); + module_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(module_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "moduleimports") == 0) { + Delete(module_imports); + module_imports = Copy(strvalue); + } else if (Strcmp(code, "moduleinterfaces") == 0) { + Delete(module_interfaces); + module_interfaces = Copy(strvalue); + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + + // Inheritance from pure C# classes + Node *attributes = NewHash(); + const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE, attributes); + bool purebase_replace = GetFlag(attributes, "tmap:csbase:replace") ? true : false; + bool purebase_notderived = GetFlag(attributes, "tmap:csbase:notderived") ? true : false; + Delete(attributes); + + // C++ inheritance + if (!purebase_replace) { + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (base.item) { + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + base = Next(base); + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (derived && purebase_notderived) + pure_baseclass = empty_string; + const String *wanted_base = baseclass ? baseclass : pure_baseclass; + + if (purebase_replace) { + wanted_base = pure_baseclass; + derived = false; + Delete(baseclass); + baseclass = NULL; + if (purebase_notderived) + Swig_error(input_file, line_number, "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure C# interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE); + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", NIL); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(proxy_class_def, "%s\n", csattributes); + + Printv(proxy_class_def, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $csclassname", // Class name and base class + (*Char(wanted_base) || *Char(pure_interfaces)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {", derived ? typemapLookup(n, "csbody_derived", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF) : // main body of class + typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + NIL); + + // C++ destructor is wrapped by the Dispose method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + attributes = NewHash(); + String *destruct_methodname = NULL; + String *destruct_methodmodifiers = NULL; + if (derived) { + tm = typemapLookup(n, "csdestruct_derived", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdestruct_derived:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdestruct_derived:methodmodifiers"); + } else { + tm = typemapLookup(n, "csdestruct", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdestruct:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdestruct:methodmodifiers"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(input_file, line_number, "No methodname attribute defined in csdestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(input_file, line_number, + "No methodmodifiers attribute defined in csdestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + } + } + // Emit the Finalize and Dispose methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "csfinalize", typemap_lookup_type, WARN_NONE), NIL); + } + // Dispose method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$imcall", destructor_call); + else + Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) + Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", + NIL); + } + + if (feature_director) { + // Generate director connect method + // put this in classDirectorEnd ??? + Printf(proxy_class_code, " private void SwigDirectorConnect() {\n"); + + int i; + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *method = Getattr(udata, "method"); + String *methid = Getattr(udata, "class_methodidx"); + String *overname = Getattr(udata, "overname"); + Printf(proxy_class_code, " if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s))\n", method, methid); + Printf(proxy_class_code, " swigDelegate%s = new SwigDelegate%s_%s(SwigDirector%s);\n", methid, proxy_class_name, methid, overname); + } + Printf(proxy_class_code, " %s.%s_director_connect(swigCPtr", imclass_name, proxy_class_name); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + Printf(proxy_class_code, ", swigDelegate%s", methid); + } + Printf(proxy_class_code, ");\n"); + Printf(proxy_class_code, " }\n"); + + if (first_class_dmethod < curr_class_dmethod) { + // Only emit if there is at least one director method + Printf(proxy_class_code, "\n"); + Printf(proxy_class_code, " private bool SwigDerivedClassHasMethod(string methodName, Type[] methodTypes) {\n"); + Printf(proxy_class_code, + " System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, methodTypes, null);\n"); + Printf(proxy_class_code, " bool hasDerivedMethod = methodInfo.DeclaringType.IsSubclassOf(typeof(%s));\n", proxy_class_name); + /* Could add this code to cover corner case where the GetMethod() returns a method which allows type + * promotion, eg it will return foo(double), if looking for foo(int). + if (hasDerivedMethod) { + hasDerivedMethod = false; + if (methodInfo != null) + { + hasDerivedMethod = true; + ParameterInfo[] parameterArray1 = methodInfo.GetParameters(); + for (int i=0; i<methodTypes.Length; i++) + { + if (parameterArray1[0].ParameterType != methodTypes[0]) + { + hasDerivedMethod = false; + break; + } + } + } + } + */ + Printf(proxy_class_code, " return hasDerivedMethod;\n"); + Printf(proxy_class_code, " }\n"); + } + + if (Len(director_delegate_callback) > 0) + Printv(proxy_class_code, director_delegate_callback, NIL); + if (Len(director_delegate_definitions) > 0) + Printv(proxy_class_code, "\n", director_delegate_definitions, NIL); + if (Len(director_delegate_instances) > 0) + Printv(proxy_class_code, "\n", director_delegate_instances, NIL); + if (Len(director_method_types) > 0) + Printv(proxy_class_code, "\n", director_method_types, NIL); + + Delete(director_callback_typedefs); + director_callback_typedefs = NULL; + Delete(director_callbacks); + director_callbacks = NULL; + Delete(director_delegate_callback); + director_delegate_callback = NULL; + Delete(director_delegate_definitions); + director_delegate_definitions = NULL; + Delete(director_delegate_instances); + director_delegate_instances = NULL; + Delete(director_method_types); + director_method_types = NULL; + Delete(director_connect_parms); + director_connect_parms = NULL; + } + + Delete(attributes); + Delete(destruct); + + // Emit extra user code + Printv(proxy_class_def, typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "\n", NIL); + + // Substitute various strings into the above template + Replaceall(proxy_class_code, "$csclassname", proxy_class_name); + Replaceall(proxy_class_def, "$csclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(imclass_cppcasts_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", proxy_class_name, "Upcast", "\")]\n", NIL); + Printf(imclass_cppcasts_code, " public static extern IntPtr $csclassnameUpcast(IntPtr objectRef);\n"); + + Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name); + + Printv(upcasts_code, + "SWIGEXPORT $cbaseclass * SWIGSTDCALL CSharp_$imclazznameUpcast", + "($cclass *objectRef) {\n", " return ($cbaseclass *)objectRef;\n" "}\n", "\n", NIL); + + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", proxy_class_name); + Replaceall(upcasts_code, "$cclass", c_classname); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + if (Cmp(proxy_class_name, imclass_name) == 0) { + Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + if (Cmp(proxy_class_name, module_class_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the proxy class file + emitBanner(f_proxy); + + addOpenNamespace(namespce, f_proxy); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + destructor_call = NewString(""); + proxy_class_constants_code = NewString(""); + } + + Language::classHandler(n); + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + Replaceall(proxy_class_constants_code, "$module", module_class_name); + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", imclass_name); + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + Replaceall(proxy_class_constants_code, "$dllimport", dllimport); + + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) + Printv(f_proxy, proxy_class_constants_code, NIL); + + Printf(f_proxy, "}\n"); + addCloseNamespace(namespce, f_proxy); + Close(f_proxy); + f_proxy = NULL; + + /* Output the downcast method, if necessary. Note: There's no other really + good place to put this code, since Abstract Base Classes (ABCs) can and should have + downcasts, making the constructorHandler() a bad place (because ABCs don't get to + have constructors emitted.) */ + if (GetFlag(n, "feature:javadowncast")) { + String *norm_name = SwigType_namestr(Getattr(n, "name")); + + Printf(imclass_class_code, " public final static native %s downcast%s(long cPtrBase, boolean cMemoryOwn);\n", proxy_class_name, proxy_class_name); + + Wrapper *dcast_wrap = NewWrapper(); + + Printf(dcast_wrap->def, "SWIGEXPORT jobject SWIGSTDCALL CSharp_downcast%s(JNIEnv *jenv, jclass jcls, jlong jCPtrBase, jboolean cMemoryOwn) {", + proxy_class_name); + Printf(dcast_wrap->code, " Swig::Director *director = (Swig::Director *) 0;\n"); + Printf(dcast_wrap->code, " jobject jresult = (jobject) 0;\n"); + Printf(dcast_wrap->code, " %s *obj = *((%s **)&jCPtrBase);\n", norm_name, norm_name); + Printf(dcast_wrap->code, " if (obj) director = dynamic_cast<Swig::Director *>(obj);\n"); + Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self(jenv);\n"); + Printf(dcast_wrap->code, " return jresult;\n"); + Printf(dcast_wrap->code, "}\n"); + + Wrapper_print(dcast_wrap, f_wrappers); + DelWrapper(dcast_wrap); + } + + emitDirectorExtraMethods(n); + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + Delete(proxy_class_constants_code); + proxy_class_constants_code = NULL; + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + Language::memberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + + return SWIG_OK; + } + + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a C# wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to C# static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the C# class proxy function, which in turn will call "imfuncname" - + * the intermediary (PInvoke) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + Parm *last_parm = 0; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + if (!proxy_flag) + return; + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in directors + if (GetFlag(n, "explicitcall")) + return; + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type + SwigType *covariant = Getattr(n, "covariant"); + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(covariant ? covariant : t, tm); + Printf(return_type, "%s", tm); + if (covariant) + Swig_warning(WARN_CSHARP_COVARIANT_RET, input_file, line_number, + "Covariant return types not supported in C#. Proxy method will return %s.\n", SwigType_str(covariant, 0)); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // Properties + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) == 0); + if (setter_flag) + Swig_typemap_attach_parms("csvarin", l, NULL); + } + + /* Start generating the proxy function */ + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(function_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (methodmods) { + if (is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. + String *mmods = Copy(methodmods); + Replaceall(mmods, "override", ""); + Replaceall(mmods, "virtual", ""); + Replaceall(mmods, "new", ""); + Chop(mmods); // remove trailing whitespace + Printf(function_code, " %s ", mmods); + Delete(mmods); + } else { + Printf(function_code, " %s ", methodmods); + } + } else { + methodmods = (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s ", methodmods); + if (!is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. + if (Getattr(n, "override")) + Printf(function_code, "override "); + else if (checkAttribute(n, "storage", "virtual")) + Printf(function_code, "virtual "); + if (Getattr(n, "hides")) + Printf(function_code, "new "); + } + } + if (static_flag) + Printf(function_code, "static "); + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + Printv(imcall, imclass_name, ".$imfuncname(", NIL); + if (!static_flag) + Printf(imcall, "swigCPtr"); + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0)) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + if (setter_flag) + last_parm = p; + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, setter_flag); + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class) + if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { + excodeSubstitute(n, tm, "csout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + + // For director methods: generate code to selectively make a normal polymorphic call or + // an explicit method call - needed to prevent infinite recursion calls in director methods. + Node *explicit_n = Getattr(n, "explicitcallnode"); + if (explicit_n) { + String *ex_overloaded_name = getOverloadedName(explicit_n); + String *ex_intermediary_function_name = Swig_name_member(proxy_class_name, ex_overloaded_name); + + String *ex_imcall = Copy(imcall); + Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); + Replaceall(imcall, "$imfuncname", intermediary_function_name); + + String *excode = NewString(""); + if (!Cmp(return_type, "void")) + Printf(excode, "if (this.GetType() == typeof(%s)) %s; else %s", proxy_class_name, imcall, ex_imcall); + else + Printf(excode, "((this.GetType() == typeof(%s)) ? %s : %s)", proxy_class_name, imcall, ex_imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + Delete(ex_overloaded_name); + Delete(excode); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // Properties + if (generate_property_declaration_flag) { // Ensure the declaration is generated just once should the property contain both a set and get + // Get the C# variable type - obtained differently depending on whether a setter is required. + String *variable_type = return_type; + if (setter_flag) { + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + String *cstypeout = Getattr(p, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + variable_type = cstypeout ? cstypeout : tm; + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(proxy_class_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (!methodmods) + methodmods = (is_public(n) ? public_string : protected_string); + Printf(proxy_class_code, " %s %s%s %s {", methodmods, static_flag ? "static " : "", variable_type, variable_name); + } + generate_property_declaration_flag = false; + + if (setter_flag) { + // Setter method + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:csvarin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", p); + Printf(proxy_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + // Getter method + if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarout", n); + Printf(proxy_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); + } + } + } else { + // Normal function call + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(proxy_class_code, function_code, NIL); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *function_code = NewString(""); + String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the csin typemap has code in the pre or post attributes + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + String *im_return_type = NewString(""); + bool feature_director = (parentNode(n) && Swig_directorclass(n)); + + Language::constructorHandler(n); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(overloaded_name); + String *imcall = NewString(""); + + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) { + Printf(function_code, " %s\n", csattributes); + Printf(helper_code, " %s\n", csattributes); + } + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + tm = Getattr(n, "tmap:imtype"); // typemaps were attached earlier to the node + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + Printf(im_return_type, "%s", tm); + + Printf(function_code, " %s %s(", methodmods, proxy_class_name); + Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + + Printv(imcall, imclass_name, ".", mangled_overname, "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, false); + String *cshin = 0; + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + cshin = Getattr(p, "tmap:csin:cshin"); + if (cshin) + Replaceall(cshin, "$csinput", arg); + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma) { + Printf(function_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } + Printf(function_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", cshin ? cshin : arg); + ++gencomma; + + Delete(cshin); + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + + Printf(function_code, ")"); + Printf(helper_code, ")"); + + /* Insert the csconstruct typemap, doing the replacement for $directorconnect, as needed */ + Hash *attributes = NewHash(); + String *construct_tm = Copy(typemapLookup(n, "csconstruct", Getattr(n, "name"), + WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF, attributes)); + if (construct_tm) { + if (!feature_director) { + Replaceall(construct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(attributes, "tmap:csconstruct:directorconnect"); + + if (connect_attr) { + Replaceall(construct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_CSHARP_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"csconstruct\" typemap.\n", + Getattr(n, "name")); + Replaceall(construct_tm, "$directorconnect", ""); + } + } + + Printv(function_code, " ", construct_tm, NIL); + } + + excodeSubstitute(n, function_code, "csconstruct", attributes); + + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Printf(helper_code, " {\n"); + if (is_pre_code) { + Printv(helper_code, pre_code, "\n", NIL); + } + if (is_post_code) { + Printf(helper_code, " try {\n"); + Printv(helper_code, " return ", imcall, ";\n", NIL); + Printv(helper_code, " } finally {\n", post_code, "\n }", NIL); + } else { + Printv(helper_code, " return ", imcall, ";", NIL); + } + if (is_terminator_code) { + Printv(helper_code, "\n", terminator_code, NIL); + } + Printf(helper_code, "\n }\n"); + String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); + String *im_outattributes = Getattr(n, "tmap:imtype:outattributes"); + if (im_outattributes) + Printf(proxy_class_code, " %s\n", im_outattributes); + Printv(proxy_class_code, helper_code, "\n", NIL); + Replaceall(function_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(function_code, "$imcall", imcall); + } + + Printv(proxy_class_code, function_code, "\n", NIL); + + Delete(helper_args); + Delete(im_return_type); + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(construct_tm); + Delete(attributes); + Delete(overloaded_name); + Delete(imcall); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, imclass_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + generate_property_declaration_flag = false; + + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + + bool static_const_member_flag = (Getattr(n, "value") == 0); + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + generate_property_declaration_flag = false; + + if (static_const_member_flag) + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + Language::memberconstantHandler(n); + wrapping_member_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + + /* A C# HandleRef is used for all classes in the SWIG intermediary class. + * The intermediary class methods are thus mangled when overloaded to give + * a unique name. */ + String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * moduleClassFunctionHandler() + * ----------------------------------------------------------------------------- */ + + void moduleClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + Parm *last_parm = 0; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + int num_required = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (proxy_flag && global_variable_flag) { + // Capitalize the first letter in the variable to create the getter/setter function name + func_name = NewString(""); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(variable_name)) == 0); + if (setter_flag) + Printf(func_name, "set"); + else + Printf(func_name, "get"); + Putc(toupper((int) *Char(variable_name)), func_name); + Printf(func_name, "%s", Char(variable_name) + 1); + if (setter_flag) + Swig_typemap_attach_parms("csvarin", l, NULL); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(function_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name); + Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; i < num_arguments; i++) { + + /* Ignored parameters */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + last_parm = p; + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, global_or_member_variable); + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to module class function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + p = Getattr(p, "tmap:in:next"); + Delete(arg); + Delete(param_type); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in module class) + if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { + excodeSubstitute(n, tm, "csout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (proxy_flag && global_variable_flag) { + // Properties + if (generate_property_declaration_flag) { // Ensure the declaration is generated just once should the property contain both a set and get + // Get the C# variable type - obtained differently depending on whether a setter is required. + String *variable_type = return_type; + if (setter_flag) { + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + String *cstypeout = Getattr(p, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + variable_type = cstypeout ? cstypeout : tm; + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(module_class_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (!methodmods) + methodmods = (is_public(n) ? public_string : protected_string); + Printf(module_class_code, " %s static %s %s {", methodmods, variable_type, variable_name); + } + generate_property_declaration_flag = false; + + if (setter_flag) { + // Setter method + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:csvarin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", "value"); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", p); + Printf(module_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + // Getter method + if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarout", n); + Printf(module_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); + } + } + } else { + // Normal function call + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(module_class_code, function_code, NIL); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(func_name); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /*---------------------------------------------------------------------- + * decodeEnumFeature() + * Decode the possible enum features, which are one of: + * %csenum(simple) + * %csenum(typeunsafe) - default + * %csenum(typesafe) + * %csenum(proper) + *--------------------------------------------------------------------*/ + + EnumFeature decodeEnumFeature(Node *n) { + EnumFeature enum_feature = TypeunsafeEnum; + String *feature = Getattr(n, "feature:cs:enum"); + if (feature) { + if (Cmp(feature, "simple") == 0) + enum_feature = SimpleEnum; + else if (Cmp(feature, "typesafe") == 0) + enum_feature = TypesafeEnum; + else if (Cmp(feature, "proper") == 0) + enum_feature = ProperEnum; + } + return enum_feature; + } + + /* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in C# generated + * code. If the %csconst feature is not used, the string will contain the intermediary + * class call to obtain the enum value. The intermediary class and PINVOKE methods to obtain + * the enum value will be generated. Otherwise the C/C++ enum value will be used if there + * is one and hopefully it will compile as C# code - e.g. 20 as in: enum E{e=20}; + * The %csconstvalue feature overrides all other ways to generate the constant value. + * The caller must delete memory allocated for the returned string. + * ------------------------------------------------------------------------ */ + + String *enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + if (!value) { + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + if (const_feature_flag) { + // Use the C syntax to make a true C# constant and hope that it compiles as C# code + value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); + } else { + // Get the enumvalue from a PINVOKE call + if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(Swig_name_member(proxy_class_name, symname))); + } + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t) { + Node *enum_name = NULL; + Node *n = enumLookup(t); + if (n) { + String *symname = Getattr(n, "sym:name"); + if (symname) { + // Add in class scope when referencing enum if not a global enum + String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); + String *proxyname = 0; + if (scopename_prefix) { + proxyname = getProxyName(scopename_prefix); + } + if (proxyname) + enum_name = NewStringf("%s.%s", proxyname, symname); + else + enum_name = NewStringf("%s", symname); + Delete(scopename_prefix); + } + } + + return enum_name; + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $csclassname with the proxy class name for classes/structs/unions + * that SWIG knows about. Also substitutes enums with enum name. + * Otherwise use the $descriptor name for the C# class name. Note that the $&csclassname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm) { + bool substitution_performed = false; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + SwigType *strippedtype = SwigType_strip_qualifiers(type); + + if (Strstr(tm, "$csclassname")) { + SwigType *classnametype = Copy(strippedtype); + substituteClassnameSpecialVariable(classnametype, tm, "$csclassname"); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$*csclassname")) { + SwigType *classnametype = Copy(strippedtype); + Delete(SwigType_pop(classnametype)); + substituteClassnameSpecialVariable(classnametype, tm, "$*csclassname"); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$&csclassname")) { + SwigType *classnametype = Copy(strippedtype); + SwigType_add_pointer(classnametype); + substituteClassnameSpecialVariable(classnametype, tm, "$&csclassname"); + substitution_performed = true; + Delete(classnametype); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) { + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype); + if (enumname) + Replaceall(tm, classnamespecialvariable, enumname); + else + Replaceall(tm, classnamespecialvariable, NewStringf("int")); + } else { + String *classname = getProxyName(classnametype); + if (classname) { + Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replaceall(tm, classnamespecialvariable, descriptor); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, classnametype); + Delete(descriptor); + } + } + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) { + + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0; + arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn); + + if (setter && Cmp(arg, "self") != 0) { + // Note that in C# properties, the input variable name is always called 'value' + Delete(arg); + arg = NewString("value"); + } + + return arg; + } + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *swigtype = NewString(""); + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the type wrapper class file + emitBanner(f_swigtype); + + addOpenNamespace(namespce, f_swigtype); + + // Pure C# baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "csbase", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "csinterfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "csimports", type, WARN_NONE), // Import statements + "\n", NIL); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(swigtype, "%s\n", csattributes); + + Printv(swigtype, typemapLookup(n, "csclassmodifiers", type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $csclassname", // Class name and base class + (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {", typemapLookup(n, "csbody", type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + typemapLookup(n, "cscode", type, WARN_NONE), // extra C# code + "}\n", NIL); + + Replaceall(swigtype, "$csclassname", classname); + Replaceall(swigtype, "$module", module_class_name); + Replaceall(swigtype, "$imclassname", imclass_name); + Replaceall(swigtype, "$dllimport", dllimport); + + Printv(f_swigtype, swigtype, NIL); + + addCloseNamespace(namespce, f_swigtype); + + Close(f_swigtype); + Delete(swigtype); + Delete(n); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * n - for input only and must contain info for Getfile(n) and Getline(n) to work + * tmap_method - typemap method name + * type - typemap type to lookup + * warning - warning number to issue if no typemaps found + * typemap_attributes - the typemap attributes are attached to this node and will + * also be used for temporary storage if non null + * return is never NULL, unlike Swig_typemap_lookup() + * ----------------------------------------------------------------------------- */ + + const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + Node *node = !typemap_attributes ? NewHash() : typemap_attributes; + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + if (!tm) { + tm = empty_string; + if (warning != WARN_NONE) + Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); + } + if (!typemap_attributes) + Delete(node); + return tm; + } + + /* ----------------------------------------------------------------------------- + * canThrow() + * Determine whether the code in the typemap can throw a C# exception. + * If so, note it for later when excodeSubstitute() is called. + * ----------------------------------------------------------------------------- */ + + void canThrow(Node *n, const String *typemap, Node *parameter) { + String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap); + String *canthrow = Getattr(parameter, canthrow_attribute); + if (canthrow) + Setattr(n, "csharp:canthrow", "1"); + Delete(canthrow_attribute); + } + + /* ----------------------------------------------------------------------------- + * excodeSubstitute() + * If a method can throw a C# exception, additional exception code is added to + * check for the pending exception so that it can then throw the exception. The + * $excode special variable is replaced by the exception code in the excode + * typemap attribute. + * ----------------------------------------------------------------------------- */ + + void excodeSubstitute(Node *n, String *code, const String *typemap, Node *parameter) { + String *excode_attribute = NewStringf("tmap:%s:excode", typemap); + String *excode = Getattr(parameter, excode_attribute); + if (Getattr(n, "csharp:canthrow")) { + int count = Replaceall(code, "$excode", excode); + if (count < 1 || !excode) { + Swig_warning(WARN_CSHARP_EXCODE, input_file, line_number, + "C# exception may not be thrown - no $excode or excode attribute in '%s' typemap.\n", typemap); + } + } else { + Replaceall(code, "$excode", empty_string); + } + Delete(excode_attribute); + } + + /* ----------------------------------------------------------------------------- + * addOpenNamespace() + * ----------------------------------------------------------------------------- */ + + void addOpenNamespace(String *namspace, File *file) { + if (namspace) + if (Len(namspace) > 0) + Printf(file, "namespace %s {\n", namspace); + } + + /* ----------------------------------------------------------------------------- + * addCloseNamespace() + * ----------------------------------------------------------------------------- */ + + void addCloseNamespace(String *namspace, File *file) { + if (namspace) + if (Len(namspace) > 0) + Printf(file, "\n}\n"); + } + + /*---------------------------------------------------------------------- + * Start of director methods + *--------------------------------------------------------------------*/ + +#if 0 + /*---------------------------------------------------------------------- + * emitDirectorUpcalls() + *--------------------------------------------------------------------*/ + + void emitDirectorUpcalls() { + if (n_dmethods) { + Wrapper *w = NewWrapper(); + String *dmethod_data = NewString(""); + int n_methods = 0; + Iterator udata_iter; + + udata_iter = First(dmethods_seq); + while (udata_iter.item) { + UpcallData *udata = udata_iter.item; + Printf(dmethod_data, " { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); + ++n_methods; + + udata_iter = Next(udata_iter); + + if (udata_iter.item) + Putc(',', dmethod_data); + Putc('\n', dmethod_data); + } + + + Wrapper_print(w, f_wrappers); + Delete(dmethod_data); + Delete(swig_module_init); + DelWrapper(w); + } + } +#endif + + /*---------------------------------------------------------------------- + * emitDirectorExtraMethods() + * + * This is where the director connect method is + * generated. + *--------------------------------------------------------------------*/ + void emitDirectorExtraMethods(Node *n) { + if (!Swig_directorclass(n)) + return; + + // Output the director connect method: + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name); + String *sym_name = Getattr(n, "sym:name"); + Wrapper *code_wrap; + + Printv(imclass_class_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", swig_director_connect, "\")]\n", NIL); + Printf(imclass_class_code, " public static extern void %s(HandleRef jarg1", swig_director_connect); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, "SWIGEXPORT void SWIGSTDCALL CSharp_%s(void *objarg", swig_director_connect); + + Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + // TODO: if statement not needed?? - Java too + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_connect_director("); + + for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + + Printf(code_wrap->def, ", "); + if (i != first_class_dmethod) + Printf(code_wrap->code, ", "); + Printf(code_wrap->def, "SwigDirector_%s::SWIG_Callback%s_t callback%s", sym_name, methid, methid); + Printf(code_wrap->code, "callback%s", methid); + Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", sym_name, sym_name, methid, methid); + } + + Printf(code_wrap->def, ") {\n"); + Printf(code_wrap->code, ");\n"); + Printf(imclass_class_code, ");\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect); + } + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Java object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + String *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *returntype = Getattr(n, "returntype"); + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *tm; + Parm *p; + int i; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(returntype, "void")); + String *qualified_return = NewString(""); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + int status = SWIG_OK; + bool output_director = true; + String *dirclassname = directorClassName(parent); + String *qualified_name = NewStringf("%s::%s", dirclassname, name); + SwigType *c_ret_type = NULL; + String *jupcall_args = NewString(""); + String *imclass_dmethod; + String *callback_typedef_parms = NewString(""); + String *delegate_parms = NewString(""); + String *proxy_method_types = NewString(""); + String *callback_def = NewString(""); + String *callback_code = NewString(""); + String *imcall_args = NewString(""); + int gencomma = 0; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + // Kludge Alert: functionWrapper sets sym:overload properly, but it + // isn't at this point, so we have to manufacture it ourselves. At least + // we're consistent with the sym:overload name in functionWrapper. (?? when + // does the overloaded method name get set?) + + imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(classname, overloaded_name)); + + if (returntype) { + + qualified_return = SwigType_rcaststr(returntype, "c_result"); + + if (!is_void && !ignored_method) { + if (!SwigType_isclass(returntype)) { + if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + String *base_typename = SwigType_base(returntype); + String *resolved_typename = SwigType_typedef_resolve_all(base_typename); + Symtab *symtab = Getattr(n, "sym:symtab"); + Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + + if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default - if a C# exception occurs, then the pointer returns + something other than a NULL-initialized reference. */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= &result_default", NIL); + + Delete(non_ref_type); + } + + Delete(base_typename); + Delete(resolved_typename); + } + } else { + SwigType *vt; + + vt = cplus_value_type(returntype); + if (!vt) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); + Delete(vt); + } + } + } + + /* Create the intermediate class wrapper */ + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + tm = Swig_typemap_lookup("imtype", tp, "", 0); + if (tm) { + String *imtypeout = Getattr(tp, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + const String *im_directoroutattributes = Getattr(tp, "tmap:imtype:directoroutattributes"); + if (im_directoroutattributes) { + Printf(callback_def, " %s\n", im_directoroutattributes); + Printf(director_delegate_definitions, " %s\n", im_directoroutattributes); + } + + Printf(callback_def, " private %s SwigDirector%s(", tm, overloaded_name); + if (!ignored_method) + Printf(director_delegate_definitions, " public delegate %s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(returntype, 0)); + } + + Parm *retpm = NewParmFromNode(returntype, empty_str, n); + + if ((c_ret_type = Swig_typemap_lookup("ctype", retpm, "", 0))) { + + if (!is_void && !ignored_method) { + String *jretval_decl = NewStringf("%s jresult", c_ret_type); + Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); + Delete(jretval_decl); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(retpm); + } + + /* Go through argument list, attach lnames for arguments */ + for (i = 0, p = l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + /* Attach the standard typemaps */ + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("ctype", l, 0); + Swig_typemap_attach_parms("imtype", l, 0); + Swig_typemap_attach_parms("cstype", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("csdirectorin", l, 0); + + /* Preamble code */ + if (!ignored_method) + Printf(w->code, "if (!swig_callback%s) {\n", overloaded_name); + + if (!pure_virtual) { + String *super_call = Swig_method_call(super, l); + if (is_void) { + Printf(w->code, "%s;\n", super_call); + if (!ignored_method) + Printf(w->code, "return;\n"); + } else { + Printf(w->code, "return %s;\n", super_call); + } + Delete(super_call); + } else { + Printf(w->code, " throw Swig::DirectorPureVirtualException(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + } + + if (!ignored_method) + Printf(w->code, "} else {\n"); + + /* Go through argument list, convert from native to Java */ + for (p = l; p; /* empty */ ) { + /* Is this superfluous? */ + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Copy(Getattr(p, "name")); + String *c_param_type = NULL; + String *c_decl = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* And add to the upcall args */ + if (gencomma > 0) + Printf(jupcall_args, ", "); + Printf(jupcall_args, "%s", arg); + + /* Get parameter's intermediary C type */ + if ((c_param_type = Getattr(p, "tmap:ctype"))) { + String *ctypeout = Getattr(p, "tmap:ctype:out"); // the type in the ctype typemap's out attribute overrides the type in the typemap + if (ctypeout) + c_param_type = ctypeout; + + Parm *tp = NewParmFromNode(c_param_type, empty_str, n); + String *desc_tm = NULL; + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + if (!ignored_method) + Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + + /* Add input marshalling code */ + if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (tm = Getattr(p, "tmap:directorin"))) { + + Replaceall(tm, "$input", arg); + Replaceall(tm, "$owner", "0"); + + if (Len(tm)) + if (!ignored_method) + Printf(w->code, "%s\n", tm); + + Delete(tm); + + /* Add C type to callback typedef */ + if (gencomma > 0) + Printf(callback_typedef_parms, ", "); + Printf(callback_typedef_parms, "%s", c_param_type); + + /* Add parameter to the intermediate class code if generating the + * intermediate's upcall code */ + if ((tm = Getattr(p, "tmap:imtype"))) { + + String *imtypeout = Getattr(p, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + const String *im_directorinattributes = Getattr(p, "tmap:imtype:directorinattributes"); + + String *din = Copy(Getattr(p, "tmap:csdirectorin")); + + if (din) { + Replaceall(din, "$module", module_class_name); + Replaceall(din, "$imclassname", imclass_name); + substituteClassname(pt, din); + Replaceall(din, "$iminput", ln); + + if (gencomma > 0) { + Printf(delegate_parms, ", "); + Printf(proxy_method_types, ", "); + Printf(imcall_args, ", "); + } + Printf(delegate_parms, "%s%s %s", im_directorinattributes ? im_directorinattributes : empty_string, tm, ln); + + if (Cmp(din, ln)) { + Printv(imcall_args, din, NIL); + } else + Printv(imcall_args, ln, NIL); + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + Printf(proxy_method_types, "typeof(%s)", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, "No csdirectorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + p = Getattr(p, "tmap:directorin:next"); + + Delete(desc_tm); + } else { + if (!desc_tm) { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } else if (!tm) { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } + + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + gencomma++; + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + } + + /* header declaration, start wrapper definition */ + String *target; + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Add any exception specifications to the methods in the director class + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* Finish off the inherited upcall's definition */ + + Printf(callback_def, "%s)", delegate_parms); + Printf(callback_def, " {\n"); + + /* Emit the intermediate class's upcall to the actual class */ + + String *upcall = NewStringf("%s(%s)", symname, imcall_args); + + if (!is_void) { + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + if ((tm = Swig_typemap_lookup("csdirectorout", tp, "", 0))) { + substituteClassname(returntype, tm); + Replaceall(tm, "$cscall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + Delete(tm); + Delete(tp); + } else + Printf(callback_code, " %s;\n", upcall); + + Printf(callback_code, " }\n"); + Delete(upcall); + + if (!ignored_method) { + if (!is_void) + Printf(w->code, "jresult = (%s) ", c_ret_type); + + Printf(w->code, "swig_callback%s(%s);\n", overloaded_name, jupcall_args); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("c_result"); + Parm *tp = NewParmFromNode(returntype, result_str, n); + + /* Copy jresult into c_result... */ + if ((tm = Swig_typemap_lookup("directorout", tp, result_str, w))) { + Replaceall(tm, "$input", jresult_str); + Replaceall(tm, "$result", result_str); + Printf(w->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s used in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } + + /* Terminate wrapper code */ + Printf(w->code, "}\n"); + if (!is_void) + Printf(w->code, "return %s;", qualified_return); + } + + Printf(w->code, "}"); + + // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit code */ + if (status == SWIG_OK && output_director) { + if (!is_void) { + Replaceall(w->code, "$null", qualified_return); + } else { + Replaceall(w->code, "$null", ""); + } + if (!ignored_method) + Printv(director_delegate_callback, "\n", callback_def, callback_code, NIL); + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + if (!ignored_method) { + /* Emit the actual upcall through */ + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name); + String *methid = Getattr(udata, "class_methodidx"); + + Printf(director_callback_typedefs, " typedef %s (SWIGSTDCALL* SWIG_Callback%s_t)(", c_ret_type, methid); + Printf(director_callback_typedefs, "%s);\n", callback_typedef_parms); + Printf(director_callbacks, " SWIG_Callback%s_t swig_callback%s;\n", methid, overloaded_name); + + Printf(director_delegate_definitions, " SwigDelegate%s_%s(%s);\n", classname, methid, delegate_parms); + Printf(director_delegate_instances, " private SwigDelegate%s_%s swigDelegate%s;\n", classname, methid, methid); + Printf(director_method_types, " private static Type[] swigMethodTypes%s = new Type[] { %s };\n", methid, proxy_method_types); + Printf(director_connect_parms, "SwigDirector%s%s delegate%s", classname, methid, methid); + } + + Delete(qualified_return); + Delete(c_ret_type); + Delete(declaration); + Delete(callback_typedef_parms); + Delete(delegate_parms); + Delete(proxy_method_types); + Delete(callback_def); + Delete(callback_code); + DelWrapper(w); + + return status; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = parentNode(n); + String *decl = Getattr(n, "decl");; + String *supername = Swig_class_name(parent); + String *classname = directorClassName(parent); + String *sub = NewString(""); + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms; + int argidx = 0; + + /* Assign arguments to superclass's parameters, if not already done */ + for (p = superparms; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + + if (!pname) { + pname = NewStringf("arg%d", argidx++); + Setattr(p, "name", pname); + } + } + + // TODO: Is this copy needed? + parms = CopyParmList(superparms); + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + String *call = Swig_csuperclass_call(0, basetype, superparms); + String *classtype = SwigType_namestr(Getattr(n, "name")); + + Printf(f_directors, "%s::%s : %s, %s {\n", classname, target, call, Getattr(parent, "director:ctor")); + Printf(f_directors, " swig_init_callbacks();\n"); + Printf(f_directors, "}\n\n"); + + Delete(classtype); + Delete(target); + Delete(call); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + Wrapper *w = NewWrapper(); + + Printf(w->def, "SwigDirector_%s::SwigDirector_%s() : %s {", classname, classname, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " SwigDirector_%s();\n", classname); + DelWrapper(w); + Delete(classtype); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + Java_director_declaration(n); + + Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); + Printf(f_directors_h, "\npublic:\n"); + + /* Keep track of the director methods for this class */ + first_class_dmethod = curr_class_dmethod = n_dmethods; + + director_callback_typedefs = NewString(""); + director_callbacks = NewString(""); + director_delegate_callback = NewString(""); + director_delegate_definitions = NewString(""); + director_delegate_instances = NewString(""); + director_method_types = NewString(""); + director_connect_parms = NewString(""); + + return Language::classDirectorInit(n); + } + + /* ---------------------------------------------------------------------- + * classDirectorDestructor() + * ---------------------------------------------------------------------- */ + + int classDirectorDestructor(Node *n) { + Node *current_class = getCurrentClass(); + String *full_classname = Getattr(current_class, "name"); + String *classname = Swig_class_name(current_class); + Wrapper *w = NewWrapper(); + + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() throw () {\n", classname, classname); + } else { + Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); + } + + /* Ensure that correct directordisconnect typemap's method name is called + * here: */ + + const String *disconn_tm = NULL; + Node *disconn_attr = NewHash(); + String *disconn_methodname = NULL; + + disconn_tm = typemapLookup(n, "directordisconnect", full_classname, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); + + Printv(w->code, "}\n", NIL); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(disconn_attr); + Delete(classname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + int i; + String *director_classname = directorClassName(n); + + Wrapper *w = NewWrapper(); + + if (Len(director_callback_typedefs) > 0) { + Printf(f_directors_h, "\n%s", director_callback_typedefs); + } + + Printf(f_directors_h, " void swig_connect_director("); + + Printf(w->def, "void %s::swig_connect_director(", director_classname); + + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + String *overname = Getattr(udata, "overname"); + + Printf(f_directors_h, "SWIG_Callback%s_t callback%s", methid, overname); + Printf(w->def, "SWIG_Callback%s_t callback%s", methid, overname); + Printf(w->code, "swig_callback%s = callback%s;\n", overname, overname); + if (i != curr_class_dmethod - 1) { + Printf(f_directors_h, ", "); + Printf(w->def, ", "); + } + } + + Printf(f_directors_h, ");\n"); + Printf(w->def, ") {"); + + + if (Len(director_callback_typedefs) > 0) { + Printf(f_directors_h, "\nprivate:\n%s", director_callbacks); + } + Printf(f_directors_h, " void swig_init_callbacks();\n"); + Printf(f_directors_h, "};\n\n"); + Printf(w->code, "}\n\n"); + + Printf(w->code, "void %s::swig_init_callbacks() {\n", director_classname); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *overname = Getattr(udata, "overname"); + Printf(w->code, "swig_callback%s = 0;\n", overname); + } + Printf(w->code, "}"); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + + return Language::classDirectorEnd(n); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + *--------------------------------------------------------------------*/ + + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * Java_director_declaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void Java_director_declaration(Node *n) { + + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director()"); + + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *declaration = Swig_class_declaration(n, directorname); + + Printf(declaration, " : public %s, public Swig::Director", base); + + // Stash stuff for later. + Setattr(n, "director:decl", declaration); + Setattr(n, "director:ctor", class_ctor); + } + +}; /* class CSHARP */ + +/* ----------------------------------------------------------------------------- + * swig_csharp() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_csharp() { + return new CSHARP(); +} +extern "C" Language *swig_csharp(void) { + return new_swig_csharp(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *CSHARP::usage = (char *) "\ +C# Options (available with -csharp)\n\ + -dllimport <dl> - Override DllImport attribute name to <dl>\n\ + -namespace <nm> - Generate wrappers into C# namespace <nm>\n\ + -noproxy - Generate the low-level functional interface instead\n\ + of proxy classes\n\ + -oldvarnames - old intermediary method names for variable wrappers\n\ +\n"; diff --git a/Source/Modules/directors.cxx b/Source/Modules/directors.cxx new file mode 100644 index 0000000..158b535 --- /dev/null +++ b/Source/Modules/directors.cxx @@ -0,0 +1,288 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * directors.cxx + * + * Director support functions. + * Not all of these may be necessary, and some may duplicate existing functionality + * in SWIG. --MR + * ----------------------------------------------------------------------------- */ + +char cvsroot_directors_cxx[] = "$Id"; + +#include "swigmod.h" + +/* Swig_csuperclass_call() + * + * Generates a fully qualified method call, including the full parameter list. + * e.g. "base::method(i, j)" + * + */ + +String *Swig_csuperclass_call(String *base, String *method, ParmList *l) { + String *call = NewString(""); + int arg_idx = 0; + Parm *p; + if (base) { + Printf(call, "%s::", base); + } + Printf(call, "%s(", method); + for (p = l; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + if (!pname && Cmp(Getattr(p, "type"), "void")) { + pname = NewString(""); + Printf(pname, "arg%d", arg_idx++); + } + if (p != l) + Printf(call, ", "); + Printv(call, pname, NIL); + } + Printf(call, ")"); + return call; +} + +/* Swig_class_declaration() + * + * Generate the start of a class/struct declaration. + * e.g. "class myclass" + * + */ + +String *Swig_class_declaration(Node *n, String *name) { + if (!name) { + name = Getattr(n, "sym:name"); + } + String *result = NewString(""); + String *kind = Getattr(n, "kind"); + Printf(result, "%s %s", kind, name); + return result; +} + +String *Swig_class_name(Node *n) { + String *name; + name = Copy(Getattr(n, "sym:name")); + return name; +} + +/* Swig_director_declaration() + * + * Generate the full director class declaration, complete with base classes. + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + * + */ + +String *Swig_director_declaration(Node *n) { + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *base = Getattr(n, "classtype"); + String *declaration = Swig_class_declaration(n, directorname); + Printf(declaration, " : public %s, public Swig::Director {\n", base); + Delete(classname); + Delete(directorname); + return declaration; +} + + +String *Swig_method_call(const_String_or_char_ptr name, ParmList *parms) { + String *func; + int i = 0; + int comma = 0; + Parm *p = parms; + SwigType *pt; + String *nname; + + func = NewString(""); + nname = SwigType_namestr(name); + Printf(func, "%s(", nname); + while (p) { + String *pname; + pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + if (comma) + Printf(func, ","); + pname = Getattr(p, "name"); + Printf(func, "%s", pname); + comma = 1; + i++; + } + p = nextSibling(p); + } + Printf(func, ")"); + return func; +} + +/* Swig_method_decl + * + * Misnamed and misappropriated! Taken from SWIG's type string manipulation utilities + * and modified to generate full (or partial) type qualifiers for method declarations, + * local variable declarations, and return value casting. More importantly, it merges + * parameter type information with actual parameter names to produce a complete method + * declaration that fully mirrors the original method declaration. + * + * There is almost certainly a saner way to do this. + * + * This function needs to be cleaned up and possibly split into several smaller + * functions. For instance, attaching default names to parameters should be done in a + * separate function. + * + */ + +String *Swig_method_decl(SwigType *returntype, SwigType *decl, const_String_or_char_ptr id, List *args, int strip, int values) { + String *result; + List *elements; + String *element = 0, *nextelement; + int is_const = 0; + int nelements, i; + int is_func = 0; + int arg_idx = 0; + + if (id) { + result = NewString(Char(id)); + } else { + result = NewString(""); + } + + elements = SwigType_split(decl); + nelements = Len(elements); + if (nelements > 0) { + element = Getitem(elements, 0); + } + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i + 1); + } else { + nextelement = 0; + } + if (SwigType_isqualifier(element)) { + int skip = 0; + DOH *q = 0; + if (!strip) { + q = SwigType_parm(element); + if (!Cmp(q, "const")) { + is_const = 1; + is_func = SwigType_isfunction(nextelement); + if (is_func) + skip = 1; + skip = 1; + } + if (!skip) { + Insert(result, 0, " "); + Insert(result, 0, q); + } + Delete(q); + } + } else if (SwigType_isfunction(element)) { + Parm *parm; + String *p; + Append(result, "("); + parm = args; + while (parm != 0) { + String *type = Getattr(parm, "type"); + String *name = Getattr(parm, "name"); + if (!name && Cmp(type, "void")) { + name = NewString(""); + Printf(name, "arg%d", arg_idx++); + Setattr(parm, "name", name); + } + if (!name) { + name = NewString(""); + } + p = SwigType_str(type, name); + Append(result, p); + String *value = Getattr(parm, "value"); + if (values && (value != 0)) { + Printf(result, " = %s", value); + } + parm = nextSibling(parm); + if (parm != 0) + Append(result, ", "); + } + Append(result, ")"); + } else if (returntype) { // This check is intended for conversion operators to a pointer/reference which needs the pointer/reference ignoring in the declaration + if (SwigType_ispointer(element)) { + Insert(result, 0, "*"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_ismemberpointer(element)) { + String *q; + q = SwigType_parm(element); + Insert(result, 0, "::*"); + Insert(result, 0, q); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + Delete(q); + } else if (SwigType_isreference(element)) { + Insert(result, 0, "&"); + } else if (SwigType_isarray(element)) { + DOH *size; + Append(result, "["); + size = SwigType_parm(element); + Append(result, size); + Append(result, "]"); + Delete(size); + } else { + if (Strcmp(element, "v(...)") == 0) { + Insert(result, 0, "..."); + } else { + String *bs = SwigType_namestr(element); + Insert(result, 0, " "); + Insert(result, 0, bs); + Delete(bs); + } + } + } + element = nextelement; + } + + Delete(elements); + + if (is_const) { + if (is_func) { + Append(result, " "); + Append(result, "const"); + } else { + Insert(result, 0, "const "); + } + } + + Chop(result); + + if (returntype) { + Insert(result, 0, " "); + String *rtype = SwigType_str(returntype, 0); + Insert(result, 0, rtype); + Delete(rtype); + } + + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_director_emit_dynamic_cast() + * + * In order to call protected virtual director methods from the target language, we need + * to add an extra dynamic_cast to call the public C++ wrapper in the director class. + * Also for non-static protected members when the allprotected option is on. + * ----------------------------------------------------------------------------- */ +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f) { + // TODO: why is the storage element removed in staticmemberfunctionHandler ?? + if ((!is_public(n) && (is_member_director(n) || GetFlag(n, "explicitcall"))) || + (is_non_virtual_protected_access(n) && !(checkAttribute(n, "staticmemberfunctionHandler:storage", "static") || + checkAttribute(n, "storage", "static")) + && !Equal(nodeType(n), "constructor"))) { + Node *parent = Getattr(n, "parentNode"); + String *symname = Getattr(parent, "sym:name"); + String *dirname = NewStringf("SwigDirector_%s", symname); + String *dirdecl = NewStringf("%s *darg = 0", dirname); + Wrapper_add_local(f, "darg", dirdecl); + Printf(f->code, "darg = dynamic_cast<%s *>(arg1);\n", dirname); + Delete(dirname); + Delete(dirdecl); + } +} + diff --git a/Source/Modules/emit.cxx b/Source/Modules/emit.cxx new file mode 100644 index 0000000..99631c1 --- /dev/null +++ b/Source/Modules/emit.cxx @@ -0,0 +1,512 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * emit.cxx + * + * Useful functions for emitting various pieces of code. + * ----------------------------------------------------------------------------- */ + +char cvsroot_emit_cxx[] = "$Id: emit.cxx 11471 2009-07-29 20:52:29Z wsfulton $"; + +#include "swigmod.h" + +/* ----------------------------------------------------------------------------- + * emit_return_variable() + * + * Emits a variable declaration for a function return value. + * The variable name is always called result. + * n => Node of the method being wrapped + * rt => the return type + * f => the wrapper to generate code into + * ----------------------------------------------------------------------------- */ + +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f) { + + if (!GetFlag(n, "tmap:out:optimal")) { + if (rt && (SwigType_type(rt) != T_VOID)) { + SwigType *vt = cplus_value_type(rt); + SwigType *tt = vt ? vt : rt; + SwigType *lt = SwigType_ltype(tt); + String *lstr = SwigType_str(lt, "result"); + if (SwigType_ispointer(lt)) { + Wrapper_add_localv(f, "result", lstr, "= 0", NULL); + } else { + Wrapper_add_local(f, "result", lstr); + } + if (vt) { + Delete(vt); + } + Delete(lt); + Delete(lstr); + } + } +} + +/* ----------------------------------------------------------------------------- + * emit_parameter_variables() + * + * Emits a list of variable declarations for function parameters. + * The variable names are always called arg1, arg2, etc... + * l => the parameter list + * f => the wrapper to generate code into + * ----------------------------------------------------------------------------- */ + +void emit_parameter_variables(ParmList *l, Wrapper *f) { + + Parm *p; + String *tm; + + /* Emit function arguments */ + Swig_cargs(f, l); + + /* Attach typemaps to parameters */ + /* Swig_typemap_attach_parms("ignore",l,f); */ + + Swig_typemap_attach_parms("default", l, f); + Swig_typemap_attach_parms("arginit", l, f); + + /* Apply the arginit and default */ + p = l; + while (p) { + tm = Getattr(p, "tmap:arginit"); + if (tm) { + Replace(tm, "$target", Getattr(p, "lname"), DOH_REPLACE_ANY); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:arginit:next"); + } else { + p = nextSibling(p); + } + } + + /* Apply the default typemap */ + p = l; + while (p) { + tm = Getattr(p, "tmap:default"); + if (tm) { + Replace(tm, "$target", Getattr(p, "lname"), DOH_REPLACE_ANY); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:default:next"); + } else { + p = nextSibling(p); + } + } +} + +/* ----------------------------------------------------------------------------- + * emit_attach_parmmaps() + * + * Attach the standard parameter related typemaps. + * ----------------------------------------------------------------------------- */ + +void emit_attach_parmmaps(ParmList *l, Wrapper *f) { + Swig_typemap_attach_parms("in", l, f); + Swig_typemap_attach_parms("typecheck", l, 0); + Swig_typemap_attach_parms("argout", l, f); + Swig_typemap_attach_parms("check", l, f); + Swig_typemap_attach_parms("freearg", l, f); + + { + /* This is compatibility code to deal with the deprecated "ignore" typemap */ + Parm *p = l; + Parm *np; + String *tm; + while (p) { + tm = Getattr(p, "tmap:in"); + if (tm && checkAttribute(p, "tmap:in:numinputs", "0")) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + np = Getattr(p, "tmap:in:next"); + while (p && (p != np)) { + /* Setattr(p,"ignore","1"); Deprecate */ + p = nextSibling(p); + } + } else if (tm) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Perform a sanity check on "in" and "freearg" typemaps. These + must exactly match to avoid chaos. If a mismatch occurs, we + nuke the freearg typemap */ + + { + Parm *p = l; + Parm *npin, *npfreearg; + while (p) { + npin = Getattr(p, "tmap:in:next"); + + /* + if (Getattr(p,"tmap:ignore")) { + npin = Getattr(p,"tmap:ignore:next"); + } else if (Getattr(p,"tmap:in")) { + npin = Getattr(p,"tmap:in:next"); + } + */ + + if (Getattr(p, "tmap:freearg")) { + npfreearg = Getattr(p, "tmap:freearg:next"); + if (npin != npfreearg) { + while (p != npin) { + Delattr(p, "tmap:freearg"); + Delattr(p, "tmap:freearg:next"); + p = nextSibling(p); + } + } + } + p = npin; + } + } + + /* Check for variable length arguments with no input typemap. + If no input is defined, we set this to ignore and print a + message. + */ + { + Parm *p = l; + Parm *lp = 0; + while (p) { + if (!checkAttribute(p, "tmap:in:numinputs", "0")) { + lp = p; + p = Getattr(p, "tmap:in:next"); + continue; + } + if (SwigType_isvarargs(Getattr(p, "type"))) { + Swig_warning(WARN_LANG_VARARGS, input_file, line_number, "Variable length arguments discarded.\n"); + Setattr(p, "tmap:in", ""); + } + lp = 0; + p = nextSibling(p); + } + + /* Check if last input argument is variable length argument */ + if (lp) { + p = lp; + while (p) { + if (SwigType_isvarargs(Getattr(p, "type"))) { + Setattr(l, "emit:varargs", lp); + break; + } + p = nextSibling(p); + } + } + } +} + +/* ----------------------------------------------------------------------------- + * emit_num_arguments() + * + * Calculate the total number of arguments. This function is safe for use + * with multi-argument typemaps which may change the number of arguments in + * strange ways. + * ----------------------------------------------------------------------------- */ + +int emit_num_arguments(ParmList *parms) { + Parm *p = parms; + int nargs = 0; + + while (p) { + if (Getattr(p, "tmap:in")) { + nargs += GetInt(p, "tmap:in:numinputs"); + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + + /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ + /* + if (parms && (p = Getattr(parms,"emit:varargs"))) { + if (!nextSibling(p)) { + nargs--; + } + } + */ + return nargs; +} + +/* ----------------------------------------------------------------------------- + * emit_num_required() + * + * Computes the number of required arguments. This function is safe for + * use with multi-argument typemaps and knows how to skip over everything + * properly. Note that parameters with default values are counted unless + * the compact default args option is on. + * ----------------------------------------------------------------------------- */ + +int emit_num_required(ParmList *parms) { + Parm *p = parms; + int nargs = 0; + Parm *first_default_arg = 0; + int compactdefargs = ParmList_is_compactdefargs(p); + + while (p) { + if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } else { + if (Getattr(p, "tmap:default")) + break; + if (Getattr(p, "value")) { + if (!first_default_arg) + first_default_arg = p; + if (compactdefargs) + break; + } + nargs += GetInt(p, "tmap:in:numinputs"); + if (Getattr(p, "tmap:in")) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Print error message for non-default arguments following default arguments */ + /* The error message is printed more than once with most language modules, this ought to be fixed */ + if (first_default_arg) { + p = first_default_arg; + while (p) { + if (Getattr(p, "tmap:in") && checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } else { + if (!Getattr(p, "value") && (!Getattr(p, "tmap:default"))) { + Swig_error(Getfile(p), Getline(p), "Non-optional argument '%s' follows an optional argument.\n", Getattr(p, "name")); + } + if (Getattr(p, "tmap:in")) { + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + } + + /* DB 04/02/2003: Not sure this is necessary with tmap:in:numinputs */ + /* + if (parms && (p = Getattr(parms,"emit:varargs"))) { + if (!nextSibling(p)) { + nargs--; + } + } + */ + return nargs; +} + +/* ----------------------------------------------------------------------------- + * emit_isvarargs() + * + * Checks if a function is a varargs function + * ----------------------------------------------------------------------------- */ + +int emit_isvarargs(ParmList *p) { + if (!p) + return 0; + if (Getattr(p, "emit:varargs")) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * void emit_mark_vararg_parms() + * + * Marks the vararg parameters which are to be ignored. + * Vararg parameters are marked as ignored if there is no 'in' varargs (...) + * typemap. + * ----------------------------------------------------------------------------- */ + +void emit_mark_varargs(ParmList *l) { + Parm *p = l; + while (p) { + if (SwigType_isvarargs(Getattr(p, "type"))) + if (!Getattr(p, "tmap:in")) + Setattr(p, "varargs:ignore", "1"); + p = nextSibling(p); + } +} + +#if 0 +/* replace_contract_args. This function replaces argument names in contract + specifications. Used in conjunction with the %contract directive. */ + +static void replace_contract_args(Parm *cp, Parm *rp, String *s) { + while (cp && rp) { + String *n = Getattr(cp, "name"); + if (n) { + Replace(s, n, Getattr(rp, "lname"), DOH_REPLACE_ID); + } + cp = nextSibling(cp); + rp = nextSibling(rp); + } +} +#endif + +/* ----------------------------------------------------------------------------- + * int emit_action_code() + * + * Emits action code for a wrapper. Adds in exception handling code (%exception). + * eaction -> the action code to emit + * wrappercode -> the emitted code (output) + * ----------------------------------------------------------------------------- */ +int emit_action_code(Node *n, String *wrappercode, String *eaction) { + assert(Getattr(n, "wrap:name")); + + /* Look for except feature (%exception) */ + String *tm = GetFlagAttr(n, "feature:except"); + if (tm) + tm = Copy(tm); + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + if (Strstr(tm, "$")) { + Replaceall(tm, "$name", Getattr(n, "name")); + Replaceall(tm, "$symname", Getattr(n, "sym:name")); + Replaceall(tm, "$function", eaction); // deprecated + Replaceall(tm, "$action", eaction); + Replaceall(tm, "$wrapname", Getattr(n, "wrap:name")); + String *overloaded = Getattr(n, "sym:overloaded"); + Replaceall(tm, "$overname", overloaded ? Char(Getattr(n, "sym:overname")) : ""); + + if (Strstr(tm, "$decl")) { + String *decl = Swig_name_decl(n); + Replaceall(tm, "$decl", decl); + Delete(decl); + } + if (Strstr(tm, "$fulldecl")) { + String *fulldecl = Swig_name_fulldecl(n); + Replaceall(tm, "$fulldecl", fulldecl); + Delete(fulldecl); + } + } + Printv(wrappercode, tm, "\n", NIL); + Delete(tm); + return 1; + } else { + Printv(wrappercode, eaction, "\n", NIL); + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * int emit_action() + * + * Emits the call to the wrapped function. + * Adds in exception specification exception handling and %exception code. + * ----------------------------------------------------------------------------- */ +String *emit_action(Node *n) { + String *actioncode = NewStringEmpty(); + String *tm; + String *action; + String *wrap; + SwigType *rt; + ParmList *catchlist = Getattr(n, "catchlist"); + + /* Look for fragments */ + { + String *fragment = Getattr(n, "feature:fragment"); + if (fragment) { + char *c, *tok; + String *t = Copy(fragment); + c = Char(t); + tok = strtok(c, ","); + while (tok) { + String *fname = NewString(tok); + Setfile(fname, Getfile(n)); + Setline(fname, Getline(n)); + Swig_fragment_emit(fname); + Delete(fname); + tok = strtok(NULL, ","); + } + Delete(t); + } + } + + /* Emit wrapper code (if any) */ + wrap = Getattr(n, "wrap:code"); + if (wrap && Swig_filebyname("header") != Getattr(n, "wrap:code:done")) { + File *f_code = Swig_filebyname("header"); + if (f_code) { + Printv(f_code, wrap, NIL); + } + Setattr(n, "wrap:code:done", f_code); + } + + action = Getattr(n, "feature:action"); + if (!action) + action = Getattr(n, "wrap:action"); + assert(action != 0); + + /* Get the return type */ + rt = Getattr(n, "type"); + + /* Emit contract code (if any) */ + if (Swig_contract_mode_get()) { + /* Preassertion */ + tm = Getattr(n, "contract:preassert"); + if (Len(tm)) { + Printv(actioncode, tm, "\n", NIL); + } + } + /* Exception handling code */ + + /* saves action -> eaction for postcatching exception */ + String *eaction = NewString(""); + + /* If we are in C++ mode and there is an exception specification. We're going to + enclose the block in a try block */ + if (catchlist) { + Printf(eaction, "try {\n"); + } + + Printv(eaction, action, NIL); + + if (catchlist) { + int unknown_catch = 0; + Printf(eaction, "}\n"); + for (Parm *ep = catchlist; ep; ep = nextSibling(ep)) { + String *em = Swig_typemap_lookup("throws", ep, "_e", 0); + if (em) { + SwigType *et = Getattr(ep, "type"); + SwigType *etr = SwigType_typedef_resolve_all(et); + if (SwigType_isreference(etr) || SwigType_ispointer(etr) || SwigType_isarray(etr)) { + Printf(eaction, "catch(%s) {", SwigType_str(et, "_e")); + } else if (SwigType_isvarargs(etr)) { + Printf(eaction, "catch(...) {"); + } else { + Printf(eaction, "catch(%s) {", SwigType_str(et, "&_e")); + } + Printv(eaction, em, "\n", NIL); + Printf(eaction, "}\n"); + } else { + Swig_warning(WARN_TYPEMAP_THROW, Getfile(n), Getline(n), "No 'throws' typemap defined for exception type '%s'\n", SwigType_str(Getattr(ep, "type"), 0)); + unknown_catch = 1; + } + } + if (unknown_catch) { + Printf(eaction, "catch(...) { throw; }\n"); + } + } + + /* Look for except typemap (Deprecated) */ + tm = Swig_typemap_lookup("except", n, "result", 0); + if (tm) { + Setattr(n, "feature:except", tm); + tm = 0; + } + + /* emit the except feature code */ + emit_action_code(n, actioncode, eaction); + + Delete(eaction); + + /* Emit contract code (if any) */ + if (Swig_contract_mode_get()) { + /* Postassertion */ + tm = Getattr(n, "contract:postassert"); + if (Len(tm)) { + Printv(actioncode, tm, "\n", NIL); + } + } + + return actioncode; +} diff --git a/Source/Modules/guile.cxx b/Source/Modules/guile.cxx new file mode 100644 index 0000000..2520a07 --- /dev/null +++ b/Source/Modules/guile.cxx @@ -0,0 +1,1759 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * guile.cxx + * + * Guile language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_guile_cxx[] = "$Id: guile.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +// Note string broken in half for compilers that can't handle long strings +static const char *guile_usage = (char *) "\ +Guile Options (available with -guile)\n\ + -prefix <name> - Use <name> as prefix [default \"gswig_\"]\n\ + -package <name> - Set the path of the module to <name>\n\ + (default NULL)\n\ + -emitsetters - Emit procedures-with-setters for variables\n\ + and structure slots.\n\ + -onlysetters - Don't emit traditional getter and setter\n\ + procedures for structure slots,\n\ + only emit procedures-with-setters.\n\ + -procdoc <file> - Output procedure documentation to <file>\n\ + -procdocformat <format> - Output procedure documentation in <format>;\n\ + one of `guile-1.4', `plain', `texinfo'\n\ + -linkage <lstyle> - Use linkage protocol <lstyle> (default `simple')\n\ + Use `module' for native Guile module linking\n\ + (requires Guile >= 1.5.0). Use `passive' for\n\ + passive linking (no C-level module-handling code),\n\ + `ltdlmod' for Guile's old dynamic module\n\ + convention (Guile <= 1.4), or `hobbit' for hobbit\n\ + modules.\n\ + -scmstub - Output Scheme file with module declaration and\n\ + exports; only with `passive' and `simple' linkage\n\ + -gh - Use the gh_ Guile API. (Guile <= 1.8) \n\ + -scm - Use the scm Guile API. (Guile >= 1.6, default) \n\ + -proxy - Export GOOPS class definitions\n\ + -emitslotaccessors - Emit accessor methods for all GOOPS slots\n" "\ + -primsuffix <suffix> - Name appended to primitive module when exporting\n\ + GOOPS classes. (default = \"primitive\")\n\ + -goopsprefix <prefix> - Prepend <prefix> to all goops identifiers\n\ + -useclassprefix - Prepend the class name to all goops identifiers\n\ + -exportprimitive - Add the (export ...) code from scmstub into the\n\ + GOOPS file.\n"; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; + + +static char *prefix = (char *) "gswig_"; +static char *module = 0; +static char *package = 0; +static enum { + GUILE_LSTYLE_SIMPLE, // call `SWIG_init()' + GUILE_LSTYLE_PASSIVE, // passive linking (no module code) + GUILE_LSTYLE_MODULE, // native guile module linking (Guile >= 1.4.1) + GUILE_LSTYLE_LTDLMOD_1_4, // old (Guile <= 1.4) dynamic module convention + GUILE_LSTYLE_HOBBIT // use (hobbit4d link) +} linkage = GUILE_LSTYLE_SIMPLE; + +static File *procdoc = 0; +static bool scmstub = false; +static String *scmtext; +static bool goops = false; +static String *goopstext; +static String *goopscode; +static String *goopsexport; + +static enum { + GUILE_1_4, + PLAIN, + TEXINFO +} docformat = GUILE_1_4; + +static int emit_setters = 0; +static int only_setters = 0; +static int emit_slot_accessors = 0; +static int struct_member = 0; + +static String *beforereturn = 0; +static String *return_nothing_doc = 0; +static String *return_one_doc = 0; +static String *return_multi_doc = 0; + +static String *exported_symbols = 0; + +static int use_scm_interface = 1; +static int exporting_destructor = 0; +static String *swigtype_ptr = 0; + +/* GOOPS stuff */ +static String *primsuffix = 0; +static String *class_name = 0; +static String *short_class_name = 0; +static String *goops_class_methods; +static int in_class = 0; +static int have_constructor = 0; +static int useclassprefix = 0; // -useclassprefix argument +static String *goopsprefix = 0; // -goopsprefix argument +static int primRenamer = 0; // if (use-modules ((...) :renamer ...) is exported to GOOPS file +static int exportprimitive = 0; // -exportprimitive argument +static String *memberfunction_name = 0; + +extern "C" { + static int has_classname(Node *class_node) { + return Getattr(class_node, "guile:goopsclassname") != NULL; + } +} + +class GUILE:public Language { +public: + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i, orig_len; + + SWIG_library_directory("guile"); + SWIG_typemap_lang("guile"); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(guile_usage, stdout); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = new char[strlen(argv[i + 1]) + 2]; + strcpy(prefix, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-package") == 0) { + if (argv[i + 1]) { + package = new char[strlen(argv[i + 1]) + 2]; + strcpy(package, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-Linkage") == 0 || strcmp(argv[i], "-linkage") == 0) { + if (argv[i + 1]) { + if (0 == strcmp(argv[i + 1], "ltdlmod")) + linkage = GUILE_LSTYLE_LTDLMOD_1_4; + else if (0 == strcmp(argv[i + 1], "hobbit")) + linkage = GUILE_LSTYLE_HOBBIT; + else if (0 == strcmp(argv[i + 1], "simple")) + linkage = GUILE_LSTYLE_SIMPLE; + else if (0 == strcmp(argv[i + 1], "passive")) + linkage = GUILE_LSTYLE_PASSIVE; + else if (0 == strcmp(argv[i + 1], "module")) + linkage = GUILE_LSTYLE_MODULE; + else + Swig_arg_error(); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-procdoc") == 0) { + if (argv[i + 1]) { + procdoc = NewFile(argv[i + 1], "w", SWIG_output_files()); + if (!procdoc) { + FileErrorDisplay(argv[i + 1]); + SWIG_exit(EXIT_FAILURE); + } + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-procdocformat") == 0) { + if (strcmp(argv[i + 1], "guile-1.4") == 0) + docformat = GUILE_1_4; + else if (strcmp(argv[i + 1], "plain") == 0) + docformat = PLAIN; + else if (strcmp(argv[i + 1], "texinfo") == 0) + docformat = TEXINFO; + else + Swig_arg_error(); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else if (strcmp(argv[i], "-emit-setters") == 0 || strcmp(argv[i], "-emitsetters") == 0) { + emit_setters = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-only-setters") == 0 || strcmp(argv[i], "-onlysetters") == 0) { + emit_setters = 1; + only_setters = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-emit-slot-accessors") == 0 || strcmp(argv[i], "-emitslotaccessors") == 0) { + emit_slot_accessors = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-scmstub") == 0) { + scmstub = true; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + goops = true; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-gh") == 0) { + use_scm_interface = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-scm") == 0) { + use_scm_interface = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-primsuffix") == 0) { + if (argv[i + 1]) { + primsuffix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-goopsprefix") == 0) { + if (argv[i + 1]) { + goopsprefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-useclassprefix") == 0) { + useclassprefix = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-exportprimitive") == 0) { + exportprimitive = 1; + // should use Swig_warning() here? + Swig_mark_arg(i); + } + } + } + + // set default value for primsuffix + if (primsuffix == NULL) + primsuffix = NewString("primitive"); + + //goops support can only be enabled if passive or module linkage is used + if (goops) { + if (linkage != GUILE_LSTYLE_PASSIVE && linkage != GUILE_LSTYLE_MODULE) { + Printf(stderr, "guile: GOOPS support requires passive or module linkage\n"); + exit(1); + } + } + + if (goops) { + // -proxy implies -emit-setters + emit_setters = 1; + } + + if ((linkage == GUILE_LSTYLE_PASSIVE && scmstub) || linkage == GUILE_LSTYLE_MODULE) + primRenamer = 1; + + if (exportprimitive && primRenamer) { + // should use Swig_warning() ? + Printf(stderr, "guile: Warning: -exportprimitive only makes sense with passive linkage without a scmstub.\n"); + } + // Make sure `prefix' ends in an underscore + + orig_len = strlen(prefix); + if (prefix[orig_len - 1] != '_') { + prefix[1 + orig_len] = 0; + prefix[orig_len] = '_'; + } + + /* Add a symbol for this module */ + Preprocessor_define("SWIGGUILE 1", 0); + /* Read in default typemaps */ + if (use_scm_interface) + SWIG_config_file("guile_scm.swg"); + else + SWIG_config_file("guile_gh.swg"); + allow_overloading(); + + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + + scmtext = NewString(""); + Swig_register_filebyname("scheme", scmtext); + exported_symbols = NewString(""); + goopstext = NewString(""); + Swig_register_filebyname("goops", goopstext); + goopscode = NewString(""); + goopsexport = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGGUILE\n"); + + if (!use_scm_interface) { + if (SwigRuntime == 1) + Printf(f_runtime, "#define SWIG_GLOBAL\n"); + if (SwigRuntime == 2) + Printf(f_runtime, "#define SWIG_NOINCLUDE\n"); + } + + /* Write out directives and declarations */ + + module = Swig_copy_string(Char(Getattr(n, "name"))); + + switch (linkage) { + case GUILE_LSTYLE_SIMPLE: + /* Simple linkage; we have to export the SWIG_init function. The user can + rename the function by a #define. */ + Printf(f_runtime, "#define SWIG_GUILE_INIT_STATIC extern\n"); + break; + default: + /* Other linkage; we make the SWIG_init function static */ + Printf(f_runtime, "#define SWIG_GUILE_INIT_STATIC static\n"); + break; + } + + if (CPlusPlus) { + Printf(f_runtime, "extern \"C\" {\n\n"); + } + Printf(f_runtime, "SWIG_GUILE_INIT_STATIC void\nSWIG_init (void);\n"); + if (CPlusPlus) { + Printf(f_runtime, "\n}\n"); + } + + Printf(f_runtime, "\n"); + + Language::top(n); + + /* Close module */ + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printf(f_init, "}\n\n"); + Printf(f_init, "#ifdef __cplusplus\n}\n#endif\n"); + + String *module_name = NewString(""); + + if (!module) + Printv(module_name, "swig", NIL); + else { + if (package) + Printf(module_name, "%s/%s", package, module); + else + Printv(module_name, module, NIL); + } + emit_linkage(module_name); + + Delete(module_name); + + if (procdoc) { + Delete(procdoc); + procdoc = NULL; + } + Delete(goopscode); + Delete(goopsexport); + Delete(goopstext); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + void emit_linkage(String *module_name) { + String *module_func = NewString(""); + + if (CPlusPlus) { + Printf(f_init, "extern \"C\" {\n\n"); + } + + Printv(module_func, module_name, NIL); + Replaceall(module_func, "-", "_"); + + switch (linkage) { + case GUILE_LSTYLE_SIMPLE: + Printf(f_init, "\n/* Linkage: simple */\n"); + break; + case GUILE_LSTYLE_PASSIVE: + Printf(f_init, "\n/* Linkage: passive */\n"); + Replaceall(module_func, "/", "_"); + Insert(module_func, 0, "scm_init_"); + Append(module_func, "_module"); + + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + Printf(f_init, " SWIG_init();\n"); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Printf(f_init, "}\n"); + break; + case GUILE_LSTYLE_LTDLMOD_1_4: + Printf(f_init, "\n/* Linkage: ltdlmod */\n"); + Replaceall(module_func, "/", "_"); + Insert(module_func, 0, "scm_init_"); + Append(module_func, "_module"); + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + { + String *mod = NewString(module_name); + Replaceall(mod, "/", " "); + Printf(f_init, " scm_register_module_xxx (\"%s\", (void *) SWIG_init);\n", mod); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Delete(mod); + } + Printf(f_init, "}\n"); + break; + case GUILE_LSTYLE_MODULE: + Printf(f_init, "\n/* Linkage: module */\n"); + Replaceall(module_func, "/", "_"); + Insert(module_func, 0, "scm_init_"); + Append(module_func, "_module"); + + Printf(f_init, "static void SWIG_init_helper(void *data)\n"); + Printf(f_init, "{\n SWIG_init();\n"); + if (Len(exported_symbols) > 0) + Printf(f_init, " scm_c_export(%sNULL);", exported_symbols); + Printf(f_init, "\n}\n\n"); + + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + { + String *mod = NewString(module_name); + if (goops) + Printv(mod, "-", primsuffix, NIL); + Replaceall(mod, "/", " "); + Printf(f_init, " scm_c_define_module(\"%s\",\n", mod); + Printf(f_init, " SWIG_init_helper, NULL);\n"); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Delete(mod); + } + Printf(f_init, "}\n"); + break; + case GUILE_LSTYLE_HOBBIT: + Printf(f_init, "\n/* Linkage: hobbit */\n"); + Replaceall(module_func, "/", "_slash_"); + Insert(module_func, 0, "scm_init_"); + Printf(f_init, "SCM\n%s (void)\n{\n", module_func); + { + String *mod = NewString(module_name); + Replaceall(mod, "/", " "); + Printf(f_init, " scm_register_module_xxx (\"%s\", (void *) SWIG_init);\n", mod); + Printf(f_init, " return SCM_UNSPECIFIED;\n"); + Delete(mod); + } + Printf(f_init, "}\n"); + break; + default: + abort(); // for now + } + + if (scmstub) { + /* Emit Scheme stub if requested */ + String *primitive_name = NewString(module_name); + if (goops) + Printv(primitive_name, "-", primsuffix, NIL); + + String *mod = NewString(primitive_name); + Replaceall(mod, "/", " "); + + String *fname = NewStringf("%s%s.scm", + SWIG_output_directory(), + primitive_name); + Delete(primitive_name); + File *scmstubfile = NewFile(fname, "w", SWIG_output_files()); + if (!scmstubfile) { + FileErrorDisplay(fname); + SWIG_exit(EXIT_FAILURE); + } + Delete(fname); + + Swig_banner_target_lang(scmstubfile, ";;;"); + Printf(scmstubfile, "\n"); + if (linkage == GUILE_LSTYLE_SIMPLE || linkage == GUILE_LSTYLE_PASSIVE) + Printf(scmstubfile, "(define-module (%s))\n\n", mod); + Delete(mod); + Printf(scmstubfile, "%s", scmtext); + if ((linkage == GUILE_LSTYLE_SIMPLE || linkage == GUILE_LSTYLE_PASSIVE) + && Len(exported_symbols) > 0) { + String *ex = NewString(exported_symbols); + Replaceall(ex, ", ", "\n "); + Replaceall(ex, "\"", ""); + Chop(ex); + Printf(scmstubfile, "\n(export %s)\n", ex); + Delete(ex); + } + Delete(scmstubfile); + } + + if (goops) { + String *mod = NewString(module_name); + Replaceall(mod, "/", " "); + + String *fname = NewStringf("%s%s.scm", SWIG_output_directory(), + module_name); + File *goopsfile = NewFile(fname, "w", SWIG_output_files()); + if (!goopsfile) { + FileErrorDisplay(fname); + SWIG_exit(EXIT_FAILURE); + } + Delete(fname); + Swig_banner_target_lang(goopsfile, ";;;"); + Printf(goopsfile, "\n"); + Printf(goopsfile, "(define-module (%s))\n", mod); + Printf(goopsfile, "%s\n", goopstext); + Printf(goopsfile, "(use-modules (oop goops) (Swig common))\n"); + if (primRenamer) { + Printf(goopsfile, "(use-modules ((%s-%s) :renamer (symbol-prefix-proc 'primitive:)))\n", mod, primsuffix); + } + Printf(goopsfile, "%s\n(export %s)", goopscode, goopsexport); + if (exportprimitive) { + String *ex = NewString(exported_symbols); + Replaceall(ex, ", ", "\n "); + Replaceall(ex, "\"", ""); + Chop(ex); + Printf(goopsfile, "\n(export %s)", ex); + Delete(ex); + } + Delete(mod); + Delete(goopsfile); + } + + Delete(module_func); + if (CPlusPlus) { + Printf(f_init, "\n}\n"); + } + } + + /* Return true iff T is a pointer type */ + + int is_a_pointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); + } + + /* Report an error handling the given type. */ + + void throw_unhandled_guile_type_error(SwigType *d) { + Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s.\n", SwigType_str(d, 0)); + } + + /* Write out procedure documentation */ + + void write_doc(const String *proc_name, const String *signature, const String *doc, const String *signature2 = NULL) { + switch (docformat) { + case GUILE_1_4: + Printv(procdoc, "\f\n", NIL); + Printv(procdoc, "(", signature, ")\n", NIL); + if (signature2) + Printv(procdoc, "(", signature2, ")\n", NIL); + Printv(procdoc, doc, "\n", NIL); + break; + case PLAIN: + Printv(procdoc, "\f", proc_name, "\n\n", NIL); + Printv(procdoc, "(", signature, ")\n", NIL); + if (signature2) + Printv(procdoc, "(", signature2, ")\n", NIL); + Printv(procdoc, doc, "\n\n", NIL); + break; + case TEXINFO: + Printv(procdoc, "\f", proc_name, "\n", NIL); + Printv(procdoc, "@deffn primitive ", signature, "\n", NIL); + if (signature2) + Printv(procdoc, "@deffnx primitive ", signature2, "\n", NIL); + Printv(procdoc, doc, "\n", NIL); + Printv(procdoc, "@end deffn\n\n", NIL); + break; + } + } + + /* returns false if the typemap is an empty string */ + bool handle_documentation_typemap(String *output, + const String *maybe_delimiter, Parm *p, const String *typemap, const String *default_doc, const String *name = NULL) { + String *tmp = NewString(""); + String *tm; + if (!(tm = Getattr(p, typemap))) { + Printf(tmp, "%s", default_doc); + tm = tmp; + } + bool result = (Len(tm) > 0); + if (maybe_delimiter && Len(output) > 0 && Len(tm) > 0) { + Printv(output, maybe_delimiter, NIL); + } + const String *pn = (name == NULL) ? (const String *) Getattr(p, "name") : name; + String *pt = Getattr(p, "type"); + Replaceall(tm, "$name", pn); // legacy for $parmname + Replaceall(tm, "$type", SwigType_str(pt, 0)); + /* $NAME is like $name, but marked-up as a variable. */ + String *ARGNAME = NewString(""); + if (docformat == TEXINFO) + Printf(ARGNAME, "@var{%s}", pn); + else + Printf(ARGNAME, "%(upper)s", pn); + Replaceall(tm, "$NAME", ARGNAME); + Replaceall(tm, "$PARMNAME", ARGNAME); + Printv(output, tm, NIL); + Delete(tmp); + return result; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * Create a function declaration and register it with the interpreter. + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *proc_name = 0; + char source[256]; + Wrapper *f = NewWrapper();; + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *signature = NewString(""); + String *doc_body = NewString(""); + String *returns = NewString(""); + String *method_signature = NewString(""); + String *primitive_args = NewString(""); + Hash *scheme_arg_names = NewHash(); + int num_results = 1; + String *tmp = NewString(""); + String *tm; + int i; + int numargs = 0; + int numreq = 0; + String *overname = 0; + int args_passed_as_array = 0; + int scheme_argnum = 0; + bool any_specialized_arg = false; + + // Make a wrapper name for this + String *wname = Swig_name_wrapper(iname); + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + args_passed_as_array = 1; + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Build the name for scheme. + proc_name = NewString(iname); + Replaceall(proc_name, "_", "-"); + + /* Emit locals etc. into f->code; figure out which args to ignore */ + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + numargs = emit_num_arguments(l); + numreq = emit_num_required(l); + + /* Declare return variable */ + + Wrapper_add_local(f, "gswig_result", "SCM gswig_result"); + Wrapper_add_local(f, "gswig_list_p", "SWIGUNUSED int gswig_list_p = 0"); + + /* Open prototype and signature */ + + Printv(f->def, "static SCM\n", wname, " (", NIL); + if (args_passed_as_array) { + Printv(f->def, "int argc, SCM *argv", NIL); + } + Printv(signature, proc_name, NIL); + + /* Now write code to extract the parameters */ + + for (i = 0, p = l; i < numargs; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + int opt_p = (i >= numreq); + + // Produce names of source and target + if (args_passed_as_array) + sprintf(source, "argv[%d]", i); + else + sprintf(source, "s_%d", i); + String *target = Getattr(p, "lname"); + + if (!args_passed_as_array) { + if (i != 0) + Printf(f->def, ", "); + Printf(f->def, "SCM s_%d", i); + } + if (opt_p) { + Printf(f->code, " if (%s != SCM_UNDEFINED) {\n", source); + } + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", target); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printv(f->code, tm, "\n", NIL); + + SwigType *pb = SwigType_typedef_resolve_all(SwigType_base(pt)); + SwigType *pn = Getattr(p, "name"); + String *argname; + scheme_argnum++; + if (pn && !Getattr(scheme_arg_names, pn)) + argname = pn; + else { + /* Anonymous arg or re-used argument name -- choose a name that cannot clash */ + argname = NewStringf("%%arg%d", scheme_argnum); + } + + if (procdoc) { + if (i == numreq) { + /* First optional argument */ + Printf(signature, " #:optional"); + } + /* Add to signature (arglist) */ + handle_documentation_typemap(signature, " ", p, "tmap:in:arglist", "$name", argname); + /* Document the type of the arg in the documentation body */ + handle_documentation_typemap(doc_body, ", ", p, "tmap:in:doc", "$NAME is of type <$type>", argname); + } + + if (goops) { + if (i < numreq) { + if (strcmp("void", Char(pt)) != 0) { + Node *class_node = Swig_symbol_clookup_check(pb, Getattr(n, "sym:symtab"), + has_classname); + String *goopsclassname = (class_node == NULL) ? NULL : Getattr(class_node, "guile:goopsclassname"); + /* do input conversion */ + if (goopsclassname) { + Printv(method_signature, " (", argname, " ", goopsclassname, ")", NIL); + any_specialized_arg = true; + } else { + Printv(method_signature, " ", argname, NIL); + } + Printv(primitive_args, " ", argname, NIL); + Setattr(scheme_arg_names, argname, p); + } + } + } + + if (!pn) { + Delete(argname); + } + p = Getattr(p, "tmap:in:next"); + } else { + throw_unhandled_guile_type_error(pt); + p = nextSibling(p); + } + if (opt_p) + Printf(f->code, " }\n"); + } + if (Len(doc_body) > 0) + Printf(doc_body, ".\n"); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + /* Pass output arguments back to the caller. */ + + /* Insert argument output code */ + String *returns_argout = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", Getattr(p, "lname")); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + if (procdoc) { + if (handle_documentation_typemap(returns_argout, ", ", p, "tmap:argout:doc", "$NAME (of type $type)")) { + /* A documentation typemap that is not the empty string + indicates that a value is returned to Scheme. */ + num_results++; + } + } + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + if (use_scm_interface && exporting_destructor) { + /* Mark the destructor's argument as destroyed. */ + String *tm = NewString("SWIG_Guile_MarkPointerDestroyed($input);"); + Replaceall(tm, "$input", Getattr(l, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + Delete(tm); + } + + /* Close prototype */ + + Printf(f->def, ")\n{\n"); + + /* Define the scheme name in C. This define is used by several Guile + macros. */ + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + // Now write code to make the function call + if (!use_scm_interface) + Printv(f->code, tab4, "gh_defer_ints();\n", NIL); + + String *actioncode = emit_action(n); + + if (!use_scm_interface) + Printv(actioncode, tab4, "gh_allow_ints();\n", NIL); + + // Now have return value, figure out what to do with it. + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$result", "gswig_result"); + Replaceall(tm, "$target", "gswig_result"); + Replaceall(tm, "$source", "result"); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_guile_type_error(d); + } + emit_return_variable(n, d, f); + + // Documentation + if ((tm = Getattr(n, "tmap:out:doc"))) { + Printv(returns, tm, NIL); + if (Len(tm) > 0) + num_results = 1; + else + num_results = 0; + } else { + String *s = SwigType_str(d, 0); + Chop(s); + Printf(returns, "<%s>", s); + Delete(s); + num_results = 1; + } + Append(returns, returns_argout); + + + // Dump the argument output code + Printv(f->code, outarg, NIL); + + // Dump the argument cleanup code + Printv(f->code, cleanup, NIL); + + // Look for any remaining cleanup + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + // Wrap things up (in a manner of speaking) + + if (beforereturn) + Printv(f->code, beforereturn, "\n", NIL); + Printv(f->code, "return gswig_result;\n", NIL); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + // Undefine the scheme name + + Printf(f->code, "#undef FUNC_NAME\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + if (!Getattr(n, "sym:overloaded")) { + if (numargs > 10) { + int i; + /* gh_new_procedure would complain: too many args */ + /* Build a wrapper wrapper */ + Printv(f_wrappers, "static SCM\n", wname, "_rest (SCM rest)\n", NIL); + Printv(f_wrappers, "{\n", NIL); + Printf(f_wrappers, "SCM arg[%d];\n", numargs); + Printf(f_wrappers, "SWIG_Guile_GetArgs (arg, rest, %d, %d, \"%s\");\n", numreq, numargs - numreq, proc_name); + Printv(f_wrappers, "return ", wname, "(", NIL); + Printv(f_wrappers, "arg[0]", NIL); + for (i = 1; i < numargs; i++) + Printf(f_wrappers, ", arg[%d]", i); + Printv(f_wrappers, ");\n", NIL); + Printv(f_wrappers, "}\n", NIL); + /* Register it */ + if (use_scm_interface) { + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s_rest);\n", proc_name, wname); + } else { + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s_rest, 0, 0, 1);\n", proc_name, wname); + } + } else if (emit_setters && struct_member && strlen(Char(proc_name)) > 3) { + int len = Len(proc_name); + const char *pc = Char(proc_name); + /* MEMBER-set and MEMBER-get functions. */ + int is_setter = (pc[len - 3] == 's'); + if (is_setter) { + Printf(f_init, "SCM setter = "); + struct_member = 2; /* have a setter */ + } else + Printf(f_init, "SCM getter = "); + if (use_scm_interface) { + /* GOOPS support uses the MEMBER-set and MEMBER-get functions, + so ignore only_setters in this case. */ + if (only_setters && !goops) + Printf(f_init, "scm_c_make_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + else + Printf(f_init, "scm_c_define_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + } else { + if (only_setters && !goops) + Printf(f_init, "scm_make_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + else + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s, %d, %d, 0);\n", proc_name, wname, numreq, numargs - numreq); + } + if (!is_setter) { + /* Strip off "-get" */ + char *pws_name = (char *) malloc(sizeof(char) * (len - 3)); + strncpy(pws_name, pc, len - 3); + pws_name[len - 4] = 0; + if (struct_member == 2) { + /* There was a setter, so create a procedure with setter */ + if (use_scm_interface) { + Printf(f_init, "scm_c_define"); + } else { + Printf(f_init, "gh_define"); + } + Printf(f_init, "(\"%s\", " "scm_make_procedure_with_setter(getter, setter));\n", pws_name); + } else { + /* There was no setter, so make an alias to the getter */ + if (use_scm_interface) { + Printf(f_init, "scm_c_define"); + } else { + Printf(f_init, "gh_define"); + } + Printf(f_init, "(\"%s\", getter);\n", pws_name); + } + Printf(exported_symbols, "\"%s\", ", pws_name); + free(pws_name); + } + } else { + /* Register the function */ + if (use_scm_interface) { + if (exporting_destructor) { + Printf(f_init, "((swig_guile_clientdata *)(SWIGTYPE%s->clientdata))->destroy = (guile_destructor) %s;\n", swigtype_ptr, wname); + //Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) %s);\n", swigtype_ptr, wname); + } + Printf(f_init, "scm_c_define_gsubr(\"%s\", %d, %d, 0, (swig_guile_proc) %s);\n", proc_name, numreq, numargs - numreq, wname); + } else { + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s, %d, %d, 0);\n", proc_name, wname, numreq, numargs - numreq); + } + } + } else { /* overloaded function; don't export the single methods */ + if (!Getattr(n, "sym:nextSibling")) { + /* Emit overloading dispatch function */ + + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(argc,argv);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "static SCM\n", dname, "(SCM rest)\n{\n", NIL); + Printf(df->code, "#define FUNC_NAME \"%s\"\n", proc_name); + Printf(df->code, "SCM argv[%d];\n", maxargs); + Printf(df->code, "int argc = SWIG_Guile_GetArgs (argv, rest, %d, %d, \"%s\");\n", 0, maxargs, proc_name); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "scm_misc_error(\"%s\", \"No matching method for generic function `%s'\", SCM_EOL);\n", proc_name, iname); + Printf(df->code, "#undef FUNC_NAME\n"); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + if (use_scm_interface) { + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, 0, 1, (swig_guile_proc) %s);\n", proc_name, dname); + } else { + Printf(f_init, "gh_new_procedure(\"%s\", (swig_guile_proc) %s, 0, 0, 1);\n", proc_name, dname); + } + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + } + Printf(exported_symbols, "\"%s\", ", proc_name); + + if (!in_class || memberfunction_name) { + // export wrapper into goops file + String *method_def = NewString(""); + String *goops_name; + if (in_class) + goops_name = NewString(memberfunction_name); + else + goops_name = goopsNameMapping(proc_name, (char *) ""); + String *primitive_name = NewString(""); + if (primRenamer) + Printv(primitive_name, "primitive:", proc_name, NIL); + else + Printv(primitive_name, proc_name, NIL); + Replaceall(method_signature, "_", "-"); + Replaceall(primitive_args, "_", "-"); + if (!any_specialized_arg) { + /* If there would not be any specialized argument in + the method declaration, we simply re-export the + function. This is a performance optimization. */ + Printv(method_def, "(define ", goops_name, " ", primitive_name, ")\n", NIL); + } else if (numreq == numargs) { + Printv(method_def, "(define-method (", goops_name, method_signature, ")\n", NIL); + Printv(method_def, " (", primitive_name, primitive_args, "))\n", NIL); + } else { + /* Handle optional args. For the rest argument, use a name + that cannot clash. */ + Printv(method_def, "(define-method (", goops_name, method_signature, " . %args)\n", NIL); + Printv(method_def, " (apply ", primitive_name, primitive_args, " %args))\n", NIL); + } + if (in_class) { + /* Defer method definition till end of class definition. */ + Printv(goops_class_methods, method_def, NIL); + } else { + Printv(goopscode, method_def, NIL); + } + Printf(goopsexport, "%s ", goops_name); + Delete(primitive_name); + Delete(goops_name); + Delete(method_def); + } + + if (procdoc) { + String *returns_text = NewString(""); + if (num_results == 0) + Printv(returns_text, return_nothing_doc, NIL); + else if (num_results == 1) + Printv(returns_text, return_one_doc, NIL); + else + Printv(returns_text, return_multi_doc, NIL); + /* Substitute documentation variables */ + static const char *numbers[] = { "zero", "one", "two", "three", + "four", "five", "six", "seven", + "eight", "nine", "ten", "eleven", + "twelve" + }; + if (num_results <= 12) + Replaceall(returns_text, "$num_values", numbers[num_results]); + else { + String *num_results_str = NewStringf("%d", num_results); + Replaceall(returns_text, "$num_values", num_results_str); + Delete(num_results_str); + } + Replaceall(returns_text, "$values", returns); + Printf(doc_body, "\n%s", returns_text); + write_doc(proc_name, signature, doc_body); + Delete(returns_text); + } + + Delete(proc_name); + Delete(outarg); + Delete(cleanup); + Delete(signature); + Delete(method_signature); + Delete(primitive_args); + Delete(doc_body); + Delete(returns_argout); + Delete(returns); + Delete(tmp); + Delete(scheme_arg_names); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * + * Create a link to a C variable. + * This creates a single function PREFIX_var_VARNAME(). + * This function takes a single optional argument. If supplied, it means + * we are setting this variable to some value. If omitted, it means we are + * simply evaluating this variable. Either way, we return the variables + * value. + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + String *proc_name; + Wrapper *f; + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + f = NewWrapper(); + // evaluation function names + + String *var_name = Swig_name_wrapper(iname); + + // Build the name for scheme. + proc_name = NewString(iname); + Replaceall(proc_name, "_", "-"); + Setattr(n, "wrap:name", proc_name); + + if (1 || (SwigType_type(t) != T_USER) || (is_a_pointer(t))) { + + Printf(f->def, "static SCM\n%s(SCM s_0)\n{\n", var_name); + + /* Define the scheme name in C. This define is used by several Guile + macros. */ + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + Wrapper_add_local(f, "gswig_result", "SCM gswig_result"); + + if (!GetFlag(n, "feature:immutable")) { + /* Check for a setting of the variable value */ + Printf(f->code, "if (s_0 != SCM_UNDEFINED) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "s_0"); + Replaceall(tm, "$input", "s_0"); + Replaceall(tm, "$target", name); + /* Printv(f->code,tm,"\n",NIL); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_guile_type_error(t); + } + Printf(f->code, "}\n"); + } + // Now return the value of the variable (regardless + // of evaluating or setting) + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "gswig_result"); + Replaceall(tm, "$result", "gswig_result"); + /* Printv(f->code,tm,"\n",NIL); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_guile_type_error(t); + } + Printf(f->code, "\nreturn gswig_result;\n"); + Printf(f->code, "#undef FUNC_NAME\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + // Now add symbol to the Guile interpreter + + if (!emit_setters || GetFlag(n, "feature:immutable")) { + /* Read-only variables become a simple procedure returning the + value; read-write variables become a simple procedure with + an optional argument. */ + if (use_scm_interface) { + + if (!goops && GetFlag(n, "feature:constasvar")) { + /* need to export this function as a variable instead of a procedure */ + if (scmstub) { + /* export the function in the wrapper, and (set!) it in scmstub */ + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, %d, 0, (swig_guile_proc) %s);\n", proc_name, !GetFlag(n, "feature:immutable"), var_name); + Printf(scmtext, "(set! %s (%s))\n", proc_name, proc_name); + } else { + /* export the variable directly */ + Printf(f_init, "scm_c_define(\"%s\", %s(SCM_UNDEFINED));\n", proc_name, var_name); + } + + } else { + /* Export the function as normal */ + Printf(f_init, "scm_c_define_gsubr(\"%s\", 0, %d, 0, (swig_guile_proc) %s);\n", proc_name, !GetFlag(n, "feature:immutable"), var_name); + } + + } else { + Printf(f_init, "\t gh_new_procedure(\"%s\", (swig_guile_proc) %s, 0, %d, 0);\n", proc_name, var_name, !GetFlag(n, "feature:immutable")); + } + } else { + /* Read/write variables become a procedure with setter. */ + if (use_scm_interface) { + Printf(f_init, "{ SCM p = scm_c_define_gsubr(\"%s\", 0, 1, 0, (swig_guile_proc) %s);\n", proc_name, var_name); + Printf(f_init, "scm_c_define"); + } else { + Printf(f_init, "\t{ SCM p = gh_new_procedure(\"%s\", (swig_guile_proc) %s, 0, 1, 0);\n", proc_name, var_name); + Printf(f_init, "gh_define"); + } + Printf(f_init, "(\"%s\", " "scm_make_procedure_with_setter(p, p)); }\n", proc_name); + } + Printf(exported_symbols, "\"%s\", ", proc_name); + + // export wrapper into goops file + if (!in_class) { // only if the variable is not part of a class + String *class_name = SwigType_typedef_resolve_all(SwigType_base(t)); + String *goops_name = goopsNameMapping(proc_name, (char *) ""); + String *primitive_name = NewString(""); + if (primRenamer) + Printv(primitive_name, "primitive:", NIL); + Printv(primitive_name, proc_name, NIL); + /* Simply re-export the procedure */ + if ((!emit_setters || GetFlag(n, "feature:immutable")) + && GetFlag(n, "feature:constasvar")) { + Printv(goopscode, "(define ", goops_name, " (", primitive_name, "))\n", NIL); + } else { + Printv(goopscode, "(define ", goops_name, " ", primitive_name, ")\n", NIL); + } + Printf(goopsexport, "%s ", goops_name); + Delete(primitive_name); + Delete(class_name); + Delete(goops_name); + } + + if (procdoc) { + /* Compute documentation */ + String *signature = NewString(""); + String *signature2 = NULL; + String *doc = NewString(""); + + if (GetFlag(n, "feature:immutable")) { + Printv(signature, proc_name, NIL); + if (GetFlag(n, "feature:constasvar")) { + Printv(doc, "Is constant ", NIL); + } else { + Printv(doc, "Returns constant ", NIL); + } + if ((tm = Getattr(n, "tmap:varout:doc"))) { + Printv(doc, tm, NIL); + } else { + String *s = SwigType_str(t, 0); + Chop(s); + Printf(doc, "<%s>", s); + Delete(s); + } + } else if (emit_setters) { + Printv(signature, proc_name, NIL); + signature2 = NewString(""); + Printv(signature2, "set! (", proc_name, ") ", NIL); + handle_documentation_typemap(signature2, NIL, n, "tmap:varin:arglist", "new-value"); + Printv(doc, "Get or set the value of the C variable, \n", NIL); + Printv(doc, "which is of type ", NIL); + handle_documentation_typemap(doc, NIL, n, "tmap:varout:doc", "$1_type"); + Printv(doc, "."); + } else { + Printv(signature, proc_name, " #:optional ", NIL); + if ((tm = Getattr(n, "tmap:varin:doc"))) { + Printv(signature, tm, NIL); + } else { + String *s = SwigType_str(t, 0); + Chop(s); + Printf(signature, "new-value <%s>", s); + Delete(s); + } + + Printv(doc, "If NEW-VALUE is provided, " "set C variable to this value.\n", NIL); + Printv(doc, "Returns variable value ", NIL); + if ((tm = Getattr(n, "tmap:varout:doc"))) { + Printv(doc, tm, NIL); + } else { + String *s = SwigType_str(t, 0); + Chop(s); + Printf(doc, "<%s>", s); + Delete(s); + } + } + write_doc(proc_name, signature, doc, signature2); + Delete(signature); + if (signature2) + Delete(signature2); + Delete(doc); + } + + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + Delete(var_name); + Delete(proc_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * + * We create a read-only variable. + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + int constasvar = GetFlag(n, "feature:constasvar"); + + + String *proc_name; + String *var_name; + String *rvalue; + Wrapper *f; + SwigType *nctype; + String *tm; + + f = NewWrapper(); + + // Make a static variable; + var_name = NewStringf("%sconst_%s", prefix, iname); + + // Strip const qualifier from type if present + + nctype = NewString(type); + if (SwigType_isconst(nctype)) { + Delete(SwigType_pop(nctype)); + } + // Build the name for scheme. + proc_name = NewString(iname); + Replaceall(proc_name, "_", "-"); + + if ((SwigType_type(nctype) == T_USER) && (!is_a_pointer(nctype))) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + Delete(var_name); + DelWrapper(f); + return SWIG_NOWRAP; + } + // See if there's a typemap + + if (SwigType_type(nctype) == T_STRING) { + rvalue = NewStringf("\"%s\"", value); + } else if (SwigType_type(nctype) == T_CHAR) { + rvalue = NewStringf("\'%s\'", value); + } else { + rvalue = NewString(value); + } + + if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { + Replaceall(tm, "$source", rvalue); + Replaceall(tm, "$value", rvalue); + Replaceall(tm, "$target", name); + Printv(f_header, tm, "\n", NIL); + } else { + // Create variable and assign it a value + Printf(f_header, "static %s = %s;\n", SwigType_lstr(nctype, var_name), rvalue); + } + { + /* Hack alert: will cleanup later -- Dave */ + Node *n = NewHash(); + Setattr(n, "name", var_name); + Setattr(n, "sym:name", iname); + Setattr(n, "type", nctype); + SetFlag(n, "feature:immutable"); + if (constasvar) { + SetFlag(n, "feature:constasvar"); + } + variableWrapper(n); + Delete(n); + } + Delete(var_name); + Delete(nctype); + Delete(proc_name); + Delete(rvalue); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + virtual int classDeclaration(Node *n) { + String *class_name = NewStringf("<%s>", Getattr(n, "sym:name")); + Setattr(n, "guile:goopsclassname", class_name); + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + virtual int classHandler(Node *n) { + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + + class_name = NewString(""); + short_class_name = NewString(""); + Printv(class_name, "<", Getattr(n, "sym:name"), ">", NIL); + Printv(short_class_name, Getattr(n, "sym:name"), NIL); + Replaceall(class_name, "_", "-"); + Replaceall(short_class_name, "_", "-"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + /* Handle inheritance */ + String *base_class = NewString("<"); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator i = First(baselist); + while (i.item) { + Printv(base_class, Getattr(i.item, "sym:name"), NIL); + i = Next(i); + if (i.item) { + Printf(base_class, "> <"); + } + } + } + Printf(base_class, ">"); + Replaceall(base_class, "_", "-"); + + Printv(goopscode, "(define-class ", class_name, " ", NIL); + Printf(goopsexport, "%s ", class_name); + + if (Len(base_class) > 2) { + Printv(goopscode, "(", base_class, ")\n", NIL); + } else { + Printv(goopscode, "(<swig>)\n", NIL); + } + SwigType *ct = NewStringf("p.%s", Getattr(n, "name")); + swigtype_ptr = SwigType_manglestr(ct); + + String *mangled_classname = Swig_name_mangle(Getattr(n, "sym:name")); + /* Export clientdata structure */ + if (use_scm_interface) { + Printf(f_runtime, "static swig_guile_clientdata _swig_guile_clientdata%s = { NULL, SCM_EOL };\n", mangled_classname); + + Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", swigtype_ptr, ", (void *) &_swig_guile_clientdata", mangled_classname, ");\n", NIL); + SwigType_remember(ct); + } + Delete(ct); + + /* Emit all of the members */ + goops_class_methods = NewString(""); + + in_class = 1; + Language::classHandler(n); + in_class = 0; + + Printv(goopscode, " #:metaclass <swig-metaclass>\n", NIL); + + if (have_constructor) + Printv(goopscode, " #:new-function ", primRenamer ? "primitive:" : "", "new-", short_class_name, "\n", NIL); + + Printf(goopscode, ")\n%s\n", goops_class_methods); + Delete(goops_class_methods); + goops_class_methods = 0; + + + /* export class initialization function */ + if (goops) { + /* export the wrapper function */ + String *funcName = NewString(mangled_classname); + Printf(funcName, "_swig_guile_setgoopsclass"); + String *guileFuncName = NewString(funcName); + Replaceall(guileFuncName, "_", "-"); + + Printv(f_wrappers, "static SCM ", funcName, "(SCM cl) \n", NIL); + Printf(f_wrappers, "#define FUNC_NAME %s\n{\n", guileFuncName); + Printv(f_wrappers, " ((swig_guile_clientdata *)(SWIGTYPE", swigtype_ptr, "->clientdata))->goops_class = cl;\n", NIL); + Printf(f_wrappers, " return SCM_UNSPECIFIED;\n"); + Printf(f_wrappers, "}\n#undef FUNC_NAME\n\n"); + + Printf(f_init, "scm_c_define_gsubr(\"%s\", 1, 0, 0, (swig_guile_proc) %s);\n", guileFuncName, funcName); + Printf(exported_symbols, "\"%s\", ", guileFuncName); + + /* export the call to the wrapper function */ + Printf(goopscode, "(%s%s %s)\n\n", primRenamer ? "primitive:" : "", guileFuncName, class_name); + + Delete(guileFuncName); + Delete(funcName); + } + + Delete(mangled_classname); + + Delete(swigtype_ptr); + swigtype_ptr = 0; + + Delete(class_name); + Delete(short_class_name); + class_name = 0; + short_class_name = 0; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + int memberfunctionHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + + memberfunction_name = goopsNameMapping(proc, short_class_name); + Language::memberfunctionHandler(n); + Delete(memberfunction_name); + memberfunction_name = NULL; + Delete(proc); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + int membervariableHandler(Node *n) { + String *iname = Getattr(n, "sym:name"); + + if (emit_setters) { + struct_member = 1; + Printf(f_init, "{\n"); + } + + Language::membervariableHandler(n); + + if (emit_setters) { + Printf(f_init, "}\n"); + struct_member = 0; + } + + String *proc = NewString(iname); + Replaceall(proc, "_", "-"); + String *goops_name = goopsNameMapping(proc, short_class_name); + + /* The slot name is never qualified with the class, + even if useclassprefix is true. */ + Printv(goopscode, " (", proc, " #:allocation #:virtual", NIL); + /* GOOPS (at least in Guile 1.6.3) only accepts closures, not + primitive procedures for slot-ref and slot-set. */ + Printv(goopscode, "\n #:slot-ref (lambda (obj) (", primRenamer ? "primitive:" : "", short_class_name, "-", proc, "-get", " obj))", NIL); + if (!GetFlag(n, "feature:immutable")) { + Printv(goopscode, "\n #:slot-set! (lambda (obj value) (", primRenamer ? "primitive:" : "", short_class_name, "-", proc, "-set", " obj value))", NIL); + } else { + Printf(goopscode, "\n #:slot-set! (lambda (obj value) (error \"Immutable slot\"))"); + } + if (emit_slot_accessors) { + if (GetFlag(n, "feature:immutable")) { + Printv(goopscode, "\n #:getter ", goops_name, NIL); + } else { + Printv(goopscode, "\n #:accessor ", goops_name, NIL); + } + Printf(goopsexport, "%s ", goops_name); + } + Printv(goopscode, ")\n", NIL); + Delete(proc); + Delete(goops_name); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + int constructorHandler(Node *n) { + Language::constructorHandler(n); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + virtual int destructorHandler(Node *n) { + exporting_destructor = true; + Language::destructorHandler(n); + exporting_destructor = false; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * pragmaDirective() + * ------------------------------------------------------------ */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *cmd = Getattr(n, "name"); + String *value = Getattr(n, "value"); + +# define store_pragma(PRAGMANAME) \ + if (Strcmp(cmd, #PRAGMANAME) == 0) { \ + if (PRAGMANAME) Delete(PRAGMANAME); \ + PRAGMANAME = value ? NewString(value) : NULL; \ + } + + if (Strcmp(lang, "guile") == 0) { + store_pragma(beforereturn) + store_pragma(return_nothing_doc) + store_pragma(return_one_doc) + store_pragma(return_multi_doc); +# undef store_pragma + } + } + return Language::pragmaDirective(n); + } + + + /* ------------------------------------------------------------ + * goopsNameMapping() + * Maps the identifier from C++ to the GOOPS based * on command + * line parameters and such. + * If class_name = "" that means the mapping is for a function or + * variable not attached to any class. + * ------------------------------------------------------------ */ + String *goopsNameMapping(String *name, const_String_or_char_ptr class_name) { + String *n = NewString(""); + + if (Strcmp(class_name, "") == 0) { + // not part of a class, so no class name to prefix + if (goopsprefix) { + Printf(n, "%s%s", goopsprefix, name); + } else { + Printf(n, "%s", name); + } + } else { + if (useclassprefix) { + Printf(n, "%s-%s", class_name, name); + } else { + if (goopsprefix) { + Printf(n, "%s%s", goopsprefix, name); + } else { + Printf(n, "%s", name); + } + } + } + return n; + } + + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + /* Check whether we have an R5RS identifier. Guile supports a + superset of R5RS identifiers, but it's probably a bad idea to use + those. */ + /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ + /* <initial> --> <letter> | <special initial> */ + if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~'))) { + /* <peculiar identifier> --> + | - | ... */ + if ((strcmp(c, "+") == 0) + || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) + return 1; + else + return 0; + } + /* <subsequent> --> <initial> | <digit> | <special subsequent> */ + while (*c) { + if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') + || (*c == '-') || (*c == '.') || (*c == '@'))) + return 0; + c++; + } + return 1; + } + + String *runtimeCode() { + String *s; + if (use_scm_interface) { + s = Swig_include_sys("guile_scm_run.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'guile_scm_run.swg"); + s = NewString(""); + } + } else { + s = Swig_include_sys("guile_gh_run.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'guile_gh_run.swg"); + s = NewString(""); + } + } + return s; + } + + String *defaultExternalRuntimeFilename() { + if (use_scm_interface) { + return NewString("swigguilerun.h"); + } else { + return NewString("swigguileghrun.h"); + } + } +}; + +/* ----------------------------------------------------------------------------- + * swig_guile() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_guile() { + return new GUILE(); +} +extern "C" Language *swig_guile(void) { + return new_swig_guile(); +} diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx new file mode 100644 index 0000000..469f899 --- /dev/null +++ b/Source/Modules/java.cxx @@ -0,0 +1,4166 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * java.cxx + * + * Java language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_java_cxx[] = "$Id: java.cxx 11584 2009-08-16 00:04:29Z wsfulton $"; + +#include "swigmod.h" +#include <limits.h> // for INT_MAX +#include "cparse.h" +#include <ctype.h> + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class JAVA:public Language { + static const char *usage; + const String *empty_string; + const String *public_string; + const String *protected_string; + + Hash *swig_types_hash; + File *f_begin; + File *f_runtime; + File *f_runtime_h; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_directors; + File *f_directors_h; + List *filenames_list; + + bool proxy_flag; // Flag for generating proxy classes + bool nopgcpp_flag; // Flag for suppressing the premature garbage collection prevention parameter + bool native_function_flag; // Flag for when wrapping a native function + bool enum_constant_flag; // Flag for when wrapping an enum or constant + bool static_flag; // Flag for when wrapping a static functions or member variables + bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable + bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const + bool global_variable_flag; // Flag for when wrapping a global variable + bool old_variable_names; // Flag for old style variable names in the intermediary class + bool member_func_flag; // flag set when wrapping a member function + + String *imclass_name; // intermediary class name + String *module_class_name; // module class name + String *imclass_class_code; // intermediary class code + String *proxy_class_def; + String *proxy_class_code; + String *module_class_code; + String *proxy_class_name; + String *variable_name; //Name of a variable being wrapped + String *proxy_class_constants_code; + String *module_class_constants_code; + String *enum_code; + String *package; // Optional package name + String *jnipackage; // Package name used in the JNI code + String *package_path; // Package name used internally by JNI (slashes) + String *imclass_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *imclass_baseclass; //inheritance for intermediary class class from %pragma + String *module_baseclass; //inheritance for module class from %pragma + String *imclass_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *imclass_class_modifiers; //class modifiers for intermediary class overriden by %pragma + String *module_class_modifiers; //class modifiers for module class overriden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *imclass_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *imclass_directors; // Intermediate class director code + String *destructor_call; //C++ destructor call if any + String *destructor_throws_clause; //C++ destructor throws clause if any + + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + int first_class_dmethod; + int curr_class_dmethod; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + + static Parm *NewParmFromNode(SwigType *type, const_String_or_char_ptr name, Node *n) { + Parm *p = NewParm(type, name); + Setfile(p, Getfile(n)); + Setline(p, Getline(n)); + return p; + } + +public: + + /* ----------------------------------------------------------------------------- + * JAVA() + * ----------------------------------------------------------------------------- */ + + JAVA():empty_string(NewString("")), + public_string(NewString("public")), + protected_string(NewString("protected")), + swig_types_hash(NULL), + f_begin(NULL), + f_runtime(NULL), + f_runtime_h(NULL), + f_header(NULL), + f_wrappers(NULL), + f_init(NULL), + f_directors(NULL), + f_directors_h(NULL), + filenames_list(NULL), + proxy_flag(true), + nopgcpp_flag(false), + native_function_flag(false), + enum_constant_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + old_variable_names(false), + member_func_flag(false), + imclass_name(NULL), + module_class_name(NULL), + imclass_class_code(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + module_class_code(NULL), + proxy_class_name(NULL), + variable_name(NULL), + proxy_class_constants_code(NULL), + module_class_constants_code(NULL), + package(NULL), + jnipackage(NULL), + package_path(NULL), + imclass_imports(NULL), + module_imports(NULL), + imclass_baseclass(NULL), + module_baseclass(NULL), + imclass_interfaces(NULL), + module_interfaces(NULL), + imclass_class_modifiers(NULL), + module_class_modifiers(NULL), + upcasts_code(NULL), + imclass_cppcasts_code(NULL), + imclass_directors(NULL), + destructor_call(NULL), + destructor_throws_clause(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(0) { + /* for now, multiple inheritance in directors is disabled, this + should be easy to implement though */ + director_multiple_inheritance = 0; + director_language = 1; + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class + * Return NULL if not otherwise the proxy class name + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /* ----------------------------------------------------------------------------- + * makeValidJniName() + * ----------------------------------------------------------------------------- */ + + String *makeValidJniName(const String *name) { + String *valid_jni_name = NewString(name); + Replaceall(valid_jni_name, "_", "_1"); + return valid_jni_name; + } + + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *directorClassName(Node *n) { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = Getattr(n, "sym:name"); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + + return dirclassname; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("java"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-package") == 0) { + if (argv[i + 1]) { + package = NewString(""); + Printf(package, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + Printf(stderr, "Deprecated command line option: %s. Proxy classes are now generated by default.\n", argv[i]); + Swig_mark_arg(i); + proxy_flag = true; + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + Swig_mark_arg(i); + proxy_flag = false; + } else if (strcmp(argv[i], "-nopgcpp") == 0) { + Swig_mark_arg(i); + nopgcpp_flag = true; + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } else if (strcmp(argv[i], "-jnic") == 0) { + Swig_mark_arg(i); + Printf(stderr, "Deprecated command line option: -jnic. C JNI calling convention now used when -c++ not specified.\n"); + } else if (strcmp(argv[i], "-nofinalize") == 0) { + Swig_mark_arg(i); + Printf(stderr, "Deprecated command line option: -nofinalize. Use the new javafinalize typemap instead.\n"); + } else if (strcmp(argv[i], "-jnicpp") == 0) { + Swig_mark_arg(i); + Printf(stderr, "Deprecated command line option: -jnicpp. C++ JNI calling convention now used when -c++ specified.\n"); + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGJAVA 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("java"); + SWIG_config_file("java.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + + // Get any options set in the module directive + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + + if (optionsnode) { + if (Getattr(optionsnode, "jniclassname")) + imclass_name = Copy(Getattr(optionsnode, "jniclassname")); + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + if (Getattr(optionsnode, "directors")) { + allow_directors(); + } + if (Getattr(optionsnode, "dirprot")) { + allow_dirprot(); + } + allow_allprotected(GetFlag(optionsnode, "allprotected")); + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + if (!outfile) { + Printf(stderr, "Unable to determine outfile\n"); + SWIG_exit(EXIT_FAILURE); + } + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + if (directorsEnabled()) { + if (!outfile_h) { + Printf(stderr, "Unable to determine outfile_h\n"); + SWIG_exit(EXIT_FAILURE); + } + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + swig_types_hash = NewHash(); + filenames_list = NewList(); + + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + if (!imclass_name) { + imclass_name = NewStringf("%sJNI", Getattr(n, "name")); + module_class_name = Copy(Getattr(n, "name")); + } else { + // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution + if (Cmp(imclass_name, Getattr(n, "name")) == 0) + module_class_name = NewStringf("%sModule", Getattr(n, "name")); + else + module_class_name = Copy(Getattr(n, "name")); + } + + imclass_class_code = NewString(""); + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + module_class_constants_code = NewString(""); + imclass_baseclass = NewString(""); + imclass_interfaces = NewString(""); + imclass_class_modifiers = NewString(""); + module_class_code = NewString(""); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + module_class_modifiers = NewString(""); + imclass_imports = NewString(""); + imclass_cppcasts_code = NewString(""); + imclass_directors = NewString(""); + upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + if (!package) + package = NewString(""); + jnipackage = NewString(""); + package_path = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n#define SWIGJAVA\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + + /* Emit initial director header and director code: */ + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_class_name); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_name); + + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + if (outfile_h) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + Printf(f_runtime, "\n"); + + String *wrapper_name = NewString(""); + + if (Len(package)) { + String *jniname = makeValidJniName(package); + Printv(jnipackage, jniname, NIL); + Delete(jniname); + Replaceall(jnipackage, ".", "_"); + Append(jnipackage, "_"); + Printv(package_path, package, NIL); + Replaceall(package_path, ".", "/"); + } + String *jniname = makeValidJniName(imclass_name); + Printf(wrapper_name, "Java_%s%s_%%f", Char(jnipackage), jniname); + Delete(jniname); + + Swig_name_register((char *) "wrapper", Char(wrapper_name)); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%v"); + } + + Delete(wrapper_name); + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + /* Emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director.swg", f_runtime); + } + // Generate the intermediary class + { + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), imclass_name); + File *f_im = NewFile(filen, "w", SWIG_output_files()); + if (!f_im) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the intermediary class file + emitBanner(f_im); + + if (Len(package) > 0) + Printf(f_im, "package %s;\n", package); + + if (imclass_imports) + Printf(f_im, "%s\n", imclass_imports); + + if (Len(imclass_class_modifiers) > 0) + Printf(f_im, "%s ", imclass_class_modifiers); + Printf(f_im, "%s ", imclass_name); + + if (imclass_baseclass && *Char(imclass_baseclass)) + Printf(f_im, "extends %s ", imclass_baseclass); + if (Len(imclass_interfaces) > 0) + Printv(f_im, "implements ", imclass_interfaces, " ", NIL); + Printf(f_im, "{\n"); + + // Add the intermediary class methods + Replaceall(imclass_class_code, "$module", module_class_name); + Replaceall(imclass_class_code, "$imclassname", imclass_name); + Printv(f_im, imclass_class_code, NIL); + Printv(f_im, imclass_cppcasts_code, NIL); + if (Len(imclass_directors) > 0) + Printv(f_im, "\n", imclass_directors, NIL); + + if (n_dmethods > 0) { + Putc('\n', f_im); + Printf(f_im, " private final static native void swig_module_init();\n"); + Printf(f_im, " static {\n"); + Printf(f_im, " swig_module_init();\n"); + Printf(f_im, " }\n"); + } + // Finish off the class + Printf(f_im, "}\n"); + Close(f_im); + } + + // Generate the Java module class + { + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), module_class_name); + File *f_module = NewFile(filen, "w", SWIG_output_files()); + if (!f_module) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the module class file + emitBanner(f_module); + + if (Len(package) > 0) + Printf(f_module, "package %s;\n", package); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + if (Len(module_class_modifiers) > 0) + Printf(f_module, "%s ", module_class_modifiers); + Printf(f_module, "%s ", module_class_name); + + if (module_baseclass && *Char(module_baseclass)) + Printf(f_module, "extends %s ", module_baseclass); + if (Len(module_interfaces) > 0) { + if (Len(module_class_constants_code) != 0) + Printv(f_module, "implements ", Getattr(n, "name"), "Constants, ", module_interfaces, " ", NIL); + else + Printv(f_module, "implements ", module_interfaces, " ", NIL); + } else { + if (Len(module_class_constants_code) != 0) + Printv(f_module, "implements ", Getattr(n, "name"), "Constants ", NIL); + } + Printf(f_module, "{\n"); + + Replaceall(module_class_code, "$module", module_class_name); + Replaceall(module_class_constants_code, "$module", module_class_name); + + Replaceall(module_class_code, "$imclassname", imclass_name); + Replaceall(module_class_constants_code, "$imclassname", imclass_name); + + // Add the wrapper methods + Printv(f_module, module_class_code, NIL); + + // Finish off the class + Printf(f_module, "}\n"); + Close(f_module); + } + + // Generate the Java constants interface + if (Len(module_class_constants_code) != 0) { + String *filen = NewStringf("%s%sConstants.java", SWIG_output_directory(), module_class_name); + File *f_module = NewFile(filen, "w", SWIG_output_files()); + if (!f_module) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the Java constants interface file + emitBanner(f_module); + + if (Len(package) > 0) + Printf(f_module, "package %s;\n", package); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + Printf(f_module, "public interface %sConstants {\n", module_class_name); + + // Write out all the global constants + Printv(f_module, module_class_constants_code, NIL); + + // Finish off the Java interface + Printf(f_module, "}\n"); + Close(f_module); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + emitDirectorUpcalls(); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a Java type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + // Check for overwriting file problems on filesystems that are case insensitive + Iterator it1; + Iterator it2; + for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { + String *item1_lower = Swig_string_lower(it1.item); + for (it2 = Next(it1); it2.item; it2 = Next(it2)) { + String *item2_lower = Swig_string_lower(it2.item); + if (it1.item && it2.item) { + if (Strcmp(item1_lower, item2_lower) == 0) { + Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, + "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " + "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); + } + } + Delete(item2_lower); + } + Delete(item1_lower); + } + + Delete(swig_types_hash); + swig_types_hash = NULL; + Delete(filenames_list); + filenames_list = NULL; + Delete(imclass_name); + imclass_name = NULL; + Delete(imclass_class_code); + imclass_class_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(module_class_constants_code); + module_class_constants_code = NULL; + Delete(imclass_baseclass); + imclass_baseclass = NULL; + Delete(imclass_interfaces); + imclass_interfaces = NULL; + Delete(imclass_class_modifiers); + imclass_class_modifiers = NULL; + Delete(module_class_name); + module_class_name = NULL; + Delete(module_class_code); + module_class_code = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(module_class_modifiers); + module_class_modifiers = NULL; + Delete(imclass_imports); + imclass_imports = NULL; + Delete(imclass_cppcasts_code); + imclass_cppcasts_code = NULL; + Delete(imclass_directors); + imclass_directors = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(package); + package = NULL; + Delete(jnipackage); + jnipackage = NULL; + Delete(package_path); + package_path = NULL; + Delete(dmethods_seq); + dmethods_seq = NULL; + Delete(dmethods_table); + dmethods_table = NULL; + n_dmethods = 0; + + /* Close all of the files */ + Dump(f_header, f_runtime); + + if (directorsEnabled()) { + Dump(f_directors, f_runtime); + Dump(f_directors_h, f_runtime_h); + + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + + Close(f_runtime_h); + Delete(f_runtime_h); + f_runtime_h = NULL; + Delete(f_directors); + f_directors = NULL; + Delete(f_directors_h); + f_directors_h = NULL; + } + + Dump(f_wrappers, f_runtime); + Wrapper_pretty_print(f_init, f_runtime); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Dump(f_runtime, f_begin); + Delete(f_runtime); + Close(f_begin); + Delete(f_begin); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * emitBanner() + * ----------------------------------------------------------------------------- */ + + void emitBanner(File *f) { + Printf(f, "/* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); + } + + /*----------------------------------------------------------------------- + * Add new director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *imclass_desc, String *class_desc, String *decl) { + UpcallData *udata; + String *imclass_methodidx; + String *class_methodidx; + Hash *new_udata; + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, key))) { + Delete(key); + return Getattr(udata, "methodoff"); + } + + imclass_methodidx = NewStringf("%d", n_dmethods); + class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); + n_dmethods++; + + new_udata = NewHash(); + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, key, new_udata); + + Setattr(new_udata, "method", Copy(class_method)); + Setattr(new_udata, "fdesc", Copy(class_desc)); + Setattr(new_udata, "imclass_method", Copy(imclass_method)); + Setattr(new_udata, "imclass_fdesc", Copy(imclass_desc)); + Setattr(new_udata, "imclass_methodidx", imclass_methodidx); + Setattr(new_udata, "class_methodidx", class_methodidx); + Setattr(new_udata, "decl", Copy(decl)); + + Delete(key); + return new_udata; + } + + /*----------------------------------------------------------------------- + * Get director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *getUpcallMethodData(String *director_class, String *decl) { + String *key = NewStringf("%s|%s", director_class, decl); + UpcallData *udata = Getattr(dmethods_table, key); + + Delete(key); + return udata; + } + + /* ---------------------------------------------------------------------- + * nativeWrapper() + * ---------------------------------------------------------------------- */ + + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + if (Getattr(n, "type")) { + Swig_save("nativeWrapper", n, "name", NIL); + Setattr(n, "name", wrapname); + native_function_flag = true; + functionWrapper(n); + Swig_restore(n); + native_function_flag = false; + } else { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, Getattr(n, "wrap:name")); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *c_return_type = NewString(""); + String *im_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + int num_arguments = 0; + int num_required = 0; + int gencomma = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + String *nondir_args = NewString(""); + bool is_destructor = (Cmp(Getattr(n, "nodeType"), "destructor") == 0); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(Getattr(n, "sym:name"), n)) + return SWIG_ERROR; + } + + /* + The rest of this function deals with generating the intermediary class wrapper function (that wraps + a c/c++ function) and generating the JNI c code. Each Java wrapper function has a + matching JNI c function call. + */ + + // A new wrapper function object + Wrapper *f = NewWrapper(); + + // Make a wrapper name for this function + String *jniname = makeValidJniName(overloaded_name); + String *wname = Swig_name_wrapper(jniname); + + Delete(jniname); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("jni", l, f); + Swig_typemap_attach_parms("jtype", l, f); + Swig_typemap_attach_parms("jstype", l, f); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("jni", n, "", 0))) { + Printf(c_return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s\n", SwigType_str(t, 0)); + } + + if ((tm = Swig_typemap_lookup("jtype", n, "", 0))) { + Printf(im_return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + is_void_return = (Cmp(c_return_type, "void") == 0); + if (!is_void_return) + Wrapper_add_localv(f, "jresult", c_return_type, "jresult = 0", NIL); + + Printv(f->def, "SWIGEXPORT ", c_return_type, " JNICALL ", wname, "(JNIEnv *jenv, jclass jcls", NIL); + + // Usually these function parameters are unused - The code below ensures + // that compilers do not issue such a warning if configured to do so. + + Printv(f->code, " (void)jenv;\n", NIL); + Printv(f->code, " (void)jcls;\n", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + + // Parameter overloading + Setattr(n, "wrap:parms", l); + Setattr(n, "wrap:name", wname); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java + if (Getattr(n, "sym:overloaded")) { + // Emit warnings for the few cases that can't be overloaded in Java and give up on generating wrapper + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + } + + Printf(imclass_class_code, " public final static native %s %s(", im_return_type, overloaded_name); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + // Now walk the function parameter list and generate code to get arguments + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + String *im_param_type = NewString(""); + String *c_param_type = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* Get the JNI C types of the parameter */ + if ((tm = Getattr(p, "tmap:jni"))) { + Printv(c_param_type, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Get the intermediary class parameter types of the parameter */ + if ((tm = Getattr(p, "tmap:jtype"))) { + Printv(im_param_type, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to intermediary class method */ + if (gencomma) + Printf(imclass_class_code, ", "); + Printf(imclass_class_code, "%s %s", im_param_type, arg); + + // Add parameter to C function + Printv(f->def, ", ", c_param_type, " ", arg, NIL); + + ++gencomma; + + // Premature garbage collection prevention parameter + if (!is_destructor) { + String *pgc_parameter = prematureGarbageCollectionPreventionParameter(pt, p); + if (pgc_parameter) { + Printf(imclass_class_code, ", %s %s_", pgc_parameter, arg); + Printf(f->def, ", jobject %s_", arg); + Printf(f->code, " (void)%s_;\n", arg); + } + } + // Get typemap for this argument + if ((tm = Getattr(p, "tmap:in"))) { + addThrows(n, "tmap:in", p); + Replaceall(tm, "$source", arg); /* deprecated */ + Replaceall(tm, "$target", ln); /* deprecated */ + Replaceall(tm, "$arg", arg); /* deprecated? */ + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + + Printf(nondir_args, "%s\n", tm); + + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + + Delete(im_param_type); + Delete(c_param_type); + Delete(arg); + } + + Printv(f->code, nondir_args, NIL); + Delete(nondir_args); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + addThrows(n, "tmap:check", p); + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + addThrows(n, "tmap:freearg", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + addThrows(n, "tmap:argout", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Get any Java exception classes in the throws typemap + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "catchlist"))) { + Swig_typemap_attach_parms("throws", throw_parm_list, f); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + addThrows(n, "tmap:throws", p); + } + } + } + + if (!native_function_flag) { + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + // Now write code to make the function call + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + // Handle exception classes specified in the "except" feature's "throws" attribute + addThrows(n, "feature:except", n); + + if (Cmp(nodeType(n), "constant") == 0) + Swig_restore(n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + addThrows(n, "tmap:out", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Replaceall(tm, "$target", "jresult"); /* deprecated */ + Replaceall(tm, "$result", "jresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s", tm); + if (Len(tm)) + Printf(f->code, "\n"); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); + } + emit_return_variable(n, t, f); + } + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + addThrows(n, "tmap:newfree", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if (!native_function_flag) { + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + addThrows(n, "tmap:ret", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C function and intermediary class function definitions */ + Printf(imclass_class_code, ")"); + generateThrowsClause(n, imclass_class_code); + Printf(imclass_class_code, ";\n"); + + Printf(f->def, ") {"); + + if (!is_void_return) + Printv(f->code, " return jresult;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + /* Contract macro modification */ + Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, "); + + if (!is_void_return) + Replaceall(f->code, "$null", "0"); + else + Replaceall(f->code, "$null", ""); + + /* Dump the function out */ + if (!native_function_flag) + Wrapper_print(f, f_wrappers); + + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + moduleClassFunctionHandler(n); + } + + /* + * Generate the proxy class getters/setters for public member variables. + * Not for enums and constants. + */ + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name + bool getter_flag = Cmp(symname, Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) != 0; + + String *getter_setter_name = NewString(""); + if (!getter_flag) + Printf(getter_setter_name, "set"); + else + Printf(getter_setter_name, "get"); + Putc(toupper((int) *Char(variable_name)), getter_setter_name); + Printf(getter_setter_name, "%s", Char(variable_name) + 1); + + Setattr(n, "proxyfuncname", getter_setter_name); + Setattr(n, "imfuncname", symname); + + proxyClassFunctionHandler(n); + Delete(getter_setter_name); + } + + Delete(c_return_type); + Delete(im_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(overloaded_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + variable_wrapper_flag = true; + Language::variableWrapper(n); /* Default to functions */ + variable_wrapper_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * globalvariableHandler() + * ------------------------------------------------------------------------ */ + + virtual int globalvariableHandler(Node *n) { + + variable_name = Getattr(n, "sym:name"); + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + return ret; + } + + /* ---------------------------------------------------------------------- + * enumDeclaration() + * + * C/C++ enums can be mapped in one of 4 ways, depending on the java:enum feature specified: + * 1) Simple enums - simple constant within the proxy class or module class + * 2) Typeunsafe enums - simple constant in a Java class (class named after the c++ enum name) + * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) + * 4) Proper enums - proper Java enum + * Anonymous enums always default to 1) + * ---------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + enum_code = NewString(""); + String *symname = Getattr(n, "sym:name"); + String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; + EnumFeature enum_feature = decodeEnumFeature(n); + String *typemap_lookup_type = Getattr(n, "name"); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum + + // Pure Java baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "javabase", typemap_lookup_type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + + // Emit the enum + Printv(enum_code, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers (enum modifiers really) + " ", symname, *Char(pure_baseclass) ? // Bases + " extends " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " implements " : "", pure_interfaces, " {\n", NIL); + if (proxy_flag && is_wrapping_class()) + Replaceall(enum_code, "$static ", "static "); + else + Replaceall(enum_code, "$static ", ""); + } else { + // Wrap C++ enum with integers - just indicate start of enum with a comment, no comment for anonymous enums of any sort + if (symname && !Getattr(n, "unnamedinstance")) + Printf(constants_code, " // %s \n", symname); + } + + // Emit each enum item + Language::enumDeclaration(n); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper Java enum + // Finish the enum declaration + // Typemaps are used to generate the enum definition in a similar manner to proxy classes. + Printv(enum_code, (enum_feature == ProperEnum) ? ";\n" : "", typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class + typemapLookup(n, "javacode", typemap_lookup_type, WARN_NONE), // extra Java code + "}", NIL); + + Replaceall(enum_code, "$javaclassname", symname); + + // Substitute $enumvalues - intended usage is for typesafe enums + if (Getattr(n, "enumvalues")) + Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); + else + Replaceall(enum_code, "$enumvalues", ""); + + if (proxy_flag && is_wrapping_class()) { + // Enums defined within the C++ class are defined within the proxy class + + // Add extra indentation + Replaceall(enum_code, "\n", "\n "); + Replaceall(enum_code, " \n", "\n"); + + Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL); + } else { + // Global enums are defined in their own file + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), symname); + File *f_enum = NewFile(filen, "w", SWIG_output_files()); + if (!f_enum) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the enum file + emitBanner(f_enum); + + if (Len(package) > 0) + Printf(f_enum, "package %s;\n", package); + + Printv(f_enum, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + Printf(f_enum, "\n"); + Close(f_enum); + } + } else { + // Wrap C++ enum with simple constant + Printf(enum_code, "\n"); + if (proxy_flag && is_wrapping_class()) + Printv(proxy_class_constants_code, enum_code, NIL); + else + Printv(module_class_constants_code, enum_code, NIL); + } + + Delete(enum_code); + enum_code = NULL; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + + // Strange hack from parent method + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + // Note that this is used in enumValue() amongst other places + Setattr(n, "value", tmpValue); + + { + EnumFeature enum_feature = decodeEnumFeature(parentNode(n)); + + if ((enum_feature == ProperEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymous) C/C++ enum with a proper Java enum + // Emit the enum item. + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + Printf(enum_code, " %s", symname); + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, "(%s)", value); + Delete(value); + } + } else { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + const String *parent_name = Getattr(parentNode(n), "name"); + String *typemap_lookup_type = parent_name ? Copy(parent_name) : NewString("int"); + const String *tm = typemapLookup(n, "jstype", typemap_lookup_type, WARN_JAVA_TYPEMAP_JSTYPE_UNDEF); + String *return_type = Copy(tm); + Delete(typemap_lookup_type); + typemap_lookup_type = NULL; + + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if ((enum_feature == TypesafeEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymouse) enum using the typesafe enum pattern + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, " %s final static %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); + Delete(value); + } else { + Printf(enum_code, " %s final static %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); + } + } else { + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + String *value = enumValue(n); + Printf(enum_code, " %s final static %s %s = %s;\n", methodmods, return_type, symname, value); + Delete(value); + } + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parentNode(n), "enumvalues"); + if (!enumvalues) + Setattr(parentNode(n), "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + } + + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * Used for wrapping constants - #define or %constant. + * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). + * Java static final variables are generated for these. + * If the %javaconst(1) feature is used then the C constant value is used to initialise the Java final variable. + * If not, a JNI method is generated to get the C constant value for initialisation of the Java final variable. + * However, if the %javaconstvalue feature is used, it overrides all other ways to generate the initialisation. + * Also note that this method might be called for wrapping enum items (when the enum is using %javaconst(0)). + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + // The %javaconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:java:const"); + + /* Adjust the enum type for the Swig_typemap_lookup. + * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ + if (is_enum_item) { + t = Getattr(parentNode(n), "enumtype"); + Setattr(n, "type", t); + } + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("jstype", l, NULL); + + /* Get Java return types */ + bool classname_substituted_flag = false; + + if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { + classname_substituted_flag = substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + // Add the stripped quotes back in + String *new_value = NewString(""); + Swig_save("constantWrapper", n, "value", NIL); + if (SwigType_type(t) == T_STRING) { + Printf(new_value, "\"%s\"", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } else if (SwigType_type(t) == T_CHAR) { + Printf(new_value, "\'%s\'", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } + + const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + Printf(constants_code, " %s final static %s %s = ", methodmods, return_type, itemname); + + // Check for the %javaconstvalue feature + String *value = Getattr(n, "feature:java:constvalue"); + + if (value) { + Printf(constants_code, "%s;\n", value); + } else if (!const_feature_flag) { + // Default enum and constant handling will work with any type of C constant and initialises the Java variable from C through a JNI call. + + if (classname_substituted_flag) { + if (SwigType_isenum(t)) { + // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) + Printf(constants_code, "%s.swigToEnum(%s.%s());\n", return_type, imclass_name, Swig_name_get(symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(symname)); + } + } else + Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(symname)); + + // Each constant and enum value is wrapped with a separate JNI function call + SetFlag(n, "feature:immutable"); + enum_constant_flag = true; + variableWrapper(n); + enum_constant_flag = false; + } else { + // Alternative constant handling will use the C syntax to make a true Java constant and hope that it compiles as Java code + Printf(constants_code, "%s;\n", Getattr(n, "value")); + } + + // Emit the generated code to appropriate place + // Enums only emit the intermediate and JNI methods, so no proxy or module class wrapper methods needed + if (!is_enum_item) { + if (proxy_flag && wrapping_member_flag) + Printv(proxy_class_constants_code, constants_code, NIL); + else + Printv(module_class_constants_code, constants_code, NIL); + } + // Cleanup + Swig_restore(n); + Delete(new_value); + Delete(return_type); + Delete(constants_code); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * insertDirective() + * ----------------------------------------------------------------------------- */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + return Language::insertDirective(n); + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * jniclassbase - base (extends) for the intermediary class + * jniclassclassmodifiers - class modifiers for the intermediary class + * jniclasscode - text (java code) is copied verbatim to the intermediary class + * jniclassimports - import statements for the intermediary class + * jniclassinterfaces - interface (implements) for the intermediary class + * + * modulebase - base (extends) for the module class + * moduleclassmodifiers - class modifiers for the module class + * modulecode - text (java code) is copied verbatim to the module class + * moduleimports - import statements for the module class + * moduleinterfaces - interface (implements) for the module class + * + * ----------------------------------------------------------------------------- */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *code = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "java") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); + + if (Strcmp(code, "jniclassbase") == 0) { + Delete(imclass_baseclass); + imclass_baseclass = Copy(strvalue); + } else if (Strcmp(code, "jniclassclassmodifiers") == 0) { + Delete(imclass_class_modifiers); + imclass_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "jniclasscode") == 0) { + Printf(imclass_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "jniclassimports") == 0) { + Delete(imclass_imports); + imclass_imports = Copy(strvalue); + } else if (Strcmp(code, "jniclassinterfaces") == 0) { + Delete(imclass_interfaces); + imclass_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(module_class_modifiers); + module_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(module_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "moduleimports") == 0) { + Delete(module_imports); + module_imports = Copy(strvalue); + } else if (Strcmp(code, "moduleinterfaces") == 0) { + Delete(module_interfaces); + module_interfaces = Copy(strvalue); + } else if (Strcmp(code, "moduleimport") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use the moduleimports pragma.\n", input_file, line_number); + } else if (Strcmp(code, "moduleinterface") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use the moduleinterfaces pragma.\n", input_file, line_number); + } else if (Strcmp(code, "modulemethodmodifiers") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%javamethodmodifiers.\n", input_file, line_number); + } else if (Strcmp(code, "allshadowimport") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaimports).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowcode") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javacode).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowbase") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javabase).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowinterface") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javainterfaces).\n", input_file, line_number); + } else if (Strcmp(code, "allshadowclassmodifiers") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n", input_file, line_number); + } else if (proxy_flag) { + if (Strcmp(code, "shadowcode") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javacode).\n", input_file, line_number); + } else if (Strcmp(code, "shadowimport") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaimports).\n", input_file, line_number); + } else if (Strcmp(code, "shadowbase") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javabase).\n", input_file, line_number); + } else if (Strcmp(code, "shadowinterface") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javainterfaces).\n", input_file, line_number); + } else if (Strcmp(code, "shadowclassmodifiers") == 0) { + Printf(stderr, "%s : Line %d. Ignored: Deprecated pragma. Please use %%typemap(javaclassmodifiers).\n", input_file, line_number); + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + + // Inheritance from pure Java classes + Node *attributes = NewHash(); + const String *pure_baseclass = typemapLookup(n, "javabase", typemap_lookup_type, WARN_NONE, attributes); + bool purebase_replace = GetFlag(attributes, "tmap:javabase:replace") ? true : false; + bool purebase_notderived = GetFlag(attributes, "tmap:javabase:notderived") ? true : false; + Delete(attributes); + + // C++ inheritance + if (!purebase_replace) { + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (base.item) { + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + base = Next(base); + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (derived && purebase_notderived) + pure_baseclass = empty_string; + const String *wanted_base = baseclass ? baseclass : pure_baseclass; + + if (purebase_replace) { + wanted_base = pure_baseclass; + derived = false; + Delete(baseclass); + baseclass = NULL; + if (purebase_notderived) + Swig_error(input_file, line_number, "The javabase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_JAVA_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Java. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure Java interfaces + const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); + + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $javaclassname", // Class name and bases + (*Char(wanted_base)) ? " extends " : "", wanted_base, *Char(pure_interfaces) ? // Pure Java interfaces + " implements " : "", pure_interfaces, " {", derived ? typemapLookup(n, "javabody_derived", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF) : // main body of class + typemapLookup(n, "javabody", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class + NIL); + + // C++ destructor is wrapped by the delete method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + attributes = NewHash(); + String *destruct_methodname = NULL; + String *destruct_methodmodifiers = NULL; + if (derived) { + tm = typemapLookup(n, "javadestruct_derived", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:javadestruct_derived:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:javadestruct_derived:methodmodifiers"); + } else { + tm = typemapLookup(n, "javadestruct", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:javadestruct:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:javadestruct:methodmodifiers"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(input_file, line_number, + "No methodname attribute defined in javadestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(input_file, line_number, + "No methodmodifiers attribute defined in javadestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + } + } + // Emit the finalize and delete methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "javafinalize", typemap_lookup_type, WARN_NONE), NIL); + } + // delete method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$jnicall", destructor_call); + else + Replaceall(destruct, "$jnicall", "throw new UnsupportedOperationException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) + Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " void ", destruct_methodname, "()", destructor_throws_clause, " ", destruct, "\n", NIL); + } + + /* Insert directordisconnect typemap, if this class has directors enabled */ + /* Also insert the swigTakeOwnership and swigReleaseOwnership methods */ + if (feature_director) { + String *destruct_jnicall, *release_jnicall, *take_jnicall; + + destruct_jnicall = NewStringf("%s()", destruct_methodname); + release_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, false)", imclass_name, proxy_class_name); + take_jnicall = NewStringf("%s.%s_change_ownership(this, swigCPtr, true)", imclass_name, proxy_class_name); + + emitCodeTypemap(n, false, typemap_lookup_type, "directordisconnect", "methodname", destruct_jnicall); + emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_release", "methodname", release_jnicall); + emitCodeTypemap(n, false, typemap_lookup_type, "directorowner_take", "methodname", take_jnicall); + + Delete(destruct_jnicall); + Delete(release_jnicall); + Delete(take_jnicall); + } + + Delete(attributes); + Delete(destruct); + + // Emit extra user code + Printv(proxy_class_def, typemapLookup(n, "javacode", typemap_lookup_type, WARN_NONE), // extra Java code + "\n", NIL); + + // Substitute various strings into the above template + Replaceall(proxy_class_code, "$javaclassname", proxy_class_name); + Replaceall(proxy_class_def, "$javaclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(imclass_cppcasts_code, " public final static native long SWIG$javaclassnameUpcast(long jarg1);\n", NIL); + + Replaceall(imclass_cppcasts_code, "$javaclassname", proxy_class_name); + + Printv(upcasts_code, + "SWIGEXPORT jlong JNICALL Java_$jnipackage$imimclass_SWIG$imclazznameUpcast", + "(JNIEnv *jenv, jclass jcls, jlong jarg1) {\n", + " jlong baseptr = 0;\n" + " (void)jenv;\n" " (void)jcls;\n" " *($cbaseclass **)&baseptr = *($cclass **)&jarg1;\n" " return baseptr;\n" "}\n", "\n", NIL); + + String *imimclass = makeValidJniName(imclass_name); + String *imclazzname = makeValidJniName(proxy_class_name); + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", imclazzname); + Replaceall(upcasts_code, "$cclass", c_classname); + Replaceall(upcasts_code, "$jnipackage", jnipackage); + Replaceall(upcasts_code, "$imimclass", imimclass); + + Delete(imclazzname); + Delete(imimclass); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + if (Cmp(proxy_class_name, imclass_name) == 0) { + Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + if (Cmp(proxy_class_name, module_class_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the proxy class file + emitBanner(f_proxy); + + if (Len(package) > 0) + Printf(f_proxy, "package %s;\n", package); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + destructor_call = NewString(""); + destructor_throws_clause = NewString(""); + proxy_class_constants_code = NewString(""); + } + + Language::classHandler(n); + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + Replaceall(proxy_class_constants_code, "$module", module_class_name); + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", imclass_name); + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) + Printv(f_proxy, proxy_class_constants_code, NIL); + + Printf(f_proxy, "}\n"); + Close(f_proxy); + f_proxy = NULL; + + /* Output the downcast method, if necessary. Note: There's no other really + good place to put this code, since Abstract Base Classes (ABCs) can and should have + downcasts, making the constructorHandler() a bad place (because ABCs don't get to + have constructors emitted.) */ + if (GetFlag(n, "feature:javadowncast")) { + String *jni_imclass_name = makeValidJniName(imclass_name); + String *jni_class_name = makeValidJniName(proxy_class_name); + String *norm_name = SwigType_namestr(Getattr(n, "name")); + + Printf(imclass_class_code, " public final static native %s downcast%s(long cPtrBase, boolean cMemoryOwn);\n", proxy_class_name, proxy_class_name); + + Wrapper *dcast_wrap = NewWrapper(); + + Printf(dcast_wrap->def, "SWIGEXPORT jobject JNICALL Java_%s%s_downcast%s(JNIEnv *jenv, jclass jcls, jlong jCPtrBase, jboolean cMemoryOwn) {", + jnipackage, jni_imclass_name, jni_class_name); + Printf(dcast_wrap->code, " Swig::Director *director = (Swig::Director *) 0;\n"); + Printf(dcast_wrap->code, " jobject jresult = (jobject) 0;\n"); + Printf(dcast_wrap->code, " %s *obj = *((%s **)&jCPtrBase);\n", norm_name, norm_name); + Printf(dcast_wrap->code, " if (obj) director = dynamic_cast<Swig::Director *>(obj);\n"); + Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self(jenv);\n"); + Printf(dcast_wrap->code, " return jresult;\n"); + Printf(dcast_wrap->code, "}\n"); + + Wrapper_print(dcast_wrap, f_wrappers); + DelWrapper(dcast_wrap); + } + + emitDirectorExtraMethods(n); + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + Delete(destructor_throws_clause); + destructor_throws_clause = NULL; + Delete(proxy_class_constants_code); + proxy_class_constants_code = NULL; + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + member_func_flag = true; + Language::memberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + member_func_flag = false; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + member_func_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + member_func_flag = false; + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a Java wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to Java static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the Java class proxy function, which in turn will call "imfuncname" - + * the intermediary (JNI) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + + if (!proxy_flag) + return; + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in directors + if (GetFlag(n, "explicitcall")) + return; + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("jtype", l, NULL); + Swig_typemap_attach_parms("jstype", l, NULL); + Swig_typemap_attach_parms("javain", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { + // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type + SwigType *covariant = Getattr(n, "covariant"); + substituteClassname(covariant ? covariant : t, tm); + Printf(return_type, "%s", tm); + if (covariant) + Swig_warning(WARN_JAVA_COVARIANT_RET, input_file, line_number, + "Covariant return types not supported in Java. Proxy method will return %s.\n", SwigType_str(covariant, 0)); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // For wrapping member variables (Javabean setter) + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) == 0); + } + + /* Start generating the proxy function */ + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s ", methodmods); + if (static_flag) + Printf(function_code, "static "); + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + Printv(imcall, imclass_name, ".$imfuncname(", NIL); + if (!static_flag) { + Printf(imcall, "swigCPtr"); + + String *this_type = Copy(getClassType()); + String *name = NewString("self"); + String *qualifier = Getattr(n, "qualifier"); + if (qualifier) + SwigType_push(this_type, qualifier); + SwigType_add_pointer(this_type); + Parm *this_parm = NewParm(this_type, name); + Swig_typemap_attach_parms("jtype", this_parm, NULL); + Swig_typemap_attach_parms("jstype", this_parm, NULL); + + if (prematureGarbageCollectionPreventionParameter(this_type, this_parm)) + Printf(imcall, ", this"); + + Delete(this_parm); + Delete(name); + Delete(this_type); + } + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0) || static_flag) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Java parameter type */ + if ((tm = Getattr(p, "tmap:jstype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, setter_flag); + + // Use typemaps to transform type used in Java proxy wrapper (in proxy class) to type used in JNI function (in intermediary class) + if ((tm = Getattr(p, "tmap:javain"))) { + addThrows(n, "tmap:javain", p); + substituteClassname(pt, tm); + Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in proxy class) + if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) { + addThrows(n, "tmap:javaout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + + // For director methods: generate code to selectively make a normal polymorphic call or + // an explicit method call - needed to prevent infinite recursion calls in director methods. + Node *explicit_n = Getattr(n, "explicitcallnode"); + if (explicit_n) { + String *ex_overloaded_name = getOverloadedName(explicit_n); + String *ex_intermediary_function_name = Swig_name_member(proxy_class_name, ex_overloaded_name); + + String *ex_imcall = Copy(imcall); + Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); + Replaceall(imcall, "$imfuncname", intermediary_function_name); + + String *excode = NewString(""); + if (!Cmp(return_type, "void")) + Printf(excode, "if (getClass() == %s.class) %s; else %s", proxy_class_name, imcall, ex_imcall); + else + Printf(excode, "(getClass() == %s.class) ? %s : %s", proxy_class_name, imcall, ex_imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + Delete(ex_overloaded_name); + Delete(excode); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + + Replaceall(tm, "$jnicall", imcall); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number, "No javaout typemap defined for %s\n", SwigType_str(t, 0)); + } + + generateThrowsClause(n, function_code); + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(proxy_class_code, function_code, NIL); + + Delete(pre_code); + Delete(post_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *function_code = NewString(""); + String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the javain typemap has code in the pre or post attributes + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *im_return_type = NewString(""); + bool feature_director = (parentNode(n) && Swig_directorclass(n)); + + Language::constructorHandler(n); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in Java + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(overloaded_name); + String *imcall = NewString(""); + + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + tm = Getattr(n, "tmap:jtype"); // typemaps were attached earlier to the node + Printf(im_return_type, "%s", tm); + + Printf(function_code, " %s %s(", methodmods, proxy_class_name); + Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + + Printv(imcall, imclass_name, ".", mangled_overname, "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("jtype", l, NULL); + Swig_typemap_attach_parms("jstype", l, NULL); + Swig_typemap_attach_parms("javain", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Java parameter type */ + if ((tm = Getattr(p, "tmap:jstype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, false); + + // Use typemaps to transform type used in Java wrapper function (in proxy class) to type used in JNI function (in intermediary class) + if ((tm = Getattr(p, "tmap:javain"))) { + addThrows(n, "tmap:javain", p); + substituteClassname(pt, tm); + Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma) { + Printf(function_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } + Printf(function_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", arg); + ++gencomma; + + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } + + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + + Printf(function_code, ")"); + Printf(helper_code, ")"); + generateThrowsClause(n, function_code); + + /* Insert the javaconstruct typemap, doing the replacement for $directorconnect, as needed */ + Hash *attributes = NewHash(); + String *construct_tm = Copy(typemapLookup(n, "javaconstruct", Getattr(n, "name"), + WARN_JAVA_TYPEMAP_JAVACONSTRUCT_UNDEF, attributes)); + if (construct_tm) { + if (!feature_director) { + Replaceall(construct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(attributes, "tmap:javaconstruct:directorconnect"); + + if (connect_attr) { + Replaceall(construct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_JAVA_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"javaconstruct\" typemap.\n", + Getattr(n, "name")); + Replaceall(construct_tm, "$directorconnect", ""); + } + } + + Printv(function_code, " ", construct_tm, "\n", NIL); + } + + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + generateThrowsClause(n, helper_code); + Printf(helper_code, " {\n"); + if (is_pre_code) { + Printv(helper_code, pre_code, "\n", NIL); + } + if (is_post_code) { + Printf(helper_code, " try {\n"); + Printv(helper_code, " return ", imcall, ";\n", NIL); + Printv(helper_code, " } finally {\n", post_code, "\n }", NIL); + } else { + Printv(helper_code, " return ", imcall, ";", NIL); + } + Printf(helper_code, "\n }\n"); + String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); + Printv(proxy_class_code, helper_code, "\n", NIL); + Replaceall(function_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(function_code, "$imcall", imcall); + } + + Printv(proxy_class_code, function_code, "\n", NIL); + + Delete(helper_args); + Delete(im_return_type); + Delete(pre_code); + Delete(post_code); + Delete(construct_tm); + Delete(attributes); + Delete(overloaded_name); + Delete(imcall); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, imclass_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + generateThrowsClause(n, destructor_throws_clause); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + Language::memberconstantHandler(n); + wrapping_member_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + + /* Although JNI functions are designed to handle overloaded Java functions, + * a Java long is used for all classes in the SWIG intermediary class. + * The intermediary class methods are thus mangled when overloaded to give + * a unique name. */ + String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * moduleClassFunctionHandler() + * ----------------------------------------------------------------------------- */ + + void moduleClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + int num_required = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("jstype", l, NULL); + Swig_typemap_attach_parms("javain", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("jstype", n, "", 0))) { + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (proxy_flag && global_variable_flag) { + // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name + func_name = NewString(""); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(variable_name)) == 0); + if (setter_flag) + Printf(func_name, "set"); + else + Printf(func_name, "get"); + Putc(toupper((int) *Char(variable_name)), func_name); + Printf(func_name, "%s", Char(variable_name) + 1); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *methodmods = Getattr(n, "feature:java:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name); + Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; i < num_arguments; i++) { + + /* Ignored parameters */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Java parameter type */ + if ((tm = Getattr(p, "tmap:jstype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JSTYPE_UNDEF, input_file, line_number, "No jstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, global_or_member_variable); + + // Use typemaps to transform type used in Java wrapper function (in proxy class) to type used in JNI function (in intermediary class) + if ((tm = Getattr(p, "tmap:javain"))) { + addThrows(n, "tmap:javain", p); + substituteClassname(pt, tm); + Replaceall(tm, "$javainput", arg); + String *pre = Getattr(p, "tmap:javain:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$javainput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:javain:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$javainput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAIN_UNDEF, input_file, line_number, "No javain typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to module class function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + if (prematureGarbageCollectionPreventionParameter(pt, p)) { + String *pgcppname = Getattr(p, "tmap:javain:pgcppname"); + if (pgcppname) { + String *argname = Copy(pgcppname); + Replaceall(argname, "$javainput", arg); + Printf(imcall, ", %s", argname); + Delete(argname); + } else { + Printf(imcall, ", %s", arg); + } + } + + p = Getattr(p, "tmap:in:next"); + Delete(arg); + Delete(param_type); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in JNI function (in intermediary class) to type used in Java wrapper function (in module class) + if ((tm = Swig_typemap_lookup("javaout", n, "", 0))) { + addThrows(n, "tmap:javaout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + if (is_pre_code || is_post_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$jnicall", imcall); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVAOUT_UNDEF, input_file, line_number, "No javaout typemap defined for %s\n", SwigType_str(t, 0)); + } + + generateThrowsClause(n, function_code); + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(module_class_code, function_code, NIL); + + Delete(pre_code); + Delete(post_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(func_name); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /*---------------------------------------------------------------------- + * decodeEnumFeature() + * Decode the possible enum features, which are one of: + * %javaenum(simple) + * %javaenum(typeunsafe) - default + * %javaenum(typesafe) + * %javaenum(proper) + *--------------------------------------------------------------------*/ + + EnumFeature decodeEnumFeature(Node *n) { + EnumFeature enum_feature = TypeunsafeEnum; + String *feature = Getattr(n, "feature:java:enum"); + if (feature) { + if (Cmp(feature, "simple") == 0) + enum_feature = SimpleEnum; + else if (Cmp(feature, "typesafe") == 0) + enum_feature = TypesafeEnum; + else if (Cmp(feature, "proper") == 0) + enum_feature = ProperEnum; + } + return enum_feature; + } + + /* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in Java generated + * code. If the %javaconst feature is not used, the string will contain the intermediary + * class call to obtain the enum value. The intermediary class and JNI methods to obtain + * the enum value will be generated. Otherwise the C/C++ enum value will be used if there + * is one and hopefully it will compile as Java code - e.g. 20 as in: enum E{e=20}; + * The %javaconstvalue feature overrides all other ways to generate the constant value. + * The caller must delete memory allocated for the returned string. + * ------------------------------------------------------------------------ */ + + String *enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + + // Check for the %javaconstvalue feature + String *value = Getattr(n, "feature:java:constvalue"); + + if (!value) { + // The %javaconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:java:const"); + + if (const_feature_flag) { + // Use the C syntax to make a true Java constant and hope that it compiles as Java code + value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); + } else { + // Get the enumvalue from a JNI call + if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(Swig_name_member(proxy_class_name, symname))); + } + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * + * If jnidescriptor is set, inner class names are separated with '$' otherwise a '.' + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t, bool jnidescriptor) { + Node *enum_name = NULL; + Node *n = enumLookup(t); + if (n) { + String *symname = Getattr(n, "sym:name"); + if (symname) { + // Add in class scope when referencing enum if not a global enum + String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); + String *proxyname = 0; + if (scopename_prefix) { + proxyname = getProxyName(scopename_prefix); + } + if (proxyname) { + const char *class_separator = jnidescriptor ? "$" : "."; + enum_name = NewStringf("%s%s%s", proxyname, class_separator, symname); + } else { + enum_name = NewStringf("%s", symname); + } + Delete(scopename_prefix); + } + } + + return enum_name; + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $javaclassname with the proxy class name for classes/structs/unions + * that SWIG knows about. Also substitutes enums with enum name. + * Otherwise use the $descriptor name for the Java class name. Note that the $&javaclassname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * jnidescriptor - if set, inner class names are separated with '$' otherwise a '.' + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm, bool jnidescriptor = false) { + bool substitution_performed = false; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + SwigType *strippedtype = SwigType_strip_qualifiers(type); + + if (Strstr(tm, "$javaclassname")) { + SwigType *classnametype = Copy(strippedtype); + substituteClassnameSpecialVariable(classnametype, tm, "$javaclassname", jnidescriptor); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$*javaclassname")) { + SwigType *classnametype = Copy(strippedtype); + Delete(SwigType_pop(classnametype)); + substituteClassnameSpecialVariable(classnametype, tm, "$*javaclassname", jnidescriptor); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$&javaclassname")) { + SwigType *classnametype = Copy(strippedtype); + SwigType_add_pointer(classnametype); + substituteClassnameSpecialVariable(classnametype, tm, "$&javaclassname", jnidescriptor); + substitution_performed = true; + Delete(classnametype); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable, bool jnidescriptor) { + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype, jnidescriptor); + if (enumname) + Replaceall(tm, classnamespecialvariable, enumname); + else + Replaceall(tm, classnamespecialvariable, NewStringf("int")); + } else { + String *classname = getProxyName(classnametype); + if (classname) { + Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replaceall(tm, classnamespecialvariable, descriptor); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, classnametype); + Delete(descriptor); + } + } + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) { + + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0; + arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn); + + if (setter && Cmp(arg, "self") != 0) { + // Note that for setters the parameter name is always set but sometimes includes C++ + // scope resolution, so we need to strip off the scope resolution to make a valid name. + Delete(arg); + arg = NewString("value"); //Swig_scopename_last(pn); + } + + return arg; + } + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *swigtype = NewString(""); + String *filen = NewStringf("%s%s.java", SWIG_output_directory(), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the type wrapper class file + emitBanner(f_swigtype); + + if (Len(package) > 0) + Printf(f_swigtype, "package %s;\n", package); + + // Pure Java baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "javabase", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "javainterfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "javaimports", type, WARN_NONE), // Import statements + "\n", typemapLookup(n, "javaclassmodifiers", type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $javaclassname", // Class name and bases + *Char(pure_baseclass) ? " extends " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " implements " : "", pure_interfaces, " {", typemapLookup(n, "javabody", type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF), // main body of class + typemapLookup(n, "javacode", type, WARN_NONE), // extra Java code + "}\n", "\n", NIL); + + Replaceall(swigtype, "$javaclassname", classname); + Replaceall(swigtype, "$module", module_class_name); + Replaceall(swigtype, "$imclassname", imclass_name); + Printv(f_swigtype, swigtype, NIL); + + Close(f_swigtype); + Delete(swigtype); + Delete(n); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * n - for input only and must contain info for Getfile(n) and Getline(n) to work + * tmap_method - typemap method name + * type - typemap type to lookup + * warning - warning number to issue if no typemaps found + * typemap_attributes - the typemap attributes are attached to this node and will + * also be used for temporary storage if non null + * return is never NULL, unlike Swig_typemap_lookup() + * ----------------------------------------------------------------------------- */ + + const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + Node *node = !typemap_attributes ? NewHash() : typemap_attributes; + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + if (!tm) { + tm = empty_string; + if (warning != WARN_NONE) + Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); + } + if (!typemap_attributes) + Delete(node); + return tm; + } + + /* ----------------------------------------------------------------------------- + * addThrows() + * + * Adds exception classes to a throws list. The throws list is the list of classes + * that will form the Java throws clause. Mainly for checked exceptions. + * ----------------------------------------------------------------------------- */ + + void addThrows(Node *n, const String *attribute, Node *parameter) { + // Get the comma separated exception classes for the throws clause - held in typemap/feature's "throws" attribute + String *throws_attribute = NewStringf("%s:throws", attribute); + String *throws = Getattr(parameter, throws_attribute); + + if (throws && Len(throws) > 0) { + String *throws_list = Getattr(n, "java:throwslist"); + if (!throws_list) { + throws_list = NewList(); + Setattr(n, "java:throwslist", throws_list); + } + // Put the exception classes in the throws clause into a temporary List + List *temp_classes_list = Split(throws, ',', INT_MAX); + + // Add the exception classes to the node throws list, but don't duplicate if already in list + if (temp_classes_list && Len(temp_classes_list) > 0) { + for (Iterator cls = First(temp_classes_list); cls.item; cls = Next(cls)) { + String *exception_class = NewString(cls.item); + Replaceall(exception_class, " ", ""); // remove spaces + Replaceall(exception_class, "\t", ""); // remove tabs + if (Len(exception_class) > 0) { + // $javaclassname substitution + SwigType *pt = Getattr(parameter, "type"); + substituteClassname(pt, exception_class); + + // Don't duplicate the Java exception class in the throws clause + bool found_flag = false; + for (Iterator item = First(throws_list); item.item; item = Next(item)) { + if (Strcmp(item.item, exception_class) == 0) + found_flag = true; + } + if (!found_flag) + Append(throws_list, exception_class); + } + Delete(exception_class); + } + } + Delete(temp_classes_list); + } + Delete(throws_attribute); + } + + /* ----------------------------------------------------------------------------- + * generateThrowsClause() + * + * Generates throws clause for checked exception + * ----------------------------------------------------------------------------- */ + + void generateThrowsClause(Node *n, String *code) { + // Add the throws clause into code + List *throws_list = Getattr(n, "java:throwslist"); + if (throws_list) { + Iterator cls = First(throws_list); + Printf(code, " throws %s", cls.item); + while ((cls = Next(cls)).item) + Printf(code, ", %s", cls.item); + } + } + + /* ----------------------------------------------------------------------------- + * prematureGarbageCollectionPreventionParameter() + * + * Get the proxy class name for use in an additional generated parameter. The + * additional parameter is added to a native method call purely to prevent + * premature garbage collection of proxy classes which pass their C++ class pointer + * in a Java long to the JNI layer. + * ----------------------------------------------------------------------------- */ + + String *prematureGarbageCollectionPreventionParameter(SwigType *t, Parm *p) { + String *proxyClassName = 0; + String *jtype = NewString(Getattr(p, "tmap:jtype")); + + // Strip C comments + String *stripped_jtype = Swig_strip_c_comments(jtype); + if (stripped_jtype) { + Delete(jtype); + jtype = stripped_jtype; + } + + // Remove whitespace + Replaceall(jtype, " ", ""); + Replaceall(jtype, "\t", ""); + + if (Cmp(jtype, "long") == 0) { + if (proxy_flag) { + if (!GetFlag(p, "tmap:jtype:nopgcpp") && !nopgcpp_flag) { + Node *n = classLookup(t); + if (n) { + // Found a struct/class parameter passed by value, reference, pointer, or pointer reference + proxyClassName = Getattr(n, "sym:name"); + } else { + // Look for proxy class parameters passed to C++ layer using non-default typemaps, ie not one of above types + String *jstype = NewString(Getattr(p, "tmap:jstype")); + if (jstype) { + Hash *classes = getClassHash(); + if (classes) { + // Strip C comments + String *stripped_jstype = Swig_strip_c_comments(jstype); + if (stripped_jstype) { + Delete(jstype); + jstype = stripped_jstype; + } + // Remove whitespace + Replaceall(jstype, " ", ""); + Replaceall(jstype, "\t", ""); + + Iterator ki; + for (ki = First(classes); ki.key; ki = Next(ki)) { + Node *cls = ki.item; + if (cls && !Getattr(cls, "feature:ignore")) { + String *symname = Getattr(cls, "sym:name"); + if (symname && Strcmp(symname, jstype) == 0) { + proxyClassName = symname; + } + } + } + } + } + Delete(jstype); + } + } + } + } + Delete(jtype); + return proxyClassName; + } + + /*---------------------------------------------------------------------- + * Start of director methods + *--------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------- + * getUpcallJNIMethod() + *--------------------------------------------------------------------*/ + + String *getUpcallJNIMethod(String *descrip) { + static struct { + char code; + const char *method; + } upcall_methods[] = { + { + 'B', "CallStaticByteMethod"}, { + 'C', "CallStaticCharMethod"}, { + 'D', "CallStaticDoubleMethod"}, { + 'F', "CallStaticFloatMethod"}, { + 'I', "CallStaticIntMethod"}, { + 'J', "CallStaticLongMethod"}, { + 'L', "CallStaticObjectMethod"}, { + 'S', "CallStaticShortMethod"}, { + 'V', "CallStaticVoidMethod"}, { + 'Z', "CallStaticBooleanMethod"}, { + '[', "CallStaticObjectMethod"} + }; + + char code; + int i; + + code = *Char(descrip); + for (i = 0; i < (int) (sizeof(upcall_methods) / sizeof(upcall_methods[0])); ++i) + if (code == upcall_methods[i].code) + return NewString(upcall_methods[i].method); + return NULL; + } + + /*---------------------------------------------------------------------- + * emitDirectorUpcalls() + *--------------------------------------------------------------------*/ + + void emitDirectorUpcalls() { + if (n_dmethods) { + Wrapper *w = NewWrapper(); + String *jni_imclass_name = makeValidJniName(imclass_name); + String *swig_module_init = NewString("swig_module_init"); + String *swig_module_init_jni = makeValidJniName(swig_module_init); + String *dmethod_data = NewString(""); + int n_methods = 0; + Iterator udata_iter; + + udata_iter = First(dmethods_seq); + while (udata_iter.item) { + UpcallData *udata = udata_iter.item; + Printf(dmethod_data, " { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); + ++n_methods; + + udata_iter = Next(udata_iter); + + if (udata_iter.item) + Putc(',', dmethod_data); + Putc('\n', dmethod_data); + } + + Printf(f_runtime, "namespace Swig {\n"); + Printf(f_runtime, " static jclass jclass_%s = NULL;\n", imclass_name); + Printf(f_runtime, " static jmethodID director_methids[%d];\n", n_methods); + Printf(f_runtime, "}\n"); + + Printf(w->def, "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls) {", jnipackage, jni_imclass_name, swig_module_init_jni); + Printf(w->code, "static struct {\n"); + Printf(w->code, " const char *method;\n"); + Printf(w->code, " const char *signature;\n"); + Printf(w->code, "} methods[%d] = {\n", n_methods); + Printv(w->code, dmethod_data, NIL); + Printf(w->code, "};\n"); + + Wrapper_add_local(w, "i", "int i"); + + Printf(w->code, "Swig::jclass_%s = (jclass) jenv->NewGlobalRef(jcls);\n", imclass_name); + Printf(w->code, "if (!Swig::jclass_%s) return;\n", imclass_name); + Printf(w->code, "for (i = 0; i < (int) (sizeof(methods)/sizeof(methods[0])); ++i) {\n"); + Printf(w->code, " Swig::director_methids[i] = jenv->GetStaticMethodID(jcls, methods[i].method, methods[i].signature);\n"); + Printf(w->code, " if (!Swig::director_methids[i]) return;\n"); + Printf(w->code, "}\n"); + + Printf(w->code, "}\n"); + + Wrapper_print(w, f_wrappers); + Delete(dmethod_data); + Delete(swig_module_init_jni); + Delete(swig_module_init); + Delete(jni_imclass_name); + DelWrapper(w); + } + } + + /*---------------------------------------------------------------------- + * emitDirectorExtraMethods() + * + * This is where the $javaclassname_director_connect is + * generated. + *--------------------------------------------------------------------*/ + void emitDirectorExtraMethods(Node *n) { + if (!Swig_directorclass(n)) + return; + + // Output the director connect method: + String *jni_imclass_name = makeValidJniName(imclass_name); + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name); + String *swig_director_connect_jni = makeValidJniName(swig_director_connect); + String *sym_name = Getattr(n, "sym:name"); + Wrapper *code_wrap; + + Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean mem_own, boolean weak_global);\n", + swig_director_connect, proxy_class_name); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, + "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jswig_mem_own, " + "jboolean jweak_global) {\n", jnipackage, jni_imclass_name, swig_director_connect_jni); + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_connect_director(jenv, jself, jenv->GetObjectClass(jself), " + "(jswig_mem_own == JNI_TRUE), (jweak_global == JNI_TRUE));\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect_jni); + Delete(swig_director_connect); + + // Output the swigReleaseOwnership, swigTakeOwnership methods: + String *changeown_method_name = NewStringf("%s_change_ownership", proxy_class_name); + String *changeown_jnimethod_name = makeValidJniName(changeown_method_name); + + Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", changeown_method_name, proxy_class_name); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, + "SWIGEXPORT void JNICALL Java_%s%s_%s(JNIEnv *jenv, jclass jcls, jobject jself, jlong objarg, jboolean jtake_or_release) {\n", + jnipackage, jni_imclass_name, changeown_jnimethod_name); + Printf(code_wrap->code, " %s *obj = *((%s **)&objarg);\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + Printf(code_wrap->code, " (void)jcls;\n"); + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_java_change_ownership(jenv, jself, jtake_or_release ? true : false);\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(changeown_method_name); + Delete(changeown_jnimethod_name); + Delete(norm_name); + Delete(jni_imclass_name); + } + + /*---------------------------------------------------------------------- + * emitCodeTypemap() + * + * Output a code typemap that uses $methodname and $jnicall, as used + * in the directordisconnect, director_release and director_take + * typemaps. + *--------------------------------------------------------------------*/ + + void emitCodeTypemap(Node *n, bool derived, SwigType *lookup_type, const String *typemap, const String *methodname, const String *jnicall) { + const String *tm = NULL; + Node *tmattrs = NewHash(); + String *lookup_tmname = NewString(typemap); + String *method_attr_name; + String *method_attr; + + if (derived) { + Append(lookup_tmname, "_derived"); + } + + tm = typemapLookup(n, lookup_tmname, lookup_type, WARN_NONE, tmattrs); + method_attr_name = NewStringf("tmap:%s:%s", lookup_tmname, methodname); + method_attr = Getattr(tmattrs, method_attr_name); + + if (*Char(tm)) { + if (method_attr) { + String *codebody = Copy(tm); + Replaceall(codebody, "$methodname", method_attr); + Replaceall(codebody, "$jnicall", jnicall); + Append(proxy_class_def, codebody); + Delete(codebody); + } else { + Swig_error(input_file, line_number, "No %s method name attribute for %s\n", lookup_tmname, proxy_class_name); + } + } else { + Swig_error(input_file, line_number, "No %s typemap for %s\n", lookup_tmname, proxy_class_name); + } + + Delete(tmattrs); + Delete(lookup_tmname); + // Delete(method_attr); + } + + /* --------------------------------------------------------------- + * Canonicalize the JNI field descriptor + * + * Replace the $javapackage and $javaclassname family of special + * variables with the desired package and Java proxy name as + * required in the JNI field descriptors. + * + * !!SFM!! If $packagepath occurs in the field descriptor, but + * package_path isn't set (length == 0), then strip it and the + * optional trailing '/' from the resulting name. + * + * --------------------------------------------------------------- */ + + String *canonicalizeJNIDescriptor(String *descriptor_in, Parm *p) { + String *pkg_path = Swig_typemap_lookup("javapackage", p, "", 0); + SwigType *type = Getattr(p, "type"); + + if (pkg_path && Len(pkg_path) != 0) { + Replaceall(pkg_path, ".", "/"); + } else + pkg_path = package_path; + + String *descriptor_out = Copy(descriptor_in); + + if (Len(pkg_path) > 0) { + Replaceall(descriptor_out, "$packagepath", pkg_path); + } else { + Replaceall(descriptor_out, "$packagepath/", empty_string); + Replaceall(descriptor_out, "$packagepath", empty_string); + } + + substituteClassname(type, descriptor_out, true); + + if (pkg_path != package_path) + Delete(pkg_path); + + return descriptor_out; + } + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Java object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + String *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *returntype = Getattr(n, "returntype"); + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *tm; + Parm *p; + int i; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(returntype, "void")); + String *qualified_return = NewString(""); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + int status = SWIG_OK; + bool output_director = true; + String *dirclassname = directorClassName(parent); + String *qualified_name = NewStringf("%s::%s", dirclassname, name); + String *jnidesc = NewString(""); + String *classdesc = NewString(""); + String *jniret_desc = NewString(""); + String *classret_desc = NewString(""); + SwigType *c_ret_type = NULL; + String *jupcall_args = NewString("swigjobj"); + String *imclass_dmethod; + String *callback_def = NewString(""); + String *callback_code = NewString(""); + String *imcall_args = NewString(""); + int gencomma = 0; + int classmeth_off = curr_class_dmethod - first_class_dmethod; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + // Kludge Alert: functionWrapper sets sym:overload properly, but it + // isn't at this point, so we have to manufacture it ourselves. At least + // we're consistent with the sym:overload name in functionWrapper. (?? when + // does the overloaded method name get set?) + + imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(classname, overloaded_name)); + + if (returntype) { + + qualified_return = SwigType_rcaststr(returntype, "c_result"); + + if (!is_void && (!ignored_method || pure_virtual)) { + if (!SwigType_isclass(returntype)) { + if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + String *base_typename = SwigType_base(returntype); + String *resolved_typename = SwigType_typedef_resolve_all(base_typename); + Symtab *symtab = Getattr(n, "sym:symtab"); + Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + + if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default - if a Java exception occurs, then the pointer returns + something other than a NULL-initialized reference. */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= &result_default", NIL); + + Delete(non_ref_type); + } + + Delete(base_typename); + Delete(resolved_typename); + } + } else { + SwigType *vt; + + vt = cplus_value_type(returntype); + if (!vt) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); + Delete(vt); + } + } + } + + /* Create the intermediate class wrapper */ + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + tm = Swig_typemap_lookup("jtype", tp, "", 0); + if (tm) { + Printf(callback_def, " public static %s %s(%s self", tm, imclass_dmethod, classname); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s\n", SwigType_str(returntype, 0)); + } + + String *cdesc = NULL; + SwigType *covariant = Getattr(n, "covariant"); + SwigType *adjustedreturntype = covariant ? covariant : returntype; + Parm *adjustedreturntypeparm = NewParmFromNode(adjustedreturntype, empty_str, n); + + if ((tm = Swig_typemap_lookup("directorin", adjustedreturntypeparm, "", 0)) + && (cdesc = Getattr(adjustedreturntypeparm, "tmap:directorin:descriptor"))) { + + // Note that in the case of polymorphic (covariant) return types, the + // method's return type is changed to be the base of the C++ return + // type + String *jnidesc_canon = canonicalizeJNIDescriptor(cdesc, adjustedreturntypeparm); + Append(classret_desc, jnidesc_canon); + Delete(jnidesc_canon); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + /* Get the JNI field descriptor for this return type, add the JNI field descriptor + to jniret_desc */ + + Parm *retpm = NewParmFromNode(returntype, empty_str, n); + + if ((c_ret_type = Swig_typemap_lookup("jni", retpm, "", 0))) { + Parm *tp = NewParmFromNode(c_ret_type, empty_str, n); + + if (!is_void && !ignored_method) { + String *jretval_decl = NewStringf("%s jresult", c_ret_type); + Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); + Delete(jretval_decl); + } + + String *jdesc = NULL; + if ((tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (jdesc = Getattr(tp, "tmap:directorin:descriptor"))) { + + // Objects marshalled passing a Java class across JNI boundary use jobject - the nouse flag indicates this + // We need the specific Java class name instead of the generic 'Ljava/lang/Object;' + if (GetFlag(tp, "tmap:directorin:nouse")) + jdesc = cdesc; + String *jnidesc_canon = canonicalizeJNIDescriptor(jdesc, tp); + Append(jniret_desc, jnidesc_canon); + Delete(jnidesc_canon); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_ret_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(adjustedreturntypeparm); + Delete(retpm); + } + + /* Go through argument list, attach lnames for arguments */ + for (i = 0, p = l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + /* Attach the standard typemaps */ + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("jni", l, 0); + Swig_typemap_attach_parms("jtype", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("javadirectorin", l, 0); + + if (!ignored_method) { + /* Add Java environment pointer to wrapper */ + String *jenvstr = NewString("jenv"); + String *jobjstr = NewString("swigjobj"); + + Wrapper_add_localv(w, "swigjnienv", "JNIEnvWrapper", "swigjnienv(this)", NIL, NIL); + Wrapper_add_localv(w, jenvstr, "JNIEnv *", jenvstr, "= swigjnienv.getJNIEnv()", NIL); + Wrapper_add_localv(w, jobjstr, "jobject", jobjstr, "= (jobject) NULL", NIL); + Delete(jenvstr); + Delete(jobjstr); + + /* Preamble code */ + Printf(w->code, "if (!swig_override[%d]) {\n", classmeth_off); + } + + if (!pure_virtual) { + String *super_call = Swig_method_call(super, l); + if (is_void) { + Printf(w->code, "%s;\n", super_call); + if (!ignored_method) + Printf(w->code, "return;\n"); + } else { + Printf(w->code, "return %s;\n", super_call); + } + Delete(super_call); + } else { + Printf(w->code, "SWIG_JavaThrowException(JNIEnvWrapper(this).getJNIEnv(), SWIG_JavaDirectorPureVirtual, "); + Printf(w->code, "\"Attempted to invoke pure virtual method %s::%s.\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + + /* Make sure that we return something in the case of a pure + * virtual method call for syntactical reasons. */ + if (!is_void) + Printf(w->code, "return %s;", qualified_return); + else if (!ignored_method) + Printf(w->code, "return;\n"); + } + + if (!ignored_method) { + Printf(w->code, "}\n"); + Printf(w->code, "swigjobj = swig_get_self(jenv);\n"); + Printf(w->code, "if (swigjobj && jenv->IsSameObject(swigjobj, NULL) == JNI_FALSE) {\n"); + } + + /* Start the Java field descriptor for the intermediate class's upcall (insert self object) */ + Parm *tp = NewParmFromNode(c_classname, empty_str, n); + String *jdesc; + + if ((tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (jdesc = Getattr(tp, "tmap:directorin:descriptor"))) { + String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); + Append(jnidesc, jni_canon); + Delete(jni_canon); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap for type %s for use in %s::%s (skipping director method)\n", + SwigType_str(type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + + /* Go through argument list, convert from native to Java */ + for (p = l; p; /* empty */ ) { + /* Is this superfluous? */ + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Copy(Getattr(p, "name")); + String *c_param_type = NULL; + String *c_decl = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* Add various typemap's 'throws' clauses */ + addThrows(n, "tmap:directorin", p); + addThrows(n, "tmap:out", p); + + /* And add to the upcall args */ + Printf(jupcall_args, ", %s", arg); + + /* Get parameter's intermediary C type */ + if ((c_param_type = Getattr(p, "tmap:jni"))) { + Parm *tp = NewParmFromNode(c_param_type, empty_str, n); + String *desc_tm = NULL, *jdesc = NULL, *cdesc = NULL; + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + if (!ignored_method) + Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + + /* Add input marshalling code and update JNI field descriptor */ + if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (jdesc = Getattr(tp, "tmap:directorin:descriptor")) + && (tm = Getattr(p, "tmap:directorin")) + && (cdesc = Getattr(p, "tmap:directorin:descriptor"))) { + + // Objects marshalled by passing a Java class across the JNI boundary use jobject as the JNI type - + // the nouse flag indicates this. We need the specific Java class name instead of the generic 'Ljava/lang/Object;' + if (GetFlag(tp, "tmap:directorin:nouse")) + jdesc = cdesc; + String *jni_canon = canonicalizeJNIDescriptor(jdesc, tp); + Append(jnidesc, jni_canon); + Delete(jni_canon); + + Replaceall(tm, "$input", arg); + Replaceall(tm, "$owner", "0"); + + if (Len(tm)) + if (!ignored_method) + Printf(w->code, "%s\n", tm); + + Delete(tm); + + /* Add parameter to the intermediate class code if generating the + * intermediate's upcall code */ + if ((tm = Getattr(p, "tmap:jtype"))) { + String *din = Copy(Getattr(p, "tmap:javadirectorin")); + addThrows(n, "tmap:javadirectorin", p); + + if (din) { + Replaceall(din, "$module", module_class_name); + Replaceall(din, "$imclassname", imclass_name); + substituteClassname(pt, din); + Replaceall(din, "$jniinput", ln); + + if (++gencomma > 1) + Printf(imcall_args, ", "); + Printf(callback_def, ", %s %s", tm, ln); + + if (Cmp(din, ln)) { + Printv(imcall_args, din, NIL); + } else + Printv(imcall_args, ln, NIL); + + jni_canon = canonicalizeJNIDescriptor(cdesc, p); + Append(classdesc, jni_canon); + Delete(jni_canon); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, "No javadirectorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JTYPE_UNDEF, input_file, line_number, "No jtype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + p = Getattr(p, "tmap:directorin:next"); + + Delete(desc_tm); + } else { + if (!desc_tm) { + Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } else if (!jdesc) { + Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC, input_file, line_number, + "Missing JNI descriptor in directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = Getattr(p, "tmap:directorin:next"); + } else if (!tm) { + Swig_warning(WARN_JAVA_TYPEMAP_JAVADIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } else if (!cdesc) { + Swig_warning(WARN_JAVA_TYPEMAP_DIRECTORIN_NODESC, input_file, line_number, + "Missing JNI descriptor in directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = Getattr(p, "tmap:directorin:next"); + } + + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_JAVA_TYPEMAP_JNI_UNDEF, input_file, line_number, "No jni typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + } + + /* header declaration, start wrapper definition */ + String *target; + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Add any exception specifications to the methods in the director class + // Get any Java exception classes in the throws typemap + ParmList *throw_parm_list = NULL; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + addThrows(n, "tmap:throws", p); + + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* Emit the intermediate class's upcall to the actual class */ + + String *upcall = NewStringf("self.%s(%s)", symname, imcall_args); + + if (!is_void) { + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + if ((tm = Swig_typemap_lookup("javadirectorout", tp, "", 0))) { + addThrows(n, "tmap:javadirectorout", tp); + substituteClassname(returntype, tm); + Replaceall(tm, "$javacall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + if ((tm = Swig_typemap_lookup("out", tp, "", 0))) + addThrows(n, "tmap:out", tp); + + Delete(tm); + Delete(tp); + } else + Printf(callback_code, " %s;\n", upcall); + + Printf(callback_code, " }\n"); + Delete(upcall); + + /* Finish off the inherited upcall's definition */ + Putc(')', callback_def); + generateThrowsClause(n, callback_def); + Printf(callback_def, " {\n"); + + if (!ignored_method) { + /* Emit the actual upcall through */ + String *imclass_desc = NewStringf("(%s)%s", jnidesc, jniret_desc); + String *class_desc = NewStringf("(%s)%s", classdesc, classret_desc); + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, imclass_desc, class_desc, decl); + String *methid = Getattr(udata, "imclass_methodidx"); + String *methop = getUpcallJNIMethod(jniret_desc); + + if (!is_void) + Printf(w->code, "jresult = (%s) ", c_ret_type); + + Printf(w->code, "jenv->%s(Swig::jclass_%s, Swig::director_methids[%s], %s);\n", methop, imclass_name, methid, jupcall_args); + + Printf(w->code, "if (jenv->ExceptionOccurred()) return $null;\n"); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("c_result"); + Parm *tp = NewParmFromNode(returntype, result_str, n); + + /* Copy jresult into c_result... */ + if ((tm = Swig_typemap_lookup("directorout", tp, result_str, w))) { + addThrows(n, "tmap:directorout", tp); + Replaceall(tm, "$input", jresult_str); + Replaceall(tm, "$result", result_str); + Printf(w->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s used in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } + + Delete(imclass_desc); + Delete(class_desc); + + /* Terminate wrapper code */ + Printf(w->code, "} else {\n"); + Printf(w->code, "SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, \"null upcall object\");\n"); + Printf(w->code, "}\n"); + + Printf(w->code, "if (swigjobj) jenv->DeleteLocalRef(swigjobj);\n"); + + if (!is_void) + Printf(w->code, "return %s;", qualified_return); + } + + Printf(w->code, "}"); + + // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit code */ + if (status == SWIG_OK && output_director) { + if (!is_void) { + Replaceall(w->code, "$null", qualified_return); + } else { + Replaceall(w->code, "$null", ""); + } + if (!GetFlag(n, "feature:ignore")) + Printv(imclass_directors, callback_def, callback_code, NIL); + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + Delete(inline_extra_method); + Delete(qualified_return); + Delete(jnidesc); + Delete(c_ret_type); + Delete(jniret_desc); + Delete(declaration); + Delete(callback_def); + Delete(callback_code); + DelWrapper(w); + + return status; + } + + /* ------------------------------------------------------------ + * directorPrefixArgs() + * ------------------------------------------------------------ */ + + void directorPrefixArgs(Node *n) { + Parm *p; + + /* Need to prepend 'jenv' to the director constructor's argument list */ + + String *jenv_type = NewString("JNIEnv"); + + SwigType_add_pointer(jenv_type); + + p = NewParmFromNode(jenv_type, NewString("jenv"), n); + Setattr(p, "arg:byname", "1"); + set_nextSibling(p, NULL); + + Setattr(n, "director:prefix_args", p); + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = parentNode(n); + String *decl = Getattr(n, "decl");; + String *supername = Swig_class_name(parent); + String *classname = directorClassName(parent); + String *sub = NewString(""); + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms; + int argidx = 0; + + /* Assign arguments to superclass's parameters, if not already done */ + for (p = superparms; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + + if (!pname) { + pname = NewStringf("arg%d", argidx++); + Setattr(p, "name", pname); + } + } + + /* insert jenv prefix argument */ + parms = CopyParmList(superparms); + + String *jenv_type = NewString("JNIEnv"); + SwigType_add_pointer(jenv_type); + p = NewParmFromNode(jenv_type, NewString("jenv"), n); + set_nextSibling(p, parms); + parms = p; + + directorPrefixArgs(n); + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + String *call = Swig_csuperclass_call(0, basetype, superparms); + String *classtype = SwigType_namestr(Getattr(n, "name")); + + Printf(f_directors, "%s::%s : %s, %s {\n", classname, target, call, Getattr(parent, "director:ctor")); + Printf(f_directors, "}\n\n"); + + Delete(classtype); + Delete(target); + Delete(call); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(supername); + Delete(jenv_type); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + Wrapper *w = NewWrapper(); + + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(JNIEnv *jenv) : %s {", classname, classname, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " SwigDirector_%s(JNIEnv *jenv);\n", classname); + DelWrapper(w); + Delete(classtype); + Delete(classname); + directorPrefixArgs(n); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + Java_director_declaration(n); + + Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); + Printf(f_directors_h, "\npublic:\n"); + Printf(f_directors_h, " void swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global);\n"); + + /* Keep track of the director methods for this class */ + first_class_dmethod = curr_class_dmethod = n_dmethods; + + return Language::classDirectorInit(n); + } + + /* ---------------------------------------------------------------------- + * classDirectorDestructor() + * ---------------------------------------------------------------------- */ + + int classDirectorDestructor(Node *n) { + Node *current_class = getCurrentClass(); + String *full_classname = Getattr(current_class, "name"); + String *classname = Swig_class_name(current_class); + Wrapper *w = NewWrapper(); + + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() throw () {\n", classname, classname); + } else { + Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); + } + + /* Ensure that correct directordisconnect typemap's method name is called + * here: */ + + const String *disconn_tm = NULL; + Node *disconn_attr = NewHash(); + String *disconn_methodname = NULL; + + disconn_tm = typemapLookup(n, "directordisconnect", full_classname, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); + + Printv(w->code, " swig_disconnect_director_self(\"", disconn_methodname, "\");\n", "}\n", NIL); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(disconn_attr); + Delete(classname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + String *classname = Getattr(n, "sym:name"); + String *director_classname = directorClassName(n); + String *internal_classname; + + Wrapper *w = NewWrapper(); + + if (Len(package_path) > 0) + internal_classname = NewStringf("%s/%s", package_path, classname); + else + internal_classname = NewStringf("%s", classname); + + Wrapper_add_localv(w, "baseclass", "static jclass baseclass", "= 0", NIL); + Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global) {", director_classname); + + if (first_class_dmethod != curr_class_dmethod) { + Printf(w->def, "static struct {\n"); + Printf(w->def, "const char *mname;\n"); + Printf(w->def, "const char *mdesc;\n"); + Printf(w->def, "jmethodID base_methid;\n"); + Printf(w->def, "} methods[] = {\n"); + + for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + + Printf(w->def, "{ \"%s\", \"%s\", NULL }", Getattr(udata, "method"), Getattr(udata, "fdesc")); + if (i != curr_class_dmethod - 1) + Putc(',', w->def); + Putc('\n', w->def); + } + + Printf(w->def, "};\n"); + } + + Printf(w->code, "if (swig_set_self(jenv, jself, swig_mem_own, weak_global)) {\n"); + Printf(w->code, "if (!baseclass) {\n"); + Printf(w->code, "baseclass = jenv->FindClass(\"%s\");\n", internal_classname); + Printf(w->code, "if (!baseclass) return;\n"); + Printf(w->code, "baseclass = (jclass) jenv->NewGlobalRef(baseclass);\n"); + Printf(w->code, "}\n"); + + int n_methods = curr_class_dmethod - first_class_dmethod; + + if (n_methods) { + /* Emit the swig_overrides() method and the swig_override array */ + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_overrides(int n) {\n"); + Printf(f_directors_h, " return (n < %d ? swig_override[n] : false);\n", n_methods); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, "protected:\n"); + Printf(f_directors_h, " bool swig_override[%d];\n", n_methods); + + /* Emit the code to look up the class's methods, initialize the override array */ + + Printf(w->code, "bool derived = (jenv->IsSameObject(baseclass, jcls) ? false : true);\n"); + Printf(w->code, "for (int i = 0; i < %d; ++i) {\n", n_methods); + Printf(w->code, " if (!methods[i].base_methid) {\n"); + Printf(w->code, " methods[i].base_methid = jenv->GetMethodID(baseclass, methods[i].mname, methods[i].mdesc);\n"); + Printf(w->code, " if (!methods[i].base_methid) return;\n"); + Printf(w->code, " }\n"); + Printf(w->code, " swig_override[i] = false;\n"); + Printf(w->code, " if (derived) {\n"); + Printf(w->code, " jmethodID methid = jenv->GetMethodID(jcls, methods[i].mname, methods[i].mdesc);\n"); + Printf(w->code, " swig_override[i] = (methid != methods[i].base_methid);\n"); + Printf(w->code, " jenv->ExceptionClear();\n"); + Printf(w->code, " }\n"); + Printf(w->code, "}\n"); + } else { + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_overrides(int n) {\n"); + Printf(f_directors_h, " return false;\n"); + Printf(f_directors_h, " }\n"); + } + + Printf(f_directors_h, "};\n\n"); + Printf(w->code, "}\n"); + Printf(w->code, "}\n"); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(internal_classname); + + return Language::classDirectorEnd(n); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + *--------------------------------------------------------------------*/ + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * Java_director_declaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void Java_director_declaration(Node *n) { + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director(jenv)"); + + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *declaration = Swig_class_declaration(n, directorname); + + Printf(declaration, " : public %s, public Swig::Director", base); + + // Stash stuff for later. + Setattr(n, "director:decl", declaration); + Setattr(n, "director:ctor", class_ctor); + } + +}; /* class JAVA */ + +/* ----------------------------------------------------------------------------- + * swig_java() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_java() { + return new JAVA(); +} +extern "C" Language *swig_java(void) { + return new_swig_java(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *JAVA::usage = (char *) "\ +Java Options (available with -java)\n\ + -nopgcpp - Suppress premature garbage collection prevention parameter\n\ + -noproxy - Generate the low-level functional interface instead\n\ + of proxy classes\n\ + -oldvarnames - old intermediary method names for variable wrappers\n\ + -package <name> - set name of the Java package to <name>\n\ +\n"; diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx new file mode 100644 index 0000000..d4715ee --- /dev/null +++ b/Source/Modules/lang.cxx @@ -0,0 +1,3431 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * lang.cxx + * + * Language base class functions. Default C++ handling is also implemented here. + * ----------------------------------------------------------------------------- */ + +char cvsroot_lang_cxx[] = "$Id: lang.cxx 11482 2009-07-30 18:48:14Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +#include <ctype.h> + +/* default mode settings */ +static int director_mode = 0; +static int director_protected_mode = 1; +static int all_protected_mode = 0; +static int naturalvar_mode = 0; +Language* Language::this_ = 0; + +/* Set director_protected_mode */ +void Wrapper_director_mode_set(int flag) { + director_mode = flag; +} + +void Wrapper_director_protected_mode_set(int flag) { + director_protected_mode = flag; +} + +void Wrapper_all_protected_mode_set(int flag) { + all_protected_mode = flag; +} + +void Wrapper_naturalvar_mode_set(int flag) { + naturalvar_mode = flag; +} + +extern "C" { + int Swig_director_mode() { + return director_mode; + } + int Swig_director_protected_mode() { + return director_protected_mode; + } + int Swig_all_protected_mode() { + return all_protected_mode; + } + void Language_replace_special_variables(String *method, String *tm, Parm *parm) { + Language::instance()->replaceSpecialVariables(method, tm, parm); + } +} + +/* Some status variables used during parsing */ +static int InClass = 0; /* Parsing C++ or not */ +static String *ClassName = 0; /* This is the real name of the current class */ +static String *ClassPrefix = 0; /* Class prefix */ +static String *ClassType = 0; /* Fully qualified type name to use */ +static String *DirectorClassName = 0; /* Director name of the current class */ +int Abstract = 0; +int ImportMode = 0; +int IsVirtual = 0; +static String *AttributeFunctionGet = 0; +static String *AttributeFunctionSet = 0; +static Node *CurrentClass = 0; +int line_number = 0; +String *input_file = 0; +int SmartPointer = 0; +static Hash *classhash; + +extern int GenerateDefault; +extern int ForceExtern; +extern int AddExtern; + +/* import modes */ + +#define IMPORT_MODE 1 +#define IMPORT_MODULE 2 + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_one() + * + * Dispatch a single node + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_one(Node *n) { + String *wrn; + int ret = SWIG_OK; + + char *tag = Char(nodeType(n)); + if (!tag) { + /* Printf(stderr,"SWIG: Fatal internal error. Malformed parse tree + node!\n"); */ + return SWIG_OK; + } + + /* Do not proceed if marked with an error */ + + if (Getattr(n, "error")) + return SWIG_OK; + + /* Look for warnings */ + wrn = Getattr(n, "feature:warnfilter"); + if (wrn) { + Swig_warnfilter(wrn, 1); + } + + /* ============================================================ + * C/C++ parsing + * ============================================================ */ + + if (strcmp(tag, "extern") == 0) { + ret = externDeclaration(n); + } else if (strcmp(tag, "cdecl") == 0) { + ret = cDeclaration(n); + } else if (strcmp(tag, "enum") == 0) { + ret = enumDeclaration(n); + } else if (strcmp(tag, "enumitem") == 0) { + ret = enumvalueDeclaration(n); + } else if (strcmp(tag, "enumforward") == 0) { + ret = enumforwardDeclaration(n); + } else if (strcmp(tag, "class") == 0) { + ret = classDeclaration(n); + } else if (strcmp(tag, "classforward") == 0) { + ret = classforwardDeclaration(n); + } else if (strcmp(tag, "constructor") == 0) { + ret = constructorDeclaration(n); + } else if (strcmp(tag, "destructor") == 0) { + ret = destructorDeclaration(n); + } else if (strcmp(tag, "access") == 0) { + ret = accessDeclaration(n); + } else if (strcmp(tag, "using") == 0) { + ret = usingDeclaration(n); + } else if (strcmp(tag, "namespace") == 0) { + ret = namespaceDeclaration(n); + } else if (strcmp(tag, "template") == 0) { + ret = templateDeclaration(n); + } + + /* =============================================================== + * SWIG directives + * =============================================================== */ + + else if (strcmp(tag, "top") == 0) { + ret = top(n); + } else if (strcmp(tag, "extend") == 0) { + ret = extendDirective(n); + } else if (strcmp(tag, "apply") == 0) { + ret = applyDirective(n); + } else if (strcmp(tag, "clear") == 0) { + ret = clearDirective(n); + } else if (strcmp(tag, "constant") == 0) { + ret = constantDirective(n); + } else if (strcmp(tag, "fragment") == 0) { + ret = fragmentDirective(n); + } else if (strcmp(tag, "import") == 0) { + ret = importDirective(n); + } else if (strcmp(tag, "include") == 0) { + ret = includeDirective(n); + } else if (strcmp(tag, "insert") == 0) { + ret = insertDirective(n); + } else if (strcmp(tag, "module") == 0) { + ret = moduleDirective(n); + } else if (strcmp(tag, "native") == 0) { + ret = nativeDirective(n); + } else if (strcmp(tag, "pragma") == 0) { + ret = pragmaDirective(n); + } else if (strcmp(tag, "typemap") == 0) { + ret = typemapDirective(n); + } else if (strcmp(tag, "typemapcopy") == 0) { + ret = typemapcopyDirective(n); + } else if (strcmp(tag, "typemapitem") == 0) { + ret = typemapitemDirective(n); + } else if (strcmp(tag, "types") == 0) { + ret = typesDirective(n); + } else { + Printf(stderr, "%s:%d. Unrecognized parse tree node type '%s'\n", input_file, line_number, tag); + ret = SWIG_ERROR; + } + if (wrn) { + Swig_warnfilter(wrn, 0); + } + return ret; +} + +/* ---------------------------------------------------------------------- + * Dispatcher::emit_children() + * + * Emit all children that match the given type. type = 0 means all types. + * ---------------------------------------------------------------------- */ + +int Dispatcher::emit_children(Node *n) { + Node *c; + char *eo = Char(Getattr(n, "feature:emitonlychildren")); + for (c = firstChild(n); c; c = nextSibling(c)) { + if (eo) { + const char *tag = Char(nodeType(c)); + if (strcmp(tag, "cdecl") == 0) { + if (checkAttribute(c, "storage", "typedef")) + tag = "typedef"; + } + if (strstr(eo, tag) == 0) { + continue; + } + } + emit_one(c); + } + return SWIG_OK; +} + + +/* Stubs for dispatcher class. We don't do anything by default---up to derived class + to fill in traversal code */ + +int Dispatcher::defaultHandler(Node *) { + return SWIG_OK; +} +int Dispatcher::extendDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::applyDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::clearDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::constantDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::fragmentDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::importDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::includeDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::insertDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::moduleDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::nativeDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::pragmaDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typemapDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typemapitemDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typemapcopyDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::typesDirective(Node *n) { + return defaultHandler(n); +} +int Dispatcher::cDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::externDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::enumDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::enumvalueDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::enumforwardDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::classDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::templateDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::classforwardDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::constructorDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::destructorDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::accessDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::usingDeclaration(Node *n) { + return defaultHandler(n); +} +int Dispatcher::namespaceDeclaration(Node *n) { + return defaultHandler(n); +} + + +/* Allocators */ +Language::Language(): +none_comparison(NewString("$arg != 0")), +director_ctor_code(NewString("")), +director_prot_ctor_code(0), +symbols(NewHash()), +classtypes(NewHash()), +enumtypes(NewHash()), +overloading(0), +multiinput(0), +cplus_runtime(0), +directors(0) { + argc_template_string = NewString("argc"); + argv_template_string = NewString("argv[%d]"); + + /* Default director constructor code, passed to Swig_ConstructorToFunction */ + Printv(director_ctor_code, "if ( $comparison ) { /* subclassed */\n", " $director_new \n", "} else {\n", " $nondirector_new \n", "}\n", NIL); + + /* + Default director 'protected' constructor code, disabled by + default. Each language that needs it, has to define it. + */ + director_prot_ctor_code = 0; + director_multiple_inheritance = 1; + director_language = 0; + assert(!this_); + this_ = this; +} + +Language::~Language() { + Delete(symbols); + Delete(classtypes); + Delete(enumtypes); + Delete(director_ctor_code); + Delete(none_comparison); + this_ = 0; +} + +/* ---------------------------------------------------------------------- + emit_one() + ---------------------------------------------------------------------- */ + +int Language::emit_one(Node *n) { + int ret; + int oldext; + if (!n) + return SWIG_OK; + + if (GetFlag(n, "feature:ignore") + && !Getattr(n, "feature:onlychildren")) + return SWIG_OK; + + oldext = Extend; + if (Getattr(n, "feature:extend")) + Extend = 1; + + line_number = Getline(n); + input_file = Getfile(n); + + /* + symtab = Getattr(n,"symtab"); + if (symtab) { + symtab = Swig_symbol_setscope(symtab); + } + */ + ret = Dispatcher::emit_one(n); + /* + if (symtab) { + Swig_symbol_setscope(symtab); + } + */ + Extend = oldext; + return ret; +} + + +static Parm *nonvoid_parms(Parm *p) { + if (p) { + SwigType *t = Getattr(p, "type"); + if (SwigType_type(t) == T_VOID) + return 0; + } + return p; +} + +/* ----------------------------------------------------------------------------- + * cplus_value_type() + * + * Returns the alternative value type needed in C++ for class value + * types. When swig is not sure about using a plain $ltype value, + * since the class doesn't have a default constructor, or it can't be + * assigned, you will get back 'SwigValueWrapper<type >'. + * + * ----------------------------------------------------------------------------- */ + +SwigType *cplus_value_type(SwigType *t) { + return SwigType_alttype(t, 0); +} + +static Node *first_nontemplate(Node *n) { + while (n) { + if (Strcmp(nodeType(n), "template") != 0) + return n; + n = Getattr(n, "sym:nextSibling"); + } + return n; +} + + + +/* -------------------------------------------------------------------------- + * swig_pragma() + * + * Handle swig pragma directives. + * -------------------------------------------------------------------------- */ + +void swig_pragma(char *lang, char *name, char *value) { + if (strcmp(lang, "swig") == 0) { + if ((strcmp(name, "make_default") == 0) || ((strcmp(name, "makedefault") == 0))) { + GenerateDefault = 1; + } else if ((strcmp(name, "no_default") == 0) || ((strcmp(name, "nodefault") == 0))) { + Swig_warning(WARN_DEPRECATED_NODEFAULT, "SWIG", 1, "dangerous, use %%nodefaultctor, %%nodefaultdtor instead.\n"); + GenerateDefault = 0; + } else if (strcmp(name, "attributefunction") == 0) { + String *nvalue = NewString(value); + char *s = strchr(Char(nvalue), ':'); + if (!s) { + Swig_error(input_file, line_number, "Bad value for attributefunction. Expected \"fmtget:fmtset\".\n"); + } else { + *s = 0; + AttributeFunctionGet = NewString(Char(nvalue)); + AttributeFunctionSet = NewString(s + 1); + } + Delete(nvalue); + } else if (strcmp(name, "noattributefunction") == 0) { + AttributeFunctionGet = 0; + AttributeFunctionSet = 0; + } + } +} + +/* -------------------------------------------------------------------------- + * use_naturalvar_mode() + * -------------------------------------------------------------------------- */ +int use_naturalvar_mode(Node *n) { + if (Getattr(n, "unnamed")) + return 0; + int nvar = naturalvar_mode || GetFlag(n, "feature:naturalvar"); + if (!nvar) { + /* look for feature in the class */ + SwigType *ty = Getattr(n, "type"); + SwigType *fullty = SwigType_typedef_resolve_all(ty); + if (SwigType_isclass(fullty)) { + Node *m = Copy(n); + SwigType *tys = SwigType_strip_qualifiers(fullty); + Swig_features_get(Swig_cparse_features(), 0, tys, 0, m); + nvar = GetFlag(m, "feature:naturalvar"); + Delete(tys); + Delete(m); + } + Delete(fullty); + } + return nvar ? CWRAP_NATURAL_VAR : 0; +} + +/* ---------------------------------------------------------------------- + * Language::top() - Top of parsing tree + * ---------------------------------------------------------------------- */ + +int Language::top(Node *n) { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + if (Getattr(options, "naturalvar")) { + naturalvar_mode = 1; + } + if (Getattr(options, "nonaturalvar")) { + naturalvar_mode = 0; + } + } + } + classhash = Getattr(n, "classes"); + return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::extendDirective() + * ---------------------------------------------------------------------- */ + +int Language::extendDirective(Node *n) { + int oldam = Extend; + AccessMode oldmode = cplus_mode; + Extend = CWRAP_EXTEND; + cplus_mode = PUBLIC; + + emit_children(n); + + Extend = oldam; + cplus_mode = oldmode; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::applyDirective() + * ---------------------------------------------------------------------- */ + +int Language::applyDirective(Node *n) { + + Parm *pattern = Getattr(n, "pattern"); + Node *c = firstChild(n); + while (c) { + Parm *apattern = Getattr(c, "pattern"); + if (ParmList_len(pattern) != ParmList_len(apattern)) { + Swig_error(input_file, line_number, "Can't apply (%s) to (%s). Number of arguments don't match.\n", ParmList_str(pattern), ParmList_str(apattern)); + } else { + if (!Swig_typemap_apply(pattern, apattern)) { + Swig_warning(WARN_TYPEMAP_APPLY_UNDEF, input_file, line_number, "Can't apply (%s). No typemaps are defined.\n", ParmList_str(pattern)); + } + } + c = nextSibling(c); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::clearDirective() + * ---------------------------------------------------------------------- */ + +int Language::clearDirective(Node *n) { + Node *p; + for (p = firstChild(n); p; p = nextSibling(p)) { + ParmList *pattern = Getattr(p, "pattern"); + Swig_typemap_clear_apply(pattern); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::constantDirective() + * ---------------------------------------------------------------------- */ + +int Language::constantDirective(Node *n) { + + if (CurrentClass && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + if (!GetFlag(n, "feature:allowexcept")) { + UnsetFlag(n, "feature:except"); + } + if (Getattr(n, "feature:exceptvar")) { + Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); + } + + if (!ImportMode) { + Swig_require("constantDirective", n, "name", "?value", NIL); + String *name = Getattr(n, "name"); + String *value = Getattr(n, "value"); + if (!value) { + value = Copy(name); + } else { + /* if (checkAttribute(n,"type","char")) { + value = NewString(value); + } else { + value = NewStringf("%(escape)s", value); + } + */ + Setattr(n, "rawvalue", value); + value = NewStringf("%(escape)s", value); + if (!Len(value)) + Append(value, "\\0"); + /* Printf(stdout,"'%s' = '%s'\n", name, value); */ + } + Setattr(n, "value", value); + this->constantWrapper(n); + Swig_restore(n); + return SWIG_OK; + } + return SWIG_NOWRAP; +} + +/* ---------------------------------------------------------------------- + * Language::fragmentDirective() + * ---------------------------------------------------------------------- */ + +int Language::fragmentDirective(Node *n) { + Swig_fragment_register(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::importDirective() + * ---------------------------------------------------------------------- */ + +int Language::importDirective(Node *n) { + int oldim = ImportMode; + ImportMode = IMPORT_MODE; + emit_children(n); + ImportMode = oldim; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::includeDirective() + * ---------------------------------------------------------------------- */ + +int Language::includeDirective(Node *n) { + emit_children(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::insertDirective() + * ---------------------------------------------------------------------- */ + +int Language::insertDirective(Node *n) { + /* %insert directive */ + if ((!ImportMode) || Getattr(n, "generated")) { + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + File *f = 0; + if (!section) { /* %{ ... %} */ + f = Swig_filebyname("header"); + } else { + f = Swig_filebyname(section); + } + if (f) { + Printf(f, "%s\n", code); + } else { + Swig_error(input_file, line_number, "Unknown target '%s' for %%insert directive.\n", section); + } + return SWIG_OK; + } else { + return SWIG_NOWRAP; + } +} + +/* ---------------------------------------------------------------------- + * Language::moduleDirective() + * ---------------------------------------------------------------------- */ + +int Language::moduleDirective(Node *n) { + (void) n; + /* %module directive */ + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::nativeDirective() + * ---------------------------------------------------------------------- */ + +int Language::nativeDirective(Node *n) { + if (!ImportMode) { + return nativeWrapper(n); + } else { + return SWIG_NOWRAP; + } +} + +/* ---------------------------------------------------------------------- + * Language::pragmaDirective() + * ---------------------------------------------------------------------- */ + +int Language::pragmaDirective(Node *n) { + /* %pragma directive */ + if (!ImportMode) { + String *lan = Getattr(n, "lang"); + String *name = Getattr(n, "name"); + String *value = Getattr(n, "value"); + swig_pragma(Char(lan), Char(name), Char(value)); + /* pragma(Char(lan),Char(name),Char(value)); */ + return SWIG_OK; + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typemapDirective() + * ---------------------------------------------------------------------- */ + +int Language::typemapDirective(Node *n) { + /* %typemap directive */ + String *method = Getattr(n, "method"); + String *code = Getattr(n, "code"); + Parm *kwargs = Getattr(n, "kwargs"); + Node *items = firstChild(n); + static int namewarn = 0; + + + if (code && (Strstr(code, "$source") || (Strstr(code, "$target")))) { + Swig_warning(WARN_TYPEMAP_SOURCETARGET, Getfile(n), Getline(n), "Deprecated typemap feature ($source/$target).\n"); + if (!namewarn) { + Swig_warning(WARN_TYPEMAP_SOURCETARGET, Getfile(n), Getline(n), "The use of $source and $target in a typemap declaration is deprecated.\n\ +For typemaps related to argument input (in,ignore,default,arginit,check), replace\n\ +$source by $input and $target by $1. For typemaps related to return values (out,\n\ +argout,ret,except), replace $source by $1 and $target by $result. See the file\n\ +Doc/Manual/Typemaps.html for complete details.\n"); + namewarn = 1; + } + } + + if (Strcmp(method, "except") == 0) { + Swig_warning(WARN_DEPRECATED_EXCEPT_TM, Getfile(n), Getline(n), "%%typemap(except) is deprecated. Use the %%exception directive.\n"); + } + + if (Strcmp(method, "in") == 0) { + Hash *k; + k = kwargs; + while (k) { + if (checkAttribute(k, "name", "numinputs")) { + if (!multiinput && (GetInt(k, "value") > 1)) { + Swig_error(Getfile(n), Getline(n), "Multiple-input typemaps (numinputs > 1) not supported by this target language module.\n"); + return SWIG_ERROR; + } + break; + } + k = nextSibling(k); + } + if (!k) { + k = NewHash(); + Setattr(k, "name", "numinputs"); + Setattr(k, "value", "1"); + set_nextSibling(k, kwargs); + Setattr(n, "kwargs", k); + kwargs = k; + } + } + + if (Strcmp(method, "ignore") == 0) { + Swig_warning(WARN_DEPRECATED_IGNORE_TM, Getfile(n), Getline(n), "%%typemap(ignore) has been replaced by %%typemap(in,numinputs=0).\n"); + + Clear(method); + Append(method, "in"); + Hash *k = NewHash(); + Setattr(k, "name", "numinputs"); + Setattr(k, "value", "0"); + set_nextSibling(k, kwargs); + Setattr(n, "kwargs", k); + kwargs = k; + } + + /* Replace $descriptor() macros */ + + if (code) { + Setfile(code, Getfile(n)); + Setline(code, Getline(n)); + Swig_cparse_replace_descriptor(code); + } + + while (items) { + Parm *pattern = Getattr(items, "pattern"); + Parm *parms = Getattr(items, "parms"); + + if (code) { + Swig_typemap_register(method, pattern, code, parms, kwargs); + } else { + Swig_typemap_clear(method, pattern); + } + items = nextSibling(items); + } + return SWIG_OK; + +} + +/* ---------------------------------------------------------------------- + * Language::typemapcopyDirective() + * ---------------------------------------------------------------------- */ + +int Language::typemapcopyDirective(Node *n) { + String *method = Getattr(n, "method"); + Parm *pattern = Getattr(n, "pattern"); + Node *items = firstChild(n); + int nsrc = 0; + nsrc = ParmList_len(pattern); + while (items) { + ParmList *npattern = Getattr(items, "pattern"); + if (nsrc != ParmList_len(npattern)) { + Swig_error(input_file, line_number, "Can't copy typemap. Number of types differ.\n"); + } else { + if (Swig_typemap_copy(method, pattern, npattern) < 0) { + Swig_error(input_file, line_number, "Can't copy typemap.\n"); + } + } + items = nextSibling(items); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typesDirective() + * ---------------------------------------------------------------------- */ + +int Language::typesDirective(Node *n) { + Parm *parms = Getattr(n, "parms"); + String *convcode = Getattr(n, "convcode"); /* optional user supplied conversion code for custom casting */ + while (parms) { + SwigType *t = Getattr(parms, "type"); + String *v = Getattr(parms, "value"); + if (!v) { + SwigType_remember(t); + } else { + if (SwigType_issimple(t)) { + SwigType_inherit(t, v, 0, convcode); + } + } + parms = nextSibling(parms); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::cDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::cDeclaration(Node *n) { + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *decl = Getattr(n, "decl"); + String *storage = Getattr(n, "storage"); + Node *over; + File *f_header = 0; + SwigType *ty, *fullty; + + /* discards nodes following the access control rules */ + if (cplus_mode != PUBLIC || !is_public(n)) { + /* except for friends, they are not affected by access control */ + int isfriend = storage && (Cmp(storage, "friend") == 0); + if (!isfriend) { + /* Check what the director needs. If the method is pure virtual, it is always needed. + * Also wrap non-virtual protected members if asked for (allprotected mode). */ + if (!(directorsEnabled() && ((is_member_director(CurrentClass, n) && need_nonpublic_member(n)) || is_non_virtual_protected_access(n)))) { + return SWIG_NOWRAP; + } + // Prevent wrapping protected overloaded director methods more than once - + // This bit of code is only needed due to the cDeclaration call in classHandler() + String *wrapname = NewStringf("nonpublic_%s%s", symname, Getattr(n, "sym:overname")); + if (Getattr(CurrentClass, wrapname)) { + Delete(wrapname); + return SWIG_NOWRAP; + } + SetFlag(CurrentClass, wrapname); + Delete(wrapname); + } + } + + if (Cmp(storage, "typedef") == 0) { + Swig_save("cDeclaration", n, "type", NIL); + SwigType *t = Copy(type); + if (t) { + SwigType_push(t, decl); + Setattr(n, "type", t); + typedefHandler(n); + } + Swig_restore(n); + return SWIG_OK; + } + + /* If in import mode, we proceed no further */ + if (ImportMode) + return SWIG_NOWRAP; + + /* If we're in extend mode and there is code, replace the $descriptor macros */ + if (Extend) { + String *code = Getattr(n, "code"); + if (code) { + Setfile(code, Getfile(n)); + Setline(code, Getline(n)); + Swig_cparse_replace_descriptor(code); + } + } + + /* Overloaded symbol check */ + over = Swig_symbol_isoverloaded(n); + if (!overloading) { + if (over) + over = first_nontemplate(over); + if (over && (over != n)) { + Swig_warning(WARN_LANG_OVERLOAD_DECL, input_file, line_number, "Overloaded declaration ignored. %s\n", Swig_name_decl(n)); + Swig_warning(WARN_LANG_OVERLOAD_DECL, Getfile(over), Getline(over), "Previous declaration is %s\n", Swig_name_decl(over)); + return SWIG_NOWRAP; + } + } + + if (symname && !validIdentifier(symname)) { + Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap '%s' unless renamed to a valid identifier.\n", symname); + return SWIG_NOWRAP; + } + + ty = NewString(type); + SwigType_push(ty, decl); + fullty = SwigType_typedef_resolve_all(ty); + if (SwigType_isfunction(fullty)) { + if (!SwigType_isfunction(ty)) { + Delete(ty); + ty = fullty; + fullty = 0; + ParmList *parms = SwigType_function_parms(ty); + Setattr(n, "parms", parms); + } + /* Transform the node into a 'function' node and emit */ + if (!CurrentClass) { + f_header = Swig_filebyname("header"); + + if (AddExtern) { + if (f_header) { + if ((Cmp(storage, "extern") == 0) || (ForceExtern && !storage)) { + /* we don't need the 'extern' part in the C/C++ declaration, + and it produces some problems when namespace and SUN + Studio is used. + + Printf(f_header,"extern %s", SwigType_str(ty,name)); + + In fact generating extern declarations is quite error prone and is + no longer the default. Getting it right seems impossible with namespaces + and default arguments and when a method is declared with the various Windows + calling conventions - SWIG doesn't understand Windows (non standard) calling + conventions in the first place, so can't regenerate them. + */ + String *str = SwigType_str(ty, name); + Printf(f_header, "%s", str); + Delete(str); + { + DOH *t = Getattr(n, "throws"); + if (t) { + Printf(f_header, " throw("); + while (t) { + Printf(f_header, "%s", Getattr(t, "type")); + t = nextSibling(t); + if (t) + Printf(f_header, ","); + } + Printf(f_header, ")"); + } + } + Printf(f_header, ";\n"); + } else if (Cmp(storage, "externc") == 0) { + /* here 'extern "C"' is needed */ + String *str = SwigType_str(ty, name); + Printf(f_header, "extern \"C\" %s;\n", str); + Delete(str); + } + } + } + } + /* This needs to check qualifiers */ + if (SwigType_isqualifier(ty)) { + SwigType *qual = SwigType_pop(ty); + Setattr(n, "qualifier", qual); + Delete(qual); + } + Delete(SwigType_pop_function(ty)); + DohIncref(type); + Setattr(n, "type", ty); + if (GetFlag(n, "feature:onlychildren") && !GetFlag(n, "feature:ignore")) { + // Found an unignored templated method that has a an empty template instantiation (%template()) + // Ignore it unless it has been %rename'd + if (Strncmp(symname, "__dummy_", 8) == 0) { + SetFlag(n, "feature:ignore"); + Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number, + "%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n)); + } + } + if (!GetFlag(n, "feature:ignore")) + functionHandler(n); + Setattr(n, "type", type); + Delete(ty); + Delete(type); + return SWIG_OK; + } else { + /* Some kind of variable declaration */ + String *declaration = Copy(decl); + Delattr(n, "decl"); + if (Getattr(n, "nested")) + SetFlag(n, "feature:immutable"); + if (!CurrentClass) { + if ((Cmp(storage, "extern") == 0) || ForceExtern) { + f_header = Swig_filebyname("header"); + if (AddExtern) { + if (f_header) { + String *str = SwigType_str(ty, name); + Printf(f_header, "extern %s;\n", str); + Delete(str); + } + } + } + } + if (!SwigType_ismutable(ty)) { + SetFlag(n, "feature:immutable"); + } + /* If an array and elements are const, then read-only */ + if (SwigType_isarray(ty)) { + SwigType *tya = SwigType_array_type(ty); + if (SwigType_isconst(tya)) { + SetFlag(n, "feature:immutable"); + } + Delete(tya); + } + DohIncref(type); + Setattr(n, "type", ty); + variableHandler(n); + Setattr(n, "type", type); + Setattr(n, "decl", declaration); + Delete(ty); + Delete(type); + Delete(fullty); + return SWIG_OK; + } +} + +/* ---------------------------------------------------------------------- + * Language::functionHandler() + * ---------------------------------------------------------------------- */ + +int Language::functionHandler(Node *n) { + String *storage = Getattr(n, "storage"); + int isfriend = CurrentClass && Cmp(storage, "friend") == 0; + int isstatic = CurrentClass && Cmp(storage, "static") == 0 && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess")); + Parm *p = Getattr(n, "parms"); + if (GetFlag(n, "feature:del")) { + /* the method acts like a delete operator, ie, we need to disown the parameter */ + if (CurrentClass && !isstatic && !isfriend) { + SetFlag(n, "feature:self:disown"); + } else { + if (p) + SetFlag(p, "wrap:disown"); + } + } + if (!CurrentClass) { + globalfunctionHandler(n); + } else { + if (isstatic) { + staticmemberfunctionHandler(n); + } else if (isfriend) { + globalfunctionHandler(n); + } else { + Node *explicit_n = 0; + if (directorsEnabled() && is_member_director(CurrentClass, n) && !extraDirectorProtectedCPPMethodsRequired()) { + bool virtual_but_not_pure_virtual = (!(Cmp(storage, "virtual")) && (Cmp(Getattr(n, "value"), "0") != 0)); + if (virtual_but_not_pure_virtual) { + // Add additional wrapper which makes an explicit call to the virtual method (ie not a virtual call) + explicit_n = Copy(n); + String *new_symname = Copy(Getattr(n, "sym:name")); + String *suffix = Getattr(parentNode(n), "sym:name"); + Printv(new_symname, "SwigExplicit", suffix, NIL); + Setattr(explicit_n, "sym:name", new_symname); + Delattr(explicit_n, "storage"); + Delattr(explicit_n, "override"); + Delattr(explicit_n, "hides"); + SetFlag(explicit_n, "explicitcall"); + Setattr(n, "explicitcallnode", explicit_n); + } + } + + memberfunctionHandler(n); + + if (explicit_n) { + memberfunctionHandler(explicit_n); + Delattr(explicit_n, "explicitcall"); + Delete(explicit_n); + } + } + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::globalfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::globalfunctionHandler(Node *n) { + + Swig_require("globalfunctionHandler", n, "name", "sym:name", "type", "?parms", NIL); + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + + /* Check for callback mode */ + String *cb = GetFlagAttr(n, "feature:callback"); + if (cb) { + String *cbname = Getattr(n, "feature:callback:name"); + if (!cbname) { + cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", cbname); + } + + callbackfunctionHandler(n); + if (Cmp(cbname, symname) == 0) { + Delete(cbname); + Swig_restore(n); + return SWIG_NOWRAP; + } + Delete(cbname); + } + Setattr(n, "parms", nonvoid_parms(parms)); + String *call = Swig_cfunction_call(name, parms); + String *cres = Swig_cresult(type, "result", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + functionWrapper(n); + + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::callbackfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::callbackfunctionHandler(Node *n) { + Swig_require("callbackfunctionHandler", n, "name", "*sym:name", "*type", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + String *parms = Getattr(n, "parms"); + String *cb = GetFlagAttr(n, "feature:callback"); + String *cbname = Getattr(n, "feature:callback:name"); + String *calltype = NewStringf("(%s (*)(%s))(%s)", SwigType_str(type, 0), ParmList_str(parms), SwigType_namestr(name)); + SwigType *cbty = Copy(type); + SwigType_add_function(cbty, parms); + SwigType_add_pointer(cbty); + + if (!cbname) { + cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", cbname); + } + + Setattr(n, "sym:name", cbname); + Setattr(n, "type", cbty); + Setattr(n, "value", calltype); + + Node *ns = Getattr(symbols, cbname); + if (!ns) + constantWrapper(n); + + Delete(cbname); + Delete(cbty); + + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::memberfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::memberfunctionHandler(Node *n) { + + Swig_require("memberfunctionHandler", n, "*name", "*sym:name", "*type", "?parms", "?value", NIL); + + String *storage = Getattr(n, "storage"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + ParmList *parms = Getattr(n, "parms"); + String *cb = GetFlagAttr(n, "feature:callback"); + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + IsVirtual = PURE_VIRTUAL; + } else { + IsVirtual = PLAIN_VIRTUAL; + } + } else { + IsVirtual = 0; + } + if (cb) { + Node *cbn = NewHash(); + String *cbname = Getattr(n, "feature:callback:name"); + if (!cbname) { + cbname = NewStringf(cb, symname); + } + + SwigType *cbty = Copy(type); + SwigType_add_function(cbty, parms); + SwigType_add_memberpointer(cbty, ClassName); + String *cbvalue = NewStringf("&%s::%s", ClassName, name); + Setattr(cbn, "sym:name", cbname); + Setattr(cbn, "type", cbty); + Setattr(cbn, "value", cbvalue); + Setattr(cbn, "name", name); + + memberconstantHandler(cbn); + Setattr(n, "feature:callback:name", Swig_name_member(ClassPrefix, cbname)); + + Delete(cb); + Delete(cbn); + Delete(cbvalue); + Delete(cbty); + Delete(cbname); + if (Cmp(cbname, symname) == 0) { + Swig_restore(n); + return SWIG_NOWRAP; + } + } + + String *fname = Swig_name_member(ClassPrefix, symname); + if (Extend && SmartPointer) { + if (!Getattr(n, "classname")) { + Setattr(n, "classname", Getattr(CurrentClass, "allocate:smartpointerbase")); + } + } + // Set up the type for the cast to this class for use when wrapping const director (virtual) methods. + // Note: protected director methods or when allprotected mode turned on. + String *director_type = 0; + if (!is_public(n) && (is_member_director(CurrentClass, n) || GetFlag(n, "explicitcall") || is_non_virtual_protected_access(n))) { + director_type = Copy(DirectorClassName); + String *qualifier = Getattr(n, "qualifier"); + if (qualifier) + SwigType_push(director_type, qualifier); + SwigType_add_pointer(director_type); + } + + int DirectorExtraCall = 0; + if (directorsEnabled() && is_member_director(CurrentClass, n) && !SmartPointer) + if (extraDirectorProtectedCPPMethodsRequired()) + DirectorExtraCall = CWRAP_DIRECTOR_TWO_CALLS; + + if (GetFlag(n, "explicitcall")) + DirectorExtraCall = CWRAP_DIRECTOR_ONE_CALL; + + Swig_MethodToFunction(n, ClassType, Getattr(n, "template") ? SmartPointer : Extend | SmartPointer | DirectorExtraCall, director_type, + is_member_director(CurrentClass, n)); + Setattr(n, "sym:name", fname); + + functionWrapper(n); + + Delete(director_type); + Delete(fname); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + +int Language::staticmemberfunctionHandler(Node *n) { + + Swig_require("staticmemberfunctionHandler", n, "*name", "*sym:name", "*type", NIL); + Swig_save("staticmemberfunctionHandler", n, "storage", NIL); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + String *cb = GetFlagAttr(n, "feature:callback"); + String *cname, *mrename; + + if (!Extend) { + Node *sb = Getattr(n, "cplus:staticbase"); + String *sname = Getattr(sb, "name"); + if (is_non_virtual_protected_access(n)) + cname = NewStringf("%s::%s", DirectorClassName, name); + else + cname = NewStringf("%s::%s", sname, name); + } else { + String *mname = Swig_name_mangle(ClassName); + cname = Swig_name_member(mname, name); + Delete(mname); + } + mrename = Swig_name_member(ClassPrefix, symname); + + if (Extend) { + String *code = Getattr(n, "code"); + String *defaultargs = Getattr(n, "defaultargs"); + String *mangled = Swig_name_mangle(mrename); + Delete(mrename); + mrename = mangled; + + if (Getattr(n, "sym:overloaded") && code) { + Append(cname, Getattr(defaultargs ? defaultargs : n, "sym:overname")); + } + + if (!defaultargs && code) { + /* Hmmm. An added static member. We have to create a little wrapper for this */ + Swig_add_extension_code(n, cname, parms, type, code, CPlusPlus, 0); + } + } + + Setattr(n, "name", cname); + Setattr(n, "sym:name", mrename); + + if (cb) { + String *cbname = NewStringf(cb, symname); + Setattr(n, "feature:callback:name", Swig_name_member(ClassPrefix, cbname)); + Setattr(n, "feature:callback:staticname", name); + } + Delattr(n, "storage"); + + globalfunctionHandler(n); + + Delete(cname); + Delete(mrename); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::variableHandler() + * ---------------------------------------------------------------------- */ + +int Language::variableHandler(Node *n) { + + /* If not a smart-pointer access or added method. We clear + feature:except. There is no way C++ or C would throw + an exception merely for accessing a member data. + + Caveat: Some compilers seem to route attribute access through + methods which can generate exceptions. The feature:allowexcept + allows this. Also, the feature:exceptvar can be used to match + only variables. + */ + if (!(Extend | SmartPointer)) { + if (!GetFlag(n, "feature:allowexcept")) { + UnsetFlag(n, "feature:except"); + } + if (Getattr(n, "feature:exceptvar")) { + Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); + } + } + + if (!CurrentClass) { + globalvariableHandler(n); + } else { + String *storage = Getattr(n, "storage"); + Swig_save("variableHandler", n, "feature:immutable", NIL); + if (SmartPointer) { + /* If a smart-pointer and it's a constant access, we have to set immutable */ + if (Getattr(CurrentClass, "allocate:smartpointerconst")) { + SetFlag(n, "feature:immutable"); + } + } + if ((Cmp(storage, "static") == 0) && !(SmartPointer && Getattr(n, "allocate:smartpointeraccess"))) { + staticmembervariableHandler(n); + } else { + membervariableHandler(n); + } + Swig_restore(n); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::globalvariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::globalvariableHandler(Node *n) { + variableWrapper(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::membervariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::membervariableHandler(Node *n) { + + Swig_require("membervariableHandler", n, "*name", "*sym:name", "*type", NIL); + Swig_save("membervariableHandler", n, "parms", NIL); + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + + if (!AttributeFunctionGet) { + String *mname = Swig_name_member(ClassPrefix, symname); + String *mrename_get = Swig_name_get(mname); + String *mrename_set = Swig_name_set(mname); + Delete(mname); + + /* Create a function to set the value of the variable */ + + int assignable = is_assignable(n); + + if (SmartPointer) { + if (Getattr(CurrentClass, "allocate:smartpointerconst")) { + assignable = 0; + } + } + + if (assignable) { + int make_set_wrapper = 1; + String *tm = 0; + String *target = 0; + if (!Extend) { + if (SmartPointer) { + if (checkAttribute(n, "storage", "static")) { + Node *sn = Getattr(n, "cplus:staticbase"); + String *base = Getattr(sn, "name"); + target = NewStringf("%s::%s", base, name); + } else { + String *pname = Swig_cparm_name(0, 0); + target = NewStringf("(*%s)->%s", pname, name); + Delete(pname); + } + } else { + String *pname = is_non_virtual_protected_access(n) ? NewString("darg") : Swig_cparm_name(0, 0); + target = NewStringf("%s->%s", pname, name); + Delete(pname); + } + } else { + target = NewStringf("$extendgetcall"); // member variable access expanded later + } + tm = Swig_typemap_lookup("memberin", n, target, 0); + int flags = Extend | SmartPointer | use_naturalvar_mode(n); + if (is_non_virtual_protected_access(n)) + flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + + String *call = 0; + Swig_MembersetToFunction(n, ClassType, flags, &call); + Setattr(n, "memberset", "1"); + + if (!tm) { + if (SwigType_isarray(type)) { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(type, 0)); + make_set_wrapper = 0; + } + } else { + String *pname0 = Swig_cparm_name(0, 0); + String *pname1 = Swig_cparm_name(0, 1); + Replace(tm, "$source", pname1, DOH_REPLACE_ANY); + Replace(tm, "$target", target, DOH_REPLACE_ANY); + Replace(tm, "$input", pname1, DOH_REPLACE_ANY); + Replace(tm, "$self", pname0, DOH_REPLACE_ANY); + Replace(tm, "$extendgetcall", call, DOH_REPLACE_ANY); + Setattr(n, "wrap:action", tm); + Delete(tm); + Delete(pname0); + Delete(pname1); + } + Delete(call); + Delete(target); + + if (make_set_wrapper) { + Setattr(n, "sym:name", mrename_set); + functionWrapper(n); + } else { + SetFlag(n, "feature:immutable"); + } + /* Restore parameters */ + Setattr(n, "type", type); + Setattr(n, "name", name); + Setattr(n, "sym:name", symname); + + /* Delete all attached typemaps and typemap attributes */ + Iterator ki; + for (ki = First(n); ki.key; ki = Next(ki)) { + if (Strncmp(ki.key, "tmap:", 5) == 0) + Delattr(n, ki.key); + } + } + /* Emit get function */ + { + int flags = Extend | SmartPointer | use_naturalvar_mode(n); + if (is_non_virtual_protected_access(n)) + flags = flags | CWRAP_ALL_PROTECTED_ACCESS; + Swig_MembergetToFunction(n, ClassType, flags); + Setattr(n, "sym:name", mrename_get); + Setattr(n, "memberget", "1"); + functionWrapper(n); + } + Delete(mrename_get); + Delete(mrename_set); + + } else { + + /* This code is used to support the attributefunction directive + where member variables are converted automagically to + accessor functions */ + +#if 0 + Parm *p; + String *gname; + SwigType *vty; + p = NewParm(type, 0); + gname = NewStringf(AttributeFunctionGet, symname); + if (!Extend) { + ActionFunc = Copy(Swig_cmemberget_call(name, type)); + cpp_member_func(Char(gname), Char(gname), type, 0); + Delete(ActionFunc); + } else { + String *cname = Swig_name_get(name); + cpp_member_func(Char(cname), Char(gname), type, 0); + Delete(cname); + } + Delete(gname); + if (!GetFlag(n, "feature:immutable")) { + gname = NewStringf(AttributeFunctionSet, symname); + vty = NewString("void"); + if (!Extend) { + ActionFunc = Copy(Swig_cmemberset_call(name, type)); + cpp_member_func(Char(gname), Char(gname), vty, p); + Delete(ActionFunc); + } else { + String *cname = Swig_name_set(name); + cpp_member_func(Char(cname), Char(gname), vty, p); + Delete(cname); + } + Delete(gname); + } + ActionFunc = 0; +#endif + } + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + +int Language::staticmembervariableHandler(Node *n) { + Swig_require("staticmembervariableHandler", n, "*name", "*sym:name", "*type", "?value", NIL); + String *value = Getattr(n, "value"); + String *classname = !SmartPointer ? (is_non_virtual_protected_access(n) ? DirectorClassName : ClassName) : Getattr(CurrentClass, "allocate:smartpointerbase"); + + if (!value || !Getattr(n, "hasconsttype")) { + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *cname, *mrename; + + /* Create the variable name */ + mrename = Swig_name_member(ClassPrefix, symname); + cname = NewStringf("%s::%s", classname, name); + + Setattr(n, "sym:name", mrename); + Setattr(n, "name", cname); + + /* Wrap as an ordinary global variable */ + variableWrapper(n); + + Delete(mrename); + Delete(cname); + } else { + + /* This is a C++ static member declaration with an initializer and it's const. + Certain C++ compilers optimize this out so that there is no linkage to a + memory address. Example: + + class Foo { + public: + static const int x = 3; + }; + + Some discussion of this in section 9.4 of the C++ draft standard. + + Also, we have to manage the case: + + class Foo { + public: + %extend { + static const int x = 3; + } + }; + + in which there's no actual Foo::x variable to refer to. In this case, + the best we can do is to wrap the given value verbatim. + */ + + + String *name = Getattr(n, "name"); + String *cname = NewStringf("%s::%s", classname, name); + if (Extend) { + /* the variable is a synthesized one. + There's nothing we can do; we just keep the given value */ + } else { + /* we refer to the value as Foo::x */ + String *value = SwigType_namestr(cname); + Setattr(n, "value", value); + } + + SwigType *t1 = SwigType_typedef_resolve_all(Getattr(n, "type")); + SwigType *t2 = SwigType_strip_qualifiers(t1); + Setattr(n, "type", t2); + Delete(t1); + Delete(t2); + SetFlag(n, "wrappedasconstant"); + memberconstantHandler(n); + Delete(cname); + } + + Swig_restore(n); + return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::externDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::externDeclaration(Node *n) { + return emit_children(n); +} + +/* ---------------------------------------------------------------------- + * Language::enumDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumDeclaration(Node *n) { + if (!ImportMode) { + emit_children(n); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumvalueDeclaration(Node *n) { + if (CurrentClass && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + Setattr(n, "value", tmpValue); + + if (!CurrentClass || !cparse_cplusplus) { + Setattr(n, "name", tmpValue); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + } else { + memberconstantHandler(n); + } + + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::enumforwardDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::enumforwardDeclaration(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::memberconstantHandler() + * ----------------------------------------------------------------------------- */ + +int Language::memberconstantHandler(Node *n) { + + Swig_require("memberconstantHandler", n, "*name", "*sym:name", "value", NIL); + + if (!GetFlag(n, "feature:allowexcept")) { + UnsetFlag(n, "feature:except"); + } + if (Getattr(n, "feature:exceptvar")) { + Setattr(n, "feature:except", Getattr(n, "feature:exceptvar")); + } + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + + String *mrename = Swig_name_member(ClassPrefix, symname); + Setattr(n, "sym:name", mrename); + + String *new_name = 0; + if (Extend) + new_name = Copy(value); + else + new_name = NewStringf("%s::%s", is_non_virtual_protected_access(n) ? DirectorClassName : ClassName, name); + Setattr(n, "name", new_name); + + constantWrapper(n); + Delete(mrename); + Delete(new_name); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::typedefHandler() + * ---------------------------------------------------------------------- */ + +int Language::typedefHandler(Node *n) { + /* since this is a recurring issue, we are going to remember the + typedef pointer, if already it is not a pointer or reference, as + in + + typedef void NT; + int func(NT *p); + + see director_basic.i for example. + */ + SwigType *name = Getattr(n, "name"); + SwigType *decl = Getattr(n, "decl"); + if (!SwigType_ispointer(decl) && !SwigType_isreference(decl)) { + SwigType *pname = Copy(name); + SwigType_add_pointer(pname); + SwigType_remember(pname); + Delete(pname); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethod() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethod(Node *n, Node *parent, String *super) { + (void) n; + (void) parent; + (void) super; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructor(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDefaultConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDefaultConstructor(Node *n) { + (void) n; + return SWIG_OK; +} + +static String *vtable_method_id(Node *n) { + String *nodeType = Getattr(n, "nodeType"); + int is_destructor = (Cmp(nodeType, "destructor") == 0); + if (is_destructor) + return 0; + String *name = Getattr(n, "name"); + String *decl = Getattr(n, "decl"); + String *local_decl = SwigType_typedef_resolve_all(decl); + String *tmp = SwigType_pop_function(local_decl); + Delete(local_decl); + local_decl = tmp; + Node *method_id = NewStringf("%s|%s", name, local_decl); + Delete(local_decl); + return method_id; +} + + +/* ---------------------------------------------------------------------- + * Language::unrollVirtualMethods() + * ---------------------------------------------------------------------- */ +int Language::unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_director, int &virtual_destructor, int protectedbase) { + Node *ni; + String *nodeType; + String *classname; + String *decl; + bool first_base = false; + // recurse through all base classes to build the vtable + List *bl = Getattr(n, "bases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + if (first_base && !director_multiple_inheritance) + break; + unrollVirtualMethods(bi.item, parent, vm, default_director, virtual_destructor); + first_base = true; + } + } + // recurse through all protected base classes to build the vtable, as needed + bl = Getattr(n, "protectedbases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + if (first_base && !director_multiple_inheritance) + break; + unrollVirtualMethods(bi.item, parent, vm, default_director, virtual_destructor, 1); + first_base = true; + } + } + // find the methods that need directors + classname = Getattr(n, "name"); + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + /* we only need to check the virtual members */ + if (!checkAttribute(ni, "storage", "virtual")) + continue; + nodeType = Getattr(ni, "nodeType"); + /* we need to add methods(cdecl) and destructor (to check for throw decl) */ + int is_destructor = (Cmp(nodeType, "destructor") == 0); + if ((Cmp(nodeType, "cdecl") == 0) || is_destructor) { + decl = Getattr(ni, "decl"); + /* extra check for function type and proper access */ + if (SwigType_isfunction(decl) && (((!protectedbase || dirprot_mode()) && is_public(ni)) || need_nonpublic_member(ni))) { + String *name = Getattr(ni, "name"); + Node *method_id = is_destructor ? NewStringf("~destructor") : vtable_method_id(ni); + /* Make sure that the new method overwrites the existing: */ + int len = Len(vm); + const int DO_NOT_REPLACE = -1; + int replace = DO_NOT_REPLACE; + for (int i = 0; i < len; i++) { + Node *item = Getitem(vm, i); + String *check_vmid = Getattr(item, "vmid"); + + if (Strcmp(method_id, check_vmid) == 0) { + replace = i; + break; + } + } + /* filling a new method item */ + String *fqdname = NewStringf("%s::%s", classname, name); + Hash *item = NewHash(); + Setattr(item, "fqdname", fqdname); + Node *m = Copy(ni); + + /* Store the complete return type - needed for non-simple return types (pointers, references etc.) */ + SwigType *ty = NewString(Getattr(m, "type")); + SwigType_push(ty, decl); + if (SwigType_isqualifier(ty)) { + Delete(SwigType_pop(ty)); + } + Delete(SwigType_pop_function(ty)); + Setattr(m, "returntype", ty); + + String *mname = NewStringf("%s::%s", Getattr(parent, "name"), name); + /* apply the features of the original method found in the base class */ + Swig_features_get(Swig_cparse_features(), 0, mname, Getattr(m, "decl"), m); + Setattr(item, "methodNode", m); + Setattr(item, "vmid", method_id); + if (replace == DO_NOT_REPLACE) + Append(vm, item); + else + Setitem(vm, replace, item); + + Delete(mname); + } + if (is_destructor) { + virtual_destructor = 1; + } + } + } + + /* + We delete all the nodirector methods. This prevents the + generation of 'empty' director classes. + + But this has to be done outside the previous 'for' + an the recursive loop!. + */ + if (n == parent) { + int len = Len(vm); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vm, i); + Node *m = Getattr(item, "methodNode"); + /* retrieve the director features */ + int mdir = GetFlag(m, "feature:director"); + int mndir = GetFlag(m, "feature:nodirector"); + /* 'nodirector' has precedence over 'director' */ + int dir = (mdir || mndir) ? (mdir && !mndir) : 1; + /* check if the method was found only in a base class */ + Node *p = Getattr(m, "parentNode"); + if (p != n) { + Node *c = Copy(m); + Setattr(c, "parentNode", n); + int cdir = GetFlag(c, "feature:director"); + int cndir = GetFlag(c, "feature:nodirector"); + dir = (cdir || cndir) ? (cdir && !cndir) : dir; + Delete(c); + } + if (dir) { + /* be sure the 'nodirector' feature is disabled */ + if (mndir) + Delattr(m, "feature:nodirector"); + } else { + /* or just delete from the vm, since is not a director method */ + Delitem(vm, i); + len--; + i--; + } + } + } + + return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::classDirectorDisown() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDisown(Node *n) { + Node *disown = NewHash(); + String *mrename; + String *symname = Getattr(n, "sym:name"); + mrename = Swig_name_disown(symname); //Getattr(n, "name")); + String *type = NewString(ClassType); + String *name = NewString("self"); + SwigType_add_pointer(type); + Parm *p = NewParm(type, name); + Delete(name); + Delete(type); + type = NewString("void"); + String *action = NewString(""); + Printv(action, "{\n", "Swig::Director *director = dynamic_cast<Swig::Director *>(arg1);\n", "if (director) director->swig_disown();\n", "}\n", NULL); + Setattr(disown, "wrap:action", action); + Setattr(disown, "name", mrename); + Setattr(disown, "sym:name", mrename); + Setattr(disown, "type", type); + Setattr(disown, "parms", p); + Delete(action); + Delete(mrename); + Delete(type); + Delete(p); + + functionWrapper(disown); + Delete(disown); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructors() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructors(Node *n) { + Node *ni; + String *nodeType; + Node *parent = Swig_methodclass(n); + int default_ctor = Getattr(parent, "allocate:default_constructor") ? 1 : 0; + int protected_ctor = 0; + int constructor = 0; + + /* emit constructors */ + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + nodeType = Getattr(ni, "nodeType"); + if (Cmp(nodeType, "constructor") == 0) { + Parm *parms = Getattr(ni, "parms"); + if (is_public(ni)) { + /* emit public constructor */ + classDirectorConstructor(ni); + constructor = 1; + if (default_ctor) + default_ctor = !ParmList_numrequired(parms); + } else { + /* emit protected constructor if needed */ + if (need_nonpublic_ctor(ni)) { + classDirectorConstructor(ni); + constructor = 1; + protected_ctor = 1; + if (default_ctor) + default_ctor = !ParmList_numrequired(parms); + } + } + } + } + /* emit default constructor if needed */ + if (!constructor) { + if (!default_ctor) { + /* we get here because the class has no public, protected or + default constructor, therefore, the director class can't be + created, ie, is kind of abstract. */ + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), "Director class '%s' can't be constructed\n", SwigType_namestr(Getattr(n, "name"))); + return SWIG_OK; + } + classDirectorDefaultConstructor(n); + default_ctor = 1; + } + /* this is just to support old java behavior, ie, the default + constructor is always emitted, even when protected, and not + needed, since there is a public constructor already defined. + + (scottm) This code is needed here to make the director_abstract + + test generate compileable code (Example2 in director_abastract.i). + + (mmatus) This is very strange, since swig compiled with gcc3.2.3 + doesn't need it here.... + */ + if (!default_ctor && !protected_ctor) { + if (Getattr(parent, "allocate:default_base_constructor")) { + classDirectorDefaultConstructor(n); + } + } + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethods() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethods(Node *n) { + Node *vtable = Getattr(n, "vtable"); + + int len = Len(vtable); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vtable, i); + String *method = Getattr(item, "methodNode"); + String *fqdname = Getattr(item, "fqdname"); + if (GetFlag(method, "feature:nodirector")) + continue; + + String *type = Getattr(method, "nodeType"); + if (!Cmp(type, "destructor")) { + classDirectorDestructor(method); + } else { + if (classDirectorMethod(method, n, fqdname) == SWIG_OK) { + Setattr(item, "director", "1"); + } + } + } + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorInit() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorInit(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDestructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDestructor(Node *n) { + /* + Always emit the virtual destructor in the declaration and in the + compilation unit. Been explicit here can't make any damage, and + can solve some nasty C++ compiler problems. + */ + File *f_directors = Swig_filebyname("director"); + File *f_directors_h = Swig_filebyname("director_h"); + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~%s() throw ();\n", DirectorClassName); + Printf(f_directors, "%s::~%s() throw () {\n}\n\n", DirectorClassName, DirectorClassName); + } else { + Printf(f_directors_h, " virtual ~%s();\n", DirectorClassName); + Printf(f_directors, "%s::~%s() {\n}\n\n", DirectorClassName, DirectorClassName); + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorEnd() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorEnd(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirector() + * ---------------------------------------------------------------------- */ + +int Language::classDirector(Node *n) { + Node *module = Getattr(n, "module"); + String *classtype = Getattr(n, "classtype"); + Hash *directormap = 0; + if (module) { + directormap = Getattr(module, "wrap:directormap"); + if (directormap == 0) { + directormap = NewHash(); + Setattr(module, "wrap:directormap", directormap); + } + } + List *vtable = NewList(); + int virtual_destructor = 0; + unrollVirtualMethods(n, n, vtable, 0, virtual_destructor); + + // Emit all the using base::member statements for non virtual members (allprotected mode) + Node *ni; + String *using_protected_members_code = NewString(""); + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + Node *nodeType = Getattr(ni, "nodeType"); + bool cdeclaration = (Cmp(nodeType, "cdecl") == 0); + if (cdeclaration && !GetFlag(ni, "feature:ignore")) { + if (is_non_virtual_protected_access(ni)) { + Node *overloaded = Getattr(ni, "sym:overloaded"); + // emit the using base::member statement (but only once if the method is overloaded) + if (!overloaded || (overloaded && (overloaded == ni))) + Printf(using_protected_members_code, " using %s::%s;\n", SwigType_namestr(ClassName), Getattr(ni, "name")); + } + } + } + + if (virtual_destructor || Len(vtable) > 0) { + if (!virtual_destructor) { + String *classtype = Getattr(n, "classtype"); + Swig_warning(WARN_LANG_DIRECTOR_VDESTRUCT, input_file, line_number, "Director base class %s has no virtual destructor.\n", classtype); + } + + Setattr(n, "vtable", vtable); + if (directormap != 0) { + Setattr(directormap, classtype, n); + } + classDirectorInit(n); + classDirectorConstructors(n); + classDirectorMethods(n); + + File *f_directors_h = Swig_filebyname("director_h"); + Printv(f_directors_h, using_protected_members_code, NIL); + + classDirectorEnd(n); + } + Delete(vtable); + Delete(using_protected_members_code); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDeclaration() + * ---------------------------------------------------------------------- */ + +static void addCopyConstructor(Node *n) { + Node *cn = NewHash(); + set_nodeType(cn, "constructor"); + Setattr(cn, "access", "public"); + Setfile(cn, Getfile(n)); + Setline(cn, Getline(n)); + + String *cname = Getattr(n, "name"); + SwigType *type = Copy(cname); + String *last = Swig_scopename_last(cname); + String *name = NewStringf("%s::%s", cname, last); + String *cc = NewStringf("r.q(const).%s", type); + String *decl = NewStringf("f(%s).", cc); + String *csymname = Getattr(n, "sym:name"); + String *oldname = csymname; + + if (Getattr(n, "allocate:has_constructor")) { + // to work properly with '%rename Class', we must look + // for any other constructor in the class, which has not been + // renamed, and use its name as oldname. + Node *c; + for (c = firstChild(n); c; c = nextSibling(c)) { + const char *tag = Char(nodeType(c)); + if (strcmp(tag, "constructor") == 0) { + String *cname = Getattr(c, "name"); + String *csname = Getattr(c, "sym:name"); + String *clast = Swig_scopename_last(cname); + if (Equal(csname, clast)) { + oldname = csname; + break; + } + } + } + } + + String *symname = Swig_name_make(cn, cname, last, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + if (!symname) { + symname = Copy(csymname); + } + Parm *p = NewParm(cc, "other"); + + Setattr(cn, "name", name); + Setattr(cn, "sym:name", symname); + SetFlag(cn, "feature:new"); + Setattr(cn, "decl", decl); + Setattr(cn, "parentNode", n); + Setattr(cn, "parms", p); + Setattr(cn, "copy_constructor", "1"); + + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + Swig_symbol_setscope(oldscope); + Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); + + if (on == cn) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_copy_constructor", "1"); + Setattr(n, "copy_constructor_decl", decl); + Setattr(n, "allocate:copy_constructor", "1"); + Delete(access); + } + } + Delete(cn); + Delete(last); + Delete(name); + Delete(decl); + Delete(symname); +} + +static void addDefaultConstructor(Node *n) { + Node *cn = NewHash(); + set_nodeType(cn, "constructor"); + Setattr(cn, "access", "public"); + Setfile(cn, Getfile(n)); + Setline(cn, Getline(n)); + + String *cname = Getattr(n, "name"); + String *last = Swig_scopename_last(cname); + String *name = NewStringf("%s::%s", cname, last); + String *decl = NewString("f()."); + String *csymname = Getattr(n, "sym:name"); + String *oldname = csymname; + String *symname = Swig_name_make(cn, cname, last, decl, oldname); + if (Strcmp(symname, "$ignore") != 0) { + if (!symname) { + symname = Copy(csymname); + } + + Setattr(cn, "name", name); + Setattr(cn, "sym:name", symname); + SetFlag(cn, "feature:new"); + Setattr(cn, "decl", decl); + Setattr(cn, "parentNode", n); + Setattr(cn, "default_constructor", "1"); + + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + Swig_symbol_setscope(oldscope); + Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); + + if (on == cn) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_default_constructor", "1"); + Setattr(n, "allocate:default_constructor", "1"); + Delete(access); + } + } + Delete(cn); + Delete(last); + Delete(name); + Delete(decl); + Delete(symname); +} + +static void addDestructor(Node *n) { + Node *cn = NewHash(); + set_nodeType(cn, "destructor"); + Setattr(cn, "access", "public"); + Setfile(cn, Getfile(n)); + Setline(cn, Getline(n)); + + String *cname = Getattr(n, "name"); + String *last = Swig_scopename_last(cname); + Insert(last, 0, "~"); + String *name = NewStringf("%s::%s", cname, last); + String *decl = NewString("f()."); + String *symname = Swig_name_make(cn, cname, last, decl, 0); + if (Strcmp(symname, "$ignore") != 0) { + if (!symname) { + symname = NewStringf("~%s", Getattr(n, "sym:name")); + } + + Setattr(cn, "name", name); + Setattr(cn, "sym:name", symname); + Setattr(cn, "decl", "f()."); + Setattr(cn, "parentNode", n); + + Symtab *oldscope = Swig_symbol_setscope(Getattr(n, "symtab")); + Node *on = Swig_symbol_add(symname, cn); + Swig_symbol_setscope(oldscope); + Swig_features_get(Swig_cparse_features(), 0, name, decl, cn); + + if (on == cn) { + Node *access = NewHash(); + set_nodeType(access, "access"); + Setattr(access, "kind", "public"); + appendChild(n, access); + appendChild(n, cn); + Setattr(n, "has_destructor", "1"); + Setattr(n, "allocate:destructor", "1"); + Delete(access); + } + } + Delete(cn); + Delete(last); + Delete(name); + Delete(decl); + Delete(symname); +} + +int Language::classDeclaration(Node *n) { + String *ochildren = Getattr(n, "feature:onlychildren"); + if (ochildren) { + Setattr(n, "feature:emitonlychildren", ochildren); + emit_children(n); + Delattr(n, "feature:emitonlychildren"); + SetFlag(n, "feature:ignore"); + return SWIG_NOWRAP; + } + + String *kind = Getattr(n, "kind"); + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *symname = Getattr(n, "sym:name"); + + char *classname = tdname ? Char(tdname) : Char(name); + char *iname = Char(symname); + int strip = (tdname || CPlusPlus) ? 1 : 0; + + + if (!classname) { + Swig_warning(WARN_LANG_CLASS_UNNAMED, input_file, line_number, "Can't generate wrappers for unnamed struct/class.\n"); + return SWIG_NOWRAP; + } + + /* Check symbol name for template. If not renamed. Issue a warning */ + if (!validIdentifier(symname)) { + Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap class %s unless renamed to a valid identifier.\n", SwigType_namestr(symname)); + return SWIG_NOWRAP; + } + + Swig_save("classDeclaration", n, "name", NIL); + Setattr(n, "name", classname); + + if (Cmp(kind, "class") == 0) { + cplus_mode = PRIVATE; + } else { + cplus_mode = PUBLIC; + } + + ClassName = NewString(classname); + ClassPrefix = NewString(iname); + if (strip) { + ClassType = NewString(classname); + } else { + ClassType = NewStringf("%s %s", kind, classname); + } + Setattr(n, "classtypeobj", Copy(ClassType)); + Setattr(n, "classtype", SwigType_namestr(ClassType)); + + InClass = 1; + CurrentClass = n; + + + /* Call classHandler() here */ + if (!ImportMode) { + int dir = 0; + if (directorsEnabled()) { + int ndir = GetFlag(n, "feature:director"); + int nndir = GetFlag(n, "feature:nodirector"); + /* 'nodirector' has precedence over 'director' */ + dir = (ndir || nndir) ? (ndir && !nndir) : 0; + } + int abstract = !dir && abstractClassTest(n); + int odefault = (GenerateDefault && !GetFlag(n, "feature:nodefault")); + + /* default constructor */ + if (!abstract && !GetFlag(n, "feature:nodefaultctor") && odefault) { + if (!Getattr(n, "has_constructor") && !Getattr(n, "allocate:has_constructor") && (Getattr(n, "allocate:default_constructor"))) { + addDefaultConstructor(n); + } + } + /* copy constructor */ + if (CPlusPlus && !abstract && GetFlag(n, "feature:copyctor")) { + if (!Getattr(n, "has_copy_constructor") && !Getattr(n, "allocate:has_copy_constructor") + && (Getattr(n, "allocate:copy_constructor")) + && (!GetFlag(n, "feature:ignore"))) { + addCopyConstructor(n); + } + } + /* default destructor */ + if (!GetFlag(n, "feature:nodefaultdtor") && odefault) { + if (!Getattr(n, "has_destructor") && (!Getattr(n, "allocate:has_destructor")) + && (Getattr(n, "allocate:default_destructor")) + && (!GetFlag(n, "feature:ignore"))) { + addDestructor(n); + } + } + + if (dir) { + DirectorClassName = NewStringf("SwigDirector_%s", symname); + classDirector(n); + } + /* check for abstract after resolving directors */ + Abstract = abstractClassTest(n); + + classHandler(n); + } else { + Abstract = abstractClassTest(n); + Language::classHandler(n); + } + + InClass = 0; + CurrentClass = 0; + Delete(ClassType); + ClassType = 0; + Delete(ClassPrefix); + ClassPrefix = 0; + Delete(ClassName); + ClassName = 0; + Delete(DirectorClassName); + DirectorClassName = 0; + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classHandler() + * ---------------------------------------------------------------------- */ + +int Language::classHandler(Node *n) { + + bool hasDirector = Swig_directorclass(n) ? true : false; + + /* Emit all of the class members */ + emit_children(n); + + /* Look for smart pointer handling */ + if (Getattr(n, "allocate:smartpointer")) { + List *methods = Getattr(n, "allocate:smartpointer"); + cplus_mode = PUBLIC; + SmartPointer = CWRAP_SMART_POINTER; + Iterator c; + for (c = First(methods); c.item; c = Next(c)) { + emit_one(c.item); + } + SmartPointer = 0; + } + + cplus_mode = PUBLIC; + + /* emit director disown method */ + if (hasDirector) { + classDirectorDisown(n); + + /* Emit additional protected virtual methods - only needed if the language module + * codes logic in the C++ layer instead of the director proxy class method - primarily + * to catch public use of protected methods by the scripting languages. */ + if (dirprot_mode() && extraDirectorProtectedCPPMethodsRequired()) { + Node *vtable = Getattr(n, "vtable"); + String *symname = Getattr(n, "sym:name"); + AccessMode old_mode = cplus_mode; + cplus_mode = PROTECTED; + int len = Len(vtable); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vtable, i); + Node *method = Getattr(item, "methodNode"); + SwigType *type = Getattr(method, "nodeType"); + if (Strcmp(type, "cdecl") != 0) + continue; + if (GetFlag(method, "feature:ignore")) + continue; + String *methodname = Getattr(method, "sym:name"); + String *wrapname = NewStringf("%s_%s", symname, methodname); + if (!Getattr(symbols, wrapname) && (!is_public(method))) { + Node *m = Copy(method); + Setattr(m, "director", "1"); + Setattr(m, "parentNode", n); + /* + * There is a bug that needs fixing still... + * This area of code is creating methods which have not been overidden in a derived class (director methods that are protected in the base) + * If the method is overloaded, then Swig_overload_dispatch() incorrectly generates a call to the base wrapper, _wrap_xxx method + * See director_protected_overloaded.i - Possibly sym:overname needs correcting here. + Printf(stdout, "new method: %s::%s(%s)\n", Getattr(parentNode(m), "name"), Getattr(m, "name"), ParmList_str_defaultargs(Getattr(m, "parms"))); + */ + cDeclaration(m); + Delete(m); + } + Delete(wrapname); + } + cplus_mode = old_mode; + } + } + + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classforwardDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::classforwardDeclaration(Node *n) { + (void) n; + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::constructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::constructorDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + + if (!symname) + return SWIG_NOWRAP; + if (!CurrentClass) + return SWIG_NOWRAP; + if (ImportMode) + return SWIG_NOWRAP; + + if (Extend) { + /* extend default constructor can be safely ignored if there is already one */ + int num_required = ParmList_numrequired(Getattr(n, "parms")); + if ((num_required == 0) && Getattr(CurrentClass, "has_default_constructor")) { + return SWIG_NOWRAP; + } + if ((num_required == 1) && Getattr(CurrentClass, "has_copy_constructor")) { + String *ccdecl = Getattr(CurrentClass, "copy_constructor_decl"); + if (ccdecl && (Strcmp(ccdecl, Getattr(n, "decl")) == 0)) { + return SWIG_NOWRAP; + } + } + } + + /* clean protected overloaded constructors, in case they are not needed anymore */ + Node *over = Swig_symbol_isoverloaded(n); + if (over && !Getattr(CurrentClass, "sym:cleanconstructor")) { + int dirclass = Swig_directorclass(CurrentClass); + Node *nn = over; + while (nn) { + if (!is_public(nn)) { + if (!dirclass || !need_nonpublic_ctor(nn)) { + SetFlag(nn, "feature:ignore"); + } + } + nn = Getattr(nn, "sym:nextSibling"); + } + clean_overloaded(over); + Setattr(CurrentClass, "sym:cleanconstructor", "1"); + } + + if ((cplus_mode != PUBLIC)) { + /* check only for director classes */ + if (!Swig_directorclass(CurrentClass) || !need_nonpublic_ctor(n)) + return SWIG_NOWRAP; + } + + /* Name adjustment for %name */ + Swig_save("constructorDeclaration", n, "sym:name", NIL); + + { + String *base = Swig_scopename_last(name); + if ((Strcmp(base, symname) == 0) && (Strcmp(symname, ClassPrefix) != 0)) { + Setattr(n, "sym:name", ClassPrefix); + } + Delete(base); + } + + /* Only create a constructor if the class is not abstract */ + if (!Abstract) { + Node *over; + over = Swig_symbol_isoverloaded(n); + if (over) + over = first_nontemplate(over); + if ((over) && (!overloading)) { + /* If the symbol is overloaded. We check to see if it is a copy constructor. If so, + we invoke copyconstructorHandler() as a special case. */ + if (Getattr(n, "copy_constructor") && (!Getattr(CurrentClass, "has_copy_constructor"))) { + copyconstructorHandler(n); + Setattr(CurrentClass, "has_copy_constructor", "1"); + } else { + if (Getattr(over, "copy_constructor")) + over = Getattr(over, "sym:nextSibling"); + if (over != n) { + Swig_warning(WARN_LANG_OVERLOAD_CONSTRUCT, input_file, line_number, + "Overloaded constructor ignored. %s\n", Swig_name_decl(n)); + Swig_warning(WARN_LANG_OVERLOAD_CONSTRUCT, Getfile(over), Getline(over), + "Previous declaration is %s\n", Swig_name_decl(over)); + } else { + constructorHandler(n); + } + } + } else { + if (name && (Cmp(Swig_scopename_last(name), Swig_scopename_last(ClassName))) && !(Getattr(n, "template"))) { + Swig_warning(WARN_LANG_RETURN_TYPE, input_file, line_number, "Function %s must have a return type.\n", SwigType_namestr(name)); + Swig_restore(n); + return SWIG_NOWRAP; + } + constructorHandler(n); + } + } + Setattr(CurrentClass, "has_constructor", "1"); + + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * get_director_ctor_code() + * ---------------------------------------------------------------------- */ + +static String *get_director_ctor_code(Node *n, String *director_ctor_code, String *director_prot_ctor_code, List *&abstract) { + String *director_ctor = director_ctor_code; + int use_director = Swig_directorclass(n); + if (use_director) { + Node *pn = Swig_methodclass(n); + abstract = Getattr(pn, "abstract"); + if (director_prot_ctor_code) { + int is_notabstract = GetFlag(pn, "feature:notabstract"); + int is_abstract = abstract && !is_notabstract; + if (is_protected(n) || is_abstract) { + director_ctor = director_prot_ctor_code; + Delattr(pn, "abstract"); + } else { + if (is_notabstract) { + Delattr(pn, "abstract"); + } else { + abstract = 0; + } + } + } + } + return director_ctor; +} + + +/* ---------------------------------------------------------------------- + * Language::constructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::constructorHandler(Node *n) { + Swig_require("constructorHandler", n, "?name", "*sym:name", "?type", "?parms", NIL); + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_construct(symname); + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + List *abstract = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstract); + if (!constructor) { + /* if not originally a constructor, still handle it as one */ + Setattr(n, "handled_as_constructor", "1"); + } + + Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 : Extend); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + if (abstract) + Setattr(Swig_methodclass(n), "abstract", abstract); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::copyconstructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::copyconstructorHandler(Node *n) { + Swig_require("copyconstructorHandler", n, "?name", "*sym:name", "?type", "?parms", NIL); + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_copyconstructor(symname); + List *abstract = 0; + String *director_ctor = get_director_ctor_code(n, director_ctor_code, + director_prot_ctor_code, + abstract); + Swig_ConstructorToFunction(n, ClassType, none_comparison, director_ctor, CPlusPlus, Getattr(n, "template") ? 0 : Extend); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + if (abstract) + Setattr(Swig_methodclass(n), "abstract", abstract); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::destructorDeclaration(Node *n) { + + if (!CurrentClass) + return SWIG_NOWRAP; + if (cplus_mode != PUBLIC) + return SWIG_NOWRAP; + if (ImportMode) + return SWIG_NOWRAP; + + if (Extend) { + /* extend destructor can be safetly ignored if there is already one */ + if (Getattr(CurrentClass, "has_destructor")) { + return SWIG_NOWRAP; + } + } + + Swig_save("destructorDeclaration", n, "name", "sym:name", NIL); + + char *c = GetChar(n, "name"); + if (c && (*c == '~')) + Setattr(n, "name", c + 1); + + c = GetChar(n, "sym:name"); + if (c && (*c == '~')) + Setattr(n, "sym:name", c + 1); + + /* Name adjustment for %name */ + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + + if ((Strcmp(name, symname) == 0) || (Strcmp(symname, ClassPrefix) != 0)) { + Setattr(n, "sym:name", ClassPrefix); + } + + destructorHandler(n); + + Setattr(CurrentClass, "has_destructor", "1"); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::destructorHandler() + * ---------------------------------------------------------------------- */ + +int Language::destructorHandler(Node *n) { + Swig_require("destructorHandler", n, "?name", "*sym:name", NIL); + Swig_save("destructorHandler", n, "type", "parms", NIL); + + String *symname = Getattr(n, "sym:name"); + String *mrename; + char *csymname = Char(symname); + if (csymname && (*csymname == '~')) + csymname += 1; + + mrename = Swig_name_destroy(csymname); + + Swig_DestructorToFunction(n, ClassType, CPlusPlus, Extend); + Setattr(n, "sym:name", mrename); + functionWrapper(n); + Delete(mrename); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::accessDeclaration() + * ---------------------------------------------------------------------- */ + +int Language::accessDeclaration(Node *n) { + String *kind = Getattr(n, "kind"); + if (Cmp(kind, "public") == 0) { + cplus_mode = PUBLIC; + } else if (Cmp(kind, "private") == 0) { + cplus_mode = PRIVATE; + } else if (Cmp(kind, "protected") == 0) { + cplus_mode = PROTECTED; + } + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::namespaceDeclaration() + * ----------------------------------------------------------------------------- */ + +int Language::namespaceDeclaration(Node *n) { + if (Getattr(n, "alias")) + return SWIG_OK; + if (Getattr(n, "unnamed")) + return SWIG_OK; + emit_children(n); + return SWIG_OK; +} + +int Language::validIdentifier(String *s) { + char *c = Char(s); + while (*c) { + if (!(isalnum(*c) || (*c == '_'))) + return 0; + c++; + } + return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::usingDeclaration() + * ----------------------------------------------------------------------------- */ + +int Language::usingDeclaration(Node *n) { + if ((cplus_mode == PUBLIC)) { + Node *np = Copy(n); + Node *c; + for (c = firstChild(np); c; c = nextSibling(c)) { + /* it seems for some cases this is needed, like A* A::boo() */ + if (CurrentClass) + Setattr(c, "parentNode", CurrentClass); + emit_one(c); + } + Delete(np); + } + return SWIG_OK; +} + +/* Stubs. Language modules need to implement these */ + +/* ---------------------------------------------------------------------- + * Language::constantWrapper() + * ---------------------------------------------------------------------- */ + +int Language::constantWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *str = SwigType_str(type, name); + Printf(stdout, "constantWrapper : %s = %s\n", str, value); + Delete(str); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::variableWrapper() + * ---------------------------------------------------------------------- */ + +int Language::variableWrapper(Node *n) { + Swig_require("variableWrapper", n, "*name", "*sym:name", "*type", "?parms", NIL); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *name = Getattr(n, "name"); + + /* If no way to set variables. We simply create functions */ + int assignable = is_assignable(n); + int flags = use_naturalvar_mode(n); + if (!GetFlag(n, "wrappedasconstant")) + flags = flags | Extend; + + if (assignable) { + int make_set_wrapper = 1; + String *tm = Swig_typemap_lookup("globalin", n, name, 0); + + Swig_VarsetToFunction(n, flags); + String *sname = Swig_name_set(symname); + Setattr(n, "sym:name", sname); + Delete(sname); + + if (!tm) { + if (SwigType_isarray(type)) { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(type, 0)); + make_set_wrapper = 0; + } + } else { + String *pname0 = Swig_cparm_name(0, 0); + Replace(tm, "$source", pname0, DOH_REPLACE_ANY); + Replace(tm, "$target", name, DOH_REPLACE_ANY); + Replace(tm, "$input", pname0, DOH_REPLACE_ANY); + Setattr(n, "wrap:action", tm); + Delete(tm); + Delete(pname0); + } + if (make_set_wrapper) { + functionWrapper(n); + } + /* Restore parameters */ + Setattr(n, "sym:name", symname); + Setattr(n, "type", type); + Setattr(n, "name", name); + + /* Delete all attached typemaps and typemap attributes */ + Iterator ki; + for (ki = First(n); ki.key; ki = Next(ki)) { + if (Strncmp(ki.key, "tmap:", 5) == 0) + Delattr(n, ki.key); + } + } + + Swig_VargetToFunction(n, flags); + String *gname = Swig_name_get(symname); + Setattr(n, "sym:name", gname); + Delete(gname); + functionWrapper(n); + Swig_restore(n); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::functionWrapper() + * ---------------------------------------------------------------------- */ + +int Language::functionWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + + Printf(stdout, "functionWrapper : %s\n", SwigType_str(type, NewStringf("%s(%s)", name, ParmList_str_defaultargs(parms)))); + Printf(stdout, " action : %s\n", Getattr(n, "wrap:action")); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Language::nativeWrapper() + * ----------------------------------------------------------------------------- */ + +int Language::nativeWrapper(Node *n) { + (void) n; + return SWIG_OK; +} + +void Language::main(int argc, char *argv[]) { + (void) argc; + (void) argv; +} + +/* ----------------------------------------------------------------------------- + * Language::addSymbol() + * + * Adds a symbol entry. Returns 1 if the symbol is added successfully. + * Prints an error message and returns 0 if a conflict occurs. + * ----------------------------------------------------------------------------- */ + +int +Language::addSymbol(const String *s, const Node *n) { + Node *c = Getattr(symbols, s); + if (c && (c != n)) { + Swig_error(input_file, line_number, "'%s' is multiply defined in the generated module.\n", s); + Swig_error(Getfile(c), Getline(c), "Previous declaration of '%s'\n", s); + return 0; + } + Setattr(symbols, s, n); + return 1; +} + +/* ----------------------------------------------------------------------------- + * Language::symbolLookup() + * ----------------------------------------------------------------------------- */ + +Node *Language::symbolLookup(String *s) { + return Getattr(symbols, s); +} + +/* ----------------------------------------------------------------------------- + * Language::classLookup() + * + * Tries to locate a class from a type definition + * ----------------------------------------------------------------------------- */ + +Node *Language::classLookup(SwigType *s) { + Node *n = 0; + + /* Look in hash of cached values */ + n = Getattr(classtypes, s); + if (!n) { + Symtab *stab = 0; + SwigType *ty1 = SwigType_typedef_resolve_all(s); + SwigType *ty2 = SwigType_strip_qualifiers(ty1); + Delete(ty1); + ty1 = 0; + + String *base = SwigType_base(ty2); + + Replaceall(base, "class ", ""); + Replaceall(base, "struct ", ""); + Replaceall(base, "union ", ""); + + if (strncmp(Char(base), "::", 2) == 0) { + String *oldbase = base; + base = NewString(Char(base) + 2); + Delete(oldbase); + } + + String *prefix = SwigType_prefix(ty2); + + /* Do a symbol table search on the base type */ + while (!n) { + Hash *nstab; + n = Swig_symbol_clookup(base, stab); + if (!n) + break; + if (Strcmp(nodeType(n), "class") == 0) + break; + n = parentNode(n); + if (!n) + break; + nstab = Getattr(n, "sym:symtab"); + n = 0; + if ((!nstab) || (nstab == stab)) { + break; + } + stab = nstab; + } + if (n) { + /* Found a match. Look at the prefix. We only allow + the cases where where we want a proxy class for the particular type */ + if ((Len(prefix) == 0) || // simple type (pass by value) + (Strcmp(prefix, "p.") == 0) || // pointer + (Strcmp(prefix, "r.") == 0) || // reference + (Strcmp(prefix, "r.p.") == 0) || // pointer by reference + SwigType_prefix_is_simple_1D_array(prefix)) { // Simple 1D array (not arrays of pointers/references) + SwigType *cs = Copy(s); + Setattr(classtypes, cs, n); + Delete(cs); + } else { + n = 0; + } + } + Delete(ty2); + Delete(base); + Delete(prefix); + } + if (n && (GetFlag(n, "feature:ignore") || Getattr(n, "feature:onlychildren"))) { + n = 0; + } + + return n; +} + +/* ----------------------------------------------------------------------------- + * Language::enumLookup() + * + * Finds and returns the Node containing the enum declaration for the (enum) + * type passed in. + * ----------------------------------------------------------------------------- */ + +Node *Language::enumLookup(SwigType *s) { + Node *n = 0; + + /* Look in hash of cached values */ + n = Getattr(enumtypes, s); + if (!n) { + Symtab *stab = 0; + SwigType *lt = SwigType_ltype(s); + SwigType *ty1 = SwigType_typedef_resolve_all(lt); + SwigType *ty2 = SwigType_strip_qualifiers(ty1); + Delete(lt); + Delete(ty1); + lt = 0; + ty1 = 0; + + String *base = SwigType_base(ty2); + + Replaceall(base, "enum ", ""); + String *prefix = SwigType_prefix(ty2); + + if (strncmp(Char(base), "::", 2) == 0) { + String *oldbase = base; + base = NewString(Char(base) + 2); + Delete(oldbase); + } + + /* Look for type in symbol table */ + while (!n) { + Hash *nstab; + n = Swig_symbol_clookup(base, stab); + if (!n) + break; + if (Strcmp(nodeType(n), "enum") == 0) + break; + n = parentNode(n); + if (!n) + break; + nstab = Getattr(n, "sym:symtab"); + n = 0; + if ((!nstab) || (nstab == stab)) { + break; + } + stab = nstab; + } + if (n) { + /* Found a match. Look at the prefix. We only allow simple types. */ + if (Len(prefix) == 0) { /* Simple type */ + Setattr(enumtypes, Copy(s), n); + } else { + n = 0; + } + } + Delete(ty2); + Delete(base); + Delete(prefix); + } + if (n && (GetFlag(n, "feature:ignore"))) { + n = 0; + } + + return n; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_overloading() + * ----------------------------------------------------------------------------- */ + +void Language::allow_overloading(int val) { + overloading = val; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_multiple_input() + * ----------------------------------------------------------------------------- */ + +void Language::allow_multiple_input(int val) { + multiinput = val; +} + +/* ----------------------------------------------------------------------------- + * Language::enable_cplus_runtime_mode() + * ----------------------------------------------------------------------------- */ + +void Language::enable_cplus_runtime_mode() { + cplus_runtime = 1; +} + +/* ----------------------------------------------------------------------------- + * Language::cplus_runtime_mode() + * ----------------------------------------------------------------------------- */ + +int Language::cplus_runtime_mode() { + return cplus_runtime; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_directors() + * ----------------------------------------------------------------------------- */ + +void Language::allow_directors(int val) { + directors = val; +} + +/* ----------------------------------------------------------------------------- + * Language::directorsEnabled() + * ----------------------------------------------------------------------------- */ + +int Language::directorsEnabled() const { + return director_language && CPlusPlus && (directors || director_mode); +} + +/* ----------------------------------------------------------------------------- + * Language::allow_dirprot() + * ----------------------------------------------------------------------------- */ + +void Language::allow_dirprot(int val) { + director_protected_mode = val; +} + +/* ----------------------------------------------------------------------------- + * Language::allow_allprotected() + * ----------------------------------------------------------------------------- */ + +void Language::allow_allprotected(int val) { + all_protected_mode = val; +} + +/* ----------------------------------------------------------------------------- + * Language::dirprot_mode() + * ----------------------------------------------------------------------------- */ + +int Language::dirprot_mode() const { + return directorsEnabled() ? director_protected_mode : 0; +} + +/* ----------------------------------------------------------------------------- + * Language::need_nonpublic_ctor() + * ----------------------------------------------------------------------------- */ + +int Language::need_nonpublic_ctor(Node *n) { + /* + detects when a protected constructor is needed, which is always + the case if 'dirprot' mode is used. However, if that is not the + case, we will try to strictly emit what is minimal to don't break + the generated, while preserving compatibility with java, which + always try to emit the default constructor. + + rules: + + - when dirprot mode is used, the protected constructors are + always needed. + + - the protected default constructor is always needed. + + - if dirprot mode is not used, the protected constructors will be + needed only if: + + - there is no any public constructor in the class, and + - there is no protected default constructor + + In that case, all the declared protected constructors are + needed since we don't know which one to pick up. + + Note: given all the complications here, I am always in favor to + always enable 'dirprot', since is the C++ idea of protected + members, and use %ignore for the method you don't whan to add in + the director class. + */ + if (directorsEnabled()) { + if (is_protected(n)) { + if (dirprot_mode()) { + /* when using dirprot mode, the protected constructors are + always needed */ + return 1; + } else { + int is_default_ctor = !ParmList_numrequired(Getattr(n, "parms")); + if (is_default_ctor) { + /* the default protected constructor is always needed, for java compatibility */ + return 1; + } else { + /* check if there is a public constructor */ + Node *parent = Swig_methodclass(n); + int public_ctor = Getattr(parent, "allocate:default_constructor") + || Getattr(parent, "allocate:public_constructor"); + if (!public_ctor) { + /* if not, the protected constructor will be needed only + if there is no protected default constructor declared */ + int no_prot_default_ctor = !Getattr(parent, "allocate:default_base_constructor"); + return no_prot_default_ctor; + } + } + } + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Language::need_nonpublic_member() + * ----------------------------------------------------------------------------- */ +int Language::need_nonpublic_member(Node *n) { + if (directorsEnabled()) { + if (is_protected(n)) { + if (dirprot_mode()) { + /* when using dirprot mode, the protected members are always needed. */ + return 1; + } else { + /* if the method is pure virtual, we need it. */ + int pure_virtual = (Cmp(Getattr(n, "value"), "0") == 0); + return pure_virtual; + } + } + } + return 0; +} + + +/* ----------------------------------------------------------------------------- + * Language::is_smart_pointer() + * ----------------------------------------------------------------------------- */ + +int Language::is_smart_pointer() const { + return SmartPointer; +} + +/* ----------------------------------------------------------------------------- + * Language::extraDirectorProtectedCPPMethodsRequired() + * ----------------------------------------------------------------------------- */ + +bool Language::extraDirectorProtectedCPPMethodsRequired() const { + return true; +} + +/* ----------------------------------------------------------------------------- + * Language::is_wrapping_class() + * ----------------------------------------------------------------------------- */ + +int Language::is_wrapping_class() { + return InClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getCurrentClass() + * ----------------------------------------------------------------------------- */ + +Node *Language::getCurrentClass() const { + return CurrentClass; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassName() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassName() const { + return ClassName; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassPrefix() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassPrefix() const { + return ClassPrefix; +} + +/* ----------------------------------------------------------------------------- + * Language::getClassType() + * ----------------------------------------------------------------------------- */ + +String *Language::getClassType() const { + return ClassType; +} + +/* ----------------------------------------------------------------------------- + * Language::abstractClassTest() + * ----------------------------------------------------------------------------- */ +//#define SWIG_DEBUG +int Language::abstractClassTest(Node *n) { + /* check for non public operator new */ + if (GetFlag(n, "feature:notabstract")) + return 0; + if (Getattr(n, "allocate:nonew")) + return 1; + /* now check for the rest */ + List *abstract = Getattr(n, "abstract"); + if (!abstract) + return 0; + int labs = Len(abstract); +#ifdef SWIG_DEBUG + List *bases = Getattr(n, "allbases"); + Printf(stderr, "testing %s %d %d\n", Getattr(n, "name"), labs, Len(bases)); +#endif + if (!labs) + return 0; /*strange, but need to be fixed */ + if (abstract && !directorsEnabled()) + return 1; + if (!GetFlag(n, "feature:director")) + return 1; + + Node *dirabstract = 0; + Node *vtable = Getattr(n, "vtable"); + if (vtable) { +#ifdef SWIG_DEBUG + Printf(stderr, "vtable %s %d %d\n", Getattr(n, "name"), Len(vtable), labs); +#endif + for (int i = 0; i < labs; i++) { + Node *ni = Getitem(abstract, i); + Node *method_id = vtable_method_id(ni); + if (!method_id) + continue; + bool exists_item = false; + int len = Len(vtable); + for (int i = 0; i < len; i++) { + Node *item = Getitem(vtable, i); + String *check_item = Getattr(item, "vmid"); + if (Strcmp(method_id, check_item) == 0) { + exists_item = true; + break; + } + } +#ifdef SWIG_DEBUG + Printf(stderr, "method %s %d\n", method_id, exists_item ? 1 : 0); +#endif + Delete(method_id); + if (!exists_item) { + dirabstract = ni; + break; + } + } + if (dirabstract) { + if (is_public(dirabstract)) { + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), + "Director class '%s' is abstract, abstract method '%s' is not accesible, maybe due to multiple inheritance or 'nodirector' feature\n", + SwigType_namestr(Getattr(n, "name")), Getattr(dirabstract, "name")); + } else { + Swig_warning(WARN_LANG_DIRECTOR_ABSTRACT, Getfile(n), Getline(n), + "Director class '%s' is abstract, abstract method '%s' is private\n", SwigType_namestr(Getattr(n, "name")), Getattr(dirabstract, "name")); + } + return 1; + } + } else { + return 1; + } + return dirabstract ? 1 : 0; +} + +void Language::setSubclassInstanceCheck(String *nc) { + none_comparison = nc; +} + +void Language::setOverloadResolutionTemplates(String *argc, String *argv) { + Delete(argc_template_string); + argc_template_string = Copy(argc); + Delete(argv_template_string); + argv_template_string = Copy(argv); +} + +int Language::is_assignable(Node *n) { + if (GetFlag(n, "feature:immutable")) + return 0; + SwigType *type = Getattr(n, "type"); + Node *cn = 0; + SwigType *ftd = SwigType_typedef_resolve_all(type); + SwigType *td = SwigType_strip_qualifiers(ftd); + if (SwigType_type(td) == T_USER) { + cn = Swig_symbol_clookup(td, 0); + if (cn) { + if ((Strcmp(nodeType(cn), "class") == 0)) { + if (Getattr(cn, "allocate:noassign")) { + SetFlag(n, "feature:immutable"); + Delete(ftd); + Delete(td); + return 0; + } + } + } + } + Delete(ftd); + Delete(td); + return 1; +} + +String *Language::runtimeCode() { + return NewString(""); +} + +String *Language::defaultExternalRuntimeFilename() { + return 0; +} + +/* ----------------------------------------------------------------------------- + * Language::replaceSpecialVariables() + * Language modules should implement this if special variables are to be handled + * correctly in the $typemap(...) special variable macro. + * method - typemap method name + * tm - string containing typemap contents + * parm - a parameter describing the typemap type to be handled + * ----------------------------------------------------------------------------- */ +void Language::replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + (void)tm; + (void)parm; +} + +Language *Language::instance() { + return this_; +} + +Hash *Language::getClassHash() const { + return classhash; +} diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx new file mode 100644 index 0000000..8835667 --- /dev/null +++ b/Source/Modules/lua.cxx @@ -0,0 +1,1226 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * lua.cxx + * + * Lua language module for SWIG. + * ----------------------------------------------------------------------------- */ + +/* NEW LANGUAGE NOTE: + * ver001 + this is simply a copy of tcl8.cxx, which has been renamed + * ver002 + all non essential code commented out, program now does virtually nothing + it prints to stderr the list of functions to wrap, but does not create + the XXX_wrap.c file + * ver003 + added back top(), still prints the list of fns to stderr + but now creates a rather empty XXX_wrap.c with some basic boilerplate code + * ver004 + very basic version of functionWrapper() + also uncommented usage_string() to keep compiler happy + this will start producing proper looking code soon (I hope) + produced the wrapper code, but without any type conversion (in or out) + generates a few warning because of no wrappering + does not generate SWIG_init() + reason for this is that lua.swg is empty + we will need to add code into this to make it work + * ver005/6 + massive rework, basing work on the pike module instead of tcl + (pike module it only 1/3 of the size)(though not as complete) + * ver007 + added simple type checking + * ver008 + INPUT, OUTPUT, INOUT typemaps handled (though not all types yet) + * ver009 + class support: ok for basic types, but methods still TDB + (code is VERY messed up & needs to be cleaned) + + +*/ + +char cvsroot_lua_cxx[] = "$Id: lua.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +/**** Diagnostics: + With the #define REPORT(), you can change the amount of diagnostics given + This helps me search the parse tree & figure out what is going on inside SWIG + (because its not clear or documented) +*/ +#define REPORT(T,D) // no info: +//#define REPORT(T,D) {Printf(stdout,T"\n");} // only title +//#define REPORT(T,D) {Printf(stdout,T" %p\n",n);} // title & pointer +//#define REPORT(T,D) {Printf(stdout,T"\n");display_mapping(D);} // the works +//#define REPORT(T,D) {Printf(stdout,T"\n");if(D)Swig_print_node(D);} // the works + +void display_mapping(DOH *d) { + if (d == 0 || !DohIsMapping(d)) + return; + for (DohIterator it = DohFirst(d); it.item; it = DohNext(it)) { + if (DohIsString(it.item)) + Printf(stdout, " %s = %s\n", it.key, it.item); + else if (DohIsMapping(it.item)) + Printf(stdout, " %s = <mapping>\n", it.key); + else if (DohIsSequence(it.item)) + Printf(stdout, " %s = <sequence>\n", it.key); + else + Printf(stdout, " %s = <unknown>\n", it.key); + } +} + + + +/* NEW LANGUAGE NOTE:*********************************************** + most of the default options are handled by SWIG + you can add new ones here + (though for now I have not bothered) +NEW LANGUAGE NOTE:END ************************************************/ +static const char *usage = (char *) "\ + Lua Options (available with -lua)\n\ + (coming soon.)\n\n"; + + + +/* NEW LANGUAGE NOTE:*********************************************** + To add a new language, you need to derive your class from + Language and the overload various virtual functions + (more on this as I figure it out) +NEW LANGUAGE NOTE:END ************************************************/ + +class LUA:public Language { +private: + + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + String *PrefixPlusUnderscore; + String *s_cmd_tab; // table of command names + String *s_var_tab; // table of global variables + String *s_const_tab; // table of global constants + String *s_methods_tab; // table of class methods + String *s_attr_tab; // table of class atributes + String *s_luacode; // luacode to be called during init + + int have_constructor; + int have_destructor; + String *destructor_action; + String *class_name; + String *constructor_name; + + enum { + NO_CPP, + VARIABLE, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }current; + +public: + + /* --------------------------------------------------------------------- + * LUA() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + LUA() { + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_initbeforefunc = 0; + PrefixPlusUnderscore = 0; + + s_cmd_tab = s_var_tab = s_const_tab = s_luacode = 0; + current=NO_CPP; + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is called to initalise the system & read any command line args + most of this is boilerplate code, except the command line args + which depends upon what args your code supports + NEW LANGUAGE NOTE:END ************************************************/ + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + /* Set location of SWIG library */ + SWIG_library_directory("lua"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { // usage flags + fputs(usage, stderr); + } + } + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is the boilerplate code, setting a few #defines + and which lib directory to use + the SWIG_library_directory() is also boilerplate code + but it always seems to be the first line of code + NEW LANGUAGE NOTE:END ************************************************/ + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGLUA 1", 0); + + /* Set language-specific configuration file */ + SWIG_config_file("lua.swg"); + + /* Set typemap language */ + SWIG_typemap_lang("lua"); + + /* Enable overloaded methods support */ + allow_overloading(); + } + + + + + /* NEW LANGUAGE NOTE:*********************************************** + After calling main, SWIG parses the code to wrap (I believe) + then calls top() + in this is more boilerplate code to set everything up + and a call to Language::top() + which begins the code generations by calling the member fns + after all that is more boilerplate code to close all down + (overall there is virtually nothing here that needs to be edited + just use as is) + NEW LANGUAGE NOTE:END ************************************************/ + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + /* Get the module name */ + String *module = Getattr(n, "name"); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + /* Open the output file */ + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_initbeforefunc = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + + /* NEW LANGUAGE NOTE:*********************************************** + s_cmd_tab,s_var_tab & s_const_tab hold the names of the fns for + registering with SWIG. + These will be filled in when the functions/variables are wrapped & + then added to the end of the wrappering code + just before it is written to file + NEW LANGUAGE NOTE:END ************************************************/ + // Initialize some variables for the object interface + s_cmd_tab = NewString(""); + s_var_tab = NewString(""); + // s_methods_tab = NewString(""); + s_const_tab = NewString(""); + + s_luacode = NewString(""); + Swig_register_filebyname("luacode", s_luacode); + + current=NO_CPP; + + /* Standard stuff for the SWIG runtime section */ + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGLUA\n"); + + // if (NoInclude) { + // Printf(f_runtime, "#define SWIG_NOINCLUDE\n"); + // } + + Printf(f_runtime, "\n"); + + //String *init_name = NewStringf("%(title)s_Init", module); + //Printf(f_header, "#define SWIG_init %s\n", init_name); + //Printf(f_header, "#define SWIG_name \"%s\"\n", module); + /* SWIG_import is a special function name for importing within Lua5.1 */ + //Printf(f_header, "#define SWIG_import luaopen_%s\n\n", module); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + Printf(f_header, "#define SWIG_init luaopen_%s\n", module); + Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module); + Printf(f_header, "#define SWIG_LUACODE luaopen_%s_luacode\n\n", module); + + Printf(s_cmd_tab, "\nstatic const struct luaL_reg swig_commands[] = {\n"); + Printf(s_var_tab, "\nstatic swig_lua_var_info swig_variables[] = {\n"); + Printf(s_const_tab, "\nstatic swig_lua_const_info swig_constants[] = {\n"); + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* %init code inclusion, effectively in the SWIG_init function */ + Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n"); + Language::top(n); + Printf(f_init,"/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); + Printf(f_init, "}\n"); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + // Done. Close up the module & write to the wrappers + Printv(s_cmd_tab, tab4, "{0,0}\n", "};\n", NIL); + Printv(s_var_tab, tab4, "{0,0,0}\n", "};\n", NIL); + Printv(s_const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); + Printv(f_wrappers, s_cmd_tab, s_var_tab, s_const_tab, NIL); + SwigType_emit_type_table(f_runtime, f_wrappers); + + /* NEW LANGUAGE NOTE:*********************************************** + this basically combines several of the strings together + and then writes it all to a file + NEW LANGUAGE NOTE:END ************************************************/ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + /* for the Lua code it needs to be properly excaped to be added into the C/C++ code */ + EscapeCode(s_luacode); + Printf(f_begin, "const char* SWIG_LUACODE=\n \"%s\";\n\n",s_luacode); + Wrapper_pretty_print(f_init, f_begin); + /* Close all of the files */ + Delete(s_luacode); + Delete(s_cmd_tab); + Delete(s_var_tab); + Delete(s_const_tab); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_initbeforefunc); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + /* Done */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + return Language::importDirective(n); + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is it! + you get this one right, and most of your work is done + but its going to take soem file to get it working right + quite a bit of this is generally boilerplate code + (or stuff I dont understand) + that which matters will have extra added comments + NEW LANGUAGE NOTE:END ************************************************/ + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + REPORT("functionWrapper",n); + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + //Printf(stdout,"functionWrapper %s %s\n",name,iname); + Parm *p; + String *tm; + int i; + //Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); + // int returnval=0; // number of arguments returned + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + Printf(stderr,"addSymbol(%s) failed\n",iname); + return SWIG_ERROR; + } + } + + /* NEW LANGUAGE NOTE:*********************************************** + the wrapper object holds all the wrappering code + we need to add a couple of local variables + NEW LANGUAGE NOTE:END ************************************************/ + Wrapper *f = NewWrapper(); + Wrapper_add_local(f, "SWIG_arg", "int SWIG_arg = 0"); + + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + + /* NEW LANGUAGE NOTE:*********************************************** + the format of a lua fn is: + static int wrap_XXX(lua_State* L){...} + this line adds this into the wrappering code + NEW LANGUAGE NOTE:END ************************************************/ + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); + + /* NEW LANGUAGE NOTE:*********************************************** + this prints the list of args, eg for a C fn + int gcd(int x,int y); + it will print + int arg1; + int arg2; + NEW LANGUAGE NOTE:END ************************************************/ + /* Write code to extract function parameters. */ + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + int varargs = emit_isvarargs(l); + + // Check if we have to ignore arguments that are passed by LUA. + // Needed for unary minus, where lua passes two arguments and + // we have to ignore the second. + + int args_to_ignore = 0; + if (Getattr(n, "lua:ignore_args")) { + args_to_ignore = GetInt(n, "lua:ignore_args"); + } + + + /* Which input argument to start with? */ + // int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; + + /* Offset to skip over the attribute name */ + // int offset = (current == MEMBER_VAR) ? 1 : 0; + + /* NEW LANGUAGE NOTE:*********************************************** + from here on in, it gets rather hairy + this is the code to convert from the scripting language to C/C++ + some of the stuff will refer to the typemaps code written in your swig file + (lua.swg), and some is done in the code here + I suppose you could do all the conversion on C, but it would be a nightmare to do + NEW LANGUAGE NOTE:END ************************************************/ + /* Generate code for argument marshalling */ + // String *description = NewString(""); + /* NEW LANGUAGE NOTE:*********************************************** + argument_check is a new feature I added to check types of arguments: + eg for int gcd(int,int) + I want to check that arg1 & arg2 really are integers + NEW LANGUAGE NOTE:END ************************************************/ + String *argument_check = NewString(""); + String *argument_parse = NewString(""); + String *checkfn = NULL; + // String *numoutputs=NULL; + char source[64]; + //Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",name,num_required,num_arguments); + Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",name,num_required+args_to_ignore,num_arguments+args_to_ignore); + + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + /* Look for an input typemap */ + sprintf(source, "%d", i + 1); + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + /* NEW LANGUAGE NOTE:*********************************************** + look for a 'checkfn' typemap + this an additional parameter added to the in typemap + if found the type will be tested for + this will result in code either in the + argument_check or argument_parse string + NEW LANGUAGE NOTE:END ************************************************/ + if ((checkfn = Getattr(p, "tmap:in:checkfn"))) { + if (i < num_required) { + Printf(argument_check, "if(!%s(L,%s))", checkfn, source); + } else { + Printf(argument_check, "if(lua_gettop(L)>=%s && !%s(L,%s))", source, checkfn, source); + } + Printf(argument_check, " SWIG_fail_arg(\"%s\",%s,\"%s\");\n", name, source, SwigType_str(pt, 0)); + } + /* NEW LANGUAGE NOTE:*********************************************** + lua states the number of arguments passed to a function using the fn + lua_gettop() + we can use this to deal with default arguments + NEW LANGUAGE NOTE:END ************************************************/ + if (i < num_required) { + Printf(argument_parse, "%s\n", tm); + } else { + Printf(argument_parse, "if(lua_gettop(L)>=%s){%s}\n", source, tm); + } + p = Getattr(p, "tmap:in:next"); + continue; + } else { + /* NEW LANGUAGE NOTE:*********************************************** + // why is this code not called when I dont have a typemap? + // instead of giving a warning, no code is generated + NEW LANGUAGE NOTE:END ************************************************/ + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + + // add all argcheck code + Printv(f->code, argument_check, argument_parse, NIL); + + /* Check for trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + String *outarg = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + // // managing the number of returning variables + // if (numoutputs=Getattr(p,"tmap:argout:numoutputs")){ + // int i=GetInt(p,"tmap:argout:numoutputs"); + // printf("got argout:numoutputs of %d\n",i); + // returnval+=GetInt(p,"tmap:argout:numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "result"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + Setattr(n, "wrap:name", wname); + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* NEW LANGUAGE NOTE:*********************************************** + FIXME: + returns 1 if there is a void return type + this is because there is a typemap for void + NEW LANGUAGE NOTE:END ************************************************/ + // Return value if necessary + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + // managing the number of returning variables + // if (numoutputs=Getattr(tm,"numoutputs")){ + // int i=GetInt(tm,"numoutputs"); + // printf("return numoutputs %d\n",i); + // returnval+=GetInt(tm,"numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", "result"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + // returnval++; + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + + /* Close the function */ + Printv(f->code, "return SWIG_arg;\n", NIL); + // add the failure cleanup code: + Printv(f->code, "\nif(0) SWIG_fail;\n", NIL); + Printv(f->code, "\nfail:\n", NIL); + Printv(f->code, "$cleanup", "lua_error(L);\n", NIL); + Printv(f->code, "return SWIG_arg;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", "result"); + + /* Dump the function out */ + /* in Lua we will not emit the destructor as a wrappered function, + Lua will automatically call the destructor when the object is free'd + However: you cannot just skip this function as it will not emit + any custom destructor (using %extend), as you need to call emit_action() + Therefore we go though the whole function, + but do not write the code into the wrapper + */ + if(current!=DESTRUCTOR) { + Wrapper_print(f, f_wrappers); + } + + /* NEW LANGUAGE NOTE:*********************************************** + register the function in SWIG + different language mappings seem to use different ideas + NEW LANGUAGE NOTE:END ************************************************/ + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + // add_method(n, iname, wname, description); + if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns + Printv(s_cmd_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(iname), "},\n", NIL); + // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), "},\n", NIL); + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + Delete(argument_check); + Delete(argument_parse); + + Delete(cleanup); + Delete(outarg); + // Delete(description); + Delete(wname); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * + * Emit overloading dispatch function + * ------------------------------------------------------------ */ + + /* NEW LANGUAGE NOTE:*********************************************** + This is an extra function used for overloading of functions + it checks the args & then calls the relevant fn + nost of the real work in again typemaps: + look for %typecheck(SWIG_TYPECHECK_*) in the .swg file + NEW LANGUAGE NOTE:END ************************************************/ + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "return %s(L);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + //Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); + + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "int argv[%d]={1", maxargs + 1); + for (int i = 1; i <= maxargs; i++) { + Printf(tmp, ",%d", i + 1); + } + Printf(tmp, "}"); + Wrapper_add_local(f, "argv", tmp); + Printf(f->code, "argc = lua_gettop(L);\n"); + + Replaceall(dispatch, "$args", "self,args"); + Printv(f->code, dispatch, "\n", NIL); + + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + Printf(protoTypes, "\n\" %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms"))); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(f->code, "lua_pushstring(L,\"Wrong arguments for overloaded function '%s'\\n\"\n" + "\" Possible C/C++ prototypes are:\\n\"%s);\n",symname,protoTypes); + Delete(protoTypes); + + Printf(f->code, "lua_error(L);return 0;\n"); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + //add_method(symname,wname,0); + if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wname, "},\n", NIL); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + /* NEW LANGUAGE NOTE:*********************************************** + Language::variableWrapper(n) will generate two wrapper fns + Foo_get & Foo_set by calling functionWrapper() + so we will just add these into the variable lists + ideally we should not have registered these as functions, + only WRT this variable will look into this later. + NEW LANGUAGE NOTE:END ************************************************/ + // REPORT("variableWrapper", n); + String *iname = Getattr(n, "sym:name"); + current=VARIABLE; + // let SWIG generate the wrappers + int result = Language::variableWrapper(n); + current=NO_CPP; + // normally SWIG will generate 2 wrappers, a get and a set + // but in certain scenarios (immutable, or if its arrays), it will not + String *getName = Swig_name_wrapper(Swig_name_get(iname)); + String *setName = 0; + // checking whether it can be set to or not appears to be a very error prone issue + // I refered to the Language::variableWrapper() to find this out + bool assignable=is_assignable(n) ? true : false; + SwigType *type = Getattr(n, "type"); + String *tm = Swig_typemap_lookup("globalin", n, iname, 0); + if (!tm && SwigType_isarray(type)) + assignable=false; + Delete(tm); + + if (assignable) { + setName = Swig_name_wrapper(Swig_name_set(iname)); + } else { + // how about calling a 'this is not settable' error message? + setName = NewString("SWIG_Lua_set_immutable"); // error message + //setName = NewString("0"); + } + // register the variable + Printf(s_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, iname, getName, setName); + Delete(getName); + Delete(setName); + return result; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + virtual int constantWrapper(Node *n) { + // REPORT("constantWrapper", n); + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + //String *nsname = !nspace ? Copy(iname) : NewStringf("%s::%s",ns_name,iname); + String *nsname = Copy(iname); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + //if (nspace) Setattr(n,"sym:name",nsname); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(s_const_tab, "%s,\n", tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(f_init, "%s\n", tm); + } else { + Delete(nsname); + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + Delete(nsname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + // REPORT("nativeWrapper", n); + String *symname = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); + // return Language::nativeWrapper(n); // this does nothing... + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + //REPORT("classHandler", n); + + String *mangled_classname = 0; + String *real_classname = 0; + + constructor_name = 0; + have_constructor = 0; + have_destructor = 0; + destructor_action = 0; + + class_name = Getattr(n, "sym:name"); + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + real_classname = Getattr(n, "name"); + mangled_classname = Swig_name_mangle(real_classname); + + // not sure exactly how this workswhat this works, + // but tcl has a static hashtable of all classes emitted and then only emits code for them once. + // this fixes issues in test suites: template_default2 & template_specialization + + // * if i understand correctly, this is a bug. + // * consider effect on template_specialization_defarg + + static Hash *emitted = NewHash(); + if (Getattr(emitted, mangled_classname)) + return SWIG_NOWRAP; + Setattr(emitted, mangled_classname, "1"); + + s_attr_tab = NewString(""); + Printf(s_attr_tab, "static swig_lua_attribute swig_"); + Printv(s_attr_tab, mangled_classname, "_attributes[] = {\n", NIL); + + s_methods_tab = NewString(""); + Printf(s_methods_tab, "static swig_lua_method swig_"); + Printv(s_methods_tab, mangled_classname, "_methods[] = {\n", NIL); + + // Generate normal wrappers + Language::classHandler(n); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType_add_pointer(t); + + // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' + String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); + SwigType_remember_clientdata(t, wrap_class); + + String *rt = Copy(Getattr(n, "classtype")); + SwigType_add_pointer(rt); + + // Register the class structure with the type checker + // Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_classname); + + // emit a function to be called to delete the object + if (have_destructor) { + Printv(f_wrappers, "static void swig_delete_", class_name, "(void *obj) {\n", NIL); + if (destructor_action) { + Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); + Printv(f_wrappers, destructor_action, "\n", NIL); + } else { + if (CPlusPlus) { + Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); + } else { + Printv(f_wrappers, " free((char *) obj);\n", NIL); + } + } + Printf(f_wrappers, "}\n"); + } + + Printf(s_methods_tab, " {0,0}\n};\n"); + Printv(f_wrappers, s_methods_tab, NIL); + + Printf(s_attr_tab, " {0,0,0}\n};\n"); + Printv(f_wrappers, s_attr_tab, NIL); + + Delete(s_methods_tab); + Delete(s_attr_tab); + + // Handle inheritance + // note: with the idea of class hireachied spread over multiple modules + // cf test-suite: imports.i + // it is not possible to just add the pointers to the base classes to the code + // (as sometimes these classes are not present) + // therefore we instead hold the name of the base class and a null pointer + // at runtime: we can query the swig type manager & see if the class exists + // if so, we can get the pointer to the base class & replace the null pointer + // if the type does not exist, then we cannot... + String *base_class = NewString(""); + String *base_class_names = NewString(""); + + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + // old code: (used the pointer to the base class) + //String *bmangle = Swig_name_mangle(bname); + //Printf(base_class, "&_wrap_class_%s", bmangle); + //Putc(',', base_class); + //Delete(bmangle); + // new code: stores a null pointer & the name + Printf(base_class, "0,"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + + b = Next(b); + index++; + } + } + + Printv(f_wrappers, "static swig_lua_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); + Delete(base_class); + Printv(f_wrappers, "static const char *swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); + Delete(base_class_names); + + Printv(f_wrappers, "static swig_lua_class _wrap_class_", mangled_classname, " = { \"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + + if (have_constructor) { + Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(constructor_name))); + Delete(constructor_name); + constructor_name = 0; + } else { + Printf(f_wrappers, "0"); + } + + if (have_destructor) { + Printv(f_wrappers, ", swig_delete_", class_name, NIL); + } else { + Printf(f_wrappers, ",0"); + } + Printf(f_wrappers, ", swig_%s_methods, swig_%s_attributes, swig_%s_bases, swig_%s_base_names };\n\n", mangled_classname, mangled_classname, mangled_classname, mangled_classname); + + // Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases };\n\n", NIL); + // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, &_wrap_class_", mangled_classname, "},\n", NIL); + Delete(t); + Delete(mangled_classname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + //Printf(stdout,"memberfunctionHandler %s %s\n",name,iname); + + // Special case unary minus: LUA passes two parameters for the + // wrapper function while we want only one. Tell our + // functionWrapper to ignore a parameter. + + if (Cmp(Getattr(n, "sym:name"), "__unm") == 0) { + //Printf(stdout, "unary minus: ignore one argument\n"); + SetInt(n, "lua:ignore_args", 1); + } + + String *realname, *rname; + + current = MEMBER_FUNC; + Language::memberfunctionHandler(n); + current = NO_CPP; + + realname = iname ? iname : name; + rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + if (!Getattr(n, "sym:nextSibling")) { + Printv(s_methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); + } + Delete(rname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + // REPORT("membervariableHandler",n); + String *symname = Getattr(n, "sym:name"); + String *gname, *sname; + + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + gname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + if (!GetFlag(n, "feature:immutable")) { + sname = Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + } else { + //sname = NewString("0"); + sname = NewString("SWIG_Lua_set_immutable"); // error message + } + Printf(s_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,gname,sname); + Delete(gname); + Delete(sname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * + * Method for adding C++ member constructor + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + // REPORT("constructorHandler", n); + current = CONSTRUCTOR; + Language::constructorHandler(n); + current = NO_CPP; + constructor_name = NewString(Getattr(n, "sym:name")); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + REPORT("destructorHandler", n); + current = DESTRUCTOR; + Language::destructorHandler(n); + current = NO_CPP; + have_destructor = 1; + destructor_action = Getattr(n, "wrap:action"); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + current = STATIC_FUNC; + return Language::staticmemberfunctionHandler(n); + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * + * Create a C++ constant + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + // REPORT("memberconstantHandler",n); + return Language::memberconstantHandler(n); + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + // REPORT("staticmembervariableHandler",n); + current = STATIC_VAR; + return Language::staticmembervariableHandler(n); + } + + /* --------------------------------------------------------------------- + * external runtime generation + * --------------------------------------------------------------------- */ + + /* This is to support the usage + SWIG -external-runtime <filename> + The code consists of two functions: + String *runtimeCode() // returns a large string with all the runtimes in + String *defaultExternalRuntimeFilename() // returns the default filename + I am writing a generic solution, even though SWIG-Lua only has one file right now... + */ + String *runtimeCode() { + String *s = NewString(""); + const char *filenames[] = { "luarun.swg", 0 + } + ; // must be 0 termiated + String *sfile; + for (int i = 0; filenames[i] != 0; i++) { + sfile = Swig_include_sys(filenames[i]); + if (!sfile) { + Printf(stderr, "*** Unable to open '%s'\n", filenames[i]); + } else { + Append(s, sfile); + Delete(sfile); + } + } + + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigluarun.h"); + } + + /* --------------------------------------------------------------------- + * helpers + * --------------------------------------------------------------------- */ + + /* This is to convert the string of Lua code into a proper string, which can then be + emitted into the C/C++ code. + Basically is is a lot of search & replacing of odd sequences + */ + void EscapeCode(String* str) + { + //Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str); + Chop(str); // trim + Replace(str,"\\","\\\\",DOH_REPLACE_ANY); // \ to \\ (this must be done first) + Replace(str,"\"","\\\"",DOH_REPLACE_ANY); // " to \" + Replace(str,"\n","\\n\"\n \"",DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line) + //Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str); + } +}; + +/* NEW LANGUAGE NOTE:*********************************************** + in order to add you language into swig, you need to make the following changes: + - write this file (obviously) + - add into the makefile (not 100% clear on how to do this) + - edit swigmain.cxx to add your module + +near the top of swigmain.cxx, look for this code & add you own codes +======= begin change ========== +extern "C" { + Language *swig_tcl(void); + Language *swig_python(void); + //etc,etc,etc... + Language *swig_lua(void); // this is my code +} + + //etc,etc,etc... + +swig_module modules[] = { + {"-guile", swig_guile, "Guile"}, + {"-java", swig_java, "Java"}, + //etc,etc,etc... + {"-lua", swig_lua, "Lua"}, // this is my code + {NULL, NULL, NULL} // this must come at the end of the list +}; +======= end change ========== + +This is all that is needed + +NEW LANGUAGE NOTE:END ************************************************/ + +/* ----------------------------------------------------------------------------- + * swig_lua() - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_lua(void) { + return new LUA(); +} diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx new file mode 100644 index 0000000..477d83b --- /dev/null +++ b/Source/Modules/main.cxx @@ -0,0 +1,1251 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * main.cxx + * + * Main entry point to the SWIG core. + * ----------------------------------------------------------------------------- */ + +char cvsroot_main_cxx[] = "$Id: main.cxx 11135 2009-02-20 20:55:16Z wsfulton $"; + +#include "swigconfig.h" + +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "swigmod.h" + +#include "swigwarn.h" +#include "cparse.h" +#include <ctype.h> +#include <limits.h> // for INT_MAX + +// Global variables + +Language *lang; // Language method +int CPlusPlus = 0; +int Extend = 0; // Extend flag +int ForceExtern = 0; // Force extern mode +int GenerateDefault = 1; // Generate default constructors +int Verbose = 0; +int AddExtern = 0; +int NoExcept = 0; +int SwigRuntime = 0; // 0 = no option, 1 = -runtime, 2 = -noruntime + +/* Suppress warning messages for private inheritance, preprocessor evaluation etc... + WARN_PP_EVALUATION 202 + WARN_PARSE_PRIVATE_INHERIT 309 + WARN_TYPE_ABSTRACT 403 + WARN_LANG_OVERLOAD_CONST 512 + WARN_PARSE_BUILTIN_NAME 321 + WARN_PARSE_REDUNDANT 322 + */ +#define EXTRA_WARNINGS "202,309,403,512,321,322" + +extern "C" { + extern String *ModuleName; +} + +/* usage string split into multiple parts otherwise string is too big for some compilers */ +/* naming conventions for commandline options - no underscores, no capital letters, join words together + * except when using a common prefix, then use '-' to separate, eg the debug-xxx options */ +static const char *usage1 = (const char *) "\ +\nGeneral Options\n\ + -addextern - Add extra extern declarations\n\ + -c++ - Enable C++ processing\n\ + -co <file> - Check <file> out of the SWIG library\n\ + -copyctor - Automatically generate copy constructors wherever possible\n\ + -cpperraswarn - Treat the preprocessor #error statement as #warning (default)\n\ + -copyright - Display copyright notices\n\ + -debug-classes - Display information about the classes found in the interface\n\ + -debug-module <n>- Display module parse tree at stages 1-4, <n> is a csv list of stages\n\ + -debug-tags - Display information about the tags found in the interface\n\ + -debug-template - Display information for debugging templates\n\ + -debug-top <n> - Display entire parse tree at stages 1-4, <n> is a csv list of stages\n\ + -debug-typedef - Display information about the types and typedefs in the interface\n\ + -debug-typemap - Display information for debugging typemaps\n\ + -directors - Turn on director mode for all the classes, mainly for testing\n\ + -dirprot - Turn on wrapping of protected members for director classes (default)\n\ + -D<symbol> - Define a symbol <symbol> (for conditional compilation)\n\ + -E - Preprocess only, does not generate wrapper code\n\ + -external-runtime [file] - Export the SWIG runtime stack\n\ + -fakeversion <v>- Make SWIG fake the program version number to <v>\n\ + -fcompact - Compile in compact mode\n\ + -features <list>- Set global features, where <list> is a comma separated list of\n\ + features, eg -features directors,autodoc=1\n\ + If no explicit value is given to the feature, a default of 1 is used\n\ +"; + +static const char *usage2 = (const char *) "\ + -fastdispatch - Enable fast dispatch mode to produce faster overload dispatcher code\n\ + -Fmicrosoft - Display error/warning messages in Microsoft format\n\ + -Fstandard - Display error/warning messages in commonly used format\n\ + -fvirtual - Compile in virtual elimination mode\n\ + -help - This output\n\ + -I- - Don't search the current directory\n\ + -I<dir> - Look for SWIG files in directory <dir>\n\ + -ignoremissing - Ignore missing include files\n\ + -importall - Follow all #include statements as imports\n\ + -includeall - Follow all #include statements\n\ + -l<ifile> - Include SWIG library file <ifile>\n\ + -macroerrors - Report errors inside macros\n\ + -makedefault - Create default constructors/destructors (the default)\n\ + -M - List all dependencies\n\ + -MD - Is equivalent to `-M -MF <file>', except `-E' is not implied\n\ + -MF <file> - Generate dependencies into <file> and continue generating wrappers\n\ + -MM - List dependencies, but omit files in SWIG library\n\ + -MMD - Like `-MD', but omit files in SWIG library\n\ + -module <name> - Set module name to <name>\n\ + -MT <target> - Set the target of the rule emitted by dependency generation\n\ + -nocontract - Turn off contract checking\n\ + -nocpperraswarn - Do not treat the preprocessor #error statement as #warning\n\ + -nodefault - Do not generate default constructors nor default destructors\n\ + -nodefaultctor - Do not generate implicit default constructors\n\ + -nodefaultdtor - Do not generate implicit default destructors\n\ + -nodirprot - Do not wrap director protected members\n\ + -noexcept - Do not wrap exception specifiers\n\ + -nofastdispatch - Disable fast dispatch mode (default)\n\ + -nopreprocess - Skip the preprocessor step\n\ +"; + +static const char *usage3 = (const char *) "\ + -notemplatereduce - Disable reduction of the typedefs in templates\n\ + -O - Enable the optimization options: \n\ + -fastdispatch -fvirtual \n\ + -o <outfile> - Set name of the output file to <outfile>\n\ + -oh <headfile> - Set name of the output header file to <headfile>\n\ + -outcurrentdir - Set default output dir to current dir instead of input file's path\n\ + -outdir <dir> - Set language specific files output directory to <dir>\n\ + -small - Compile in virtual elimination & compact mode\n\ + -swiglib - Report location of SWIG library and exit\n\ + -templatereduce - Reduce all the typedefs in templates\n\ + -v - Run in verbose mode\n\ + -version - Display SWIG version number\n\ + -Wall - Remove all warning suppression, also implies -Wextra\n\ + -Wallkw - Enable keyword warnings for all the supported languages\n\ + -Werror - Treat warnings as errors\n\ + -Wextra - Adds the following additional warnings: " EXTRA_WARNINGS "\n\ + -w<list> - Suppress/add warning messages, eg -w401,+321 - see Warnings.html\n\ + -xmlout <file> - Write XML version of the parse tree to <file> after normal processing\n\ +\n\ +Options can also be defined using the SWIG_FEATURES environment variable, for example:\n\ +\n\ + $ SWIG_FEATURES=\"-Wall\"\n\ + $ export SWIG_FEATURES\n\ + $ swig -python interface.i\n\ +\n\ +is equivalent to: \n\ +\n\ + $ swig -Wall -python interface.i \n\ +\n\ +\n"; + +// Local variables +static String *LangSubDir = 0; // Target language library subdirectory +static char *SwigLib = 0; // Library directory +static String *SwigLibWin = 0; // Extra Library directory for Windows +static int freeze = 0; +static String *lang_config = 0; +static char *hpp_extension = (char *) "h"; +static char *cpp_extension = (char *) "cxx"; +static char *depends_extension = (char *) "d"; +static String *outdir = 0; +static String *xmlout = 0; +static int outcurrentdir = 0; +static int help = 0; +static int checkout = 0; +static int cpp_only = 0; +static int no_cpp = 0; +static char *outfile_name = 0; +static char *outfile_name_h = 0; +static int tm_debug = 0; +static int dump_tags = 0; +static int dump_module = 0; +static int dump_top = 0; +static int dump_xml = 0; +static int browse = 0; +static int dump_typedef = 0; +static int dump_classes = 0; +static int werror = 0; +static int depend = 0; +static int depend_only = 0; +static int memory_debug = 0; +static int allkw = 0; +static DOH *libfiles = 0; +static DOH *cpps = 0; +static String *dependencies_file = 0; +static File *f_dependencies_file = 0; +static String *dependencies_target = 0; +static int external_runtime = 0; +static String *external_runtime_name = 0; +enum { STAGE1=1, STAGE2=2, STAGE3=4, STAGE4=8, STAGEOVERFLOW=16 }; +static List *all_output_files = 0; + +// ----------------------------------------------------------------------------- +// check_suffix() +// +// Checks the suffix of a file to see if we should emit extern declarations. +// ----------------------------------------------------------------------------- + +static int check_suffix(String *filename) { + const char *name = Char(filename); + const char *c; + if (!name) + return 0; + c = Swig_file_suffix(name); + if ((strcmp(c, ".c") == 0) || + (strcmp(c, ".C") == 0) || (strcmp(c, ".cc") == 0) || (strcmp(c, ".cxx") == 0) || (strcmp(c, ".c++") == 0) || (strcmp(c, ".cpp") == 0)) { + return 1; + } + return 0; +} + +// ----------------------------------------------------------------------------- +// install_opts(int argc, char *argv[]) +// Install all command line options as preprocessor symbols +// ----------------------------------------------------------------------------- + +static void install_opts(int argc, char *argv[]) { + int i; + int noopt = 0; + char *c; + for (i = 1; i < (argc - 1); i++) { + if (argv[i]) { + if ((*argv[i] == '-') && (!isupper(*(argv[i] + 1)))) { + String *opt = NewStringf("SWIGOPT%(upper)s", argv[i]); + Replaceall(opt, "-", "_"); + c = Char(opt); + noopt = 0; + while (*c) { + if (!(isalnum(*c) || (*c == '_'))) { + noopt = 1; + break; + } + c++; + } + if (((i + 1) < (argc - 1)) && (argv[i + 1]) && (*argv[i + 1] != '-')) { + Printf(opt, " %s", argv[i + 1]); + i++; + } else { + Printf(opt, " 1"); + } + if (!noopt) { + /* Printf(stdout,"%s\n", opt); */ + Preprocessor_define(opt, 0); + } + Delete(opt); + } + } + } +} + +// ----------------------------------------------------------------------------- +// decode_numbers_list(String *numlist) +// Decode comma separated list into a binary number of the inputs or'd together +// eg list="1,4" will return (2^0 || 2^3) = 0x1001 +// ----------------------------------------------------------------------------- + +static unsigned int decode_numbers_list(String *numlist) { + unsigned int decoded_number = 0; + if (numlist) { + List *numbers = Split(numlist, ',', INT_MAX); + if (numbers && Len(numbers) > 0) { + for (Iterator it = First(numbers); it.item; it = Next(it)) { + String *numstring = it.item; + // TODO: check that it is a number + int number = atoi(Char(numstring)); + if (number > 0 && number <= 16) { + decoded_number |= (1 << (number-1)); + } + } + } + } + return decoded_number; +} + +// ----------------------------------------------------------------------------- +// Sets the output directory for language specific (proxy) files if not set and +// adds trailing file separator if necessary. +// ----------------------------------------------------------------------------- + +static void set_outdir(const String *c_wrapper_file_dir) { + + // Add file delimiter if not present in output directory name + if (outdir && Len(outdir) != 0) { + const char *outd = Char(outdir); + if (strcmp(outd + strlen(outd) - strlen(SWIG_FILE_DELIMITER), SWIG_FILE_DELIMITER) != 0) + Printv(outdir, SWIG_FILE_DELIMITER, NIL); + } + // Use the C wrapper file's directory if the output directory has not been set by user + if (!outdir) + outdir = NewString(c_wrapper_file_dir); +} + +/* This function sets the name of the configuration file */ +void SWIG_config_file(const_String_or_char_ptr filename) { + lang_config = NewString(filename); +} + +/* Sets the target language subdirectory name */ +void SWIG_library_directory(const char *subdirectory) { + LangSubDir = NewString(subdirectory); +} + +// Returns the directory for generating language specific files (non C/C++ files) +const String *SWIG_output_directory() { + assert(outdir); + return outdir; +} + +void SWIG_config_cppext(const char *ext) { + cpp_extension = (char *) ext; +} + +List *SWIG_output_files() { + assert(all_output_files); + return all_output_files; +} + +void SWIG_setfeature(const char *cfeature, const char *cvalue) { + Hash *features_hash = Swig_cparse_features(); + String *name = NewString(""); + String *fname = NewString(cfeature); + String *fvalue = NewString(cvalue); + Swig_feature_set(features_hash, name, 0, fname, fvalue, 0); + Delete(name); + Delete(fname); + Delete(fvalue); +} + + +void SWIG_setfeatures(const char *c) { + char feature[64]; + char *fb = feature; + char *fe = fb + 63; + Hash *features_hash = Swig_cparse_features(); + String *name = NewString(""); + /* Printf(stderr,"all features %s\n", c); */ + while (*c) { + char *f = fb; + String *fname = NewString("feature:"); + String *fvalue = NewString(""); + while ((f != fe) && *c != '=' && *c != ',' && *c) { + *(f++) = *(c++); + } + *f = 0; + Printf(fname, "%s", feature); + if (*c && *(c++) == '=') { + char value[64]; + char *v = value; + char *ve = v + 63; + while ((v != ve) && *c != ',' && *c && !isspace(*c)) { + *(v++) = *(c++); + } + *v = 0; + Printf(fvalue, "%s", value); + } else { + Printf(fvalue, "1"); + } + /* Printf(stderr,"%s %s\n", fname, fvalue); */ + Swig_feature_set(features_hash, name, 0, fname, fvalue, 0); + Delete(fname); + Delete(fvalue); + } + Delete(name); +} + +/* This function handles the -external-runtime command option */ +static void SWIG_dump_runtime() { + String *outfile; + File *runtime; + String *s; + + outfile = external_runtime_name; + if (!outfile) { + outfile = lang->defaultExternalRuntimeFilename(); + if (!outfile) { + Printf(stderr, "*** Please provide a filename for the external runtime\n"); + SWIG_exit(EXIT_FAILURE); + } + } + + runtime = NewFile(outfile, "w", SWIG_output_files()); + if (!runtime) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(runtime); + Printf(runtime, "\n"); + + s = Swig_include_sys("swiglabels.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swiglabels.swg'\n"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + s = Swig_include_sys("swigerrors.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swigerrors.swg'\n"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + s = Swig_include_sys("swigerrors.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swigerrors.swg'\n"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + s = Swig_include_sys("swigrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'swigrun.swg'\n"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + s = lang->runtimeCode(); + Printf(runtime, "%s", s); + Delete(s); + + s = Swig_include_sys("runtime.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'runtime.swg'\n"); + Close(runtime); + SWIG_exit(EXIT_FAILURE); + } + Printf(runtime, "%s", s); + Delete(s); + + Close(runtime); + Delete(runtime); + SWIG_exit(EXIT_SUCCESS); +} + +void SWIG_getoptions(int argc, char *argv[]) { + int i; + // Get options + for (i = 1; i < argc; i++) { + if (argv[i] && !Swig_check_marked(i)) { + if (strncmp(argv[i], "-I-", 3) == 0) { + // Don't push/pop directories + Swig_set_push_dir(0); + Swig_mark_arg(i); + } else if (strncmp(argv[i], "-I", 2) == 0) { + // Add a new directory search path + char *a = Swig_copy_string(argv[i] + 2); + Swig_add_directory((DOH *) a); + free(a); + Swig_mark_arg(i); + } else if (strncmp(argv[i], "-D", 2) == 0) { + String *d = NewString(argv[i] + 2); + Replace(d, (char *) "=", (char *) " ", DOH_REPLACE_ANY | DOH_REPLACE_FIRST); + Preprocessor_define((DOH *) d, 0); + Delete(d); + // Create a symbol + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-E") == 0) { + cpp_only = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nopreprocess") == 0) { + no_cpp = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-verbose") == 0) || (strcmp(argv[i], "-v") == 0)) { + Verbose = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-c++") == 0) { + CPlusPlus = 1; + Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); + Swig_cparse_cplusplus(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fcompact") == 0) { + Wrapper_compact_print_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fvirtual") == 0) { + Wrapper_virtual_elimination_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastdispatch") == 0) { + Wrapper_fast_dispatch_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastdispatch") == 0) { + Wrapper_fast_dispatch_mode_set(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-naturalvar") == 0) { + Wrapper_naturalvar_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nonaturalvar") == 0) { + Wrapper_naturalvar_mode_set(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-directors") == 0) { + SWIG_setfeature("feature:director", "1"); + Wrapper_director_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dirprot") == 0) { + Wrapper_director_protected_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nodirprot") == 0) { + Wrapper_director_protected_mode_set(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-small") == 0) { + Wrapper_compact_print_mode_set(1); + Wrapper_virtual_elimination_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-runtime") == 0) { // Used to also accept -c. removed in swig-1.3.36 + Swig_mark_arg(i); + Swig_warning(WARN_DEPRECATED_OPTC, "SWIG", 1, "-runtime, -noruntime command line options are deprecated.\n"); + SwigRuntime = 1; + } else if (strcmp(argv[i], "-noruntime") == 0) { + Swig_mark_arg(i); + Swig_warning(WARN_DEPRECATED_OPTC, "SWIG", 1, "-runtime, -noruntime command line options are deprecated.\n"); + SwigRuntime = 2; + } else if (strcmp(argv[i], "-external-runtime") == 0) { + external_runtime = 1; + Swig_mark_arg(i); + if (argv[i + 1]) { + external_runtime_name = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + i++; + } + } else if ((strcmp(argv[i], "-make_default") == 0) || (strcmp(argv[i], "-makedefault") == 0)) { + GenerateDefault = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-no_default") == 0) || (strcmp(argv[i], "-nodefault") == 0)) { + GenerateDefault = 0; + Swig_warning(WARN_DEPRECATED_NODEFAULT, "SWIG", 1, "dangerous, use -nodefaultctor, -nodefaultdtor instead.\n"); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-nodefaultctor") == 0)) { + SWIG_setfeature("feature:nodefaultctor", "1"); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-nodefaultdtor") == 0)) { + SWIG_setfeature("feature:nodefaultdtor", "1"); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-copyctor") == 0)) { + SWIG_setfeature("feature:copyctor", "1"); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noexcept") == 0) { + NoExcept = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noextern") == 0) { + Swig_warning(WARN_DEPRECATED_NOEXTERN, "SWIG", 1, "-noextern command line option is deprecated; extern is no longer generated by default.\n"); + AddExtern = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-addextern") == 0) { + AddExtern = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-template") == 0) || (strcmp(argv[i], "-debug_template") == 0) || (strcmp(argv[i], "-show_templates") == 0)) { + Swig_cparse_debug_templates(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-templatereduce") == 0) { + SWIG_cparse_template_reduce(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-notemplatereduce") == 0) { + SWIG_cparse_template_reduce(0); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-macroerrors") == 0) { + Swig_cparse_follow_locators(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-swiglib") == 0) { + if (SwigLibWin) + printf("%s\n", Char(SwigLibWin)); + printf("%s\n", SwigLib); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-o") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outfile_name = Swig_copy_string(argv[i + 1]); + if (!outfile_name_h || !dependencies_file) { + char *ext = strrchr(outfile_name, '.'); + String *basename = ext ? NewStringWithSize(outfile_name, ext - outfile_name) : NewString(outfile_name); + if (!dependencies_file) { + dependencies_file = NewStringf("%s.%s", basename, depends_extension); + } + if (!outfile_name_h) { + Printf(basename, ".%s", hpp_extension); + outfile_name_h = Swig_copy_string(Char(basename)); + } + Delete(basename); + } + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-oh") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outfile_name_h = Swig_copy_string(argv[i + 1]); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-fakeversion") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + Swig_set_fakeversion(argv[i + 1]); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-version") == 0) { + fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); + fprintf(stdout, "\nCompiled with %s [%s]\n", SWIG_CXX, SWIG_PLATFORM); + fprintf(stdout, "Please see %s for reporting bugs and further information\n", PACKAGE_BUGREPORT); + SWIG_exit(EXIT_SUCCESS); + } else if (strcmp(argv[i], "-copyright") == 0) { + fprintf(stdout, "\nSWIG Version %s\n", Swig_package_version()); + fprintf(stdout, "Copyright (c) 1995-1998\n"); + fprintf(stdout, "University of Utah and the Regents of the University of California\n"); + fprintf(stdout, "Copyright (c) 1998-2005\n"); + fprintf(stdout, "University of Chicago\n"); + fprintf(stdout, "Copyright (c) 2005-2006\n"); + fprintf(stdout, "Arizona Board of Regents (University of Arizona)\n"); + SWIG_exit(EXIT_SUCCESS); + } else if (strncmp(argv[i], "-l", 2) == 0) { + // Add a new directory search path + Append(libfiles, argv[i] + 2); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-co") == 0) { + checkout = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-features") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + SWIG_setfeatures(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-freeze") == 0) { + freeze = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-includeall") == 0) { + Preprocessor_include_all(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-importall") == 0) { + Preprocessor_import_all(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-ignoremissing") == 0) { + Preprocessor_ignore_missing(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cpperraswarn") == 0) { + Preprocessor_error_as_warning(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocpperraswarn") == 0) { + Preprocessor_error_as_warning(0); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-typemap") == 0) || (strcmp(argv[i], "-debug_typemap") == 0) || (strcmp(argv[i], "-tm_debug") == 0)) { + tm_debug = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-module") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + ModuleName = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-M") == 0) { + depend = 1; + depend_only = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MM") == 0) { + depend = 2; + depend_only = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MF") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + dependencies_file = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-MD") == 0) { + depend = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MMD") == 0) { + depend = 2; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-MT") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + if (!dependencies_target) + dependencies_target = NewString(argv[i + 1]); + else + Printf(dependencies_target, " %s", argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-outdir") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + outdir = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-outcurrentdir") == 0) { + Swig_mark_arg(i); + outcurrentdir = 1; + } else if (strcmp(argv[i], "-Wall") == 0) { + Swig_mark_arg(i); + Swig_warnall(); + } else if (strcmp(argv[i], "-Wallkw") == 0) { + allkw = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Werror") == 0) { + werror = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Wextra") == 0) { + Swig_mark_arg(i); + Swig_warnfilter(EXTRA_WARNINGS, 0); + } else if (strncmp(argv[i], "-w", 2) == 0) { + Swig_mark_arg(i); + Swig_warnfilter(argv[i] + 2, 1); + } else if ((strcmp(argv[i], "-debug-tags") == 0) || (strcmp(argv[i], "-dump_tags") == 0)) { + dump_tags = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-debug-top") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + String *dump_list = NewString(argv[i + 1]); + dump_top = decode_numbers_list(dump_list); + if (dump_top < STAGE1 || dump_top >= STAGEOVERFLOW) + Swig_arg_error(); + else + Swig_mark_arg(i + 1); + Delete(dump_list); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-debug-module") == 0) { + Swig_mark_arg(i); + if (argv[i + 1]) { + String *dump_list = NewString(argv[i + 1]); + dump_module = decode_numbers_list(dump_list); + if (dump_module < STAGE1 || dump_module >= STAGEOVERFLOW) + Swig_arg_error(); + else + Swig_mark_arg(i + 1); + Delete(dump_list); + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-dump_tree") == 0) || (strcmp(argv[i], "-dump_top") == 0)) { + dump_top |= STAGE4; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_module") == 0) { + dump_module |= STAGE4; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_parse_module") == 0) { + dump_module |= STAGE1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_parse_top") == 0) { + dump_top |= STAGE1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dump_xml") == 0) { + dump_xml = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-xmlout") == 0) { + dump_xml = 1; + Swig_mark_arg(i); + if (argv[i + 1]) { + xmlout = NewString(argv[i + 1]); + Swig_mark_arg(i + 1); + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-nocontract") == 0) { + Swig_mark_arg(i); + Swig_contract_mode_set(0); + } else if (strcmp(argv[i], "-browse") == 0) { + browse = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-typedef") == 0) || (strcmp(argv[i], "-dump_typedef") == 0)) { + dump_typedef = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-classes") == 0) || (strcmp(argv[i], "-dump_classes") == 0)) { + dump_classes = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-debug-memory") == 0) || (strcmp(argv[i], "-dump_memory") == 0)) { + memory_debug = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Fstandard") == 0) { + Swig_error_msg_format(EMF_STANDARD); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-Fmicrosoft") == 0) { + Swig_error_msg_format(EMF_MICROSOFT); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-O") == 0) { + Wrapper_virtual_elimination_mode_set(1); + Wrapper_fast_dispatch_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage1, stdout); + fputs(usage2, stdout); + fputs(usage3, stdout); + Swig_mark_arg(i); + help = 1; + } + } + } +} + + + + + +int SWIG_main(int argc, char *argv[], Language *l) { + char *c; + extern void Swig_print_xml(Node *obj, String *filename); + + /* Initialize the SWIG core */ + Swig_init(); + + // Default warning suppression + Swig_warnfilter(EXTRA_WARNINGS, 1); + + // Initialize the preprocessor + Preprocessor_init(); + + lang = l; + + // Set up some default symbols (available in both SWIG interface files + // and C files) + + Preprocessor_define((DOH *) "SWIG 1", 0); + Preprocessor_define((DOH *) "__STDC__", 0); +#ifdef MACSWIG + Preprocessor_define((DOH *) "SWIGMAC 1", 0); +#endif +#ifdef SWIGWIN32 + Preprocessor_define((DOH *) "SWIGWIN32 1", 0); +#endif + + // Set the SWIG version value in format 0xAABBCC from package version expected to be in format A.B.C + String *package_version = NewString(PACKAGE_VERSION); /* Note that the fakeversion has not been set at this point */ + char *token = strtok(Char(package_version), "."); + String *vers = NewString("SWIG_VERSION 0x"); + int count = 0; + while (token) { + int len = strlen(token); + assert(len == 1 || len == 2); + Printf(vers, "%s%s", (len == 1) ? "0" : "", token); + token = strtok(NULL, "."); + count++; + } + Delete(package_version); + assert(count == 3); // Check version format is correct + + /* Turn on contracts */ + + Swig_contract_mode_set(1); + Preprocessor_define(vers, 0); + + /* Turn off directors mode */ + Wrapper_director_mode_set(0); + Wrapper_director_protected_mode_set(1); + + // Create Library search directories + + // Check for SWIG_LIB environment variable + if ((c = getenv("SWIG_LIB")) == (char *) 0) { +#if defined(_WIN32) + char buf[MAX_PATH]; + char *p; + if (!(GetModuleFileName(0, buf, MAX_PATH) == 0 || (p = strrchr(buf, '\\')) == 0)) { + *(p + 1) = '\0'; + SwigLibWin = NewStringf("%sLib", buf); // Native windows installation path + } + SwigLib = Swig_copy_string(SWIG_LIB_WIN_UNIX); // Unix installation path using a drive letter (for msys/mingw) +#else + SwigLib = Swig_copy_string(SWIG_LIB); +#endif + } else { + SwigLib = Swig_copy_string(c); + } + + libfiles = NewList(); + all_output_files = NewList(); + + /* Check for SWIG_FEATURES environment variable */ + + SWIG_getoptions(argc, argv); + + // Define the __cplusplus symbol + if (CPlusPlus) + Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); + + // Parse language dependent options + lang->main(argc, argv); + + if (help) { + Printf(stdout, "\nNote: 'swig -<lang> -help' displays options for a specific target language.\n\n"); + SWIG_exit(EXIT_SUCCESS); // Exit if we're in help mode + } + // Check all of the options to make sure we're cool. + // Don't check for an input file if -external-runtime is passed + Swig_check_options(external_runtime ? 0 : 1); + + install_opts(argc, argv); + + // Add language dependent directory to the search path + { + String *rl = NewString(""); + Printf(rl, ".%sswig_lib%s%s", SWIG_FILE_DELIMITER, SWIG_FILE_DELIMITER, LangSubDir); + Swig_add_directory(rl); + if (SwigLibWin) { + rl = NewString(""); + Printf(rl, "%s%s%s", SwigLibWin, SWIG_FILE_DELIMITER, LangSubDir); + Swig_add_directory(rl); + } + rl = NewString(""); + Printf(rl, "%s%s%s", SwigLib, SWIG_FILE_DELIMITER, LangSubDir); + Swig_add_directory(rl); + } + + Swig_add_directory((String *) "." SWIG_FILE_DELIMITER "swig_lib"); + if (SwigLibWin) + Swig_add_directory((String *) SwigLibWin); + Swig_add_directory((String *) SwigLib); + + if (Verbose) { + printf("LangSubDir: %s\n", Char(LangSubDir)); + printf("Search paths:\n"); + List *sp = Swig_search_path(); + Iterator s; + for (s = First(sp); s.item; s = Next(s)) { + Printf(stdout, " %s\n", s.item); + } + } + // handle the -external-runtime argument + if (external_runtime) + SWIG_dump_runtime(); + + // If we made it this far, looks good. go for it.... + + input_file = NewString(argv[argc - 1]); + Swig_filename_correct(input_file); + + // If the user has requested to check out a file, handle that + if (checkout) { + DOH *s; + char *outfile = Char(input_file); + if (outfile_name) + outfile = outfile_name; + + if (Verbose) + printf("Handling checkout...\n"); + + s = Swig_include(input_file); + if (!s) { + Printf(stderr, "Unable to locate '%s' in the SWIG library.\n", input_file); + } else { + FILE *f = Swig_open(outfile); + if (f) { + fclose(f); + Printf(stderr, "File '%s' already exists. Checkout aborted.\n", outfile); + } else { + File *f_outfile = NewFile(outfile, "w", SWIG_output_files()); + if (!f_outfile) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } else { + if (Verbose) + Printf(stdout, "'%s' checked out from the SWIG library.\n", outfile); + Printv(f_outfile, s, NIL); + Close(f_outfile); + } + } + } + } else { + // Run the preprocessor + if (Verbose) + printf("Preprocessing...\n"); + + { + int i; + String *fs = NewString(""); + FILE *df = Swig_open(input_file); + if (!df) { + df = Swig_include_open(input_file); + if (!df) { + char *cfile = Char(input_file); + if (cfile && cfile[0] == '-') { + Printf(stderr, "Unable to find option or file '%s', ", input_file); + Printf(stderr, "use 'swig -help' for more information.\n"); + } else { + Printf(stderr, "Unable to find file '%s'.\n", input_file); + } + SWIG_exit(EXIT_FAILURE); + } else { + Swig_warning(WARN_DEPRECATED_INPUT_FILE, "SWIG", 1, "Use of the include path to find the input file is deprecated and will not work with ccache. Please include the path when specifying the input file.\n"); // so that behaviour is like c/c++ compilers + } + } + if (!no_cpp) { + fclose(df); + Printf(fs, "%%include <swig.swg>\n"); + if (allkw) { + Printf(fs, "%%include <allkw.swg>\n"); + } + if (lang_config) { + Printf(fs, "\n%%include <%s>\n", lang_config); + } + Printf(fs, "%%include(maininput=\"%s\") \"%s\"\n", Swig_filename_escape(input_file), Swig_last_file()); + for (i = 0; i < Len(libfiles); i++) { + Printf(fs, "\n%%include \"%s\"\n", Getitem(libfiles, i)); + } + Seek(fs, 0, SEEK_SET); + cpps = Preprocessor_parse(fs); + Delete(fs); + } else { + cpps = Swig_read_file(df); + fclose(df); + } + if (Swig_error_count()) { + SWIG_exit(EXIT_FAILURE); + } + if (cpp_only) { + Printf(stdout, "%s", cpps); + SWIG_exit(EXIT_SUCCESS); + } + if (depend) { + if (!no_cpp) { + String *outfile; + + char *basename = Swig_file_basename(outcurrentdir ? Swig_file_filename(input_file): Char(input_file)); + if (!outfile_name) { + if (CPlusPlus || lang->cplus_runtime_mode()) { + outfile = NewStringf("%s_wrap.%s", basename, cpp_extension); + } else { + outfile = NewStringf("%s_wrap.c", basename); + } + } else { + outfile = NewString(outfile_name); + } + if (dependencies_file && Len(dependencies_file) != 0) { + f_dependencies_file = NewFile(dependencies_file, "w", SWIG_output_files()); + if (!f_dependencies_file) { + FileErrorDisplay(dependencies_file); + SWIG_exit(EXIT_FAILURE); + } + } else if (!depend_only) { + String *filename = NewStringf("%s_wrap.%s", basename, depends_extension); + f_dependencies_file = NewFile(filename, "w", SWIG_output_files()); + if (!f_dependencies_file) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + } else + f_dependencies_file = stdout; + if (dependencies_target) { + Printf(f_dependencies_file, "%s: ", dependencies_target); + } else { + Printf(f_dependencies_file, "%s: ", outfile); + } + List *files = Preprocessor_depend(); + for (int i = 0; i < Len(files); i++) { + if ((depend != 2) || ((depend == 2) && (Strncmp(Getitem(files, i), SwigLib, Len(SwigLib)) != 0))) { + Printf(f_dependencies_file, "\\\n %s ", Getitem(files, i)); + } + } + Printf(f_dependencies_file, "\n"); + if (f_dependencies_file != stdout) + Close(f_dependencies_file); + if (depend_only) + SWIG_exit(EXIT_SUCCESS); + } else { + Printf(stderr, "Cannot generate dependencies with -nopreprocess\n"); + // Actually we could but it would be inefficient when just generating dependencies, as it would be done after Swig_cparse + SWIG_exit(EXIT_FAILURE); + } + } + Seek(cpps, 0, SEEK_SET); + } + + /* Register a null file with the file handler */ + Swig_register_filebyname("null", NewString("")); + + // Pass control over to the specific language interpreter + if (Verbose) { + fprintf(stdout, "Starting language-specific parse...\n"); + fflush(stdout); + } + + Node *top = Swig_cparse(cpps); + + if (dump_top & STAGE1) { + Printf(stdout, "debug-top stage 1\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE1) { + Printf(stdout, "debug-module stage 1\n"); + Swig_print_tree(Getattr(top, "module")); + } + + if (Verbose) { + Printf(stdout, "Processing types...\n"); + } + Swig_process_types(top); + + if (dump_top & STAGE2) { + Printf(stdout, "debug-top stage 2\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE2) { + Printf(stdout, "debug-module stage 2\n"); + Swig_print_tree(Getattr(top, "module")); + } + + if (Verbose) { + Printf(stdout, "C++ analysis...\n"); + } + Swig_default_allocators(top); + + if (dump_top & STAGE3) { + Printf(stdout, "debug-top stage 3\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE3) { + Printf(stdout, "debug-module stage 3\n"); + Swig_print_tree(Getattr(top, "module")); + } + + if (Verbose) { + Printf(stdout, "Generating wrappers...\n"); + } + + if (dump_classes) { + Hash *classes = Getattr(top, "classes"); + if (classes) { + Printf(stdout, "Classes\n"); + Printf(stdout, "------------\n"); + Iterator ki; + for (ki = First(classes); ki.key; ki = Next(ki)) { + Printf(stdout, "%s\n", ki.key); + } + } + } + + if (dump_typedef) { + SwigType_print_scope(0); + } + + if (dump_tags) { + Swig_print_tags(top, 0); + } + if (top) { + if (!Getattr(top, "name")) { + Printf(stderr, "No module name specified using %%module or -module.\n"); + SWIG_exit(EXIT_FAILURE); + } else { + /* Set some filename information on the object */ + String *infile = scanner_get_main_input_file(); + if (!infile) { + Printf(stderr, "Missing input file in preprocessed output.\n"); + SWIG_exit(EXIT_FAILURE); + } + Setattr(top, "infile", infile); // Note: if nopreprocess then infile is the original input file, otherwise input_file + Setattr(top, "inputfile", input_file); + + char *basename = Swig_file_basename(outcurrentdir ? Swig_file_filename(infile): Char(infile)); + if (!outfile_name) { + if (CPlusPlus || lang->cplus_runtime_mode()) { + Setattr(top, "outfile", NewStringf("%s_wrap.%s", basename, cpp_extension)); + } else { + Setattr(top, "outfile", NewStringf("%s_wrap.c", basename)); + } + } else { + Setattr(top, "outfile", outfile_name); + } + if (!outfile_name_h) { + Setattr(top, "outfile_h", NewStringf("%s_wrap.%s", basename, hpp_extension)); + } else { + Setattr(top, "outfile_h", outfile_name_h); + } + set_outdir(Swig_file_dirname(Getattr(top, "outfile"))); + if (Swig_contract_mode_get()) { + Swig_contracts(top); + } + + // Check the suffix for a c/c++ file. If so, we're going to declare everything we see as "extern" + ForceExtern = check_suffix(input_file); + + lang->top(top); + + if (browse) { + Swig_browser(top, 0); + } + } + } + if (dump_top & STAGE4) { + Printf(stdout, "debug-top stage 4\n"); + Swig_print_tree(top); + } + if (dump_module & STAGE4) { + Printf(stdout, "debug-module stage 4\n"); + Swig_print_tree(Getattr(top, "module")); + } + if (dump_xml && top) { + Swig_print_xml(top, xmlout); + } + Delete(top); + } + if (tm_debug) + Swig_typemap_debug(); + if (memory_debug) + DohMemoryDebug(); + + char *outfiles = getenv("CCACHE_OUTFILES"); + if (outfiles) { + File *f_outfiles = NewFile(outfiles, "w", 0); + if (!f_outfiles) { + Printf(stderr, "Failed to write list of output files to the filename '%s' specified in CCACHE_OUTFILES environment variable - ", outfiles); + FileErrorDisplay(outfiles); + SWIG_exit(EXIT_FAILURE); + } else { + int i; + for (i = 0; i < Len(all_output_files); i++) + Printf(f_outfiles, "%s\n", Getitem(all_output_files, i)); + Close(f_outfiles); + } + } + + // Deletes + Delete(libfiles); + Preprocessor_delete(); + + while (freeze) { + } + + if ((werror) && (Swig_warn_count())) { + return Swig_warn_count(); + } + return Swig_error_count(); +} + +// -------------------------------------------------------------------------- +// SWIG_exit(int exit_code) +// +// Cleanup and either freeze or exit +// -------------------------------------------------------------------------- + +void SWIG_exit(int exit_code) { + while (freeze) { + } + exit(exit_code); +} diff --git a/Source/Modules/modula3.cxx b/Source/Modules/modula3.cxx new file mode 100644 index 0000000..40f275a --- /dev/null +++ b/Source/Modules/modula3.cxx @@ -0,0 +1,3987 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * modula3.cxx + * + * Modula3 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_modula3_cxx[] = "$Id: modula3.cxx 11584 2009-08-16 00:04:29Z wsfulton $"; + +/* + Text formatted with + indent -sob -br -ce -nut -npsl +*/ + +/* + Report: + - It's not a good concept to use member variables or global variables + for passing parameters to functions. + It's not a good concept to use functions of superclasses for specific services. + E.g. For SWIG this means: Generating accessor functions for member variables + is the most common but no general task to be processed in membervariableHandler. + Better provide a service function which generates accessor function code + and equip this service function with all parameters needed for input (parse node) + and output (generated code). + - How can I make globalvariableHandler not to generate + interface functions to two accessor functions + (that don't exist) ? + - How can I generate a typemap that turns every C reference argument into + its Modula 3 counterpart, that is + void test(Complex &z); + PROCEDURE test(VAR z:Complex); + - neither $*n_mangle nor $*n_type nor $*n_ltype return the type without + pointer converted to Modula3 equivalent, + $*n_mangle is the variant closest to what I expect + - using a typemap like + typemap(m3wrapintype) int * %{VAR $1_name: INTEGER%} + has the advantages: + - one C parameter can be turned into multiple M3 parameters + - the argument can be renamed + - using typemaps like + typemap(m3wrapinmode) int * "VAR" + typemap(m3wrapintype) int * "INTEGER" + has the advantages: + - multiple parameters with same type and default value can be bundled + - more conform to the other language modules + - Where takes the reduction of multi-typemaps place? + How can I preserve all parameters for functions of the intermediary class? + The answer is Getattrs(n,"tmap:m3rawintype:next") + - Char() can be used to transform a String to (char *) + which can be used for output with printf + - What is the while (checkAttribute()) loop in functionWrapper good for? + Appearently for skipping (numinputs=0) typemaps. + - SWIGTYPE const * - typemap is ignored, whereas + SWIGTYPE * - typemap is invoked, why? + Had it been (const SWIGTYPE *) instead? + - enumeration items should definitely be equipped + with its plain numerical value + One could add tag 'numvalue' in CParse/parser.y, + but it is still possible that someone declares an + enumeration using a symbolic constant. + I have quickly hacked + that the successive number is assigned + if "enumvalue" has suffix "+1". + The ultimate solution would be to generate a C program + which includes the header and outputs all constants. + This program might be compiled and run + by 'make' or by SWIG and the resulting output is fed back to SWIG. + - It's a bad idea to interpret feature value "" + 'disable feature' because the value "" + might be sensible in case of feature:modula3:oldprefix. + - What's the difference between "sym:name" and "name" ? + "name" is the original name and + "sym:name" is probably modified by the user using %rename + - Is it possible for 'configure' to find out if m3pp is installed + and to invoke it for generated Modula3 files? + - It would be better to separate an arguments purpose and its name, + because an output variable with name "OUTPUT" is not very descriptive. + In case of PLPlot this could be solved by typedefs + that assign special purposes to the array types. + - Can one interpret $n_basetype as the identifier matched with SWIGTYPE ? + + Swig's odds: + - arguments of type (Node *) for SWIG functions + should be most often better (const Node *): + Swig_symbol_qualified, Getattr, nodeType, parentNode + - unique identifier style instead of + NewString, Getattr, firstChild + - 'class'.name is qualified, + 'enum'.name and 'enumitem'.name is not + - Swig_symbol_qualified() returns NIL for enumeration nodes + + - Is there a function that creates a C representation of a SWIG type string? + + ToDo: + - create WeakRefs only for resources returned by function marked with %newobject + -> part of output conversion + - clean typemap conception + - should a multi-typemap for m3wrapouttype skip the corresponding input parameters? + when yes - How to handle inout-arguments? In this case like in-argument. + - C++ classes + - C++ exceptions + - allow for moving RECORD and OBJECT definitions + to separate files, with the main type called T + - call-back functions + - special option: fast access to class members by pointer arithmetic, + member offsets can be determined by a C++ program that print them. + - emit enumeration definitions when its first item is declared, + currently enumerations are emitted at the beginning of the file + + Done: + - addThrow should convert the typemap by itself + - not possible because routine for attaching mapped types to parameter nodes + won't work for the function node + - turning error codes into exceptions + -> part of output value checking + - create WeakRefs for resources allocated by the library + -> part of output conversion + - TRY..FINALLY..END; can be omitted + - if there is no m3wrapfreearg + - no exception can be raised in the body (empty RAISES) list +*/ + +#include "swigmod.h" + +#include <limits.h> // for INT_MAX +#include <ctype.h> + +#define USAGE_ARG_DIR "m3wrapargdir typemap expect values: in, out, inout\n" + +class MODULA3:public Language { +public: + enum block_type { no_block, constant, variable, blocktype, revelation }; + +private: + struct M3File { + String *f; + Hash *import; + block_type bt; + /* VC++ 6 doesn't allow the access to 'no_block' + if it is a private member of MODULA3 class */ + M3File():f(NewString("")), import(NewHash()), bt(no_block) { + } + ~M3File() { + Delete(f); + Delete(import); + } + + /* ----------------------------------------------------------------------------- + * enterBlock() + * + * Make sure that a given declaration is written to the right declaration block, + * that is constants are written after "CONST" and so on ... + * ----------------------------------------------------------------------------- */ + void enterBlock(block_type newbt) { + static const char *ident[] = { "", "\nCONST\n", "\nVAR\n", "\nTYPE\n", "\nREVEAL\n" }; +#ifdef DEBUG + if ((bt < 0) || (4 < bt)) { + printf("bt %d out of range\n", bt); + } +#endif + if (newbt != bt) { + Append(f, ident[newbt]); + bt = newbt; + } + } + + }; + + static const char *usage; + const String *empty_string; + + Hash *swig_types_hash; + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + + bool proxy_flag; // Flag for generating proxy classes + bool have_default_constructor_flag; + bool native_function_flag; // Flag for when wrapping a native function + bool enum_constant_flag; // Flag for when wrapping an enum or constant + bool static_flag; // Flag for when wrapping a static functions or member variables + bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable + bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const + bool global_variable_flag; // Flag for when wrapping a global variable + bool old_variable_names; // Flag for old style variable names in the intermediary class + bool unsafe_module; + + String *m3raw_name; // raw interface name + M3File m3raw_intf; // raw interface + M3File m3raw_impl; // raw implementation (usually empty) + String *m3wrap_name; // wrapper module + M3File m3wrap_intf; + M3File m3wrap_impl; + String *m3makefile; + String *targetlibrary; + String *proxy_class_def; + String *proxy_class_code; + String *proxy_class_name; + String *variable_name; //Name of a variable being wrapped + String *variable_type; //Type of this variable + String *enumeration_name; //Name of the current enumeration type + Hash *enumeration_items; //and its members + int enumeration_max; + Hash *enumeration_coll; //Collection of all enumerations. + /* The items are nodes with members: + "items" - hash of with key 'itemname' and content 'itemvalue' + "max" - maximum value in item list + */ + String *constant_values; + String *constantfilename; + String *renamefilename; + String *typemapfilename; + String *m3raw_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *m3raw_baseclass; //inheritance for intermediary class class from %pragma + String *module_baseclass; //inheritance for module class from %pragma + String *m3raw_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *m3raw_class_modifiers; //class modifiers for intermediary class overriden by %pragma + String *m3wrap_modifiers; //class modifiers for module class overriden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *m3raw_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *destructor_call; //C++ destructor call if any + String *outfile; + + enum type_additions { none, pointer, reference }; + +public: + + /* ----------------------------------------------------------------------------- + * MODULA3() + * ----------------------------------------------------------------------------- */ + +MODULA3(): + empty_string(NewString("")), + swig_types_hash(NULL), + f_begin(NULL), + f_runtime(NULL), + f_header(NULL), + f_wrappers(NULL), + f_init(NULL), + proxy_flag(true), + have_default_constructor_flag(false), + native_function_flag(false), + enum_constant_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + old_variable_names(false), + unsafe_module(false), + m3raw_name(NULL), + m3raw_intf(), + m3raw_impl(), + m3wrap_name(NULL), + m3wrap_intf(), + m3wrap_impl(), + m3makefile(NULL), + targetlibrary(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + proxy_class_name(NULL), + variable_name(NULL), + variable_type(NULL), + enumeration_name(NULL), + enumeration_items(NULL), + enumeration_max(0), + enumeration_coll(NULL), + constant_values(NULL), + constantfilename(NULL), + renamefilename(NULL), + typemapfilename(NULL), + m3raw_imports(NULL), + module_imports(NULL), + m3raw_baseclass(NULL), + module_baseclass(NULL), + m3raw_interfaces(NULL), + module_interfaces(NULL), + m3raw_class_modifiers(NULL), + m3wrap_modifiers(NULL), + upcasts_code(NULL), + m3raw_cppcasts_code(NULL), + destructor_call(NULL), + outfile(NULL) { + } + + /************** some utility functions ***************/ + + /* ----------------------------------------------------------------------------- + * getMappedType() + * + * Return the type of 'p' mapped by 'map'. + * Print a standard warning if 'p' can't be mapped. + * ----------------------------------------------------------------------------- */ + + String *getMappedType(Node *p, const char *map) { + String *mapattr = NewString("tmap:"); + Append(mapattr, map); + + String *tm = Getattr(p, mapattr); + if (tm == NIL) { + Swig_warning(WARN_MODULA3_TYPEMAP_TYPE_UNDEF, input_file, line_number, + "No '%s' typemap defined for type '%s'\n", map, SwigType_str(Getattr(p, "type"), 0)); + } + Delete(mapattr); + return tm; + } + + /* ----------------------------------------------------------------------------- + * getMappedTypeNew() + * + * Similar to getMappedType but uses Swig_type_lookup_new. + * ----------------------------------------------------------------------------- */ + + String *getMappedTypeNew(Node *n, const char *map, const char *lname = "", bool warn = true) { + String *tm = Swig_typemap_lookup(map, n, lname, 0); + if ((tm == NIL) && warn) { + Swig_warning(WARN_MODULA3_TYPEMAP_TYPE_UNDEF, input_file, line_number, + "No '%s' typemap defined for type '%s'\n", map, SwigType_str(Getattr(n, "type"), 0)); + } + return tm; + } + + /* ----------------------------------------------------------------------------- + * attachMappedType() + * + * Obtain the type mapped by 'map' and attach it to the node + * ----------------------------------------------------------------------------- */ + + void attachMappedType(Node *n, const char *map, const char *lname = "") { + String *tm = Swig_typemap_lookup(map, n, lname, 0); + if (tm != NIL) { + String *attr = NewStringf("tmap:%s", map); + Setattr(n, attr, tm); + Delete(attr); + } + } + + /* ----------------------------------------------------------------------------- + * skipIgnored() + * + * Skip all parameters that have 'numinputs=0' + * with respect to a given typemap. + * ----------------------------------------------------------------------------- */ + + Node *skipIgnored(Node *p, const char *map) { + String *niattr = NewStringf("tmap:%s:numinputs", map); + String *nextattr = NewStringf("tmap:%s:next", map); + + while ((p != NIL) && checkAttribute(p, niattr, "0")) { + p = Getattr(p, nextattr); + } + + Delete(nextattr); + Delete(niattr); + return p; + } + + /* ----------------------------------------------------------------------------- + * isInParam() + * isOutParam() + * + * Check if the parameter is intended for input or for output. + * ----------------------------------------------------------------------------- */ + + bool isInParam(Node *p) { + String *dir = Getattr(p, "tmap:m3wrapargdir"); +//printf("dir for %s: %s\n", Char(Getattr(p,"name")), Char(dir)); + if ((dir == NIL) || (Strcmp(dir, "in") == 0) + || (Strcmp(dir, "inout") == 0)) { + return true; + } else if (Strcmp(dir, "out") == 0) { + return false; + } else { + printf("%s", USAGE_ARG_DIR); + return false; + } + } + + bool isOutParam(Node *p) { + String *dir = Getattr(p, "tmap:m3wrapargdir"); + if ((dir == NIL) || (Strcmp(dir, "in") == 0)) { + return false; + } else if ((Strcmp(dir, "out") == 0) || (Strcmp(dir, "inout") == 0)) { + return true; + } else { + printf("%s", USAGE_ARG_DIR); + return false; + } + } + + /* ----------------------------------------------------------------------------- + * printAttrs() + * + * For debugging: Show all attributes of a node and their values. + * ----------------------------------------------------------------------------- */ + void printAttrs(Node *n) { + Iterator it; + for (it = First(n); it.key != NIL; it = Next(it)) { + printf("%s = %s\n", Char(it.key), Char(Getattr(n, it.key))); + } + } + + /* ----------------------------------------------------------------------------- + * hasPrefix() + * + * Check if a string have a given prefix. + * ----------------------------------------------------------------------------- */ + bool hasPrefix(const String *str, const String *prefix) { + int len_prefix = Len(prefix); + return (Len(str) > len_prefix) + && (Strncmp(str, prefix, len_prefix) == 0); + } + + /* ----------------------------------------------------------------------------- + * getQualifiedName() + * + * Return fully qualified identifier of n. + * ----------------------------------------------------------------------------- */ +#if 0 + // Swig_symbol_qualified returns NIL for enumeration nodes + String *getQualifiedName(Node *n) { + String *qual = Swig_symbol_qualified(n); + String *name = Getattr(n, "name"); + if (hasContent(qual)) { + return NewStringf("%s::%s", qual, name); + } else { + return name; + } + } +#else + String *getQualifiedName(Node *n) { + String *name = Copy(Getattr(n, "name")); + n = parentNode(n); + while (n != NIL) { + const String *type = nodeType(n); + if ((Strcmp(type, "class") == 0) || (Strcmp(type, "struct") == 0) || (Strcmp(type, "namespace") == 0)) { + String *newname = NewStringf("%s::%s", Getattr(n, "name"), name); + Delete(name); + //name = newname; + // Hmpf, the class name is already qualified. + return newname; + } + n = parentNode(n); + } + //printf("qualified name: %s\n", Char(name)); + return name; + } +#endif + + /* ----------------------------------------------------------------------------- + * nameToModula3() + * + * Turn usual C identifiers like "this_is_an_identifier" + * into usual Modula 3 identifier like "thisIsAnIdentifier" + * ----------------------------------------------------------------------------- */ + String *nameToModula3(const String *sym, bool leadingCap) { + int len_sym = Len(sym); + char *csym = Char(sym); + char *m3sym = new char[len_sym + 1]; + int i, j; + bool cap = leadingCap; + for (i = 0, j = 0; j < len_sym; j++) { + char c = csym[j]; + if ((c == '_') || (c == ':')) { + cap = true; + } else { + if (isdigit(c)) { + m3sym[i] = c; + cap = true; + } else { + if (cap) { + m3sym[i] = (char)toupper(c); + } else { + m3sym[i] = (char)tolower(c); + } + cap = false; + } + i++; + } + } + m3sym[i] = 0; + String *result = NewString(m3sym); + delete[]m3sym; + return result; + } + + /* ----------------------------------------------------------------------------- + * capitalizeFirst() + * + * Make the first character upper case. + * ----------------------------------------------------------------------------- */ + String *capitalizeFirst(const String *str) { + return NewStringf("%c%s", toupper(*Char(str)), Char(str) + 1); + } + + /* ----------------------------------------------------------------------------- + * prefixedNameToModula3() + * + * If feature modula3:oldprefix and modula3:newprefix is present + * and the C identifier has leading 'oldprefix' + * then it is replaced by the 'newprefix'. + * The rest is converted to Modula style. + * ----------------------------------------------------------------------------- */ + String *prefixedNameToModula3(Node *n, const String *sym, bool leadingCap) { + String *oldPrefix = Getattr(n, "feature:modula3:oldprefix"); + String *newPrefix = Getattr(n, "feature:modula3:newprefix"); + String *result = NewString(""); + char *short_sym = Char(sym); + // if at least one prefix feature is present + // the replacement takes place + if ((oldPrefix != NIL) || (newPrefix != NIL)) { + if ((oldPrefix == NIL) || hasPrefix(sym, oldPrefix)) { + short_sym += Len(oldPrefix); + if (newPrefix != NIL) { + Append(result, newPrefix); + } + } + } + String *suffix = nameToModula3(short_sym, leadingCap || hasContent(newPrefix)); + Append(result, suffix); + Delete(suffix); + return result; + } + + /* ----------------------------------------------------------------------------- + * hasContent() + * + * Check if the string exists and contains something. + * ----------------------------------------------------------------------------- */ + bool hasContent(const String *str) { + return (str != NIL) && (Strcmp(str, "") != 0); + } + + /* ----------------------------------------------------------------------------- + * openWriteFile() + * + * Caution: The file must be freshly allocated and will be destroyed + * by this routine. + * ----------------------------------------------------------------------------- */ + + File *openWriteFile(String *name) { + File *file = NewFile(name, "w", SWIG_output_files()); + if (!file) { + FileErrorDisplay(name); + SWIG_exit(EXIT_FAILURE); + } + Delete(name); + return file; + } + + /* ----------------------------------------------------------------------------- + * aToL() + * + * like atol but with additional user warning + * ----------------------------------------------------------------------------- */ + + long aToL(const String *value) { + char *endptr; + long numvalue = strtol(Char(value), &endptr, 0); + if (*endptr != 0) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The string <%s> does not denote a numeric value.\n", value); + } + return numvalue; + } + + /* ----------------------------------------------------------------------------- + * strToL() + * + * like strtol but returns if the conversion was successful + * ----------------------------------------------------------------------------- */ + + bool strToL(const String *value, long &numvalue) { + char *endptr; + numvalue = strtol(Char(value), &endptr, 0); + return (*endptr == 0); + } + + /* ----------------------------------------------------------------------------- + * evalExpr() + * + * Evaluate simple expression as they may occur in "enumvalue" attributes. + * ----------------------------------------------------------------------------- */ + + bool evalExpr(String *value, long &numvalue) { + // Split changes file status of String and thus cannot receive 'const' strings +//printf("evaluate <%s>\n", Char(value)); + List *summands = Split(value, '+', INT_MAX); + Iterator sm = First(summands); + numvalue = 0; + for (; sm.item != NIL; sm = Next(sm)) { + String *smvalue = Getattr(constant_values, sm.item); + long smnumvalue; + if (smvalue != NIL) { + if (!strToL(smvalue, smnumvalue)) { +//printf("evaluation: abort 0 <%s>\n", Char(smvalue)); + return false; + } + } else { + if (!strToL(sm.item, smnumvalue)) { +//printf("evaluation: abort 1 <%s>\n", Char(sm)); + return false; + } + } + numvalue += smnumvalue; + } +//printf("evaluation: return %ld\n", numvalue); + return true; + } + + /* ----------------------------------------------------------------------------- + * log2() + * + * Determine the position of the single bit of a power of two. + * Returns true if the given number is a power of two. + * ----------------------------------------------------------------------------- */ + + bool log2(long n, long &exp) { + exp = 0; + while (n > 0) { + if ((n & 1) != 0) { + return n == 1; + } + exp++; + n >>= 1; + } + return false; + } + + /* ----------------------------------------------------------------------------- + * writeArg + * + * Write a function argument or RECORD entry definition. + * Bundles arguments of same type and default value. + * 'name.next==NIL' denotes the end of the entry or argument list. + * ----------------------------------------------------------------------------- */ + + bool equalNilStr(const String *str0, const String *str1) { + if (str0 == NIL) { + return (str1 == NIL); + //return (str0==NIL) == (str1==NIL); + } else { + return (str1 != NIL) && (Cmp(str0, str1) == 0); + //return Cmp(str0,str1)==0; + } + } + + struct writeArgState { + String *mode, *name, *type, *value; + bool hold; + writeArgState():mode(NIL), name(NIL), type(NIL), value(NIL), hold(false) { + } + }; + + void writeArg(File *f, writeArgState & state, String *mode, String *name, String *type, String *value) { + /* skip the first argument, + only store the information for the next call in this case */ + if (state.name != NIL) { + if ((!state.hold) && (state.mode != NIL)) { + Printf(f, "%s ", state.mode); + } + if ((name != NIL) && equalNilStr(state.mode, mode) && equalNilStr(state.type, type) && (state.value == NIL) && (value == NIL) + /* the same expression may have different values + due to side effects of the called function */ + /*equalNilStr(state.value,value) */ + ) { + Printf(f, "%s, ", state.name); + state.hold = true; + } else { + Append(f, state.name); + if (state.type != NIL) { + Printf(f, ": %s", state.type); + } + if (state.value != NIL) { + Printf(f, ":= %s", state.value); + } + Append(f, ";\n"); + state.hold = false; + } + } + /* at the next call the current argument will be the previous one */ + state.mode = mode; + state.name = name; + state.type = type; + state.value = value; + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class + * Return NULL if not otherwise the proxy class name + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /*************** language processing ********************/ + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("modula3"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-generateconst") == 0) { + if (argv[i + 1]) { + constantfilename = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-generaterename") == 0) { + if (argv[i + 1]) { + renamefilename = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-generatetypemap") == 0) { + if (argv[i + 1]) { + typemapfilename = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-noproxy") == 0) { + Swig_mark_arg(i); + proxy_flag = false; + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGMODULA3 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("modula3"); + SWIG_config_file("modula3.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + if (hasContent(constantfilename) || hasContent(renamefilename) || hasContent(typemapfilename)) { + int result = SWIG_OK; + if (hasContent(constantfilename)) { + result = generateConstantTop(n) && result; + } + if (hasContent(renamefilename)) { + result = generateRenameTop(n) && result; + } + if (hasContent(typemapfilename)) { + result = generateTypemapTop(n) && result; + } + return result; + } else { + return generateM3Top(n); + } + } + + void scanConstant(File *file, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *constname = NIL; + String *type = nodeType(child); + if ((Strcmp(type, "enumitem") == 0) + || (Strcmp(type, "constant") == 0)) { +#if 1 + constname = getQualifiedName(child); +#else + constname = Getattr(child, "value"); + if ((!hasContent(constname)) + || (('0' <= *Char(constname)) && (*Char(constname) <= '9'))) { + constname = Getattr(child, "name"); + } +#endif + } + if (constname != NIL) { + Printf(file, " printf(\"%%%%constnumeric(%%Lg) %s;\\n\", (long double)%s);\n", constname, constname); + } + scanConstant(file, child); + child = nextSibling(child); + } + } + + int generateConstantTop(Node *n) { + File *file = openWriteFile(NewStringf("%s.c", constantfilename)); + if (CPlusPlus) { + Printf(file, "#include <cstdio>\n"); + } else { + Printf(file, "#include <stdio.h>\n"); + } + Printf(file, "#include \"%s\"\n", input_file); + Printf(file, "\n"); + Printf(file, "int main (int argc, char *argv[]) {\n"); + Printf(file, "\ +/*This progam must work for floating point numbers and integers.\n\ + Thus all numbers are converted to double precision floating point format.*/\n"); + scanConstant(file, n); + Printf(file, " return 0;\n"); + Printf(file, "}\n"); + Close(file); + return SWIG_OK; + } + + void scanRename(File *file, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *type = nodeType(child); + if (Strcmp(type, "cdecl") == 0) { + ParmList *p = Getattr(child, "parms"); + if (p != NIL) { + String *name = getQualifiedName(child); + String *m3name = nameToModula3(name, true); + /*don't know how to get the original C type identifiers */ + //String *arguments = createCSignature (child); + Printf(file, "%%rename(\"%s\") %s;\n", m3name, name); + /*Printf(file, "%%rename(\"%s\") %s %s(%s);\n", + m3name, Getattr(n,"type"), name, arguments); */ + Delete(name); + Delete(m3name); + //Delete (arguments); + } + } + scanRename(file, child); + child = nextSibling(child); + } + } + + int generateRenameTop(Node *n) { + File *file = openWriteFile(NewStringf("%s.i", renamefilename)); + Printf(file, "\ +/* This file was generated from %s\n\ + by SWIG with option -generaterename. */\n\ +\n", input_file); + scanRename(file, n); + Close(file); + return SWIG_OK; + } + + void scanTypemap(File *file, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *type = nodeType(child); + //printf("nodetype %s\n", Char(type)); + String *storage = Getattr(child, "storage"); + if ((Strcmp(type, "class") == 0) || ((Strcmp(type, "cdecl") == 0) && (storage != NIL) + && (Strcmp(storage, "typedef") == 0))) { + String *name = getQualifiedName(child); + String *m3name = nameToModula3(name, true); + Printf(file, "%%typemap(\"m3wrapintype\") %s %%{%s%%}\n", name, m3name); + Printf(file, "%%typemap(\"m3rawintype\") %s %%{%s%%}\n", name, m3name); + Printf(file, "\n"); + } + scanTypemap(file, child); + child = nextSibling(child); + } + } + + int generateTypemapTop(Node *n) { + File *file = openWriteFile(NewStringf("%s.i", typemapfilename)); + Printf(file, "\ +/* This file was generated from %s\n\ + by SWIG with option -generatetypemap. */\n\ +\n", input_file); + scanTypemap(file, n); + Close(file); + return SWIG_OK; + } + + int generateM3Top(Node *n) { + /* Initialize all of the output files */ + outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + + m3makefile = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + + Swig_register_filebyname("m3rawintf", m3raw_intf.f); + Swig_register_filebyname("m3rawimpl", m3raw_impl.f); + Swig_register_filebyname("m3wrapintf", m3wrap_intf.f); + Swig_register_filebyname("m3wrapimpl", m3wrap_impl.f); + Swig_register_filebyname("m3makefile", m3makefile); + + swig_types_hash = NewHash(); + + String *name = Getattr(n, "name"); + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + if (optionsnode != NIL) { + String *m3raw_name_tmp = Getattr(optionsnode, "m3rawname"); + if (m3raw_name_tmp != NIL) { + m3raw_name = Copy(m3raw_name_tmp); + } + } + if (m3raw_name == NIL) { + m3raw_name = NewStringf("%sRaw", name); + } + Setattr(m3wrap_impl.import, m3raw_name, ""); + + m3wrap_name = Copy(name); + + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + m3raw_baseclass = NewString(""); + m3raw_interfaces = NewString(""); + m3raw_class_modifiers = NewString(""); // package access only to the intermediary class by default + m3raw_imports = NewString(""); + m3raw_cppcasts_code = NewString(""); + m3wrap_modifiers = NewString("public"); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + upcasts_code = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGMODULA3\n"); + Printf(f_runtime, "\n"); + + Swig_name_register((char *) "wrapper", (char *) "Modula3_%f"); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%v"); + } + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + constant_values = NewHash(); + scanForConstPragmas(n); + enumeration_coll = NewHash(); + collectEnumerations(enumeration_coll, n); + + /* Emit code */ + Language::top(n); + + // Generate m3makefile + // This will be unnecessary if SWIG is invoked from Quake. + { + File *file = openWriteFile(NewStringf("%sm3makefile", Swig_file_dirname(outfile))); + + Printf(file, "%% automatically generated quake file for %s\n\n", name); + + /* Write the fragments written by '%insert' + collected while 'top' processed the parse tree */ + Printv(file, m3makefile, NIL); + + Printf(file, "import(\"libm3\")\n"); + //Printf(file, "import_lib(\"%s\",\"/usr/lib\")\n", name); + Printf(file, "module(\"%s\")\n", m3raw_name); + Printf(file, "module(\"%s\")\n\n", m3wrap_name); + + if (targetlibrary != NIL) { + Printf(file, "library(\"%s\")\n", targetlibrary); + } else { + Printf(file, "library(\"m3%s\")\n", name); + } + Close(file); + } + + // Generate the raw interface + { + File *file = openWriteFile(NewStringf("%s%s.i3", Swig_file_dirname(outfile), m3raw_name)); + + emitBanner(file); + + Printf(file, "INTERFACE %s;\n\n", m3raw_name); + + emitImportStatements(m3raw_intf.import, file); + Printf(file, "\n"); + + // Write the interface generated within 'top' + Printv(file, m3raw_intf.f, NIL); + + Printf(file, "\nEND %s.\n", m3raw_name); + Close(file); + } + + // Generate the raw module + { + File *file = openWriteFile(NewStringf("%s%s.m3", Swig_file_dirname(outfile), m3raw_name)); + + emitBanner(file); + + Printf(file, "MODULE %s;\n\n", m3raw_name); + + emitImportStatements(m3raw_impl.import, file); + Printf(file, "\n"); + + // will be empty usually + Printv(file, m3raw_impl.f, NIL); + + Printf(file, "BEGIN\nEND %s.\n", m3raw_name); + Close(file); + } + + // Generate the interface for the comfort wrappers + { + File *file = openWriteFile(NewStringf("%s%s.i3", Swig_file_dirname(outfile), m3wrap_name)); + + emitBanner(file); + + Printf(file, "INTERFACE %s;\n", m3wrap_name); + + emitImportStatements(m3wrap_intf.import, file); + Printf(file, "\n"); + + { + Iterator it = First(enumeration_coll); + if (it.key != NIL) { + Printf(file, "TYPE\n"); + } + for (; it.key != NIL; it = Next(it)) { + Printf(file, "\n"); + emitEnumeration(file, it.key, it.item); + } + } + + // Add the wrapper methods + Printv(file, m3wrap_intf.f, NIL); + + // Finish off the class + Printf(file, "\nEND %s.\n", m3wrap_name); + Close(file); + } + + // Generate the wrapper routines implemented in Modula 3 + { + File *file = openWriteFile(NewStringf("%s%s.m3", Swig_file_dirname(outfile), m3wrap_name)); + + emitBanner(file); + + if (unsafe_module) { + Printf(file, "UNSAFE "); + } + Printf(file, "MODULE %s;\n\n", m3wrap_name); + + emitImportStatements(m3wrap_impl.import, file); + Printf(file, "\n"); + + // Add the wrapper methods + Printv(file, m3wrap_impl.f, NIL); + + Printf(file, "\nBEGIN\nEND %s.\n", m3wrap_name); + Close(file); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a Modula 3 type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.item != NIL; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + Delete(swig_types_hash); + swig_types_hash = NULL; + Delete(constant_values); + constant_values = NULL; + Delete(enumeration_coll); + enumeration_coll = NULL; + Delete(m3raw_name); + m3raw_name = NULL; + Delete(m3raw_baseclass); + m3raw_baseclass = NULL; + Delete(m3raw_interfaces); + m3raw_interfaces = NULL; + Delete(m3raw_class_modifiers); + m3raw_class_modifiers = NULL; + Delete(m3raw_imports); + m3raw_imports = NULL; + Delete(m3raw_cppcasts_code); + m3raw_cppcasts_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(m3wrap_name); + m3wrap_name = NULL; + Delete(m3wrap_modifiers); + m3wrap_modifiers = NULL; + Delete(targetlibrary); + targetlibrary = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(constantfilename); + constantfilename = NULL; + Delete(renamefilename); + renamefilename = NULL; + Delete(typemapfilename); + typemapfilename = NULL; + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * emitBanner() + * ----------------------------------------------------------------------------- */ + + void emitBanner(File *f) { + Printf(f, "(*******************************************************************************\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, "*******************************************************************************)\n\n"); + } + + /* ---------------------------------------------------------------------- + * nativeWrapper() + * ---------------------------------------------------------------------- */ + + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + if (Getattr(n, "type")) { + Swig_save("nativeWrapper", n, "name", NIL); + Setattr(n, "name", wrapname); + native_function_flag = true; + functionWrapper(n); + Swig_restore(n); + native_function_flag = false; + } else { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, Getattr(n, "wrap:name")); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + String *type = nodeType(n); + String *funcType = Getattr(n, "modula3:functype"); + String *rawname = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *capname = capitalizeFirst(symname); + //String *wname = Swig_name_wrapper(symname); + + //printf("function: %s\n", Char(symname)); + //printf(" purpose: %s\n", Char(funcType)); + + if (Strcmp(type, "cdecl") == 0) { + if (funcType == NIL) { + // no wrapper needed for plain functions + emitM3RawPrototype(n, rawname, symname); + emitM3Wrapper(n, symname); + } else if (Strcmp(funcType, "method") == 0) { + Setattr(n, "modula3:funcname", capname); + emitCWrapper(n, capname); + emitM3RawPrototype(n, capname, capname); + emitM3Wrapper(n, capname); + } else if (Strcmp(funcType, "accessor") == 0) { + /* + * Generate the proxy class properties for public member variables. + * Not for enums and constants. + */ + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Capitalize the first letter in the function name + Setattr(n, "proxyfuncname", capname); + Setattr(n, "imfuncname", symname); + if (hasPrefix(capname, "Set")) { + Setattr(n, "modula3:setname", capname); + } else { + Setattr(n, "modula3:getname", capname); + } + + emitCWrapper(n, capname); + emitM3RawPrototype(n, capname, capname); + emitM3Wrapper(n, capname); + //proxyClassFunctionHandler(n); + } +#ifdef DEBUG + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Function type <%s> unknown.\n", Char(funcType)); +#endif + } + } else if ((Strcmp(type, "constructor") == 0) || (Strcmp(type, "destructor") == 0)) { + emitCWrapper(n, capname); + emitM3RawPrototype(n, capname, capname); + emitM3Wrapper(n, capname); + } +// a Java relict +#if 0 + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + emitM3Wrapper(n, capname); + } +#endif + + Delete(capname); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * emitCWrapper() + * + * Generate the wrapper in C which calls C++ methods. + * ---------------------------------------------------------------------- */ + + virtual int emitCWrapper(Node *n, const String *wname) { + String *rawname = Getattr(n, "name"); + String *c_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + Hash *throws_hash = NewHash(); + ParmList *l = Getattr(n, "parms"); + SwigType *t = Getattr(n, "type"); + String *symname = Getattr(n, "sym:name"); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(wname, n)) { + return SWIG_ERROR; + } + } + // A new wrapper function object + Wrapper *f = NewWrapper(); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("ctype", l, f); + + /* Get return types */ + { + String *tm = getMappedTypeNew(n, "ctype", ""); + if (tm != NIL) { + Printf(c_return_type, "%s", tm); + } + } + + bool is_void_return = (Cmp(c_return_type, "void") == 0); + if (!is_void_return) { + Wrapper_add_localv(f, "cresult", c_return_type, "cresult = 0", NIL); + } + + Printv(f->def, " SWIGEXPORT ", c_return_type, " ", wname, "(", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + // Generate signature and argument conversion for C wrapper + { + Parm *p; + attachParameterNames(n, "tmap:name", "c:wrapname", "m3arg%d"); + bool gencomma = false; + for (p = skipIgnored(l, "in"); p != NULL; p = skipIgnored(p, "in")) { + + String *arg = Getattr(p, "c:wrapname"); + { + /* Get the ctype types of the parameter */ + String *c_param_type = getMappedType(p, "ctype"); + // Add parameter to C function + Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + Delete(c_param_type); + gencomma = true; + } + + // Get typemap for this argument + String *tm = getMappedType(p, "in"); + if (tm != NIL) { + addThrows(throws_hash, "in", p); + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); /*??? */ + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Insert constraint checking code */ + { + Parm *p; + for (p = l; p;) { + String *tm = Getattr(p, "tmap:check"); + if (tm != NIL) { + addThrows(throws_hash, "check", p); + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Insert cleanup code */ + { + Parm *p; + for (p = l; p;) { + String *tm = Getattr(p, "tmap:freearg"); + if (tm != NIL) { + addThrows(throws_hash, "freearg", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Insert argument output code */ + { + Parm *p; + for (p = l; p;) { + String *tm = Getattr(p, "tmap:argout"); + if (tm != NIL) { + addThrows(throws_hash, "argout", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$result", "cresult"); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + } + + // Get any Modula 3 exception classes in the throws typemap + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "catchlist"))) { + Swig_typemap_attach_parms("throws", throw_parm_list, f); + Parm *p; + for (p = throw_parm_list; p; p = nextSibling(p)) { + addThrows(throws_hash, "throws", p); + } + } + + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Setattr(n, "wrap:name", wname); + + // Now write code to make the function call + if (!native_function_flag) { + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) { + Swig_restore(n); + } + + /* Return value if necessary */ + String *tm; + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + addThrows(throws_hash, "out", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Replaceall(tm, "$target", "cresult"); /* deprecated */ + Replaceall(tm, "$result", "cresult"); + Printf(f->code, "%s", tm); + if (hasContent(tm)) + Printf(f->code, "\n"); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), rawname); + } + emit_return_variable(n, t, f); + } + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + String *tm = Swig_typemap_lookup("newfree", n, "result", 0); + if (tm != NIL) { + addThrows(throws_hash, "newfree", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if (!native_function_flag) { + String *tm = Swig_typemap_lookup("ret", n, "result", 0); + if (tm != NIL) { + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C wrapper */ + Printf(f->def, ") {"); + + if (!is_void_return) + Printv(f->code, " return cresult;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + if (!is_void_return) { + Replaceall(f->code, "$null", "0"); + } else { + Replaceall(f->code, "$null", ""); + } + + /* Dump the function out */ + if (!native_function_flag) { + Wrapper_print(f, f_wrappers); + } + + Delete(c_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(throws_hash); + DelWrapper(f); + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * emitM3RawPrototype() + * + * Generate an EXTERNAL procedure declaration in Modula 3 + * which is the interface to an existing C routine or a C wrapper. + * ---------------------------------------------------------------------- */ + + virtual int emitM3RawPrototype(Node *n, const String *cname, const String *m3name) { + String *im_return_type = NewString(""); + //String *symname = Getattr(n,"sym:name"); + ParmList *l = Getattr(n, "parms"); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("m3rawinmode", l, NULL); + Swig_typemap_attach_parms("m3rawintype", l, NULL); + + /* Get return types */ + bool has_return; + { + String *tm = getMappedTypeNew(n, "m3rawrettype", ""); + if (tm != NIL) { + Printf(im_return_type, "%s", tm); + } + has_return = hasContent(tm); + } + + /* cname is the original name if 'n' denotes a C function + and it is the relabeled name (sym:name) if 'n' denotes a C++ method or similar */ + m3raw_intf.enterBlock(no_block); + Printf(m3raw_intf.f, "\n<* EXTERNAL %s *>\nPROCEDURE %s (", cname, m3name); + + // Generate signature for raw interface + { + Parm *p; + writeArgState state; + attachParameterNames(n, "tmap:rawinname", "modula3:rawname", "arg%d"); + for (p = skipIgnored(l, "m3rawintype"); p != NULL; p = skipIgnored(p, "m3rawintype")) { + + /* Get argument passing mode, should be one of VALUE, VAR, READONLY */ + String *mode = Getattr(p, "tmap:m3rawinmode"); + String *argname = Getattr(p, "modula3:rawname"); + String *im_param_type = getMappedType(p, "m3rawintype"); + addImports(m3raw_intf.import, "m3rawintype", p); + + writeArg(m3raw_intf.f, state, mode, argname, im_param_type, NIL); + if (im_param_type != NIL) { + p = Getattr(p, "tmap:m3rawintype:next"); + } else { + p = nextSibling(p); + } + } + writeArg(m3raw_intf.f, state, NIL, NIL, NIL, NIL); + } + + /* Finish M3 raw prototype */ + Printf(m3raw_intf.f, ")"); + // neither a C wrapper nor a plain C function may throw an exception + //generateThrowsClause(throws_hash, m3raw_intf.f); + if (has_return) { + Printf(m3raw_intf.f, ": %s", im_return_type); + } + Printf(m3raw_intf.f, ";\n"); + + Delete(im_return_type); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + Language::variableWrapper(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * globalvariableHandler() + * ----------------------------------------------------------------------- */ + + virtual int globalvariableHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + + variable_name = Getattr(n, "sym:name"); + variable_type = Copy(tm); + + // Get the variable type expressed in terms of Modula 3 equivalents of C types + if ((tm = getMappedTypeNew(n, "m3rawtype", ""))) { + m3raw_intf.enterBlock(no_block); + Printf(m3raw_intf.f, "\n<* EXTERNAL *> VAR %s: %s;\n", variable_name, tm); + } + // Output the property's accessor methods + /* + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + */ + + Printf(m3wrap_impl.f, "\n\n"); + + //return ret; + return 1; + } + + long getConstNumeric(Node *n) { + String *constnumeric = Getfeature(n, "constnumeric"); + String *name = Getattr(n, "name"); + long numvalue; + if (constnumeric == NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Feature 'constnumeric' is necessary to obtain value of %s.\n", name); + return 0; + } else if (!strToL(constnumeric, numvalue)) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, + "The feature 'constnumeric' of %s specifies value <%s> which is not an integer constant.\n", name, constnumeric); + return 0; + } else { + return numvalue; + } + } + + /* ------------------------------------------------------------------------ + * generateIntConstant() + * + * Considers node as an integer constant definition + * and generate a Modula 3 constant definition. + * ------------------------------------------------------------------------ */ + void generateIntConstant(Node *n, String *name) { + String *value = Getattr(n, "value"); + String *type = Getfeature(n, "modula3:constint:type"); + String *conv = Getfeature(n, "modula3:constint:conv"); + + if (name == NIL) { + name = Getattr(n, "sym:name"); + } + + long numvalue; + bool isSimpleNum = strToL(value, numvalue); + if (!isSimpleNum) { + numvalue = getConstNumeric(n); + } + + String *m3value; + if ((conv == NIL) || ((Strcmp(conv, "set:int") != 0) && (Strcmp(conv, "int:set") != 0))) { + /* The original value of the constant has precedence over + 'constnumeric' feature since we like to keep + the style (that is the base) of simple numeric constants */ + if (isSimpleNum) { + if (hasPrefix(value, "0x")) { + m3value = NewStringf("16_%s", Char(value) + 2); + } else if ((Len(value) > 1) && (*Char(value) == '0')) { + m3value = NewStringf("8_%s", Char(value) + 1); + } else { + m3value = Copy(value); + } + /* If we cannot easily obtain the value of a numeric constant, + we use the results given by a C compiler. */ + } else { + m3value = Copy(Getfeature(n, "constnumeric")); + } + } else { + // if the value can't be converted, it is ignored + if (convertInt(numvalue, numvalue, conv)) { + m3value = NewStringf("%d", numvalue); + } else { + m3value = NIL; + } + } + + if (m3value != NIL) { + m3wrap_intf.enterBlock(constant); + Printf(m3wrap_intf.f, "%s", name); + if (hasContent(type)) { + Printf(m3wrap_intf.f, ": %s", type); + } + Printf(m3wrap_intf.f, " = %s;\n", m3value); + Delete(m3value); + } + } + + /* ----------------------------------------------------------------------- + * generateSetConstant() + * + * Considers node as a set constant definition + * and generate a Modula 3 constant definition. + * ------------------------------------------------------------------------ */ + void generateSetConstant(Node *n, String *name) { + String *value = Getattr(n, "value"); + String *type = Getfeature(n, "modula3:constset:type"); + String *setname = Getfeature(n, "modula3:constset:set"); + String *basename = Getfeature(n, "modula3:constset:base"); + String *conv = Getfeature(n, "modula3:constset:conv"); + + m3wrap_intf.enterBlock(constant); + + Printf(m3wrap_intf.f, "%s", name); + if (type != NIL) { + Printf(m3wrap_intf.f, ":%s ", type); + } + Printf(m3wrap_intf.f, " = %s{", setname); + + long numvalue = 0; + if (!strToL(value, numvalue)) { + numvalue = getConstNumeric(n); + } + convertInt(numvalue, numvalue, conv); + + bool isIntType = Strcmp(basename, "CARDINAL") == 0; + Hash *items = NIL; + if (!isIntType) { + Hash *enumeration = Getattr(enumeration_coll, basename); + if (enumeration == NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "There is no enumeration <%s> as needed for the set.\n", setname); + isIntType = true; + } else { + items = Getattr(enumeration, "items"); + } + } + + bool gencomma = false; + int bitpos = 0; + while (numvalue > 0) { + if ((numvalue & 1) != 0) { + if (isIntType) { + if (gencomma) { + Printv(m3wrap_intf.f, ",", NIL); + } + gencomma = true; + Printf(m3wrap_intf.f, "%d", bitpos); + } else { + char bitval[15]; + sprintf(bitval, "%d", bitpos); + String *bitname = Getattr(items, bitval); + if (bitname == NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Enumeration <%s> has no value <%s>.\n", setname, bitval); + } else { + if (gencomma) { + Printv(m3wrap_intf.f, ",", NIL); + } + gencomma = true; + Printf(m3wrap_intf.f, "%s.%s", basename, bitname); + } + } + } + numvalue >>= 1; + bitpos++; + } + Printf(m3wrap_intf.f, "};\n"); + } + + void generateConstant(Node *n) { + // any of the special interpretation disables the default behaviour + String *enumitem = Getfeature(n, "modula3:enumitem:name"); + String *constset = Getfeature(n, "modula3:constset:name"); + String *constint = Getfeature(n, "modula3:constint:name"); + if (hasContent(enumitem) || hasContent(constset) || hasContent(constint)) { + if (hasContent(constset)) { + generateSetConstant(n, constset); + } + if (hasContent(constint)) { + generateIntConstant(n, constint); + } + } else { + String *value = Getattr(n, "value"); + String *name = Getattr(n, "sym:name"); + if (name == NIL) { + name = Getattr(n, "name"); + } + m3wrap_intf.enterBlock(constant); + Printf(m3wrap_intf.f, "%s = %s;\n", name, value); + } + } + +#if 0 + void generateEnumerationItem(const String *name, const String *value, int numvalue) { + String *oldsymname = Getattr(enumeration_items, value); + if (oldsymname != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The value <%s> is already assigned to <%s>.\n", value, oldsymname); + } + Setattr(enumeration_items, value, name); + if (enumeration_max < numvalue) { + enumeration_max = numvalue; + } + } +#endif + + void emitEnumeration(File *file, String *name, Node *n) { + Printf(file, "%s = {", name); + int i; + bool gencomma = false; + int max = aToL(Getattr(n, "max")); + Hash *items = Getattr(n, "items"); + for (i = 0; i <= max; i++) { + if (gencomma) { + Printf(file, ","); + } + Printf(file, "\n"); + gencomma = true; + char numstr[15]; + sprintf(numstr, "%d", i); + String *name = Getattr(items, numstr); + if (name != NIL) { + Printv(file, name, NIL); + } else { + Printf(file, "Dummy%d", i); + } + } + Printf(file, "\n};\n"); + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * + * Handles constants and enumeration items. + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + generateConstant(n); + return SWIG_OK; + } + +#if 0 +// enumerations are handled like constant definitions + /* ----------------------------------------------------------------------------- + * enumDeclaration() + * ----------------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + String *symname = nameToModula3(Getattr(n, "sym:name"), true); + enumerationStart(symname); + int result = Language::enumDeclaration(n); + enumerationStop(); + Delete(symname); + return result; + } +#endif + + /* ----------------------------------------------------------------------------- + * enumvalueDeclaration() + * ----------------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + generateConstant(n); + /* + This call would continue processing in the constantWrapper + which cannot handle values like "RED+1". + return Language::enumvalueDeclaration(n); + */ + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * imclassbase - base (extends) for the intermediary class + * imclassclassmodifiers - class modifiers for the intermediary class + * imclasscode - text (Modula 3 code) is copied verbatim to the intermediary class + * imclassimports - import statements for the intermediary class + * imclassinterfaces - interface (implements) for the intermediary class + * + * modulebase - base (extends) for the module class + * moduleclassmodifiers - class modifiers for the module class + * modulecode - text (Modula 3 code) is copied verbatim to the module class + * moduleimports - import statements for the module class + * moduleinterfaces - interface (implements) for the module class + * + * ----------------------------------------------------------------------------- */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *code = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "modula3") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); +/* + bool isEnumItem = Strcmp(code, "enumitem") == 0; + bool isSetItem = Strcmp(code, "setitem") == 0; +*/ + if (Strcmp(code, "imclassbase") == 0) { + Delete(m3raw_baseclass); + m3raw_baseclass = Copy(strvalue); + } else if (Strcmp(code, "imclassclassmodifiers") == 0) { + Delete(m3raw_class_modifiers); + m3raw_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "imclasscode") == 0) { + Printf(m3raw_intf.f, "%s\n", strvalue); + } else if (Strcmp(code, "imclassimports") == 0) { + Delete(m3raw_imports); + m3raw_imports = Copy(strvalue); + } else if (Strcmp(code, "imclassinterfaces") == 0) { + Delete(m3raw_interfaces); + m3raw_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(m3wrap_modifiers); + m3wrap_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(m3wrap_impl.f, "%s\n", strvalue); + } else if (Strcmp(code, "moduleimports") == 0) { + Delete(module_imports); + module_imports = Copy(strvalue); + } else if (Strcmp(code, "moduleinterfaces") == 0) { + Delete(module_interfaces); + module_interfaces = Copy(strvalue); + } else if (Strcmp(code, "unsafe") == 0) { + unsafe_module = true; + } else if (Strcmp(code, "library") == 0) { + if (targetlibrary != NULL) { + Delete(targetlibrary); + } + targetlibrary = Copy(strvalue); + } else if (Strcmp(code, "enumitem") == 0) { + } else if (Strcmp(code, "constset") == 0) { + } else if (Strcmp(code, "constint") == 0) { + } else if (Strcmp(code, "makesetofenum") == 0) { + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%sSet = SET OF %s;\n", value, value); + } else { + Swig_warning(WARN_MODULA3_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", code); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + void Setfeature(Node *n, const char *feature, const String *value, bool warn = false) { + //printf("tag feature <%s> with value <%s>\n", feature, Char(value)); + String *attr = NewStringf("feature:%s", feature); + if ((Setattr(n, attr, value) != 0) && warn) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Feature <%s> of %s did already exist.\n", feature, Getattr(n, "name")); + } + Delete(attr); + } + + String *Getfeature(Node *n, const char *feature) { + //printf("retrieve feature <%s> with value <%s>\n", feature, Char(value)); + String *attr = NewStringf("feature:%s", feature); + String *result = Getattr(n, attr); + Delete(attr); + return result; + } + + bool convertInt(long in, long &out, const String *mode) { + if ((mode == NIL) || (Strcmp(mode, "int:int") == 0) || (Strcmp(mode, "set:set") == 0)) { + out = in; + return true; + } else if (Strcmp(mode, "set:int") == 0) { + return log2(in, out); + } else if (Strcmp(mode, "int:set") == 0) { + out = 1L << in; + return unsigned (in) < (sizeof(out) * 8); + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown integer conversion method <%s>.\n", mode); + return false; + } + } + + void collectEnumerations(Hash *enums, Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + String *name = Getattr(child, "name"); + const bool isConstant = Strcmp(nodeType(child), "constant") == 0; + const bool isEnumItem = Strcmp(nodeType(child), "enumitem") == 0; + if (isConstant || isEnumItem) { +//printf("%s%s name %s\n", isConstant?"constant":"", isEnumItem?"enumitem":"", Char(name)); + { + String *m3name = Getfeature(child, "modula3:enumitem:name"); + String *m3enum = Getfeature(child, "modula3:enumitem:enum"); + String *conv = Getfeature(child, "modula3:enumitem:conv"); + + if (m3enum != NIL) { +//printf("m3enum %s\n", Char(m3enum)); + if (m3name == NIL) { + m3name = name; + } + + long max = -1; + Hash *items; + Hash *enumnode = Getattr(enums, m3enum); + if (enumnode == NIL) { + enumnode = NewHash(); + items = NewHash(); + Setattr(enumnode, "items", items); + Setattr(enums, m3enum, enumnode); + } else { + String *maxstr = Getattr(enumnode, "max"); + if (maxstr != NIL) { + max = aToL(maxstr); + } + items = Getattr(enumnode, "items"); + } + long numvalue; + String *value = Getattr(child, "value"); +//printf("value: %s\n", Char(value)); + if ((value == NIL) || (!strToL(value, numvalue))) { + value = Getattr(child, "enumvalue"); + if ((value == NIL) || (!evalExpr(value, numvalue))) { + numvalue = getConstNumeric(child); + } +//printf("constnumeric: %s\n", Char(value)); + } + Setattr(constant_values, name, NewStringf("%d", numvalue)); + if (convertInt(numvalue, numvalue, conv)) { + String *newvalue = NewStringf("%d", numvalue); + String *oldname = Getattr(items, newvalue); + if (oldname != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The value <%s> is already assigned to <%s>.\n", value, oldname); + } +//printf("items %lx, set %s = %s\n", (long) items, Char(newvalue), Char(m3name)); + Setattr(items, newvalue, m3name); + if (max < numvalue) { + max = numvalue; + } + Setattr(enumnode, "max", NewStringf("%d", max)); + } + } + } + } + + collectEnumerations(enums, child); + child = nextSibling(child); + } + } + + enum const_pragma_type { cpt_none, cpt_constint, cpt_constset, cpt_enumitem }; + + struct const_id_pattern { + String *prefix, *parentEnum; + }; + + void tagConstants(Node *first, String *parentEnum, const const_id_pattern & pat, const String *pragma, List *convdesc) { + Node *n = first; + while (n != NIL) { + String *name = getQualifiedName(n); + bool isConstant = Strcmp(nodeType(n), "constant") == 0; + bool isEnumItem = Strcmp(nodeType(n), "enumitem") == 0; + if ((isConstant || isEnumItem) && ((pat.prefix == NIL) || (hasPrefix(name, pat.prefix))) && ((pat.parentEnum == NIL) || ((parentEnum != NIL) + && + (Strcmp + (pat.parentEnum, parentEnum) + == 0)))) { + //printf("tag %s\n", Char(name)); + String *srctype = Getitem(convdesc, 1); + String *relationstr = Getitem(convdesc, 3); + List *relationdesc = Split(relationstr, ',', 2); + + // transform name from C to Modula3 style + String *srcstyle = NIL; + String *newprefix = NIL; + { + //printf("name conversion <%s>\n", Char(Getitem(convdesc,2))); + List *namedesc = Split(Getitem(convdesc, 2), ',', INT_MAX); + Iterator nameit = First(namedesc); + for (; nameit.item != NIL; nameit = Next(nameit)) { + List *nameassign = Split(nameit.item, '=', 2); + String *tag = Getitem(nameassign, 0); + String *data = Getitem(nameassign, 1); + //printf("name conv <%s> = <%s>\n", Char(tag), Char(data)); + if (Strcmp(tag, "srcstyle") == 0) { + srcstyle = Copy(data); + } else if (Strcmp(tag, "prefix") == 0) { + newprefix = Copy(data); + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown name conversion tag <%s> with value <%s>.\n", tag, data); + } + Delete(nameassign); + } + Delete(namedesc); + } + const char *stem = Char(name); + if (pat.prefix != NIL) { + //printf("pat.prefix %s for %s\n", Char(pat.prefix), Char(name)); + stem += Len(pat.prefix); + } + String *newname; + if (Strcmp(srcstyle, "underscore") == 0) { + if (newprefix != NIL) { + String *newstem = nameToModula3(stem, true); + newname = NewStringf("%s%s", newprefix, newstem); + Delete(newstem); + } else { + newname = nameToModula3(stem, true); + } + } else { + if (srcstyle != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown C identifier style <%s>.\n", srcstyle); + } + newname = Copy(name); + } + + if (Strcmp(pragma, "enumitem") == 0) { + if (Len(relationdesc) != 1) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <enumeration>, got <%s>.\n", relationstr); + } + Setfeature(n, "modula3:enumitem:name", newname, true); + Setfeature(n, "modula3:enumitem:enum", relationstr, true); + Setfeature(n, "modula3:enumitem:conv", NewStringf("%s:int", srctype), true); + } else if (Strcmp(pragma, "constint") == 0) { + if (Len(relationdesc) != 1) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <ordinal type>, got <%s>.\n", relationstr); + } + Setfeature(n, "modula3:constint:name", newname, true); + Setfeature(n, "modula3:constint:type", Getitem(relationdesc, 0), true); + Setfeature(n, "modula3:constint:conv", NewStringf("%s:int", srctype), true); + } else if (Strcmp(pragma, "constset") == 0) { + if (Len(relationdesc) != 2) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <set type,base type>, got <%s>.\n", relationstr); + } + String *settype = Getitem(relationdesc, 0); + Setfeature(n, "modula3:constset:name", newname, true); + //Setfeature(n,"modula3:constset:type",settype,true); + Setfeature(n, "modula3:constset:set", settype, true); + Setfeature(n, "modula3:constset:base", Getitem(relationdesc, 1), true); + Setfeature(n, "modula3:constset:conv", NewStringf("%s:set", srctype), true); + } + + Delete(newname); + Delete(relationdesc); + } + + if (Strcmp(nodeType(n), "enum") == 0) { + //printf("explore enum %s, qualification %s\n", Char(name), Char(Swig_symbol_qualified(n))); + tagConstants(firstChild(n), name, pat, pragma, convdesc); + } else { + tagConstants(firstChild(n), NIL, pat, pragma, convdesc); + } + n = nextSibling(n); + } + } + + void scanForConstPragmas(Node *n) { + Node *child = firstChild(n); + while (child != NIL) { + const String *type = nodeType(child); + if (Strcmp(type, "pragma") == 0) { + const String *lang = Getattr(child, "lang"); + const String *code = Getattr(child, "name"); + String *value = Getattr(child, "value"); + + if (Strcmp(lang, "modula3") == 0) { + const_pragma_type cpt = cpt_none; + if (Strcmp(code, "constint") == 0) { + cpt = cpt_constint; + } else if (Strcmp(code, "constset") == 0) { + cpt = cpt_constset; + } else if (Strcmp(code, "enumitem") == 0) { + cpt = cpt_enumitem; + } + if (cpt != cpt_none) { + const_id_pattern pat = { NIL, NIL }; + + List *convdesc = Split(value, ';', 4); + List *patterndesc = Split(Getitem(convdesc, 0), ',', INT_MAX); + Iterator patternit; + for (patternit = First(patterndesc); patternit.item != NIL; patternit = Next(patternit)) { + List *patternassign = Split(patternit.item, '=', 2); + String *tag = Getitem(patternassign, 0); + String *data = Getitem(patternassign, 1); + if (Strcmp(tag, "prefix") == 0) { + pat.prefix = Copy(data); + } else if (Strcmp(tag, "enum") == 0) { + pat.parentEnum = Copy(data); + } else { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown identification tag <%s> with value <%s>.\n", tag, data); + } + Delete(patternassign); + } + tagConstants(child, NIL, pat, code, convdesc); + + Delete(patterndesc); + } + } + } + scanForConstPragmas(child); + child = nextSibling(child); + } + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + String *classDeclarationName = Getattr(n, "classDeclaration:name"); + + /* Deal with inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist != NIL) { + Iterator base = First(baselist); + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) { + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + } + base = Next(base); + if (base.item != NIL) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", + classDeclarationName, Getattr(base.item, "name")); + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (!baseclass) + baseclass = NewString(""); + + // Inheritance from pure Modula 3 classes + const String *pure_baseclass = typemapLookup(n, "m3base", classDeclarationName, WARN_NONE); + if (hasContent(pure_baseclass) && hasContent(baseclass)) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", classDeclarationName, pure_baseclass); + } + // Pure Modula 3 interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "m3interfaces_derived" : "m3interfaces", + classDeclarationName, WARN_NONE); + + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "m3imports", classDeclarationName, WARN_NONE), // Import statements + "\n", typemapLookup(n, "m3classmodifiers", classDeclarationName, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " class $m3classname", // Class name and bases + (derived || *Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", baseclass, pure_baseclass, ((derived || *Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", // Member variables for memory handling + derived ? "" : " protected bool swigCMemOwn;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", classDeclarationName, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers + " $m3classname(IntPtr cPtr, bool cMemoryOwn) ", // Constructor used for wrapping pointers + derived ? + ": base($imclassname.$m3classnameTo$baseclass(cPtr), cMemoryOwn) {\n" + : "{\n swigCMemOwn = cMemoryOwn;\n", " swigCPtr = cPtr;\n", " }\n", NIL); + + if (!have_default_constructor_flag) { // All proxy classes need a constructor + Printv(proxy_class_def, "\n", " protected $m3classname() : this(IntPtr.Zero, false) {\n", " }\n", NIL); + } + // C++ destructor is wrapped by the Dispose method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + Node *attributes = NewHash(); + String *destruct_methodname = NULL; + if (derived) { + tm = typemapLookup(n, "m3destruct_derived", classDeclarationName, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:m3destruct_derived:methodname"); + } else { + tm = typemapLookup(n, "m3destruct", classDeclarationName, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:m3destruct:methodname"); + } + if (!destruct_methodname) { + Swig_error(input_file, line_number, "No methodname attribute defined in m3destruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + // Emit the Finalize and Dispose methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "m3finalize", classDeclarationName, WARN_NONE), NIL); + } + // Dispose method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$imcall", destructor_call); + else + Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) + Printv(proxy_class_def, "\n public ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", NIL); + } + Delete(attributes); + Delete(destruct); + + // Emit various other methods + Printv(proxy_class_def, typemapLookup(n, "m3getcptr", classDeclarationName, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method + typemapLookup(n, "m3code", classDeclarationName, WARN_NONE), // extra Modula 3 code + "\n", NIL); + + // Substitute various strings into the above template + Replaceall(proxy_class_def, "$m3classname", proxy_class_name); + Replaceall(proxy_class_code, "$m3classname", proxy_class_name); + + Replaceall(proxy_class_def, "$baseclass", baseclass); + Replaceall(proxy_class_code, "$baseclass", baseclass); + + Replaceall(proxy_class_def, "$imclassname", m3raw_name); + Replaceall(proxy_class_code, "$imclassname", m3raw_name); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(m3raw_cppcasts_code, "\n [DllImport(\"", m3wrap_name, "\", EntryPoint=\"Modula3_", proxy_class_name, "To", baseclass, "\")]\n", NIL); + Printv(m3raw_cppcasts_code, " public static extern IntPtr ", "$m3classnameTo$baseclass(IntPtr objectRef);\n", NIL); + + Replaceall(m3raw_cppcasts_code, "$m3classname", proxy_class_name); + Replaceall(m3raw_cppcasts_code, "$baseclass", baseclass); + + Printv(upcasts_code, + "SWIGEXPORT long Modula3_$imclazznameTo$imbaseclass", + "(long objectRef) {\n", + " long baseptr = 0;\n" " *($cbaseclass **)&baseptr = *($cclass **)&objectRef;\n" " return baseptr;\n" "}\n", "\n", NIL); + + Replaceall(upcasts_code, "$imbaseclass", baseclass); + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", proxy_class_name); + Replaceall(upcasts_code, "$cclass", c_classname); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * getAttrString() + * + * If necessary create and return the string + * associated with a certain attribute of 'n'. + * ---------------------------------------------------------------------- */ + + String *getAttrString(Node *n, const char *attr) { + String *str = Getattr(n, attr); + if (str == NIL) { + str = NewString(""); + Setattr(n, attr, str); + } + return str; + } + + /* ---------------------------------------------------------------------- + * getMethodDeclarations() + * + * If necessary create and return the handle + * where the methods of the current access can be written to. + * 'n' must be a member of a struct or a class. + * ---------------------------------------------------------------------- */ + + String *getMethodDeclarations(Node *n) { + String *acc_str = Getattr(n, "access"); + String *methodattr; + if (acc_str == NIL) { + methodattr = NewString("modula3:method:public"); + } else { + methodattr = NewStringf("modula3:method:%s", acc_str); + } + String *methods = getAttrString(parentNode(n), Char(methodattr)); + Delete(methodattr); + return methods; + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + proxy_class_name = Copy(Getattr(n, "sym:name")); + //String *rawname = Getattr(n,"name"); + + if (proxy_flag) { + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + if (Cmp(proxy_class_name, m3raw_name) == 0) { + Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + if (Cmp(proxy_class_name, m3wrap_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + String *filen = NewStringf("%s%s.m3", Swig_file_dirname(outfile), proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Delete(filen); + filen = NULL; + + emitBanner(f_proxy); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + have_default_constructor_flag = false; + destructor_call = NewString(""); + } + + /* This will invoke memberfunctionHandler, membervariableHandler ... + and finally it may invoke functionWrapper + for wrappers and member variable accessors. + It will invoke Language:constructorDeclaration + which decides whether to call MODULA3::constructorHandler */ + Language::classHandler(n); + + { + String *kind = Getattr(n, "kind"); + if (Cmp(kind, "struct") == 0) { + String *entries = NewString(""); + Node *child; + writeArgState state; + for (child = firstChild(n); child != NIL; child = nextSibling(child)) { + String *childType = nodeType(child); + if (Strcmp(childType, "cdecl") == 0) { + String *member = Getattr(child, "sym:name"); + ParmList *pl = Getattr(child, "parms"); + if (pl == NIL) { + // Get the variable type in Modula 3 type equivalents + String *m3ct = getMappedTypeNew(child, "m3rawtype", ""); + + writeArg(entries, state, NIL, member, m3ct, NIL); + } + } + } + writeArg(entries, state, NIL, NIL, NIL, NIL); + + m3raw_intf.enterBlock(blocktype); + Printf(m3raw_intf.f, "%s =\nRECORD\n%sEND;\n", proxy_class_name, entries); + + Delete(entries); + + } else if (Cmp(kind, "class") == 0) { + enum access_privilege { acc_public, acc_protected, acc_private }; + int max_acc = acc_public; + + const char *acc_name[3] = { "public", "protected", "private" }; + String *methods[3]; + int acc; + for (acc = acc_public; acc <= acc_private; acc++) { + String *methodattr = NewStringf("modula3:method:%s", acc_name[acc]); + methods[acc] = Getattr(n, methodattr); + Delete(methodattr); + max_acc = max_acc > acc ? max_acc : acc; + } + + /* Determine the name of the base class */ + String *baseclassname = NewString(""); + { + List *baselist = Getattr(n, "bases"); + if (baselist) { + /* Look for the first (principal?) base class - + Modula 3 does not support multiple inheritance */ + Iterator base = First(baselist); + Append(baseclassname, Getattr(base.item, "sym:name")); + base = Next(base); + if (base.item != NIL) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", + proxy_class_name, Getattr(base.item, "name")); + } + } + } + + /* the private class of the base class and only this + need a pointer to the C++ object */ + bool need_private = !hasContent(baseclassname); + max_acc = need_private ? acc_private : max_acc; + + /* Declare C++ object as abstract pointer in Modula 3 */ + /* The revelation system does not allow us + to imitate the whole class hierarchy of the C++ library, + but at least we can distinguish between classes of different roots. */ + if (hasContent(baseclassname)) { + m3raw_intf.enterBlock(blocktype); + Printf(m3raw_intf.f, "%s = %s;\n", proxy_class_name, baseclassname); + } else { + m3raw_intf.enterBlock(blocktype); + Printf(m3raw_intf.f, "%s <: ADDRESS;\n", proxy_class_name); + m3raw_impl.enterBlock(revelation); + Printf(m3raw_impl.f, "%s = UNTRACED BRANDED REF RECORD (*Dummy*) END;\n", proxy_class_name); + } + + String *superclass; + m3wrap_intf.enterBlock(blocktype); + if (hasContent(methods[acc_public])) { + superclass = NewStringf("%sPublic", proxy_class_name); + } else if (hasContent(baseclassname)) { + superclass = Copy(baseclassname); + } else { + superclass = NewString("ROOT"); + } + Printf(m3wrap_intf.f, "%s <: %s;\n", proxy_class_name, superclass); + Delete(superclass); + + { + static const char *acc_m3suffix[] = { "Public", "Protected", "Private" }; + int acc; + for (acc = acc_public; acc <= acc_private; acc++) { + bool process_private = (acc == acc_private) && need_private; + if (hasContent(methods[acc]) || process_private) { + String *subclass = NewStringf("%s%s", proxy_class_name, acc_m3suffix[acc]); + /* + m3wrap_intf.enterBlock(revelation); + Printf(m3wrap_intf.f, "%s <: %s;\n", proxy_class_name, subclass); + */ + if (acc == max_acc) { + m3wrap_intf.enterBlock(revelation); + Printf(m3wrap_intf.f, "%s =\n", proxy_class_name); + } else { + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%s =\n", subclass); + } + Printf(m3wrap_intf.f, "%s BRANDED OBJECT\n", baseclassname); + if (process_private) { + Setattr(m3wrap_intf.import, m3raw_name, ""); + Printf(m3wrap_intf.f, "cxxObj:%s.%s;\n", m3raw_name, proxy_class_name); + } + if (hasContent(methods[acc])) { + Printf(m3wrap_intf.f, "METHODS\n%s", methods[acc]); + } + if (acc == max_acc) { + String *overrides = Getattr(n, "modula3:override"); + Printf(m3wrap_intf.f, "OVERRIDES\n%s", overrides); + } + Printf(m3wrap_intf.f, "END;\n"); + Delete(baseclassname); + baseclassname = subclass; + } + } + } + + Delete(methods[acc_public]); + Delete(methods[acc_protected]); + Delete(methods[acc_private]); + + } else { + Swig_warning(WARN_MODULA3_TYPECONSTRUCTOR_UNKNOWN, input_file, line_number, "Unknown type constructor %s\n", kind); + } + } + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + Printf(f_proxy, "}\n"); + Close(f_proxy); + f_proxy = NULL; + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + //printf("begin memberfunctionHandler(%s)\n", Char(Getattr(n,"name"))); + Setattr(n, "modula3:functype", "method"); + Language::memberfunctionHandler(n); + + { + /* Language::memberfunctionHandler will remove the mapped types + that emitM3Wrapper may attach */ + ParmList *pl = Getattr(n, "parms"); + Swig_typemap_attach_parms("m3wrapinmode", pl, NULL); + Swig_typemap_attach_parms("m3wrapinname", pl, NULL); + Swig_typemap_attach_parms("m3wrapintype", pl, NULL); + Swig_typemap_attach_parms("m3wrapindefault", pl, NULL); + attachParameterNames(n, "tmap:m3wrapinname", "autoname", "arg%d"); + String *rettype = getMappedTypeNew(n, "m3wrapouttype", ""); + + String *methodname = Getattr(n, "sym:name"); +/* + if (methodname==NIL) { + methodname = Getattr(n,"name"); + } +*/ + String *arguments = createM3Signature(n); + String *storage = Getattr(n, "storage"); + String *overridden = Getattr(n, "override"); + bool isVirtual = (storage != NIL) && (Strcmp(storage, "virtual") == 0); + bool isOverridden = (overridden != NIL) + && (Strcmp(overridden, "1") == 0); + if ((!isVirtual) || (!isOverridden)) { + { + String *methods = getMethodDeclarations(n); + Printf(methods, "%s(%s)%s%s;%s\n", + methodname, arguments, + hasContent(rettype) ? ": " : "", hasContent(rettype) ? (const String *) rettype : "", isVirtual ? " (* base method *)" : ""); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:funcname"); + String *overrides = getAttrString(parentNode(n), "modula3:override"); + Printf(overrides, "%s := %s;\n", methodname, fname); + } + } + } + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + //printf("end memberfunctionHandler(%s)\n", Char(Getattr(n,"name"))); + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a Modula 3 wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to Modula 3 static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the Modula 3 class proxy function, which in turn will call "imfuncname" - + * the intermediary (PInvoke) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Hash *throws_hash = NewHash(); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + + if (!proxy_flag) + return; + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("m3wraptype", l, NULL); + Swig_typemap_attach_parms("m3in", l, NULL); + + /* Get return types */ + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } + + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Properties + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) + == 0); + } + + /* Start generating the proxy function */ + Printf(function_code, " %s ", Getattr(n, "feature:modula3:methodmodifiers")); + if (static_flag) + Printf(function_code, "static "); + if (Getattr(n, "override")) + Printf(function_code, "override "); + else if (checkAttribute(n, "storage", "virtual")) + Printf(function_code, "virtual "); + + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + Printv(imcall, m3raw_name, ".", intermediary_function_name, "(", NIL); + if (!static_flag) + Printv(imcall, "swigCPtr", NIL); + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0)) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Modula 3 parameter type */ + if ((tm = getMappedType(p, "m3wraptype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = variable_wrapper_flag ? NewString("value") : makeParameterName(n, + p, + i); + + // Use typemaps to transform type used in Modula 3 wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = getMappedType(p, "in"))) { + addThrows(throws_hash, "in", p); + substituteClassname(pt, tm); + Replaceall(tm, "$input", arg); + Printv(imcall, tm, NIL); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in Modula 3 wrapper function (in proxy class) + if ((tm = getMappedTypeNew(n, "m3out", ""))) { + addThrows(throws_hash, "m3out", n); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + } + + generateThrowsClause(throws_hash, function_code); + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Properties + if (setter_flag) { + // Setter method + if ((tm = getMappedTypeNew(n, "m3varin", ""))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + Printf(proxy_class_code, "%s", tm); + } + } else { + // Getter method + if ((tm = getMappedTypeNew(n, "m3varout", ""))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + Printf(proxy_class_code, "%s", tm); + } + } + } else { + // Normal function call + Printv(proxy_class_code, function_code, NIL); + } + + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(throws_hash); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + // this invokes functionWrapper + Language::constructorHandler(n); + + if (proxy_flag) { + ParmList *l = Getattr(n, "parms"); + + Hash *throws_hash = NewHash(); + String *overloaded_name = getOverloadedName(n); + String *imcall = NewString(""); + + Printf(proxy_class_code, " %s %s(", Getattr(n, "feature:modula3:methodmodifiers"), proxy_class_name); + Printv(imcall, " : this(", m3raw_name, ".", Swig_name_construct(overloaded_name), "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("m3wraptype", l, NULL); + Swig_typemap_attach_parms("m3in", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + String *tm; + Parm *p = l; + int i; + + /* Output each parameter */ + for (i = 0; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Modula 3 parameter type */ + if ((tm = getMappedType(p, "m3wraptype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i); + + // Use typemaps to transform type used in Modula 3 wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = getMappedType(p, "in"))) { + addThrows(throws_hash, "in", p); + substituteClassname(pt, tm); + Replaceall(tm, "$input", arg); + Printv(imcall, tm, NIL); + } + + /* Add parameter to proxy function */ + if (gencomma) + Printf(proxy_class_code, ", "); + Printf(proxy_class_code, "%s %s", param_type, arg); + gencomma = 1; + + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, "), true)"); + + Printf(proxy_class_code, ")"); + Printf(proxy_class_code, "%s", imcall); + generateThrowsClause(throws_hash, proxy_class_code); + Printf(proxy_class_code, " {\n"); + Printf(proxy_class_code, " }\n\n"); + + if (!gencomma) // We must have a default constructor + have_default_constructor_flag = true; + + Delete(overloaded_name); + Delete(imcall); + Delete(throws_hash); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, m3raw_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + //printf("begin membervariableHandler(%s)\n", Char(Getattr(n,"name"))); + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + + variable_name = Getattr(n, "sym:name"); + //printf("member variable: %s\n", Char(variable_name)); + + // Output the property's field declaration and accessor methods + Printf(proxy_class_code, " public %s %s {", tm, variable_name); + + Setattr(n, "modula3:functype", "accessor"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + + Printf(proxy_class_code, "\n }\n\n"); + + { + String *methods = getMethodDeclarations(n); + String *overrides = getAttrString(parentNode(n), "modula3:override"); + SwigType *type = Getattr(n, "type"); + String *m3name = capitalizeFirst(variable_name); + //String *m3name = nameToModula3(variable_name,true); + if (!SwigType_isconst(type)) { + { + String *inmode = getMappedTypeNew(n, "m3wrapinmode", "", false); + String *intype = getMappedTypeNew(n, "m3wrapintype", ""); + Printf(methods, "set%s(%s val:%s);\n", m3name, (inmode != NIL) ? (const String *) inmode : "", intype); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:setname"); + Printf(overrides, "set%s := %s;\n", m3name, fname); + } + } + { + { + String *outtype = getMappedTypeNew(n, "m3wrapouttype", ""); + Printf(methods, "get%s():%s;\n", m3name, outtype); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:getname"); + Printf(overrides, "get%s := %s;\n", m3name, fname); + } + } + Delete(m3name); + } + //printf("end membervariableHandler(%s)\n", Char(Getattr(n,"name"))); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + + bool static_const_member_flag = (Getattr(n, "value") == 0); + if (static_const_member_flag) { + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + // Output the property's field declaration and accessor methods + Printf(proxy_class_code, " public static %s %s {", tm, Getattr(n, "sym:name")); + } + + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + + if (static_const_member_flag) + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + Language::memberconstantHandler(n); + wrapping_member_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + String *overloaded_name = Copy(Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * emitM3Wrapper() + * It is also used for set and get methods of global variables. + * ----------------------------------------------------------------------------- */ + + void emitM3Wrapper(Node *n, const String *func_name) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Hash *throws_hash = NewHash(); + int num_exceptions = 0; + int num_returns = 0; + String *rawcall = NewString(""); + String *reccall = NewString(""); + String *local_variables = NewString(""); + String *local_constants = NewString(""); + String *incheck = NewString(""); + String *outcheck = NewString(""); + String *setup = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); /* don't mix up with 'autark' :-] */ + String *storeout = NewString(""); + String *result_name = NewString(""); + String *return_variables = NewString(""); + const char *result_return = "ret"; + String *function_code = NewString(""); + /*several names for the same function */ + String *raw_name = Getattr(n, "name"); /*original C function name */ + //String *func_name = Getattr(n,"sym:name"); /*final Modula3 name chosen by the user*/ + bool setter_flag = false; + int multiretval = GetFlag(n, "feature:modula3:multiretval"); + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("m3wrapargvar", l, NULL); + Swig_typemap_attach_parms("m3wrapargconst", l, NULL); + Swig_typemap_attach_parms("m3wrapargraw", l, NULL); + Swig_typemap_attach_parms("m3wrapargdir", l, NULL); + Swig_typemap_attach_parms("m3wrapinmode", l, NULL); + Swig_typemap_attach_parms("m3wrapinname", l, NULL); + Swig_typemap_attach_parms("m3wrapintype", l, NULL); + Swig_typemap_attach_parms("m3wrapindefault", l, NULL); + Swig_typemap_attach_parms("m3wrapinconv", l, NULL); + Swig_typemap_attach_parms("m3wrapincheck", l, NULL); + Swig_typemap_attach_parms("m3wrapoutname", l, NULL); + Swig_typemap_attach_parms("m3wrapouttype", l, NULL); + Swig_typemap_attach_parms("m3wrapoutconv", l, NULL); + Swig_typemap_attach_parms("m3wrapoutcheck", l, NULL); + + attachMappedType(n, "m3wrapretraw"); + attachMappedType(n, "m3wrapretname"); + attachMappedType(n, "m3wraprettype"); + attachMappedType(n, "m3wrapretvar"); + attachMappedType(n, "m3wrapretconv"); + attachMappedType(n, "m3wrapretcheck"); + + Swig_typemap_attach_parms("m3wrapfreearg", l, NULL); + +/* + Swig_typemap_attach_parms("m3wrapargvar:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapargraw:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapinconv:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapincheck:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapoutconv:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapoutcheck:throws", l, NULL); + + attachMappedType(n, "m3wrapretvar:throws"); + attachMappedType(n, "m3wrapretconv:throws"); + attachMappedType(n, "m3wrapretcheck:throws"); + + Swig_typemap_attach_parms("m3wrapfreearg:throws", l, NULL); +*/ + + /* Attach argument names to the parameter list */ + /* should be a separate procedure making use of hashes */ + attachParameterNames(n, "tmap:m3wrapinname", "autoname", "arg%d"); + + /* Get return types */ + String *result_m3rawtype = Copy(getMappedTypeNew(n, "m3rawrettype", "")); + String *result_m3wraptype = Copy(getMappedTypeNew(n, "m3wraprettype", "")); + bool has_return_raw = hasContent(result_m3rawtype); + bool has_return_m3 = hasContent(result_m3wraptype); + if (has_return_m3) { + num_returns++; + //printf("%s: %s\n", Char(func_name),Char(result_m3wraptype)); + } + + String *arguments = createM3Signature(n); + + /* Create local variables or RECORD fields for return values + and determine return type that might result from a converted VAR argument. */ + { + writeArgState state; + if (multiretval && has_return_m3) { + writeArg(return_variables, state, NIL, NewString(result_return), result_m3wraptype, NIL); + } + + Parm *p = skipIgnored(l, "m3wrapouttype"); + while (p != NIL) { + + String *arg = Getattr(p, "tmap:m3wrapoutname"); + if (arg == NIL) { + arg = Getattr(p, "name"); + } + + String *tm = Getattr(p, "tmap:m3wrapouttype"); + if (tm != NIL) { + if (isOutParam(p)) { + if (!multiretval) { + if (num_returns == 0) { + Printv(result_name, arg, NIL); + Clear(result_m3wraptype); + Printv(result_m3wraptype, tm, NIL); + } else { + Swig_warning(WARN_MODULA3_TYPEMAP_MULTIPLE_RETURN, input_file, line_number, + "Typemap m3wrapargdir set to 'out' for %s implies a RETURN value, but the routine %s has already one.\nUse %%multiretval feature.\n", + SwigType_str(Getattr(p, "type"), 0), raw_name); + } + } + num_returns++; + addImports(m3wrap_intf.import, "m3wrapouttype", p); + writeArg(return_variables, state, NIL, arg, tm, NIL); + } + p = skipIgnored(Getattr(p, "tmap:m3wrapouttype:next"), "m3wrapouttype"); + } else { + p = nextSibling(p); + } + } + writeArg(return_variables, state, NIL, NIL, NIL, NIL); + + if (multiretval) { + Printv(result_name, "result", NIL); + Printf(result_m3wraptype, "%sResult", func_name); + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%s =\nRECORD\n%sEND;\n", result_m3wraptype, return_variables); + Printf(local_variables, "%s: %s;\n", result_name, result_m3wraptype); + } else { + Append(local_variables, return_variables); + } + } + + /* Declare local constants e.g. for storing argument names. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapargconst"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapargconst", p); + Replaceall(tm, "$input", arg); + Printv(local_constants, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapargconst:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Declare local variables e.g. for converted input values. */ + { + String *tm = getMappedTypeNew(n, "m3wrapretvar", "", false); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapretvar", n); + addThrows(throws_hash, "m3wrapretvar", n); + Printv(local_variables, tm, "\n", NIL); + } + + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + tm = Getattr(p, "tmap:m3wrapargvar"); + if (tm != NIL) { + /* exceptions that may be raised but can't be catched, + thus we won't count them in num_exceptions */ + addImports(m3wrap_impl.import, "m3wrapargvar", p); + addThrows(throws_hash, "m3wrapargvar", p); + Replaceall(tm, "$input", arg); + Printv(local_variables, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapargvar:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Convert input values from Modula 3 to C. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapinconv"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapinconv", p); + num_exceptions += addThrows(throws_hash, "m3wrapinconv", p); + Replaceall(tm, "$input", arg); + Printv(setup, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapinconv:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Generate checks for input value integrity. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapincheck"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapincheck", p); + num_exceptions += addThrows(throws_hash, "m3wrapincheck", p); + Replaceall(tm, "$input", arg); + Printv(incheck, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapincheck:next"); + } else { + p = nextSibling(p); + } + + } + } + + Printv(rawcall, m3raw_name, ".", func_name, "(", NIL); + /* Arguments to the raw C function */ + { + bool gencomma = false; + Parm *p = l; + while (p != NIL) { + if (gencomma) { + Printf(rawcall, ", "); + } + gencomma = true; + addImports(m3wrap_impl.import, "m3wrapargraw", p); + num_exceptions += addThrows(throws_hash, "m3wrapargraw", p); + + String *arg = Getattr(p, "autoname"); + String *qualarg = NewString(""); + if (!isInParam(p)) { + String *tmparg = Getattr(p, "tmap:m3wrapoutname"); + if (tmparg != NIL) { + arg = tmparg; + } + if (multiretval /*&& isOutParam(p) - automatically fulfilled */ ) { + Printf(qualarg, "%s.", result_name); + } + } + Append(qualarg, arg); + Setattr(p, "m3outarg", qualarg); + + String *tm = Getattr(p, "tmap:m3wrapargraw"); + if (tm != NIL) { + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", qualarg); + Printv(rawcall, tm, NIL); + p = Getattr(p, "tmap:m3wrapargraw:next"); + } else { + //Printv(rawcall, Getattr(p,"lname"), NIL); + Printv(rawcall, qualarg, NIL); + p = nextSibling(p); + } + Delete(qualarg); + } + } + Printf(rawcall, ")"); + + /* Check for error codes and integrity of results */ + { + String *tm = getMappedTypeNew(n, "m3wrapretcheck", "", false); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapretcheck", n); + num_exceptions += addThrows(throws_hash, "m3wrapretcheck", n); + Printv(outcheck, tm, "\n", NIL); + } + + Parm *p = l; + while (p != NIL) { + tm = Getattr(p, "tmap:m3wrapoutcheck"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapoutcheck", p); + num_exceptions += addThrows(throws_hash, "m3wrapoutcheck", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printv(outcheck, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapoutcheck:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Convert the results to Modula 3 data structures and + put them in the record prepared for returning */ + { + /* m3wrapretconv is processed + when it is clear if there is some output conversion and checking code */ + Parm *p = l; + while (p != NIL) { + String *tm = Getattr(p, "tmap:m3wrapoutconv"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapoutconv", n); + num_exceptions += addThrows(throws_hash, "m3wrapoutconv", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printf(storeout, "%s := %s;\n", outarg, tm); + p = Getattr(p, "tmap:m3wrapoutconv:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Generate cleanup code */ + { + Parm *p = l; + while (p != NIL) { + String *tm = Getattr(p, "tmap:m3wrapfreearg"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapfreearg", p); + num_exceptions += addThrows(throws_hash, "m3wrapfreearg", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapfreearg:next"); + } else { + p = nextSibling(p); + } + } + } + + { + /* Currently I don't know how a typemap similar to the original 'out' typemap + could help returning the return value. */ + /* Receive result from call to raw library function */ + if (!has_return_raw) { + /* + rawcall(arg1); + result.val := arg1; + RETURN result; + */ + /* + rawcall(arg1); + RETURN arg1; + */ + Printf(reccall, "%s;\n", rawcall); + + if (hasContent(result_name)) { + Printf(outarg, "RETURN %s;\n", result_name); + } + } else { + /* + arg0 := rawcall(arg1); + result.ret := Convert(arg0); + result.val := arg1; + RETURN result; + */ + /* + arg0 := rawcall(); + RETURN Convert(arg0); + */ + /* + RETURN rawcall(); + */ + String *return_raw = getMappedTypeNew(n, "m3wrapretraw", "", false); + String *return_conv = getMappedTypeNew(n, "m3wrapretconv", "", false); + + /* immediate RETURN would skip result checking */ + if ((hasContent(outcheck) || hasContent(storeout) + || hasContent(cleanup)) && (!hasContent(result_name)) + && (return_raw == NIL)) { + Printv(result_name, "result", NIL); + Printf(local_variables, "%s: %s;\n", result_name, result_m3wraptype); + } + + String *result_lvalue = Copy(result_name); + if (multiretval) { + Printf(result_lvalue, ".%s", result_return); + } + if (return_raw != NIL) { + Printf(reccall, "%s := %s;\n", return_raw, rawcall); + } else if (hasContent(result_name)) { + Printf(reccall, "%s := %s;\n", result_lvalue, rawcall); + } else { + Printf(outarg, "RETURN %s;\n", rawcall); + } + if (return_conv != NIL) { + addImports(m3wrap_impl.import, "m3wrapretconv", n); + num_exceptions += addThrows(throws_hash, "m3wrapretconv", n); + if (hasContent(result_name)) { + Printf(reccall, "%s := %s;\n", result_lvalue, return_conv); + Printf(outarg, "RETURN %s;\n", result_name); + } else { + Printf(outarg, "RETURN %s;\n", return_conv); + } + } else { + if (hasContent(result_name)) { + Printf(outarg, "RETURN %s;\n", result_name); + } + } + } + } + + /* Create procedure header */ + { + String *header = NewStringf("PROCEDURE %s (%s)", + func_name, arguments); + + if ((num_returns > 0) || multiretval) { + Printf(header, ": %s", result_m3wraptype); + } + generateThrowsClause(throws_hash, header); + + Append(function_code, header); + + m3wrap_intf.enterBlock(no_block); + Printf(m3wrap_intf.f, "%s;\n\n", header); + } + + { + String *body = NewStringf("%s%s%s%s%s", + incheck, + setup, + reccall, + outcheck, + storeout); + + String *exc_handler; + if (hasContent(cleanup) && (num_exceptions > 0)) { + exc_handler = NewStringf("TRY\n%sFINALLY\n%sEND;\n", body, cleanup); + } else { + exc_handler = NewStringf("%s%s", body, cleanup); + } + + Printf(function_code, " =\n%s%s%s%sBEGIN\n%s%sEND %s;\n\n", + hasContent(local_constants) ? "CONST\n" : "", local_constants, + hasContent(local_variables) ? "VAR\n" : "", local_variables, exc_handler, outarg, func_name); + + Delete(exc_handler); + Delete(body); + } + + m3wrap_impl.enterBlock(no_block); + if (proxy_flag && global_variable_flag) { + // Properties + if (setter_flag) { + // Setter method + String *tm = getMappedTypeNew(n, "m3varin", ""); + if (tm != NIL) { + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "true"); + } else { + Replaceall(tm, "$owner", "false"); + } + substituteClassname(t, tm); + Replaceall(tm, "$rawcall", rawcall); + Replaceall(tm, "$vartype", variable_type); /* $type is already replaced by some super class */ + Replaceall(tm, "$var", variable_name); + Printf(m3wrap_impl.f, "%s", tm); + } + } else { + // Getter method + String *tm = getMappedTypeNew(n, "m3varout", ""); + if (tm != NIL) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$rawcall", rawcall); + Replaceall(tm, "$vartype", variable_type); + Replaceall(tm, "$var", variable_name); + Printf(m3wrap_impl.f, "%s", tm); + } + } + } else { + // Normal function call + Printv(m3wrap_impl.f, function_code, NIL); + } + + Delete(arguments); + Delete(return_variables); + Delete(local_variables); + Delete(local_constants); + Delete(outarg); + Delete(incheck); + Delete(outcheck); + Delete(setup); + Delete(cleanup); + Delete(storeout); + Delete(function_code); + Delete(result_name); + Delete(result_m3wraptype); + Delete(reccall); + Delete(rawcall); + Delete(throws_hash); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $m3classname with the proxy class name for classes/structs/unions + * that SWIG knows about. + * Otherwise use the $descriptor name for the Modula 3 class name. Note that the $&m3classname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm) { + bool substitution_performed = false; + if (Strstr(tm, "$m3classname") || Strstr(tm, "$&m3classname")) { + String *classname = getProxyName(pt); + if (classname) { + Replaceall(tm, "$&m3classname", classname); // getProxyName() works for pointers to classes too + Replaceall(tm, "$m3classname", classname); + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NULL; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + + if (Strstr(tm, "$&m3classname")) { + SwigType_add_pointer(type); + descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); + Replaceall(tm, "$&m3classname", descriptor); + } else { // $m3classname + descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); + Replaceall(tm, "$m3classname", descriptor); + } + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, type); + Delete(descriptor); + Delete(type); + } + substitution_performed = true; + } + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num) { + + // Use C parameter name unless it is a duplicate or an empty parameter name + String *pn = Getattr(p, "name"); + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *arg = (!pn || (count > 1)) ? NewStringf("arg%d", + arg_num) : Copy(Getattr(p, + "name")); + + return arg; + } + + /* ----------------------------------------------------------------------------- + * attachParameterNames() + * + * Inputs: + * n - Node of a function declaration + * tmid - attribute name for overriding C argument names, + * e.g. "tmap:m3wrapinname", + * don't forget to attach the mapped types before + * nameid - attribute for attaching the names, + * e.g. "modula3:inname" + * fmt - format for the argument name containing %d + * e.g. "arg%d" + * ----------------------------------------------------------------------------- */ + + void attachParameterNames(Node *n, const char *tmid, const char *nameid, const char *fmt) { + /* Use C parameter name if present and unique, + otherwise create an 'arg%d' name */ + Hash *hash = NewHash(); + Parm *p = Getattr(n, "parms"); + int count = 0; + while (p != NIL) { + String *name = Getattr(p, tmid); + if (name == NIL) { + name = Getattr(p, "name"); + } + String *newname; + if ((!hasContent(name)) || (Getattr(hash, name) != NIL)) { + newname = NewStringf(fmt, count); + } else { + newname = Copy(name); + } + if (1 == Setattr(hash, newname, "1")) { + Swig_warning(WARN_MODULA3_DOUBLE_ID, input_file, line_number, "Argument '%s' twice.\n", newname); + } + Setattr(p, nameid, newname); +// Delete(newname); + p = nextSibling(p); + count++; + } + Delete(hash); + } + + /* ----------------------------------------------------------------------------- + * createM3Signature() + * + * Create signature of M3 wrapper procedure + * Call attachParameterNames and attach mapped types before! + * m3wrapintype, m3wrapinmode, m3wrapindefault + * ----------------------------------------------------------------------------- */ + + String *createM3Signature(Node *n) { + String *arguments = NewString(""); + Parm *p = skipIgnored(Getattr(n, "parms"), "m3wrapintype"); + writeArgState state; + while (p != NIL) { + + /* Get the M3 parameter type */ + String *tm = getMappedType(p, "m3wrapintype"); + if (tm != NIL) { + if (isInParam(p)) { + addImports(m3wrap_intf.import, "m3wrapintype", p); + addImports(m3wrap_impl.import, "m3wrapintype", p); + String *mode = Getattr(p, "tmap:m3wrapinmode"); + String *deflt = Getattr(p, "tmap:m3wrapindefault"); + String *arg = Getattr(p, "autoname"); + SwigType *pt = Getattr(p, "type"); + substituteClassname(pt, tm); /* do we need this ? */ + + writeArg(arguments, state, mode, arg, tm, deflt); + } + p = skipIgnored(Getattr(p, "tmap:m3wrapintype:next"), "m3wrapintype"); + } else { + p = nextSibling(p); + } + } + writeArg(arguments, state, NIL, NIL, NIL, NIL); + return (arguments); + } + +/* not used any longer + - try SwigType_str if required again */ +#if 0 + /* ----------------------------------------------------------------------------- + * createCSignature() + * + * Create signature of C function + * ----------------------------------------------------------------------------- */ + + String *createCSignature(Node *n) { + String *arguments = NewString(""); + bool gencomma = false; + Node *p; + for (p = Getattr(n, "parms"); p != NIL; p = nextSibling(p)) { + if (gencomma) { + Append(arguments, ","); + } + gencomma = true; + String *type = Getattr(p, "type"); + String *ctype = getMappedTypeNew(type, "ctype"); + Append(arguments, ctype); + } + return arguments; + } +#endif + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *filen = NewStringf("%s%s.m3", Swig_file_dirname(outfile), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + String *swigtype = NewString(""); + + // Emit banner name + emitBanner(f_swigtype); + + // Pure Modula 3 baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "m3base", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "m3interfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "m3imports", type, WARN_NONE), // Import statements + "\n", typemapLookup(n, "m3classmodifiers", type, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " class $m3classname", // Class name and bases + *Char(pure_baseclass) ? " : " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " : " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", type, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers + " $m3classname(IntPtr cPtr, bool bFutureUse) {\n", // Constructor used for wrapping pointers + " swigCPtr = cPtr;\n", " }\n", "\n", " protected $m3classname() {\n", // Default constructor + " swigCPtr = IntPtr.Zero;\n", " }\n", typemapLookup(n, "m3getcptr", type, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method + typemapLookup(n, "m3code", type, WARN_NONE), // extra Modula 3 code + "}\n", "\n", NIL); + + Replaceall(swigtype, "$m3classname", classname); + Printv(f_swigtype, swigtype, NIL); + + Close(f_swigtype); + Delete(filen); + Delete(swigtype); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * n - for input only and must contain info for Getfile(n) and Getline(n) to work + * tmap_method - typemap method name + * type - typemap type to lookup + * warning - warning number to issue if no typemaps found + * typemap_attributes - the typemap attributes are attached to this node and will + * also be used for temporary storage if non null + * return is never NULL, unlike Swig_typemap_lookup() + * ----------------------------------------------------------------------------- */ + + const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + Node *node = !typemap_attributes ? NewHash() : typemap_attributes; + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + if (!tm) { + tm = empty_string; + if (warning != WARN_NONE) + Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); + } + if (!typemap_attributes) + Delete(node); + return tm; + } + + /* ----------------------------------------------------------------------------- + * addThrows() + * + * Add all exceptions to a hash that are associated with the 'typemap'. + * Return number the number of these exceptions. + * ----------------------------------------------------------------------------- */ + + int addThrows(Hash *throws_hash, const String *typemap, Node *parameter) { + // Get the comma separated throws clause - held in "throws" attribute in the typemap passed in + int len = 0; + String *throws_attribute = NewStringf("%s:throws", typemap); + + addImports(m3wrap_intf.import, throws_attribute, parameter); + addImports(m3wrap_impl.import, throws_attribute, parameter); + + String *throws = getMappedTypeNew(parameter, Char(throws_attribute), "", false); + //printf("got exceptions %s for %s\n", Char(throws), Char(throws_attribute)); + + if (throws) { + // Put the exception classes in the throws clause into a temporary List + List *temp_classes_list = Split(throws, ',', INT_MAX); + len = Len(temp_classes_list); + + // Add the exception classes to the node throws list, but don't duplicate if already in list + if (temp_classes_list /*&& hasContent(temp_classes_list) */ ) { + for (Iterator cls = First(temp_classes_list); cls.item != NIL; cls = Next(cls)) { + String *exception_class = NewString(cls.item); + Replaceall(exception_class, " ", ""); // remove spaces + Replaceall(exception_class, "\t", ""); // remove tabs + if (hasContent(exception_class)) { + // $m3classname substitution + SwigType *pt = Getattr(parameter, "type"); + substituteClassname(pt, exception_class); + // Don't duplicate the exception class in the throws clause + //printf("add exception %s\n", Char(exception_class)); + Setattr(throws_hash, exception_class, "1"); + } + Delete(exception_class); + } + } + Delete(temp_classes_list); + } + Delete(throws_attribute); + return len; + } + + /* ----------------------------------------------------------------------------- + * generateThrowsClause() + * ----------------------------------------------------------------------------- */ + + void generateThrowsClause(Hash *throws_hash, String *code) { + // Add the throws clause into code + if (Len(throws_hash) > 0) { + Iterator cls = First(throws_hash); + Printf(code, " RAISES {%s", cls.key); + for (cls = Next(cls); cls.key != NIL; cls = Next(cls)) { + Printf(code, ", %s", cls.key); + } + Printf(code, "}"); + } + } + + /* ----------------------------------------------------------------------------- + * addImports() + * + * Add all imports that are needed for contents of 'typemap'. + * ----------------------------------------------------------------------------- */ + + void addImports(Hash *imports_hash, const String *typemap, Node *node) { + // Get the comma separated throws clause - held in "throws" attribute in the typemap passed in + String *imports_attribute = NewStringf("%s:import", typemap); + String *imports = getMappedTypeNew(node, Char(imports_attribute), "", false); + //printf("got imports %s for %s\n", Char(imports), Char(imports_attribute)); + + if (imports != NIL) { + List *import_list = Split(imports, ',', INT_MAX); + + // Add the exception classes to the node imports list, but don't duplicate if already in list + if (import_list != NIL) { + for (Iterator imp = First(import_list); imp.item != NIL; imp = Next(imp)) { + List *import_pair = Split(imp.item, ' ', 3); + if (Len(import_pair) == 1) { + Setattr(imports_hash, Getitem(import_pair, 0), ""); + } else if ((Len(import_pair) == 3) + && Strcmp(Getitem(import_pair, 1), "AS") == 0) { + Setattr(imports_hash, Getitem(import_pair, 0), Getitem(import_pair, 2)); + } else { + Swig_warning(WARN_MODULA3_BAD_IMPORT, input_file, line_number, + "Malformed import '%s' for typemap '%s' defined for type '%s'\n", imp, typemap, SwigType_str(Getattr(node, "type"), 0)); + } + Delete(import_pair); + } + } + Delete(import_list); + } + Delete(imports_attribute); + } + + /* ----------------------------------------------------------------------------- + * emitImportStatements() + * ----------------------------------------------------------------------------- */ + + void emitImportStatements(Hash *imports_hash, String *code) { + // Add the imports statements into code + Iterator imp = First(imports_hash); + while (imp.key != NIL) { + Printf(code, "IMPORT %s", imp.key); + String *imp_as = imp.item; + if (hasContent(imp_as)) { + Printf(code, " AS %s", imp_as); + } + Printf(code, ";\n"); + imp = Next(imp); + } + } + +}; /* class MODULA3 */ + +/* ----------------------------------------------------------------------------- + * swig_modula3() - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_modula3(void) { + return new MODULA3(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *MODULA3::usage = (char *) "\ +Modula 3 Options (available with -modula3)\n\ + -generateconst <file> - generate code for computing numeric values of constants\n\ + -generaterename <file> - generate suggestions for %rename\n\ + -generatetypemap <file> - generate templates for some basic typemaps\n\ + -oldvarnames - old intermediary method names for variable wrappers\n\ +\n"; + +/* + -generateconst <file> - stem of the .c source file for computing the numeric values of constants\n\ + -generaterename <file> - stem of the .i source file containing %rename suggestions\n\ + -generatetypemap <file> - stem of the .i source file containing typemap patterns\n\ +*/ diff --git a/Source/Modules/module.cxx b/Source/Modules/module.cxx new file mode 100644 index 0000000..bd82b9e --- /dev/null +++ b/Source/Modules/module.cxx @@ -0,0 +1,57 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * module.cxx + * + * This file is responsible for the module system. + * ----------------------------------------------------------------------------- */ + +char cvsroot_module_cxx[] = "$Id: module.cxx 10003 2007-10-17 21:42:11Z wsfulton $"; + +#include "swigmod.h" + +struct Module { + ModuleFactory fac; + char *name; + Module *next; + Module(const char *n, ModuleFactory f) { + fac = f; + name = new char[strlen(n) + 1]; + strcpy(name, n); + next = 0; + } ~Module() { + delete[]name; + } +}; + +static Module *modules = 0; + +/* ----------------------------------------------------------------------------- + * void Swig_register_module() + * + * Register a module. + * ----------------------------------------------------------------------------- */ + +void Swig_register_module(const char *n, ModuleFactory f) { + Module *m = new Module(n, f); + m->next = modules; + modules = m; +} + +/* ----------------------------------------------------------------------------- + * Language *Swig_find_module() + * + * Given a command line option, locates the factory function. + * ----------------------------------------------------------------------------- */ + +ModuleFactory Swig_find_module(const char *name) { + Module *m = modules; + while (m) { + if (strcmp(m->name, name) == 0) { + return m->fac; + } + m = m->next; + } + return 0; +} diff --git a/Source/Modules/mzscheme.cxx b/Source/Modules/mzscheme.cxx new file mode 100644 index 0000000..a40f00d --- /dev/null +++ b/Source/Modules/mzscheme.cxx @@ -0,0 +1,834 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * mzscheme.cxx + * + * Mzscheme language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_mzscheme_cxx[] = "$Id: mzscheme.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +static const char *usage = (char *) "\ +Mzscheme Options (available with -mzscheme)\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -declaremodule - Create extension that declares a module\n\ + -noinit - Do not emit scheme_initialize, scheme_reload,\n\ + scheme_module_name functions\n\ + -dynamic-load <library>,[library,...] - Do not link with these libraries, dynamic load\n\ + them\n\ +"; + +static String *fieldnames_tab = 0; +static String *convert_tab = 0; +static String *convert_proto_tab = 0; +static String *struct_name = 0; +static String *mangled_struct_name = 0; + +static char *prefix = 0; +static bool declaremodule = false; +static bool noinit = false; +//DLOPEN PATCH +static char *load_libraries = NULL; +//DLOPEN PATCH +static String *module = 0; +static char *mzscheme_path = (char *) "mzscheme"; +static String *init_func_def = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; + +// Used for garbage collection +static int exporting_destructor = 0; +static String *swigtype_ptr = 0; +static String *cls_swigtype = 0; + +class MZSCHEME:public Language { +public: + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + int i; + + SWIG_library_directory(mzscheme_path); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + SWIG_exit(0); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = new char[strlen(argv[i + 1]) + 2]; + strcpy(prefix, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-declaremodule") == 0) { + declaremodule = true; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noinit") == 0) { + noinit = true; + Swig_mark_arg(i); + } +// DLOPEN PATCH + else if (strcmp(argv[i], "-dynamic-load") == 0) { + load_libraries = new char[strlen(argv[i + 1]) + 2]; + strcpy(load_libraries, argv[i + 1]); + Swig_mark_arg(i++); + Swig_mark_arg(i); + } +// DLOPEN PATCH + } + } + + // If a prefix has been specified make sure it ends in a '_' + + if (prefix) { + if (prefix[strlen(prefix)] != '_') { + prefix[strlen(prefix) + 1] = 0; + prefix[strlen(prefix)] = '_'; + } + } else + prefix = (char *) "swig_"; + + // Add a symbol for this module + + Preprocessor_define("SWIGMZSCHEME 1", 0); + + // Set name of typemaps + + SWIG_typemap_lang("mzscheme"); + + // Read in default typemaps */ + SWIG_config_file("mzscheme.swg"); + allow_overloading(); + + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + + init_func_def = NewString(""); + Swig_register_filebyname("init", init_func_def); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGMZSCHEME\n"); + Printf(f_runtime, "\n"); + + module = Getattr(n, "name"); + + Language::top(n); + + SwigType_emit_type_table(f_runtime, f_wrappers); + if (!noinit) { + if (declaremodule) { + Printf(f_init, "#define SWIG_MZSCHEME_CREATE_MENV(env) scheme_primitive_module(scheme_intern_symbol(\"%s\"), env)\n", module); + } else { + Printf(f_init, "#define SWIG_MZSCHEME_CREATE_MENV(env) (env)\n"); + } + Printf(f_init, "%s\n", Char(init_func_def)); + if (declaremodule) { + Printf(f_init, "\tscheme_finish_primitive_module(menv);\n"); + } + Printf(f_init, "\treturn scheme_void;\n}\n"); + Printf(f_init, "Scheme_Object *scheme_initialize(Scheme_Env *env) {\n"); + + // DLOPEN PATCH + if (load_libraries) { + Printf(f_init, "mz_set_dlopen_libraries(\"%s\");\n", load_libraries); + } + // DLOPEN PATCH + + Printf(f_init, "\treturn scheme_reload(env);\n"); + Printf(f_init, "}\n"); + + Printf(f_init, "Scheme_Object *scheme_module_name(void) {\n"); + if (declaremodule) { + Printf(f_init, " return scheme_intern_symbol((char*)\"%s\");\n", module); + } else { + Printf(f_init, " return scheme_make_symbol((char*)\"%s\");\n", module); + } + Printf(f_init, "}\n"); + } + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * Create a function declaration and register it with the interpreter. + * ------------------------------------------------------------ */ + + void throw_unhandled_mzscheme_type_error(SwigType *d) { + Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s.\n", SwigType_str(d, 0)); + } + + /* Return true iff T is a pointer type */ + + int + is_a_pointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); + } + + virtual int functionWrapper(Node *n) { + char *iname = GetChar(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Parm *p; + + Wrapper *f = NewWrapper(); + String *proc_name = NewString(""); + String *source = NewString(""); + String *target = NewString(""); + String *arg = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *build = NewString(""); + String *tm; + int argout_set = 0; + int i = 0; + int numargs; + int numreq; + String *overname = 0; + + // PATCH DLOPEN + if (load_libraries) { + ParmList *parms = Getattr(n, "parms"); + SwigType *type = Getattr(n, "type"); + String *name = NewString("caller"); + Setattr(n, "wrap:action", Swig_cresult(type, "result", Swig_cfunction_call(name, parms))); + } + // PATCH DLOPEN + + // Make a wrapper name for this + String *wname = Swig_name_wrapper(iname); + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + // Build the name for Scheme. + Printv(proc_name, iname, NIL); + Replaceall(proc_name, "_", "-"); + + // writing the function wrapper function + Printv(f->def, "static Scheme_Object *", wname, " (", NIL); + Printv(f->def, "int argc, Scheme_Object **argv", NIL); + Printv(f->def, ")\n{", NIL); + + /* Define the scheme name in C. This define is used by several + macros. */ + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + numargs = emit_num_arguments(l); + numreq = emit_num_required(l); + + // DLOPEN PATCH + /* Add the holder for the pointer to the function to be opened */ + if (load_libraries) { + Wrapper_add_local(f, "_function_loaded", "static int _function_loaded=(1==0)"); + Wrapper_add_local(f, "_the_function", "static void *_the_function=NULL"); + { + String *parms = ParmList_protostr(l); + String *func = NewStringf("(*caller)(%s)", parms); + Wrapper_add_local(f, "caller", SwigType_lstr(d, func)); /*"(*caller)()")); */ + } + } + // DLOPEN PATCH + + // adds local variables + Wrapper_add_local(f, "lenv", "int lenv = 1"); + Wrapper_add_local(f, "values", "Scheme_Object *values[MAXVALUES]"); + + // DLOPEN PATCH + if (load_libraries) { + Printf(f->code, "if (!_function_loaded) { _the_function=mz_load_function(\"%s\");_function_loaded=(1==1); }\n", iname); + Printf(f->code, "if (!_the_function) { scheme_signal_error(\"Cannot load C function '%s'\"); }\n", iname); + Printf(f->code, "caller=_the_function;\n"); + } + // DLOPEN PATCH + + // Now write code to extract the parameters (this is super ugly) + + for (i = 0, p = l; i < numargs; i++) { + /* Skip ignored arguments */ + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + // Produce names of source and target + Clear(source); + Clear(target); + Clear(arg); + Printf(source, "argv[%d]", i); + Printf(target, "%s", ln); + Printv(arg, Getattr(p, "name"), NIL); + + if (i >= numreq) { + Printf(f->code, "if (argc > %d) {\n", i); + } + // Handle parameter types. + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", target); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:in:next"); + } else { + // no typemap found + // check if typedef and resolve + throw_unhandled_mzscheme_type_error(pt); + p = nextSibling(p); + } + if (i >= numreq) { + Printf(f->code, "}\n"); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + // Pass output arguments back to the caller. + + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* Deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* Deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + argout_set = 1; + } else { + p = nextSibling(p); + } + } + + // Free up any memory allocated for the arguments. + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + // Now write code to make the function call + + String *actioncode = emit_action(n); + + // Now have return value, figure out what to do with it. + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "values[0]"); + Replaceall(tm, "$result", "values[0]"); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_mzscheme_type_error(d); + } + emit_return_variable(n, d, f); + + // Dump the argument output code + Printv(f->code, Char(outarg), NIL); + + // Dump the argument cleanup code + Printv(f->code, Char(cleanup), NIL); + + // Look for any remaining cleanup + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + // Wrap things up (in a manner of speaking) + + Printv(f->code, tab4, "return SWIG_MzScheme_PackageValues(lenv, values);\n", NIL); + Printf(f->code, "#undef FUNC_NAME\n"); + Printv(f->code, "}\n", NIL); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, f_wrappers); + + if (!Getattr(n, "sym:overloaded")) { + + // Now register the function + char temp[256]; + sprintf(temp, "%d", numargs); + if (exporting_destructor) { + Printf(init_func_def, "SWIG_TypeClientData(SWIGTYPE%s, (void *) %s);\n", swigtype_ptr, wname); + } else { + Printf(init_func_def, "scheme_add_global(\"%s\", scheme_make_prim_w_arity(%s,\"%s\",%d,%d),menv);\n", proc_name, wname, proc_name, numreq, numargs); + } + } else { + if (!Getattr(n, "sym:nextSibling")) { + /* Emit overloading dispatch function */ + + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(argc,argv);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "static Scheme_Object *\n", dname, "(int argc, Scheme_Object **argv) {", NIL); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "scheme_signal_error(\"No matching function for overloaded '%s'\");\n", iname); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printf(init_func_def, "scheme_add_global(\"%s\", scheme_make_prim_w_arity(%s,\"%s\",%d,%d),menv);\n", proc_name, dname, proc_name, 0, maxargs); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + } + + Delete(proc_name); + Delete(source); + Delete(target); + Delete(arg); + Delete(outarg); + Delete(cleanup); + Delete(build); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * + * Create a link to a C variable. + * This creates a single function _wrap_swig_var_varname(). + * This function takes a single optional argument. If supplied, it means + * we are setting this variable to some value. If omitted, it means we are + * simply evaluating this variable. Either way, we return the variables + * value. + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + String *proc_name = NewString(""); + String *tm; + String *tm2 = NewString("");; + String *argnum = NewString("0"); + String *arg = NewString("argv[0]"); + Wrapper *f; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + f = NewWrapper(); + + // evaluation function names + String *var_name = Swig_name_wrapper(iname); + + // Build the name for scheme. + Printv(proc_name, iname, NIL); + Replaceall(proc_name, "_", "-"); + Setattr(n, "wrap:name", proc_name); + + if ((SwigType_type(t) != T_USER) || (is_a_pointer(t))) { + + Printf(f->def, "static Scheme_Object *%s(int argc, Scheme_Object** argv) {\n", var_name); + Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + Wrapper_add_local(f, "swig_result", "Scheme_Object *swig_result"); + + if (!GetFlag(n, "feature:immutable")) { + /* Check for a setting of the variable value */ + Printf(f->code, "if (argc) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "argv[0]"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "argv[0]"); + /* Printv(f->code, tm, "\n",NIL); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_mzscheme_type_error(t); + } + Printf(f->code, "}\n"); + } + // Now return the value of the variable (regardless + // of evaluating or setting) + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "swig_result"); + Replaceall(tm, "$result", "swig_result"); + /* Printf (f->code, "%s\n", tm); */ + emit_action_code(n, f->code, tm); + } else { + throw_unhandled_mzscheme_type_error(t); + } + Printf(f->code, "\nreturn swig_result;\n"); + Printf(f->code, "#undef FUNC_NAME\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + // Now add symbol to the MzScheme interpreter + + Printv(init_func_def, + "scheme_add_global(\"", proc_name, "\", scheme_make_prim_w_arity(", var_name, ", \"", proc_name, "\", ", "0", ", ", "1", "), menv);\n", NIL); + + } else { + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported variable type %s (ignored).\n", SwigType_str(t, 0)); + } + Delete(var_name); + Delete(proc_name); + Delete(argnum); + Delete(arg); + Delete(tm2); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + + String *var_name = NewString(""); + String *proc_name = NewString(""); + String *rvalue = NewString(""); + String *temp = NewString(""); + String *tm; + + // Make a static variable; + + Printf(var_name, "_wrap_const_%s", Swig_name_mangle(Getattr(n, "sym:name"))); + + // Build the name for scheme. + Printv(proc_name, iname, NIL); + Replaceall(proc_name, "_", "-"); + + if ((SwigType_type(type) == T_USER) && (!is_a_pointer(type))) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + // See if there's a typemap + + Printv(rvalue, value, NIL); + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 1)) { + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "\"", temp, "\"", NIL); + } + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 0)) { + Delete(temp); + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "'", temp, "'", NIL); + } + if ((tm = Swig_typemap_lookup("constant", n, name, 0))) { + Replaceall(tm, "$source", rvalue); + Replaceall(tm, "$value", rvalue); + Replaceall(tm, "$target", name); + Printf(f_init, "%s\n", tm); + } else { + // Create variable and assign it a value + + Printf(f_header, "static %s = ", SwigType_lstr(type, var_name)); + if ((SwigType_type(type) == T_STRING)) { + Printf(f_header, "\"%s\";\n", value); + } else if (SwigType_type(type) == T_CHAR) { + Printf(f_header, "\'%s\';\n", value); + } else { + Printf(f_header, "%s;\n", value); + } + + // Now create a variable declaration + + { + /* Hack alert: will cleanup later -- Dave */ + Node *n = NewHash(); + Setattr(n, "name", var_name); + Setattr(n, "sym:name", iname); + Setattr(n, "type", type); + SetFlag(n, "feature:immutable"); + variableWrapper(n); + Delete(n); + } + } + Delete(proc_name); + Delete(rvalue); + Delete(temp); + return SWIG_OK; + } + + virtual int destructorHandler(Node *n) { + exporting_destructor = true; + Language::destructorHandler(n); + exporting_destructor = false; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + virtual int classHandler(Node *n) { + String *mangled_classname = 0; + String *real_classname = 0; + String *scm_structname = NewString(""); + SwigType *ctype_ptr = NewStringf("p.%s", Getattr(n, "classtype")); + + SwigType *t = NewStringf("p.%s", Getattr(n, "name")); + swigtype_ptr = SwigType_manglestr(t); + Delete(t); + + cls_swigtype = SwigType_manglestr(Getattr(n, "name")); + + + fieldnames_tab = NewString(""); + convert_tab = NewString(""); + convert_proto_tab = NewString(""); + + struct_name = Getattr(n, "sym:name"); + mangled_struct_name = Swig_name_mangle(Getattr(n, "sym:name")); + + Printv(scm_structname, struct_name, NIL); + Replaceall(scm_structname, "_", "-"); + + real_classname = Getattr(n, "name"); + mangled_classname = Swig_name_mangle(real_classname); + + Printv(fieldnames_tab, "static const char *_swig_struct_", cls_swigtype, "_field_names[] = { \n", NIL); + + Printv(convert_proto_tab, "static Scheme_Object *_swig_convert_struct_", cls_swigtype, "(", SwigType_str(ctype_ptr, "ptr"), ");\n", NIL); + + Printv(convert_tab, "static Scheme_Object *_swig_convert_struct_", cls_swigtype, "(", SwigType_str(ctype_ptr, "ptr"), ")\n {\n", NIL); + + Printv(convert_tab, + tab4, "Scheme_Object *obj;\n", tab4, "Scheme_Object *fields[_swig_struct_", cls_swigtype, "_field_names_cnt];\n", tab4, "int i = 0;\n\n", NIL); + + /* Generate normal wrappers */ + Language::classHandler(n); + + Printv(convert_tab, tab4, "obj = scheme_make_struct_instance(", "_swig_struct_type_", cls_swigtype, ", i, fields);\n", NIL); + Printv(convert_tab, tab4, "return obj;\n}\n\n", NIL); + + Printv(fieldnames_tab, "};\n", NIL); + + Printv(f_header, "static Scheme_Object *_swig_struct_type_", cls_swigtype, ";\n", NIL); + + Printv(f_header, fieldnames_tab, NIL); + Printv(f_header, "#define _swig_struct_", cls_swigtype, "_field_names_cnt (sizeof(_swig_struct_", cls_swigtype, "_field_names)/sizeof(char*))\n", NIL); + + Printv(f_header, convert_proto_tab, NIL); + Printv(f_wrappers, convert_tab, NIL); + + Printv(init_func_def, "_swig_struct_type_", cls_swigtype, + " = SWIG_MzScheme_new_scheme_struct(menv, \"", scm_structname, "\", ", + "_swig_struct_", cls_swigtype, "_field_names_cnt,", "(char**) _swig_struct_", cls_swigtype, "_field_names);\n", NIL); + + Delete(mangled_classname); + Delete(swigtype_ptr); + swigtype_ptr = 0; + Delete(fieldnames_tab); + Delete(convert_tab); + Delete(ctype_ptr); + Delete(convert_proto_tab); + struct_name = 0; + mangled_struct_name = 0; + Delete(cls_swigtype); + cls_swigtype = 0; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + Language::membervariableHandler(n); + + if (!is_smart_pointer()) { + String *symname = Getattr(n, "sym:name"); + String *name = Getattr(n, "name"); + SwigType *type = Getattr(n, "type"); + String *swigtype = SwigType_manglestr(Getattr(n, "type")); + String *tm = 0; + String *access_mem = NewString(""); + SwigType *ctype_ptr = NewStringf("p.%s", Getattr(n, "type")); + + Printv(fieldnames_tab, tab4, "\"", symname, "\",\n", NIL); + Printv(access_mem, "(ptr)->", name, NIL); + if ((SwigType_type(type) == T_USER) && (!is_a_pointer(type))) { + Printv(convert_tab, tab4, "fields[i++] = ", NIL); + Printv(convert_tab, "_swig_convert_struct_", swigtype, "((", SwigType_str(ctype_ptr, ""), ")&((ptr)->", name, "));\n", NIL); + } else if ((tm = Swig_typemap_lookup("varout", n, access_mem, 0))) { + Replaceall(tm, "$result", "fields[i++]"); + Printv(convert_tab, tm, "\n", NIL); + } else + Swig_warning(WARN_TYPEMAP_VAR_UNDEF, input_file, line_number, "Unsupported member variable type %s (ignored).\n", SwigType_str(type, 0)); + + Delete(access_mem); + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * validIdentifer() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + /* Check whether we have an R5RS identifier. */ + /* <identifier> --> <initial> <subsequent>* | <peculiar identifier> */ + /* <initial> --> <letter> | <special initial> */ + if (!(isalpha(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~'))) { + /* <peculiar identifier> --> + | - | ... */ + if ((strcmp(c, "+") == 0) + || strcmp(c, "-") == 0 || strcmp(c, "...") == 0) + return 1; + else + return 0; + } + /* <subsequent> --> <initial> | <digit> | <special subsequent> */ + while (*c) { + if (!(isalnum(*c) || (*c == '!') || (*c == '$') || (*c == '%') + || (*c == '&') || (*c == '*') || (*c == '/') || (*c == ':') + || (*c == '<') || (*c == '=') || (*c == '>') || (*c == '?') + || (*c == '^') || (*c == '_') || (*c == '~') || (*c == '+') + || (*c == '-') || (*c == '.') || (*c == '@'))) + return 0; + c++; + } + return 1; + } + + String *runtimeCode() { + String *s = Swig_include_sys("mzrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'mzrun.swg'\n"); + s = NewString(""); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigmzrun.h"); + } +}; + +/* ----------------------------------------------------------------------------- + * swig_mzscheme() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_mzscheme() { + return new MZSCHEME(); +} +extern "C" Language *swig_mzscheme(void) { + return new_swig_mzscheme(); +} diff --git a/Source/Modules/ocaml.cxx b/Source/Modules/ocaml.cxx new file mode 100644 index 0000000..5b0e78a --- /dev/null +++ b/Source/Modules/ocaml.cxx @@ -0,0 +1,1866 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * ocaml.cxx + * + * Ocaml language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_ocaml_cxx[] = "$Id: ocaml.cxx 11246 2009-06-05 17:19:29Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> + +static const char *usage = (char *) + ("Ocaml Options (available with -ocaml)\n" + "-prefix <name> - Set a prefix <name> to be prepended to all names\n" + "-where - Emit library location\n" + "-suffix <name> - Change .cxx to something else\n" "-oldvarnames - old intermediary method names for variable wrappers\n" "\n"); + +static int classmode = 0; +static int in_constructor = 0, in_destructor = 0, in_copyconst = 0; +static int const_enum = 0; +static int static_member_function = 0; +static int generate_sizeof = 0; +static char *prefix = 0; +static char *ocaml_path = (char *) "ocaml"; +static bool old_variable_names = false; +static String *classname = 0; +static String *module = 0; +static String *init_func_def = 0; +static String *f_classtemplate = 0; +static String *name_qualifier = 0; + +static Hash *seen_enums = 0; +static Hash *seen_enumvalues = 0; +static Hash *seen_constructors = 0; + +static File *f_header = 0; +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_mlout = 0; +static File *f_mliout = 0; +static File *f_mlbody = 0; +static File *f_mlibody = 0; +static File *f_mltail = 0; +static File *f_mlitail = 0; +static File *f_enumtypes_type = 0; +static File *f_enumtypes_value = 0; +static File *f_class_ctors = 0; +static File *f_class_ctors_end = 0; +static File *f_enum_to_int = 0; +static File *f_int_to_enum = 0; + +class OCAML:public Language { +public: + + OCAML() { + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", "} else {\n", " failwith(\"accessing abstract class or protected constructor\"); \n", "}\n", NIL); + director_multiple_inheritance = 1; + director_language = 1; + } + + String *Swig_class_name(Node *n) { + String *name; + name = Copy(Getattr(n, "sym:name")); + return name; + } + + void PrintIncludeArg() { + Printv(stdout, SWIG_LIB, SWIG_FILE_DELIMITER, ocaml_path, "\n", NIL); + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i; + + prefix = 0; + + SWIG_library_directory(ocaml_path); + + // Look for certain command line options + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + SWIG_exit(0); + } else if (strcmp(argv[i], "-where") == 0) { + PrintIncludeArg(); + SWIG_exit(0); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = new char[strlen(argv[i + 1]) + 2]; + strcpy(prefix, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-suffix") == 0) { + if (argv[i + 1]) { + SWIG_config_cppext(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else + Swig_arg_error(); + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } + } + } + + // If a prefix has been specified make sure it ends in a '_' + + if (prefix) { + if (prefix[strlen(prefix)] != '_') { + prefix[strlen(prefix) + 1] = 0; + prefix[strlen(prefix)] = '_'; + } + } else + prefix = (char *) "swig_"; + + // Add a symbol for this module + + Preprocessor_define("SWIGOCAML 1", 0); + // Set name of typemaps + + SWIG_typemap_lang("ocaml"); + + // Read in default typemaps */ + SWIG_config_file("ocaml.i"); + allow_overloading(); + + } + + /* Swig_director_declaration() + * + * Generate the full director class declaration, complete with base classes. + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + * + */ + + String *Swig_director_declaration(Node *n) { + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *base = Getattr(n, "classtype"); + String *declaration = Swig_class_declaration(n, directorname); + Printf(declaration, " : public %s, public Swig::Director {\n", base); + Delete(classname); + Delete(directorname); + return declaration; + } + + /* ------------------------------------------------------------ + * top() + * + * Recognize the %module, and capture the module name. + * Create the default enum cases. + * Set up the named outputs: + * + * init + * ml + * mli + * wrapper + * header + * runtime + * directors + * directors_h + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* Set comparison with none for ConstructorToFunction */ + setSubclassInstanceCheck(NewString("caml_list_nth(args,0) != Val_unit")); + + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + { + Node *module = Getattr(n, "module"); + if (module) { + Node *options = Getattr(module, "options"); + if (options) { + if (Getattr(options, "directors")) { + allow_directors(); + } + if (Getattr(options, "dirprot")) { + allow_dirprot(); + } + if (Getattr(options, "sizeof")) { + generate_sizeof = 1; + } + } + } + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors = NewString(""); + f_directors_h = NewString(""); + f_enumtypes_type = NewString(""); + f_enumtypes_value = NewString(""); + init_func_def = NewString(""); + f_mlbody = NewString(""); + f_mlibody = NewString(""); + f_mltail = NewString(""); + f_mlitail = NewString(""); + f_class_ctors = NewString(""); + f_class_ctors_end = NewString(""); + f_enum_to_int = NewString(""); + f_int_to_enum = NewString(""); + f_classtemplate = NewString(""); + + module = Getattr(n, "name"); + + seen_constructors = NewHash(); + seen_enums = NewHash(); + seen_enumvalues = NewHash(); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("init", init_func_def); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("mli", f_mlibody); + Swig_register_filebyname("ml", f_mlbody); + Swig_register_filebyname("mlitail", f_mlitail); + Swig_register_filebyname("mltail", f_mltail); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + Swig_register_filebyname("classtemplate", f_classtemplate); + Swig_register_filebyname("class_ctors", f_class_ctors); + + if (old_variable_names) { + Swig_name_register("set", "%v__set__"); + Swig_name_register("get", "%v__get__"); + } + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGOCAML\n"); + Printf(f_runtime, "#define SWIG_MODULE \"%s\"\n", module); + /* Module name */ + Printf(f_mlbody, "let module_name = \"%s\"\n", module); + Printf(f_mlibody, "val module_name : string\n"); + Printf(f_enum_to_int, + "let enum_to_int x (v : c_obj) =\n" + " match v with\n" + " C_enum _y ->\n" + " (let y = _y in match (x : c_enum_type) with\n" + " `unknown -> " " (match y with\n" " `Int x -> (Swig.C_int x)\n" " | _ -> raise (LabelNotFromThisEnum v))\n"); + + Printf(f_int_to_enum, "let int_to_enum x y =\n" " match (x : c_enum_type) with\n" " `unknown -> C_enum (`Int y)\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + Printf(f_runtime, "\n"); + + /* Produce the enum_to_int and int_to_enum functions */ + + Printf(f_enumtypes_type, "open Swig\n" "type c_enum_type = [ \n `unknown\n"); + Printf(f_enumtypes_value, "type c_enum_value = [ \n `Int of int\n"); + String *mlfile = NewString(""); + String *mlifile = NewString(""); + + Printv(mlfile, module, ".ml", NIL); + Printv(mlifile, module, ".mli", NIL); + + String *mlfilen = NewStringf("%s%s", SWIG_output_directory(), mlfile); + if ((f_mlout = NewFile(mlfilen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(mlfilen); + SWIG_exit(EXIT_FAILURE); + } + String *mlifilen = NewStringf("%s%s", SWIG_output_directory(), mlifile); + if ((f_mliout = NewFile(mlifilen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(mlifilen); + SWIG_exit(EXIT_FAILURE); + } + + Language::top(n); + + Printf(f_enum_to_int, ") | _ -> (C_int (get_int v))\n" "let _ = Callback.register \"%s_enum_to_int\" enum_to_int\n", module); + Printf(f_mlibody, "val enum_to_int : c_enum_type -> c_obj -> Swig.c_obj\n"); + + Printf(f_int_to_enum, "let _ = Callback.register \"%s_int_to_enum\" int_to_enum\n", module); + Printf(f_mlibody, "val int_to_enum : c_enum_type -> int -> c_obj\n"); + Printf(f_init, "#define SWIG_init f_%s_init\n" "%s" "}\n", module, init_func_def); + Printf(f_mlbody, "external f_init : unit -> unit = \"f_%s_init\" ;;\n" "let _ = f_init ()\n", module); + Printf(f_enumtypes_type, "]\n"); + Printf(f_enumtypes_value, "]\n\n" "type c_obj = c_enum_value c_obj_t\n"); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director.swg", f_runtime); + } + + SwigType_emit_type_table(f_runtime, f_wrappers); + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_directors_h, f_header); + Dump(f_header, f_begin); + Dump(f_directors, f_wrappers); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + Dump(f_enumtypes_type, f_mlout); + Dump(f_enumtypes_value, f_mlout); + Dump(f_mlbody, f_mlout); + Dump(f_enum_to_int, f_mlout); + Dump(f_int_to_enum, f_mlout); + Delete(f_int_to_enum); + Delete(f_enum_to_int); + Dump(f_class_ctors, f_mlout); + Dump(f_class_ctors_end, f_mlout); + Dump(f_mltail, f_mlout); + Close(f_mlout); + Delete(f_mlout); + + Dump(f_enumtypes_type, f_mliout); + Dump(f_enumtypes_value, f_mliout); + Dump(f_mlibody, f_mliout); + Dump(f_mlitail, f_mliout); + Close(f_mliout); + Delete(f_mliout); + + return SWIG_OK; + } + + /* Produce an error for the given type */ + void throw_unhandled_ocaml_type_error(SwigType *d, const char *types) { + Swig_warning(WARN_TYPEMAP_UNDEF, input_file, line_number, "Unable to handle type %s (%s).\n", SwigType_str(d, 0), types); + } + + /* Return true iff T is a pointer type */ + int + is_a_pointer(SwigType *t) { + return SwigType_ispointer(SwigType_typedef_resolve_all(t)); + } + + /* + * Delete one reference from a given type. + */ + + void oc_SwigType_del_reference(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + Delete(SwigType_pop(t)); + c = Char(t); + } + if (strncmp(c, "r.", 2)) { + printf("Fatal error. SwigType_del_pointer applied to non-pointer.\n"); + abort(); + } + Replace(t, "r.", "", DOH_REPLACE_ANY | DOH_REPLACE_FIRST); + } + + void oc_SwigType_del_array(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + Delete(SwigType_pop(t)); + c = Char(t); + } + if (strncmp(c, "a(", 2) == 0) { + Delete(SwigType_pop(t)); + } + } + + /* + * Return true iff T is a reference type + */ + + int + is_a_reference(SwigType *t) { + return SwigType_isreference(SwigType_typedef_resolve_all(t)); + } + + int + is_an_array(SwigType *t) { + return SwigType_isarray(SwigType_typedef_resolve_all(t)); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * Create a function declaration and register it with the interpreter. + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + char *iname = GetChar(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + String *return_type_normalized = normalizeTemplatedClassName(d); + ParmList *l = Getattr(n, "parms"); + int director_method = 0; + Parm *p; + + Wrapper *f = NewWrapper(); + String *proc_name = NewString(""); + String *source = NewString(""); + String *target = NewString(""); + String *arg = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *build = NewString(""); + String *tm; + int argout_set = 0; + int i = 0; + int numargs; + int numreq; + int newobj = GetFlag(n, "feature:new"); + String *nodeType = Getattr(n, "nodeType"); + int destructor = (!Cmp(nodeType, "destructor")); + String *overname = 0; + bool isOverloaded = Getattr(n, "sym:overloaded") ? true : false; + + // Make a wrapper name for this + String *wname = Swig_name_wrapper(iname); + if (isOverloaded) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + DelWrapper(f); + return SWIG_ERROR; + } + } + if (overname) { + Append(wname, overname); + } + /* Do this to disambiguate functions emitted from different modules */ + Append(wname, module); + + Setattr(n, "wrap:name", wname); + + // Build the name for Scheme. + Printv(proc_name, "_", iname, NIL); + String *mangled_name = mangleNameForCaml(proc_name); + + if (classmode && in_constructor) { // Emit constructor for object + String *mangled_name_nounder = NewString((char *) (Char(mangled_name)) + 1); + Printf(f_class_ctors_end, "let %s clst = _%s clst\n", mangled_name_nounder, mangled_name_nounder); + Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name_nounder); + Delete(mangled_name_nounder); + } else if (classmode && in_destructor) { + Printf(f_class_ctors, " \"~\", %s ;\n", mangled_name); + } else if (classmode && !in_constructor && !in_destructor && !static_member_function) { + String *opname = Copy(Getattr(n, "memberfunctionHandler:sym:name")); + + Replaceall(opname, "operator ", ""); + + if (strstr(Char(mangled_name), "__get__")) { + String *set_name = Copy(mangled_name); + if (!GetFlag(n, "feature:immutable")) { + Replaceall(set_name, "__get__", "__set__"); + Printf(f_class_ctors, " \"%s\", (fun args -> " "if args = (C_list [ raw_ptr ]) then %s args else %s args) ;\n", opname, mangled_name, set_name); + Delete(set_name); + } else { + Printf(f_class_ctors, " \"%s\", (fun args -> " "if args = (C_list [ raw_ptr ]) then %s args else C_void) ;\n", opname, mangled_name); + } + } else if (strstr(Char(mangled_name), "__set__")) { + ; /* Nothing ... handled by the case above */ + } else { + Printf(f_class_ctors, " \"%s\", %s ;\n", opname, mangled_name); + } + + Delete(opname); + } + + if (classmode && in_constructor) { + Setattr(seen_constructors, mangled_name, "true"); + } + // writing the function wrapper function + Printv(f->def, "SWIGEXT CAML_VALUE ", wname, " (", NIL); + Printv(f->def, "CAML_VALUE args", NIL); + Printv(f->def, ")\n{", NIL); + + /* Define the scheme name in C. This define is used by several + macros. */ + //Printv(f->def, "#define FUNC_NAME \"", mangled_name, "\"", NIL); + + // adds local variables + Wrapper_add_local(f, "args", "CAMLparam1(args)"); + Wrapper_add_local(f, "ret", "SWIG_CAMLlocal2(swig_result,rv)"); + Wrapper_add_local(f, "_v", "int _v = 0"); + if (isOverloaded) { + Wrapper_add_local(f, "i", "int i"); + Wrapper_add_local(f, "argc", "int argc = caml_list_length(args)"); + Wrapper_add_local(f, "argv", "CAML_VALUE *argv"); + + Printv(f->code, + "argv = (CAML_VALUE *)malloc( argc * sizeof( CAML_VALUE ) );\n" + "for( i = 0; i < argc; i++ ) {\n" " argv[i] = caml_list_nth(args,i);\n" "}\n", NIL); + } + d = SwigType_typedef_qualified(d); + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + numargs = emit_num_arguments(l); + numreq = emit_num_required(l); + + Printf(f->code, "swig_result = Val_unit;\n"); + + // Now write code to extract the parameters (this is super ugly) + + for (i = 0, p = l; i < numargs; i++) { + /* Skip ignored arguments */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + pt = SwigType_typedef_qualified(pt); + + // Produce names of source and target + Clear(source); + Clear(target); + Clear(arg); + Printf(source, "caml_list_nth(args,%d)", i); + Printf(target, "%s", ln); + Printv(arg, Getattr(p, "name"), NIL); + + if (i >= numreq) { + Printf(f->code, "if (caml_list_length(args) > %d) {\n", i); + } + // Handle parameter types. + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", target); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:in:next"); + } else { + // no typemap found + // check if typedef and resolve + throw_unhandled_ocaml_type_error(pt, "in"); + p = nextSibling(p); + } + if (i >= numreq) { + Printf(f->code, "}\n"); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + // Pass output arguments back to the caller. + + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* Deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* Deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Replaceall(tm, "$ntype", normalizeTemplatedClassName(Getattr(p, "type"))); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + argout_set = 1; + } else { + p = nextSibling(p); + } + } + + // Free up any memory allocated for the arguments. + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* if the object is a director, and the method call originated from its + * underlying python object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in python. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Append(f->code, "upcall = (director);\n"); + } + + // Now write code to make the function call + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$source", "swig_result"); + Replaceall(tm, "$target", "rv"); + Replaceall(tm, "$result", "rv"); + Replaceall(tm, "$ntype", return_type_normalized); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_ocaml_type_error(d, "out"); + } + emit_return_variable(n, d, f); + + // Dump the argument output code + Printv(f->code, Char(outarg), NIL); + + // Dump the argument cleanup code + Printv(f->code, Char(cleanup), NIL); + + // Look for any remaining cleanup + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "swig_result"); + Printv(f->code, tm, "\n", NIL); + } + } + // Free any memory allocated by the function being wrapped.. + + if ((tm = Swig_typemap_lookup("swig_result", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + } + // Wrap things up (in a manner of speaking) + + Printv(f->code, tab4, "swig_result = caml_list_append(swig_result,rv);\n", NIL); + if (isOverloaded) + Printv(f->code, "free(argv);\n", NIL); + Printv(f->code, tab4, "CAMLreturn(swig_result);\n", NIL); + Printv(f->code, "}\n", NIL); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, f_wrappers); + + if (isOverloaded) { + if (!Getattr(n, "sym:nextSibling")) { + int maxargs; + Wrapper *df = NewWrapper(); + String *dispatch = Swig_overload_dispatch(n, + "free(argv);\n" "CAMLreturn(%s(args));\n", + &maxargs); + + Wrapper_add_local(df, "_v", "int _v = 0"); + Wrapper_add_local(df, "argv", "CAML_VALUE *argv"); + + /* Undifferentiate name .. this is the dispatch function */ + wname = Swig_name_wrapper(iname); + /* Do this to disambiguate functions emitted from different + * modules */ + Append(wname, module); + + Printv(df->def, + "SWIGEXT CAML_VALUE ", wname, "(CAML_VALUE args) {\n" " CAMLparam1(args);\n" " int i;\n" " int argc = caml_list_length(args);\n", NIL); + Printv(df->code, + "argv = (CAML_VALUE *)malloc( argc * sizeof( CAML_VALUE ) );\n" + "for( i = 0; i < argc; i++ ) {\n" " argv[i] = caml_list_nth(args,i);\n" "}\n", NIL); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "failwith(\"No matching function for overloaded '%s'\");\n", iname); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + + DelWrapper(df); + Delete(dispatch); + } + } + + Printf(f_mlbody, + "external %s_f : c_obj list -> c_obj list = \"%s\" ;;\n" + "let %s arg = match %s_f (fnhelper arg) with\n" + " [] -> C_void\n" + "| [x] -> (if %s then Gc.finalise \n" + " (fun x -> ignore ((invoke x) \"~\" C_void)) x) ; x\n" + "| lst -> C_list lst ;;\n", mangled_name, wname, mangled_name, mangled_name, newobj ? "true" : "false"); + + if (!classmode || in_constructor || in_destructor || static_member_function) + Printf(f_mlibody, "val %s : c_obj -> c_obj\n", mangled_name); + + Delete(proc_name); + Delete(source); + Delete(target); + Delete(arg); + Delete(outarg); + Delete(cleanup); + Delete(build); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * + * Create a link to a C variable. + * This creates a single function _wrap_swig_var_varname(). + * This function takes a single optional argument. If supplied, it means + * we are setting this variable to some value. If omitted, it means we are + * simply evaluating this variable. In the set case we return C_void. + * + * symname is the name of the variable with respect to C. This + * may need to differ from the original name in the case of enums. + * enumvname is the name of the variable with respect to ocaml. This + * will vary if the variable has been renamed. + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + char *name = GetChar(n, "feature:symname"); + String *iname = Getattr(n, "feature:enumvname"); + String *mname = mangleNameForCaml(iname); + SwigType *t = Getattr(n, "type"); + + String *proc_name = NewString(""); + String *tm; + String *tm2 = NewString("");; + String *argnum = NewString("0"); + String *arg = NewString("SWIG_Field(args,0)"); + Wrapper *f; + + if (!name) { + name = GetChar(n, "name"); + } + + if (!iname) { + iname = Getattr(n, "sym:name"); + mname = mangleNameForCaml(NewString(iname)); + } + + if (!iname || !addSymbol(iname, n)) + return SWIG_ERROR; + + f = NewWrapper(); + + // evaluation function names + String *var_name = Swig_name_wrapper(iname); + + // Build the name for scheme. + Printv(proc_name, iname, NIL); + Setattr(n, "wrap:name", proc_name); + + Printf(f->def, "SWIGEXT CAML_VALUE %s(CAML_VALUE args) {\n", var_name); + // Printv(f->def, "#define FUNC_NAME \"", proc_name, "\"", NIL); + + Wrapper_add_local(f, "swig_result", "CAML_VALUE swig_result"); + + if (!GetFlag(n, "feature:immutable")) { + /* Check for a setting of the variable value */ + Printf(f->code, "if (args != Val_int(0)) {\n"); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "args"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "args"); + /* Printv(f->code, tm, "\n",NIL); */ + emit_action_code(n, f->code, tm); + } else if ((tm = Swig_typemap_lookup("in", n, name, 0))) { + Replaceall(tm, "$source", "args"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "args"); + Printv(f->code, tm, "\n", NIL); + } else { + throw_unhandled_ocaml_type_error(t, "varin/in"); + } + Printf(f->code, "}\n"); + } + // Now return the value of the variable (regardless + // of evaluating or setting) + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "swig_result"); + Replaceall(tm, "$result", "swig_result"); + emit_action_code(n, f->code, tm); + } else if ((tm = Swig_typemap_lookup("out", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "swig_result"); + Replaceall(tm, "$result", "swig_result"); + Printf(f->code, "%s\n", tm); + } else { + throw_unhandled_ocaml_type_error(t, "varout/out"); + } + + Printf(f->code, "\nreturn swig_result;\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, f_wrappers); + + // Now add symbol to the Ocaml interpreter + + if (GetFlag(n, "feature:immutable")) { + Printf(f_mlbody, "external _%s : c_obj -> Swig.c_obj = \"%s\" \n", mname, var_name); + Printf(f_mlibody, "val _%s : c_obj -> Swig.c_obj\n", iname); + if (const_enum) { + Printf(f_enum_to_int, " | `%s -> _%s C_void\n", mname, mname); + Printf(f_int_to_enum, " if y = (get_int (_%s C_void)) then `%s else\n", mname, mname); + } + } else { + Printf(f_mlbody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name); + Printf(f_mlibody, "external _%s : c_obj -> c_obj = \"%s\"\n", mname, var_name); + } + + Delete(var_name); + Delete(proc_name); + Delete(argnum); + Delete(arg); + Delete(tm2); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler -- + * Overridden to set static_member_function + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + int rv; + static_member_function = 1; + rv = Language::staticmemberfunctionHandler(n); + static_member_function = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * + * The one trick here is that we have to make sure we rename the + * constant to something useful that doesn't collide with the + * original if any exists. + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "feature:symname"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + String *qvalue = Getattr(n, "qualified:value"); + String *rvalue = NewString(""); + String *temp = 0; + + if (qvalue) + value = qvalue; + + if (!name) { + name = mangleNameForCaml(Getattr(n, "name")); + Insert(name, 0, "_swig_wrap_"); + Setattr(n, "feature:symname", name); + } + // See if there's a typemap + + Printv(rvalue, value, NIL); + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 1)) { + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "\"", temp, "\"", NIL); + Delete(temp); + } + if ((SwigType_type(type) == T_CHAR) && (is_a_pointer(type) == 0)) { + temp = Copy(rvalue); + Clear(rvalue); + Printv(rvalue, "'", temp, "'", NIL); + Delete(temp); + } + // Create variable and assign it a value + + Printf(f_header, "static %s = ", SwigType_lstr(type, name)); + if ((SwigType_type(type) == T_STRING)) { + Printf(f_header, "\"%s\";\n", value); + } else if (SwigType_type(type) == T_CHAR) { + Printf(f_header, "\'%s\';\n", value); + } else { + Printf(f_header, "%s;\n", value); + } + + SetFlag(n, "feature:immutable"); + variableWrapper(n); + return SWIG_OK; + } + + int constructorHandler(Node *n) { + int ret; + + in_constructor = 1; + ret = Language::constructorHandler(n); + in_constructor = 0; + + return ret; + } + + /* destructorHandler: + * Turn on destructor flag to inform decisions in functionWrapper + */ + + int destructorHandler(Node *n) { + int ret; + + in_destructor = 1; + ret = Language::destructorHandler(n); + in_destructor = 0; + + return ret; + } + + /* copyconstructorHandler: + * Turn on constructor and copyconstructor flags for functionWrapper + */ + + int copyconstructorHandler(Node *n) { + int ret; + + in_copyconst = 1; + in_constructor = 1; + ret = Language::copyconstructorHandler(n); + in_constructor = 0; + in_copyconst = 0; + + return ret; + } + + /** + * A simple, somewhat general purpose function for writing to multiple + * streams from a source template. This allows the user to define the + * class definition in ways different from the one I have here if they + * want to. It will also make the class definition system easier to + * fiddle with when I want to change methods, etc. + */ + + void Multiwrite(String *s) { + char *find_marker = strstr(Char(s), "(*Stream:"); + while (find_marker) { + char *next = strstr(find_marker, "*)"); + find_marker += strlen("(*Stream:"); + + if (next) { + int num_chars = next - find_marker; + String *stream_name = NewString(find_marker); + Delslice(stream_name, num_chars, Len(stream_name)); + File *fout = Swig_filebyname(stream_name); + if (fout) { + next += strlen("*)"); + char *following = strstr(next, "(*Stream:"); + find_marker = following; + if (!following) + following = next + strlen(next); + String *chunk = NewString(next); + Delslice(chunk, following - next, Len(chunk)); + Printv(fout, chunk, NIL); + } + } + } + } + + bool isSimpleType(String *name) { + char *ch = Char(name); + + return !(strchr(ch, '(') || strchr(ch, '<') || strchr(ch, ')') || strchr(ch, '>')); + } + + /* We accept all chars in identifiers because we use strings to index + * them. */ + int validIdentifier(String *name) { + return Len(name) > 0 ? 1 : 0; + } + + /* classHandler + * + * Create a "class" definition for ocaml. I thought quite a bit about + * how I should do this part of it, and arrived here, using a function + * invocation to select a method, and dispatch. This can obviously be + * done better, but I can't see how, given that I want to support + * overloaded methods, out parameters, and operators. + * + * I needed a system that would do this: + * + * a Be able to call these methods: + * int foo( int x ); + * float foo( int x, int &out ); + * + * b Be typeable, even in the presence of mutually dependent classes. + * + * c Support some form of operator invocation. + * + * (c) I chose strings for the method names so that "+=" would be a + * valid method name, and the somewhat natural << (invoke x) "+=" y >> + * would work. + * + * (a) (b) Since the c_obj type exists, it's easy to return C_int in one + * case and C_list [ C_float ; C_int ] in the other. This makes tricky + * problems with out parameters disappear; they're simply appended to the + * return list. + * + * (b) Since every item that comes from C++ is the same type, there is no + * problem with the following: + * + * class Foo; + * class Bar { Foo *toFoo(); } + * class Foo { Bar *toBar(); } + * + * Since the Objective caml types of Foo and Bar are the same. Now that + * I correctly incorporate SWIG's typechecking, this isn't a big deal. + * + * The class is in the form of a function returning a c_obj. The c_obj + * is a C_obj containing a function which invokes a method on the + * underlying object given its type. + * + * The name emitted here is normalized before being sent to + * Callback.register, because we need this string to look up properly + * when the typemap passes the descriptor string. I've been considering + * some, possibly more forgiving method that would do some transformations + * on the $descriptor in order to find a potential match. This is for + * later. + * + * Important things to note: + * + * We rely on exception handling (BadMethodName) in order to call an + * ancestor. This can be improved. + * + * The method used to get :classof could be improved to look at the type + * info that the base pointer contains. It's really an error to have a + * SWIG-generated object that does not contain type info, since the + * existence of the object means that SWIG knows the type. + * + * :parents could use :classof to tell what class it is and make a better + * decision. This could be nice, (i.e. provide a run-time graph of C++ + * classes represented);. + * + * I can't think of a more elegant way of converting a C_obj fun to a + * pointer than "operator &"... + * + * Added a 'sizeof' that will allow you to do the expected thing. + * This should help users to fill buffer structs and the like (as is + * typical in windows-styled code). It's only enabled if you give + * %feature(sizeof) and then, only for simple types. + * + * Overall, carrying the list of methods and base classes has worked well. + * It allows me to give the Ocaml user introspection over their objects. + */ + + int classHandler(Node *n) { + String *name = Getattr(n, "name"); + + if (!name) + return SWIG_OK; + + String *mangled_sym_name = mangleNameForCaml(name); + String *this_class_def = NewString(f_classtemplate); + String *name_normalized = normalizeTemplatedClassName(name); + String *old_class_ctors = f_class_ctors; + String *base_classes = NewString(""); + f_class_ctors = NewString(""); + bool sizeof_feature = generate_sizeof && isSimpleType(name); + + + classname = mangled_sym_name; + classmode = true; + int rv = Language::classHandler(n); + classmode = false; + + if (sizeof_feature) { + Printf(f_wrappers, + "SWIGEXT CAML_VALUE _wrap_%s_sizeof( CAML_VALUE args ) {\n" + " CAMLparam1(args);\n" " CAMLreturn(Val_int(sizeof(%s)));\n" "}\n", mangled_sym_name, name_normalized); + + Printf(f_mlbody, "external __%s_sizeof : unit -> int = " "\"_wrap_%s_sizeof\"\n", classname, mangled_sym_name); + } + + + /* Insert sizeof operator for concrete classes */ + if (sizeof_feature) { + Printv(f_class_ctors, "\"sizeof\" , (fun args -> C_int (__", classname, "_sizeof ())) ;\n", NIL); + } + /* Handle up-casts in a nice way */ + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if (bname) { + String *base_create = NewString(""); + Printv(base_create, "(create_class \"", bname, "\")", NIL); + Printv(f_class_ctors, " \"::", bname, "\", (fun args -> ", base_create, " args) ;\n", NIL); + Printv(base_classes, base_create, " ;\n", NIL); + } + b = Next(b); + } + } + + Replaceall(this_class_def, "$classname", classname); + Replaceall(this_class_def, "$normalized", name_normalized); + Replaceall(this_class_def, "$realname", name); + Replaceall(this_class_def, "$baselist", base_classes); + Replaceall(this_class_def, "$classbody", f_class_ctors); + + Delete(f_class_ctors); + f_class_ctors = old_class_ctors; + + // Actually write out the class definition + + Multiwrite(this_class_def); + + Setattr(n, "ocaml:ctor", classname); + + return rv; + } + + String *normalizeTemplatedClassName(String *name) { + String *name_normalized = SwigType_typedef_resolve_all(name); + bool took_action; + + do { + took_action = false; + + if (is_a_pointer(name_normalized)) { + SwigType_del_pointer(name_normalized); + took_action = true; + } + + if (is_a_reference(name_normalized)) { + oc_SwigType_del_reference(name_normalized); + took_action = true; + } + + if (is_an_array(name_normalized)) { + oc_SwigType_del_array(name_normalized); + took_action = true; + } + } while (took_action); + + return SwigType_str(name_normalized, 0); + } + + /* + * Produce the symbol name that ocaml will use when referring to the + * target item. I wonder if there's a better way to do this: + * + * I shudder to think about doing it with a hash lookup, but that would + * make a couple of things easier: + */ + + String *mangleNameForCaml(String *s) { + String *out = Copy(s); + Replaceall(out, " ", "_xx"); + Replaceall(out, "::", "_xx"); + Replaceall(out, ",", "_x"); + Replaceall(out, "+", "_xx_plus"); + Replaceall(out, "-", "_xx_minus"); + Replaceall(out, "<", "_xx_ldbrace"); + Replaceall(out, ">", "_xx_rdbrace"); + Replaceall(out, "!", "_xx_not"); + Replaceall(out, "%", "_xx_mod"); + Replaceall(out, "^", "_xx_xor"); + Replaceall(out, "*", "_xx_star"); + Replaceall(out, "&", "_xx_amp"); + Replaceall(out, "|", "_xx_or"); + Replaceall(out, "(", "_xx_lparen"); + Replaceall(out, ")", "_xx_rparen"); + Replaceall(out, "[", "_xx_lbrace"); + Replaceall(out, "]", "_xx_rbrace"); + Replaceall(out, "~", "_xx_bnot"); + Replaceall(out, "=", "_xx_equals"); + Replaceall(out, "/", "_xx_slash"); + Replaceall(out, ".", "_xx_dot"); + return out; + } + + String *fully_qualify_enum_name(Node *n, String *name) { + Node *parent = 0; + String *qualification = NewString(""); + String *fully_qualified_name = NewString(""); + String *parent_type = 0; + String *normalized_name; + + parent = parentNode(n); + while (parent) { + parent_type = nodeType(parent); + if (Getattr(parent, "name")) { + String *parent_copy = NewStringf("%s::", Getattr(parent, "name")); + if (!Cmp(parent_type, "class") || !Cmp(parent_type, "namespace")) + Insert(qualification, 0, parent_copy); + Delete(parent_copy); + } + if (!Cmp(parent_type, "class")) + break; + parent = parentNode(parent); + } + + Printf(fully_qualified_name, "%s%s", qualification, name); + + normalized_name = normalizeTemplatedClassName(fully_qualified_name); + if (!strncmp(Char(normalized_name), "enum ", 5)) { + Insert(normalized_name, 5, qualification); + } + + return normalized_name; + } + + /* Benedikt Grundmann inspired --> Enum wrap styles */ + + int enumvalueDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *qvalue = 0; + + if (name_qualifier) { + qvalue = Copy(name_qualifier); + Printv(qvalue, name, NIL); + } + + if (const_enum && name && !Getattr(seen_enumvalues, name)) { + Setattr(seen_enumvalues, name, "true"); + SetFlag(n, "feature:immutable"); + Setattr(n, "feature:enumvalue", "1"); // this does not appear to be used + + if (qvalue) + Setattr(n, "qualified:value", qvalue); + + String *evname = SwigType_manglestr(qvalue); + Insert(evname, 0, "SWIG_ENUM_"); + + Setattr(n, "feature:enumvname", name); + Setattr(n, "feature:symname", evname); + Delete(evname); + Printf(f_enumtypes_value, "| `%s\n", name); + + return Language::enumvalueDeclaration(n); + } else + return SWIG_OK; + } + + /* ------------------------------------------------------------------- + * This function is a bit uglier than it deserves. + * + * I used to direct lookup the name of the enum. Now that certain fixes + * have been made in other places, the names of enums are now fully + * qualified, which is a good thing, overall, but requires me to do + * some legwork. + * + * The other thing that uglifies this function is the varying way that + * typedef enum and enum are handled. I need to produce consistent names, + * which means looking up and registering by typedef and enum name. */ + int enumDeclaration(Node *n) { + String *name = Getattr(n, "name"); + if (name) { + String *oname = NewString(name); + /* name is now fully qualified */ + String *fully_qualified_name = NewString(name); + bool seen_enum = false; + if (name_qualifier) + Delete(name_qualifier); + char *strip_position; + name_qualifier = fully_qualify_enum_name(n, NewString("")); + + strip_position = strstr(Char(oname), "::"); + + while (strip_position) { + strip_position += 2; + oname = NewString(strip_position); + strip_position = strstr(Char(oname), "::"); + } + + seen_enum = (Getattr(seen_enums, fully_qualified_name) ? true : false); + + if (!seen_enum) { + const_enum = true; + Printf(f_enum_to_int, "| `%s -> (match y with\n", oname); + Printf(f_int_to_enum, "| `%s -> C_enum (\n", oname); + /* * * * A note about enum name resolution * * * * + * This code should now work, but I think we can do a bit better. + * The problem I'm having is that swig isn't very precise about + * typedef name resolution. My opinion is that SwigType_typedef + * resolve_all should *always* return the enum tag if one exists, + * rather than the admittedly friendlier enclosing typedef. + * + * This would make one of the cases below unnecessary. + * * * */ + Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", fully_qualified_name, oname); + if (!strncmp(Char(fully_qualified_name), "enum ", 5)) { + String *fq_noenum = NewString(Char(fully_qualified_name) + 5); + Printf(f_mlbody, + "let _ = Callback.register \"%s_marker\" (`%s)\n" "let _ = Callback.register \"%s_marker\" (`%s)\n", fq_noenum, oname, fq_noenum, name); + } + + Printf(f_enumtypes_type, "| `%s\n", oname); + Insert(fully_qualified_name, 0, "enum "); + Setattr(seen_enums, fully_qualified_name, n); + } + } + + int ret = Language::enumDeclaration(n); + + if (const_enum) { + Printf(f_int_to_enum, "`Int y)\n"); + Printf(f_enum_to_int, "| `Int x -> Swig.C_int x\n" "| _ -> raise (LabelNotFromThisEnum v))\n"); + } + + const_enum = false; + + return ret; + } + + /* ---------------------------------------------------------------------------- + * BEGIN C++ Director Class modifications + * ------------------------------------------------------------------------- */ + + /* + * Modified polymorphism code for Ocaml language module. + * Original: + * C++/Python polymorphism demo code, copyright (C) 2002 Mark Rose + * <mrose@stm.lbl.gov> + * + * TODO + * + * Move some boilerplate code generation to Swig_...() functions. + * + */ + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *storage; + String *value; + String *decl; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_type; + int status = SWIG_OK; + int idx; + bool pure_virtual = false; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + storage = Getattr(n, "storage"); + value = Getattr(n, "value"); + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + w = NewWrapper(); + declaration = NewString(""); + Wrapper_add_local(w, "swig_result", "CAMLparam0();\n" "SWIG_CAMLlocal2(swig_result,args)"); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s {", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s;", target); + Delete(target); + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($result). + */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), NIL); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> Ocaml) */ + String *arglist = NewString(""); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + int num_arguments = emit_num_arguments(l); + int i; + char source[256]; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + for (i = 0, idx = 0, p = l; i < num_arguments; i++) { + + while (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + Putc(',', arglist); + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + Printv(wrap_args, tm, "\n", NIL); + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + /* special handling for pointers to other C++ director classes. + * ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. in other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. we avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, ptype); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(ptype) + 2); + /* name as pointer */ + String *ppname = Copy(pname); + if (SwigType_isreference(ptype)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Python doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", pname); + String *nonconst_i = NewStringf("= const_cast<%s>(%s)", SwigType_lstr(ptype, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(ptype, pname), + SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(ptype); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "CAML_VALUE", source, "= Val_unit", NIL); + Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Printf(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "}\n"); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "CAML_VALUE", source, "= Val_unit", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + Printv(w->code, "swig_result = Val_unit;\n", 0); + Printf(w->code, "args = Val_unit;\n"); + + /* wrap complex arguments to values */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Python object */ + Printv(w->code, + "swig_result = caml_swig_alloc(1,C_list);\n" "SWIG_Store_field(swig_result,0,args);\n" "args = swig_result;\n" "swig_result = Val_unit;\n", 0); + Printf(w->code, "swig_result = " "callback3(*caml_named_value(\"swig_runmethod\")," "swig_get_self(),copy_string(\"%s\"),args);\n", Getattr(n, "name")); + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Printf(w->code, "if (result == NULL) {\n"); + Printf(w->code, " CAML_VALUE error = *caml_named_value(\"director_except\");\n"); + Replaceall(tm, "$error", "error"); + Printv(w->code, Str(tm), "\n", NIL); + Printf(w->code, "}\n"); + } + + /* + * Python method may return a simple object, or a tuple. + * for in/out aruments, we have to extract the appropriate values from the + * argument list, then marshal everything back to C/C++ (return value and + * output arguments). + */ + + /* marshal return value and other outputs (if any) from value to C/C++ + * type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + idx = 0; + + /* this seems really silly. the node's type excludes + * qualifier/pointer/reference markers, which have to be retrieved + * from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and + * out the correct type. it's not just me, similar silliness also + * occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "c_result", w); + Setattr(n, "type", type); + if (tm != 0) { + Replaceall(tm, "$input", "swig_result"); + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + Replaceall(tm, "$input", "swig_result"); + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(arglist); + Delete(cleanup); + Delete(outarg); + } + + /* any existing helper functions to handle this? */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + /* A little explanation: + * The director_enum test case makes a method whose return type + * is an enum type. return_type here is "int". gcc complains + * about an implicit enum conversion, and although i don't strictly + * agree with it, I'm working on fixing the error: + * + * Below is what I came up with. It's not great but it should + * always essentially work. + */ + if (!SwigType_isreference(return_type)) { + Printf(w->code, "CAMLreturn_type((%s)c_result);\n", SwigType_lstr(return_type, "")); + } else { + Printf(w->code, "CAMLreturn_type(*c_result);\n"); + } + } + } + + Printf(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit the director method */ + if (status == SWIG_OK) { + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(return_type); + Delete(pclassname); + DelWrapper(w); + return status; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p, *q; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("CAML_VALUE"); + p = NewParm(type, NewString("self")); + q = Copy(p); + set_nextSibling(q, superparms); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Setattr(n, "parms", q); + Language::classDirectorConstructor(n); + + Delete(sub); + Delete(classname); + Delete(supername); + //Delete(parms); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname; + classname = Swig_class_name(n); + + /* insert self parameter */ + Parm *p, *q; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("CAML_VALUE"); + p = NewParm(type, NewString("self")); + q = Copy(p); + set_nextSibling(p, parms); + parms = p; + + { + Wrapper *w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(CAML_VALUE self) : Swig::Director(self) { }", classname, classname); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " SwigDirector_%s(CAML_VALUE self);\n", classname); + Delete(classname); + Setattr(n, "parms", q); + return Language::classDirectorDefaultConstructor(n); + } + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n" "%s\n" "public:\n", declaration); + Delete(declaration); + return Language::classDirectorInit(n); + } + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + /* --------------------------------------------------------------------- + * typedefHandler + * + * This is here in order to maintain the correct association between + * typedef names and enum names. + * + * Since I implement enums as polymorphic variant tags, I need to call + * back into ocaml to evaluate them. This requires a string that can + * be generated in the typemaps, and also at SWIG time to be the same + * string. The problem that arises is that SWIG variously generates + * enum e_name_tag + * e_name_tag + * e_typedef_name + * for + * typedef enum e_name_tag { ... } e_typedef_name; + * + * Since I need these strings to be consistent, I must maintain a correct + * association list between typedef and enum names. + * --------------------------------------------------------------------- */ + int typedefHandler(Node *n) { + String *type = Getattr(n, "type"); + Node *enum_node = type ? Getattr(seen_enums, type) : 0; + if (enum_node) { + String *name = Getattr(enum_node, "name"); + + Printf(f_mlbody, "let _ = Callback.register \"%s_marker\" (`%s)\n", Getattr(n, "name"), name); + + } + return SWIG_OK; + } + + String *runtimeCode() { + String *s = Swig_include_sys("ocaml.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'ocaml.swg'\n"); + s = NewString(""); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigocamlrun.h"); + } +}; + +/* ------------------------------------------------------------------------- + * swig_ocaml() - Instantiate module + * ------------------------------------------------------------------------- */ + +static Language *new_swig_ocaml() { + return new OCAML(); +} +extern "C" Language *swig_ocaml(void) { + return new_swig_ocaml(); +} diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx new file mode 100644 index 0000000..aeb72f7 --- /dev/null +++ b/Source/Modules/octave.cxx @@ -0,0 +1,1425 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * octave.cxx + * + * Octave language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_octave_cxx[] = "$Id$"; + +#include "swigmod.h" + +static const char *usage = (char *) "\ +Octave Options (available with -octave)\n\ + -api <N> - Generate code that assumes Octave API N [default: 37]\n\ + \n"; + + +class OCTAVE:public Language { +private: + File *f_begin; + File *f_runtime; + File *f_header; + File *f_doc; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + File *f_directors; + File *f_directors_h; + String *s_global_tab; + String *s_members_tab; + String *class_name; + + int have_constructor; + int have_destructor; + String *constructor_name; + + int api_version; + + Hash *docs; + +public: + OCTAVE():f_begin(0), f_runtime(0), f_header(0), f_doc(0), f_wrappers(0), + f_init(0), f_initbeforefunc(0), f_directors(0), f_directors_h(0), + s_global_tab(0), s_members_tab(0), class_name(0) { + /* Add code to manage protected constructors and directors */ + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " error(\"accessing abstract class or protected constructor\"); \n", " SWIG_fail;\n", "}\n", NIL); + + enable_cplus_runtime_mode(); + allow_overloading(); + director_multiple_inheritance = 1; + director_language = 1; + docs = NewHash(); + api_version = 0; + } + + virtual void main(int argc, char *argv[]) { + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stderr); + } else if (strcmp(argv[i], "-api") == 0) { + if (argv[i + 1]) { + api_version = atoi(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } + } + } + + SWIG_library_directory("octave"); + Preprocessor_define("SWIGOCTAVE 1", 0); + SWIG_config_file("octave.swg"); + SWIG_typemap_lang("octave"); + allow_overloading(); + } + + virtual int top(Node *n) { + { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + int dirprot = 0; + if (Getattr(options, "dirprot")) { + dirprot = 1; + } + if (Getattr(options, "nodirprot")) { + dirprot = 0; + } + if (Getattr(options, "directors")) { + allow_directors(); + if (dirprot) + allow_dirprot(); + } + } + } + } + + String *module = Getattr(n, "name"); + String *outfile = Getattr(n, "outfile"); + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_header = NewString(""); + f_doc = NewString(""); + f_wrappers = NewString(""); + f_init = NewString(""); + f_initbeforefunc = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + s_global_tab = NewString(""); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("doc", f_doc); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGOCTAVE\n"); + Printf(f_runtime, "#define SWIG_name_d \"%s\"\n", module); + Printf(f_runtime, "#define SWIG_name %s\n", module); + Printf(f_runtime, "#define OCTAVE_API_VERSION_OPTION %i\n", api_version); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + Swig_banner(f_directors_h); + if (dirprot_mode()) { + // Printf(f_directors_h, "#include <map>\n"); + // Printf(f_directors_h, "#include <string>\n\n"); + } + } + + Printf(f_runtime, "\n"); + + Printf(s_global_tab, "\nstatic const struct swig_octave_member swig_globals[] = {\n"); + Printf(f_init, "static void SWIG_init_user(octave_swig_type* module_ns)\n{\n"); + + if (!CPlusPlus) + Printf(f_header,"extern \"C\" {\n"); + + Language::top(n); + + if (!CPlusPlus) + Printf(f_header,"}\n"); + + if (Len(docs)) + emit_doc_texinfo(); + + if (directorsEnabled()) + Swig_insert_file("director.swg", f_runtime); + + Printf(f_init, "}\n"); + Printf(s_global_tab, "{0,0,0,0,0}\n};\n"); + + Printv(f_wrappers, s_global_tab, NIL); + SwigType_emit_type_table(f_runtime, f_wrappers); + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_doc, f_begin); + if (directorsEnabled()) { + Dump(f_directors_h, f_begin); + Dump(f_directors, f_begin); + } + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(s_global_tab); + Delete(f_initbeforefunc); + Delete(f_init); + Delete(f_wrappers); + Delete(f_doc); + Delete(f_header); + Delete(f_directors); + Delete(f_directors_h); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + String *texinfo_escape(String *_s) { + const char* s=(const char*)Data(_s); + while (*s&&(*s=='\t'||*s=='\r'||*s=='\n'||*s==' ')) + ++s; + String *r = NewString(""); + for (int j=0;s[j];++j) { + if (s[j] == '\n') { + Append(r, "\\n\\\n"); + } else if (s[j] == '\r') { + Append(r, "\\r"); + } else if (s[j] == '\t') { + Append(r, "\\t"); + } else if (s[j] == '\\') { + Append(r, "\\\\"); + } else if (s[j] == '\'') { + Append(r, "\\\'"); + } else if (s[j] == '\"') { + Append(r, "\\\""); + } else + Putc(s[j], r); + } + return r; + } + void emit_doc_texinfo() { + for (Iterator it = First(docs); it.key; it = Next(it)) { + String *wrap_name = it.key; + + String *synopsis = Getattr(it.item, "synopsis"); + String *decl_info = Getattr(it.item, "decl_info"); + String *cdecl_info = Getattr(it.item, "cdecl_info"); + String *args_info = Getattr(it.item, "args_info"); + + String *doc_str = NewString(""); + Printv(doc_str, synopsis, decl_info, cdecl_info, args_info, NIL); + String *escaped_doc_str = texinfo_escape(doc_str); + + if (Len(doc_str)>0) { + Printf(f_doc,"const char* %s_texinfo = ",wrap_name); + Printf(f_doc,"\"-*- texinfo -*-\\n\\\n%s", escaped_doc_str); + if (Len(decl_info)) + Printf(f_doc,"\\n\\\n@end deftypefn"); + Printf(f_doc,"\";\n"); + } + + Delete(escaped_doc_str); + Delete(doc_str); + Delete(wrap_name); + } + Printf(f_doc,"\n"); + } + bool is_empty_doc_node(Node* n) { + if (!n) + return true; + String *synopsis = Getattr(n, "synopsis"); + String *decl_info = Getattr(n, "decl_info"); + String *cdecl_info = Getattr(n, "cdecl_info"); + String *args_info = Getattr(n, "args_info"); + return !Len(synopsis) && !Len(decl_info) && + !Len(cdecl_info) && !Len(args_info); + } + String *texinfo_name(Node* n) { + String *tname = NewString(""); + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(iname); + Node* d = Getattr(docs, wname); + + if (is_empty_doc_node(d)) + Printf(tname, "0"); + else + Printf(tname, "%s_texinfo", wname); + + return tname; + } + void process_autodoc(Node *n) { + String *iname = Getattr(n, "sym:name"); + String *name = Getattr(n, "name"); + String *wname = Swig_name_wrapper(iname); + String *str = Getattr(n, "feature:docstring"); + bool autodoc_enabled = !Cmp(Getattr(n, "feature:autodoc"), "1"); + Node* d = Getattr(docs, wname); + if (!d) { + d = NewHash(); + Setattr(d, "synopsis", NewString("")); + Setattr(d, "decl_info", NewString("")); + Setattr(d, "cdecl_info", NewString("")); + Setattr(d, "args_info", NewString("")); + Setattr(docs, wname, d); + } + + String *synopsis = Getattr(d, "synopsis"); + String *decl_info = Getattr(d, "decl_info"); + // String *cdecl_info = Getattr(d, "cdecl_info"); + String *args_info = Getattr(d, "args_info"); + + // * couldn't we just emit the docs here? + + if (autodoc_enabled) { + String *decl_str = NewString(""); + String *args_str = NewString(""); + make_autodocParmList(n, decl_str, args_str); + Append(decl_info, "@deftypefn {Loadable Function} "); + + SwigType *type = Getattr(n, "type"); + if (type && Strcmp(type, "void")) { + type = SwigType_base(type); + Node *lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + Append(decl_info, "@var{retval} = "); + String *type_str = NewString(""); + Printf(type_str, "@var{retval} is of type %s. ", type); + Append(args_str, type_str); + Delete(type_str); + } + + Append(decl_info, name); + Append(decl_info, " ("); + Append(decl_info, decl_str); + Append(decl_info, ")\n"); + Append(args_info, args_str); + Delete(decl_str); + Delete(args_str); + } + + if (str && Len(str) > 0) { + // strip off {} if necessary + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + + // emit into synopsis section + Append(synopsis, str); + } + } + + virtual int importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname) + Printf(f_init, "feval(\"%s\",octave_value_list(),0);\n", modname); + return Language::importDirective(n); + } + + const char *get_implicitconv_flag(Node *n) { + int conv = 0; + if (n && GetFlag(n, "feature:implicitconv")) { + conv = 1; + } + return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0"; + } + + void make_autodocParmList(Node *n, String *decl_str, String *args_str) { + String *pdocs = Copy(Getattr(n, "feature:pdocs")); + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + Node *lookup; + + if (pdocs) + Append(pdocs, "\n"); + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + for (p = plist; p; p = pnext) { + String *name = 0; + String *type = 0; + String *value = 0; + String *ptype = 0; + String *pdoc = Getattr(p, "tmap:doc"); + if (pdoc) { + name = Getattr(p, "tmap:doc:name"); + type = Getattr(p, "tmap:doc:type"); + value = Getattr(p, "tmap:doc:value"); + ptype = Getattr(p, "tmap:doc:pytype"); + } + + name = name ? name : Getattr(p, "name"); + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + String *tex_name = NewString(""); + if (name) + Printf(tex_name, "@var{%s}", name); + else + Printf(tex_name, "@var{?}"); + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + } else { + pnext = nextSibling(p); + } + + if (Len(decl_str)) + Append(decl_str, ", "); + Append(decl_str, tex_name); + + if (value) { + if (Strcmp(value, "NULL") == 0) + value = NewString("nil"); + else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0) + value = NewString("true"); + else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0) + value = NewString("false"); + else { + lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(decl_str, " = %s", value); + } + + if (type) { + String *type_str = NewString(""); + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + Printf(type_str, "%s is of type %s. ", tex_name, type); + Append(args_str, type_str); + Delete(type_str); + } + + Delete(tex_name); + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + } + + virtual int functionWrapper(Node *n) { + Wrapper *f = NewWrapper(); + Parm *p; + String *tm; + int j; + + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + int destructor = (!Cmp(nodeType, "destructor")); + String *storage = Getattr(n, "storage"); + + bool overloaded = !!Getattr(n, "sym:overloaded"); + bool last_overload = overloaded && !Getattr(n, "sym:nextSibling"); + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(iname); + String *overname = Copy(wname); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + if (!overloaded && !addSymbol(iname, n)) + return SWIG_ERROR; + + if (overloaded) + Append(overname, Getattr(n, "sym:overname")); + + Printv(f->def, "static octave_value_list ", overname, " (const octave_value_list& args, int nargout) {", NIL); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + int varargs = emit_isvarargs(l); + char source[64]; + + Printf(f->code, "if (!SWIG_check_num_args(\"%s\",args.length(),%i,%i,%i)) " + "{\n SWIG_fail;\n }\n", iname, num_arguments, num_required, varargs); + + if (constructor && num_arguments == 1 && num_required == 1) { + if (Cmp(storage, "explicit") == 0) { + Node *parent = Swig_methodclass(n); + if (GetFlag(parent, "feature:implicitconv")) { + String *desc = NewStringf("SWIGTYPE%s", SwigType_manglestr(Getattr(n, "type"))); + Printf(f->code, "if (SWIG_CheckImplicit(%s)) SWIG_fail;\n", desc); + Delete(desc); + } + } + } + + for (j = 0, p = l; j < num_arguments; ++j) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + if (!tm || checkAttribute(p, "tmap:in:numinputs", "0")) { + p = nextSibling(p); + continue; + } + + sprintf(source, "args(%d)", j); + Setattr(p, "emit:input", source); + + Replaceall(tm, "$source", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Replaceall(tm, "$target", Getattr(p, "lname")); + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + if (Getattr(p, "tmap:in:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p, "hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + Replaceall(tm, "$implicitconv", convflag); + Setattr(p, "implicitconv", convflag); + } + + String *getargs = NewString(""); + if (j >= num_required) + Printf(getargs, "if (%d<args.length()) {\n%s\n}", j, tm); + else + Printv(getargs, tm, NIL); + Printv(f->code, getargs, "\n", NIL); + Delete(getargs); + + p = Getattr(p, "tmap:in:next"); + continue; + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + + // Check for trailing varargs + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + // Insert constraint checking code + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + // Insert cleanup code + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + if (Getattr(p, "tmap:freearg:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p, "hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + if (strcmp(convflag, "0") == 0) { + tm = 0; + } + } + if (tm && (Len(tm) != 0)) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + // Insert argument output code + String *outarg = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "_outp"); + Replaceall(tm, "$result", "_outp"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + int director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Append(f->code, "upcall = !!dynamic_cast<Swig::Director*>(arg1);\n"); + } + + Setattr(n, "wrap:name", overname); + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + Wrapper_add_local(f, "_out", "octave_value_list _out"); + Wrapper_add_local(f, "_outp", "octave_value_list *_outp=&_out"); + Wrapper_add_local(f, "_outv", "octave_value _outv"); + + // Return the function value + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "_outv"); + Replaceall(tm, "$result", "_outv"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s\n", tm); + Printf(f->code, "if (_outv.is_defined()) _outp = " "SWIG_Octave_AppendOutput(_outp, _outv);\n"); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), iname); + } + emit_return_variable(n, d, f); + + Printv(f->code, outarg, NIL); + Printv(f->code, cleanup, NIL); + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$result", "_outv"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printf(f->code, "fail:\n"); // we should free locals etc if this happens + Printf(f->code, "return _out;\n"); + Printf(f->code, "}\n"); + + Replaceall(f->code, "$symname", iname); + Wrapper_print(f, f_wrappers); + DelWrapper(f); + + if (last_overload) + dispatchFunction(n); + + if (!overloaded || last_overload) { + process_autodoc(n); + String *tname = texinfo_name(n); + Printf(s_global_tab, "{\"%s\",%s,0,0,2,%s},\n", iname, wname, tname); + Delete(tname); + } + + Delete(overname); + Delete(wname); + Delete(cleanup); + Delete(outarg); + + return SWIG_OK; + } + + void dispatchFunction(Node *n) { + Wrapper *f = NewWrapper(); + + String *iname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(iname); + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(args, nargout);", &maxargs); + String *tmp = NewString(""); + + Printv(f->def, "static octave_value_list ", wname, " (const octave_value_list& args, int nargout) {", NIL); + Wrapper_add_local(f, "argc", "int argc = args.length()"); + Printf(tmp, "octave_value_ref argv[%d]={", maxargs); + for (int j = 0; j < maxargs; ++j) + Printf(tmp, "%soctave_value_ref(args,%d)", j ? "," : " ", j); + Printf(tmp, "}"); + Wrapper_add_local(f, "argv", tmp); + Printv(f->code, dispatch, "\n", NIL); + Printf(f->code, "error(\"No matching function for overload\");\n", iname); + Printf(f->code, "return octave_value_list();\n"); + Printv(f->code, "}\n", NIL); + + Wrapper_print(f, f_wrappers); + Delete(tmp); + DelWrapper(f); + Delete(dispatch); + Delete(wname); + } + + virtual int variableWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + String *tm; + Wrapper *getf = NewWrapper(); + Wrapper *setf = NewWrapper(); + + String *getname = Swig_name_get(iname); + String *setname = Swig_name_set(iname); + + Printf(setf->def, "static octave_value_list _wrap_%s(const octave_value_list& args,int nargout) {", setname); + Printf(setf->def, "if (!SWIG_check_num_args(\"%s_set\",args.length(),1,1,0)) return octave_value_list();", iname); + if (is_assignable(n)) { + Setattr(n, "wrap:name", setname); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "args(0)"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "args(0)"); + if (Getattr(n, "tmap:varin:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + emit_action_code(n, setf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + } + Append(setf->code, "fail:\n"); + Printf(setf->code, "return octave_value_list();\n"); + } else { + Printf(setf->code, "return octave_set_immutable(args,nargout);"); + } + Append(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + + Setattr(n, "wrap:name", getname); + int addfail = 0; + Printf(getf->def, "static octave_value_list _wrap_%s(const octave_value_list& args,int nargout) {", getname); + Wrapper_add_local(getf, "obj", "octave_value obj"); + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "obj"); + Replaceall(tm, "$result", "obj"); + addfail = emit_action_code(n, getf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + Append(getf->code, " return obj;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return octave_value_list();\n"); + } + Append(getf->code, "}\n"); + Wrapper_print(getf, f_wrappers); + + Printf(s_global_tab, "{\"%s\",0,_wrap_%s,_wrap_%s,2,0},\n", iname, getname, setname); + + return SWIG_OK; + } + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + String *str = SwigType_str(type, wname); + Printf(f_header, "static %s = %s;\n", str, value); + Delete(str); + value = wname; + } + if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", iname); + Printf(f_init, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + + return SWIG_OK; + } + + virtual int nativeWrapper(Node *n) { + return Language::nativeWrapper(n); + } + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + virtual int classHandler(Node *n) { + have_constructor = 0; + have_destructor = 0; + constructor_name = 0; + + class_name = Getattr(n, "sym:name"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + // This is a bug, due to the fact that swig_type -> octave_class mapping + // is 1-to-n. + static Hash *emitted = NewHash(); + String *mangled_classname = Swig_name_mangle(Getattr(n, "name")); + if (Getattr(emitted, mangled_classname)) { + Delete(mangled_classname); + return SWIG_NOWRAP; + } + Setattr(emitted, mangled_classname, "1"); + Delete(mangled_classname); + + assert(!s_members_tab); + s_members_tab = NewString(""); + Printv(s_members_tab, "static swig_octave_member swig_", class_name, "_members[] = {\n", NIL); + + Language::classHandler(n); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType_add_pointer(t); + + String *wrap_class = NewStringf("&_wrap_class_%s", class_name); + SwigType_remember_clientdata(t, wrap_class); + + int use_director = Swig_directorclass(n); + if (use_director) { + String *disown_shadow = NewString(""); + Printf(disown_shadow, "static octave_value_list _wrap_disown_%s_shadow " "(const octave_value_list& args, int nargout) {\n", class_name); + Printf(disown_shadow, " if (args.length()!=1) {\n"); + Printf(disown_shadow, " error(\"disown takes no arguments\");\n"); + Printf(disown_shadow, " return octave_value_list();\n"); + Printf(disown_shadow, " }\n"); + Printf(disown_shadow, " _wrap_disown_%s (args, nargout);\n", class_name); + Printf(disown_shadow, " return args;\n"); + Printf(disown_shadow, "}\n"); + Printv(f_wrappers, disown_shadow, NIL); + Delete(disown_shadow); + Printf(s_members_tab, "{\"__disown\",_wrap_disown_%s_shadow,0,0,0,0},\n", class_name); + } + + Printf(s_members_tab, "{0,0,0,0}\n};\n"); + Printv(f_wrappers, s_members_tab, NIL); + + String *base_class_names = NewString(""); + String *base_class = NewString(""); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + + String *bname_mangled = SwigType_manglestr(SwigType_add_pointer(Copy(bname))); + Printf(base_class_names, "\"%s\",", bname_mangled); + Printf(base_class, "0,"); + b = Next(b); + index++; + Delete(bname_mangled); + } + } + + Printv(f_wrappers, "static const char *swig_", class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); + Printv(f_wrappers, "static const swig_type_info *swig_", class_name, "_base[] = {", base_class, "0};\n", NIL); + Printv(f_wrappers, "static swig_octave_class _wrap_class_", class_name, " = {\"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + Printv(f_wrappers, Swig_directorclass(n) ? "1," : "0,", NIL); + if (have_constructor) { + String *cname = Swig_name_construct(constructor_name); + String *wcname = Swig_name_wrapper(cname); + String *tname = texinfo_name(n); + Printf(f_wrappers, "%s,%s,", wcname, tname); + Delete(tname); + Delete(wcname); + Delete(cname); + } else + Printv(f_wrappers, "0,0,", NIL); + if (have_destructor) + Printv(f_wrappers, "_wrap_delete_", class_name, ",", NIL); + else + Printv(f_wrappers, "0", ",", NIL); + Printf(f_wrappers, "swig_%s_members,swig_%s_base_names,swig_%s_base };\n\n", class_name, class_name, class_name); + + Delete(base_class); + Delete(base_class_names); + Delete(t); + Delete(s_members_tab); + s_members_tab = 0; + class_name = 0; + + return SWIG_OK; + } + + virtual int memberfunctionHandler(Node *n) { + Language::memberfunctionHandler(n); + + assert(s_members_tab); + assert(class_name); + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + String *realname = iname ? iname : name; + String *rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + + if (!Getattr(n, "sym:nextSibling")) { + String *tname = texinfo_name(n); + Printf(s_members_tab, "{\"%s\",%s,0,0,0,%s},\n", + realname, rname, tname); + Delete(tname); + } + + Delete(rname); + return SWIG_OK; + } + + virtual int membervariableHandler(Node *n) { + Setattr(n, "feature:autodoc", "0"); + + Language::membervariableHandler(n); + + assert(s_members_tab); + assert(class_name); + String *symname = Getattr(n, "sym:name"); + String *getname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + String *setname = GetFlag(n, "feature:immutable") ? + NewString("octave_set_immutable") : Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + assert(s_members_tab); + + Printf(s_members_tab, "{\"%s\",0,%s,%s,0,0},\n", symname, getname, setname); + + Delete(getname); + Delete(setname); + return SWIG_OK; + } + + virtual int constructorHandler(Node *n) { + have_constructor = 1; + if (!constructor_name) + constructor_name = NewString(Getattr(n, "sym:name")); + + int use_director = Swig_directorclass(n); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("void"); + SwigType_add_pointer(type); + self = NewParm(type, name); + Delete(type); + Delete(name); + Setattr(self, "lname", "self_obj"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Setattr(n, "hidden", "1"); + Delete(self); + } + + return Language::constructorHandler(n);; + } + + virtual int destructorHandler(Node *n) { + have_destructor = 1; + return Language::destructorHandler(n);; + } + + virtual int staticmemberfunctionHandler(Node *n) { + Language::staticmemberfunctionHandler(n); + + assert(s_members_tab); + assert(class_name); + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + String *realname = iname ? iname : name; + String *rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + + if (!Getattr(n, "sym:nextSibling")) { + String *tname = texinfo_name(n); + Printf(s_members_tab, "{\"%s\",%s,0,0,1,%s},\n", + realname, rname, tname); + Delete(tname); + } + + Delete(rname); + return SWIG_OK; + } + + virtual int memberconstantHandler(Node *n) { + return Language::memberconstantHandler(n); + } + + virtual int staticmembervariableHandler(Node *n) { + Setattr(n, "feature:autodoc", "0"); + + Language::staticmembervariableHandler(n); + + if (!GetFlag(n, "wrappedasconstant")) { + assert(s_members_tab); + assert(class_name); + String *symname = Getattr(n, "sym:name"); + String *getname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + String *setname = GetFlag(n, "feature:immutable") ? + NewString("octave_set_immutable") : Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + assert(s_members_tab); + + Printf(s_members_tab, "{\"%s\",0,%s,%s,1,0},\n", symname, getname, setname); + + Delete(getname); + Delete(setname); + } + return SWIG_OK; + } + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + // insert self parameter + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("void"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self")); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + // constructor + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s," "\nSwig::Director(static_cast<%s*>(this)) { \n", classname, target, call, basetype); + Append(w->def, "}\n"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + // constructor header + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + { + Wrapper *w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(void* self) :" + "\nSwig::Director((octave_swig_type*)self,static_cast<%s*>(this)) { \n", classname, classname, classname); + Append(w->def, "}\n"); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " SwigDirector_%s(octave_swig_type* self);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_type; + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + // determine if the method returns a pointer + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + // form complete return type + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + // virtual method definition + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + + // header declaration + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + // declare method return value + // if the return value is a reference or const reference, a specialized typemap must + // handle it, including declaration of c_result ($result). + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *cres = SwigType_lstr(return_type, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + // attach typemaps to arguments (C/C++ -> Python) + String *parse_args = NewString(""); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + + int outputs = 0; + if (!is_void) + outputs++; + + // build argument list and type conversion string + idx = 0; + p = l; + int use_parse = 0; + while (p != NULL) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + Wrapper_add_local(w, "tmpv", "octave_value tmpv"); + + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + String *parse = Getattr(p, "tmap:directorin:parse"); + if (!parse) { + Replaceall(tm, "$input", "tmpv"); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, tm, "\n", NIL); + Printf(wrap_args, "args.append(tmpv);\n"); + Putc('O', parse_args); + } else { + use_parse = 1; + Append(parse_args, parse); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + } + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + p = nextSibling(p); + } + + String *method_name = Getattr(n, "sym:name"); + + Printv(w->code, wrap_args, NIL); + + // emit method invocation + Wrapper_add_local(w, "args", "octave_value_list args"); + Wrapper_add_local(w, "out", "octave_value_list out"); + Wrapper_add_local(w, "idx", "std::list<octave_value_list> idx"); + Printf(w->code, "idx.push_back(octave_value_list(\"%s\"));\n", method_name); + Printf(w->code, "idx.push_back(args);\n"); + Printf(w->code, "out=swig_get_self()->subsref(\".(\",idx,%d);\n", outputs); + + String *cleanup = NewString(""); + String *outarg = NewString(""); + idx = 0; + + // marshal return value + if (!is_void) { + Printf(w->code, "if (out.length()<%d) {\n", outputs); + Printf(w->code, "Swig::DirectorTypeMismatchException::raise(\"Octave " + "method %s.%s failed to return the required number " "of arguments.\");\n", classname, method_name); + Printf(w->code, "}\n"); + + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + char temp[24]; + sprintf(temp, "out(%d)", idx); + Replaceall(tm, "$input", temp); + // Replaceall(tm, "$argnum", temp); + Replaceall(tm, "$disown", Getattr(n, "wrap:disown") ? "SWIG_POINTER_DISOWN" : "0"); + if (Getattr(n, "tmap:directorout:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", + SwigType_str(return_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + idx++; + + // marshal outputs + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + char temp[24]; + sprintf(temp, "out(%d)", idx); + Replaceall(tm, "$input", temp); + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(parse_args); + Delete(cleanup); + Delete(outarg); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(return_type, 0); + if (!SwigType_isreference(return_type)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Append(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + // emit the director method + if (status == SWIG_OK) { + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + // clean up + Delete(wrap_args); + Delete(return_type); + Delete(pclassname); + DelWrapper(w); + return status; + } + + String *runtimeCode() { + String *s = NewString(""); + String *srun = Swig_include_sys("octrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'octrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigoctaverun.h"); + } +}; + +extern "C" Language *swig_octave(void) { + return new OCTAVE(); +} diff --git a/Source/Modules/overload.cxx b/Source/Modules/overload.cxx new file mode 100644 index 0000000..38cb729 --- /dev/null +++ b/Source/Modules/overload.cxx @@ -0,0 +1,792 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * overload.cxx + * + * This file is used to analyze overloaded functions and methods. + * It looks at signatures and tries to gather information for + * building a dispatch function. + * ----------------------------------------------------------------------------- */ + +char cvsroot_overload_cxx[] = "$Id: overload.cxx 11455 2009-07-26 21:29:55Z wsfulton $"; + +#include "swigmod.h" + +#define MAX_OVERLOAD 4096 + +/* Overload "argc" and "argv" */ +String *argv_template_string; +String *argc_template_string; + +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ +}; + +static int fast_dispatch_mode = 0; +static int cast_dispatch_mode = 0; + +/* Set fast_dispatch_mode */ +void Wrapper_fast_dispatch_mode_set(int flag) { + fast_dispatch_mode = flag; +} + +void Wrapper_cast_dispatch_mode_set(int flag) { + cast_dispatch_mode = flag; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_rank() + * + * This function takes an overloaded declaration and creates a list that ranks + * all overloaded methods in an order that can be used to generate a dispatch + * function. + * Slight difference in the way this function is used by scripting languages and + * statically typed languages. The script languages call this method via + * Swig_overload_dispatch() - where wrappers for all overloaded methods are generated, + * however sometimes the code can never be executed. The non-scripting languages + * call this method via Swig_overload_check() for each overloaded method in order + * to determine whether or not the method should be wrapped. Note the slight + * difference when overloading methods that differ by const only. The + * scripting languages will ignore the const method, whereas the non-scripting + * languages ignore the first method parsed. + * ----------------------------------------------------------------------------- */ + +static List *Swig_overload_rank(Node *n, bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n, "sym:overloaded"); + Node *c; + + if (!o) + return 0; + + c = o; + while (c) { + if (Getattr(c, "error")) { + c = Getattr(c, "sym:nextSibling"); + continue; + } + /* if (SmartPointer && Getattr(c,"cplus:staticbase")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } */ + + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + if (Getattr(c, "wrap:name")) { + assert(nnodes < MAX_OVERLOAD); + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c, "wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nnodes++; + } + c = Getattr(c, "sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i, j; + for (i = 0; i < nnodes; i++) { + for (j = i + 1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i, j; + for (i = 0; i < nnodes - 1; i++) { + if (nodes[i].argc == nodes[i + 1].argc) { + for (j = i + 1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + // Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + if (checkAttribute(p1, "tmap:in:numinputs", "0")) { + p1 = Getattr(p1, "tmap:in:next"); + continue; + } + if (checkAttribute(p2, "tmap:in:numinputs", "0")) { + p2 = Getattr(p2, "tmap:in:next"); + continue; + } + String *t1 = Getattr(p1, "tmap:typecheck:precedence"); + String *t2 = Getattr(p2, "tmap:typecheck:precedence"); + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded method %s not supported (no type checking rule for '%s').\n", + Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s not supported (no type checking rule for '%s').\n", + Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v - t2v; + } else if (!t1 && t2) + differ = 1; + else if (t1 && !t2) + differ = -1; + else if (!t1 && !t2) + differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1, "0") == 0)) { + t1 = Getattr(p1, "ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1, "type")); + if (Getattr(p1, "tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1, "ltype", t1); + } + t2 = Getattr(p2, "ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2, "type")); + if (Getattr(p2, "tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2, "ltype", t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2, t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1, t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1, "tmap:in:next")) { + p1 = Getattr(p1, "tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2, "tmap:in:next")) { + p2 = Getattr(p2, "tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *d1 = Getattr(nodes[i].n, "decl"); + String *d2 = Getattr(nodes[j].n, "decl"); + if (d1 && d2) { + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1, dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Non-const method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Non-const method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s is shadowed by %s at %s:%d.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result, nodes[i].n); + // Printf(stdout,"[ %d ] %s\n", i, ParmList_errorstr(nodes[i].parms)); + // Swig_print_node(nodes[i].n); + } + } + return result; +} + +// /* ----------------------------------------------------------------------------- +// * print_typecheck() +// * ----------------------------------------------------------------------------- */ + +static bool print_typecheck(String *f, int j, Parm *pj) { + char tmp[256]; + sprintf(tmp, Char(argv_template_string), j); + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + Replaceid(tm, Getattr(pj, "lname"), "_v"); + String *conv = Getattr(pj, "implicitconv"); + if (conv) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, tm, "\n", NIL); + return true; + } else + return false; +} + +/* ----------------------------------------------------------------------------- + * ReplaceFormat() + * ----------------------------------------------------------------------------- */ + +static String *ReplaceFormat(const_String_or_char_ptr fmt, int j) { + String *lfmt = NewString(fmt); + char buf[50]; + sprintf(buf, "%d", j); + Replaceall(lfmt, "$numargs", buf); + int i; + String *commaargs = NewString(""); + for (i = 0; i < j; i++) { + Printv(commaargs, ", ", NIL); + Printf(commaargs, Char(argv_template_string), i); + } + Replaceall(lfmt, "$commaargs", commaargs); + return lfmt; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_dispatch() + * + * Generate a dispatch function. argc is assumed to hold the argument count. + * argv is the argument vector. + * + * Note that for C++ class member functions, Swig_overload_dispatch() assumes + * that argc includes the "self" argument and that the first element of argv[] + * is the "self" argument. So for a member function: + * + * Foo::bar(int x, int y, int z); + * + * the argc should be 4 (not 3!) and the first element of argv[] would be + * the appropriate scripting language reference to "self". For regular + * functions (and static class functions) the argc and argv only include + * the regular function arguments. + * ----------------------------------------------------------------------------- */ + +/* + Cast dispatch mechanism. +*/ +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *maxargs) { + int i, j; + + *maxargs = 1; + + String *f = NewString(""); + String *sw = NewString(""); + Printf(f, "{\n"); + Printf(f, "unsigned long _index = 0;\n"); + Printf(f, "SWIG_TypeRank _rank = 0; \n"); + + /* Get a list of methods ranked by precedence values and argument count */ + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + + /* Loop over the functions */ + + bool emitcheck = 1; + for (i = 0; i < nfunc; i++) { + int fn = 0; + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (num_arguments > *maxargs) + *maxargs = num_arguments; + int varargs = emit_isvarargs(pi); + + if (!varargs) { + if (num_required == num_arguments) { + Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); + } else { + Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); + } + } else { + Printf(f, "if (%s >= %d) {\n", argc_template_string, num_required); + } + Printf(f, "SWIG_TypeRank _ranki = 0;\n"); + Printf(f, "SWIG_TypeRank _rankm = 0;\n"); + if (num_arguments) + Printf(f, "SWIG_TypeRank _pi = 1;\n"); + + /* create a list with the wrappers that collide with the + current one based on argument number */ + List *coll = NewList(); + for (int k = i + 1; k < nfunc; k++) { + Node *nk = Getitem(dispatch, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nrk = emit_num_required(pk); + int nak = emit_num_arguments(pk); + if ((nrk >= num_required && nrk <= num_arguments) || (nak >= num_required && nak <= num_arguments) || (nrk <= num_required && nak >= num_arguments)) + Append(coll, nk); + } + + // printf("overload: %s coll=%d\n", Char(Getattr(n, "sym:name")), Len(coll)); + + int num_braces = 0; + bool test = (num_arguments > 0); + if (test) { + int need_v = 1; + j = 0; + Parm *pj = pi; + while (pj) { + if (checkAttribute(pj, "tmap:in:numinputs", "0")) { + pj = Getattr(pj, "tmap:in:next"); + continue; + } + + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + /* normalise for comparison later */ + Replaceid(tm, Getattr(pj, "lname"), "_v"); + + /* if all the wrappers have the same type check on this + argument we can optimize it out */ + for (int k = 0; k < Len(coll) && !emitcheck; k++) { + Node *nk = Getitem(coll, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nak = emit_num_arguments(pk); + if (nak <= j) + continue; + int l = 0; + Parm *pl = pk; + /* finds arg j on the collider wrapper */ + while (pl && l <= j) { + if (checkAttribute(pl, "tmap:in:numinputs", "0")) { + pl = Getattr(pl, "tmap:in:next"); + continue; + } + if (l == j) { + /* we are at arg j, so we compare the tmaps now */ + String *tml = Getattr(pl, "tmap:typecheck"); + /* normalise it before comparing */ + if (tml) + Replaceid(tml, Getattr(pl, "lname"), "_v"); + if (!tml || Cmp(tm, tml)) + emitcheck = 1; + //printf("tmap: %s[%d] (%d) => %s\n\n", + // Char(Getattr(nk, "sym:name")), + // l, emitcheck, tml?Char(tml):0); + } + Parm *pl1 = Getattr(pl, "tmap:in:next"); + if (pl1) + pl = pl1; + else + pl = nextSibling(pl); + l++; + } + } + + if (emitcheck) { + if (need_v) { + Printf(f, "int _v = 0;\n"); + need_v = 0; + } + if (j >= num_required) { + Printf(f, "if (%s > %d) {\n", argc_template_string, j); + num_braces++; + } + String *tmp = NewStringf(argv_template_string, j); + + String *conv = Getattr(pj, "implicitconv"); + if (conv) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, "{\n", tm, "}\n", NIL); + fn = i + 1; + Printf(f, "if (!_v) goto check_%d;\n", fn); + Printf(f, "_ranki += _v*_pi;\n"); + Printf(f, "_rankm += _pi;\n"); + Printf(f, "_pi *= SWIG_MAXCASTRANK;\n"); + } + } + if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { + /* we emit a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ + Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), + "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", + Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); + } + Parm *pj1 = Getattr(pj, "tmap:in:next"); + if (pj1) + pj = pj1; + else + pj = nextSibling(pj); + j++; + } + } + + /* close braces */ + for ( /* empty */ ; num_braces > 0; num_braces--) + Printf(f, "}\n"); + + Printf(f, "if (!_index || (_ranki < _rank)) {\n"); + Printf(f, " _rank = _ranki; _index = %d;\n", i + 1); + Printf(f, " if (_rank == _rankm) goto dispatch;\n"); + Printf(f, "}\n"); + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(sw, "case %d:\n", i + 1); + Printf(sw, Char(lfmt), Getattr(ni, "wrap:name")); + Printf(sw, "\n"); + + Printf(f, "}\n"); /* braces closes "if" for this method */ + if (fn) + Printf(f, "check_%d:\n\n", fn); + + Delete(lfmt); + Delete(coll); + } + Delete(dispatch); + Printf(f, "dispatch:\n"); + Printf(f, "switch(_index) {\n"); + Printf(f, "%s", sw); + Printf(f, "}\n"); + + Printf(f, "}\n"); + return f; +} + +/* + Fast dispatch mechanism, provided by Salvador Fandi~no Garc'ia (#930586). +*/ +String *Swig_overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *maxargs) { + int i, j; + + *maxargs = 1; + + String *f = NewString(""); + + /* Get a list of methods ranked by precedence values and argument count */ + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + + /* Loop over the functions */ + + for (i = 0; i < nfunc; i++) { + int fn = 0; + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (num_arguments > *maxargs) + *maxargs = num_arguments; + int varargs = emit_isvarargs(pi); + + if (!varargs) { + if (num_required == num_arguments) { + Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); + } else { + Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); + } + } else { + Printf(f, "if (%s >= %d) {\n", argc_template_string, num_required); + } + + /* create a list with the wrappers that collide with the + current one based on argument number */ + List *coll = NewList(); + for (int k = i + 1; k < nfunc; k++) { + Node *nk = Getitem(dispatch, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nrk = emit_num_required(pk); + int nak = emit_num_arguments(pk); + if ((nrk >= num_required && nrk <= num_arguments) || (nak >= num_required && nak <= num_arguments) || (nrk <= num_required && nak >= num_arguments)) + Append(coll, nk); + } + + // printf("overload: %s coll=%d\n", Char(Getattr(n, "sym:name")), Len(coll)); + + int num_braces = 0; + bool test = (Len(coll) > 0 && num_arguments); + if (test) { + int need_v = 1; + j = 0; + Parm *pj = pi; + while (pj) { + if (checkAttribute(pj, "tmap:in:numinputs", "0")) { + pj = Getattr(pj, "tmap:in:next"); + continue; + } + + String *tm = Getattr(pj, "tmap:typecheck"); + if (tm) { + /* normalise for comparison later */ + Replaceid(tm, Getattr(pj, "lname"), "_v"); + + /* if all the wrappers have the same type check on this + argument we can optimize it out */ + bool emitcheck = 0; + for (int k = 0; k < Len(coll) && !emitcheck; k++) { + Node *nk = Getitem(coll, k); + Parm *pk = Getattr(nk, "wrap:parms"); + int nak = emit_num_arguments(pk); + if (nak <= j) + continue; + int l = 0; + Parm *pl = pk; + /* finds arg j on the collider wrapper */ + while (pl && l <= j) { + if (checkAttribute(pl, "tmap:in:numinputs", "0")) { + pl = Getattr(pl, "tmap:in:next"); + continue; + } + if (l == j) { + /* we are at arg j, so we compare the tmaps now */ + String *tml = Getattr(pl, "tmap:typecheck"); + /* normalise it before comparing */ + if (tml) + Replaceid(tml, Getattr(pl, "lname"), "_v"); + if (!tml || Cmp(tm, tml)) + emitcheck = 1; + //printf("tmap: %s[%d] (%d) => %s\n\n", + // Char(Getattr(nk, "sym:name")), + // l, emitcheck, tml?Char(tml):0); + } + Parm *pl1 = Getattr(pl, "tmap:in:next"); + if (pl1) + pl = pl1; + else + pl = nextSibling(pl); + l++; + } + } + + if (emitcheck) { + if (need_v) { + Printf(f, "int _v = 0;\n"); + need_v = 0; + } + if (j >= num_required) { + Printf(f, "if (%s > %d) {\n", argc_template_string, j); + num_braces++; + } + String *tmp = NewStringf(argv_template_string, j); + + String *conv = Getattr(pj, "implicitconv"); + if (conv) { + Replaceall(tm, "$implicitconv", conv); + } else { + Replaceall(tm, "$implicitconv", "0"); + } + Replaceall(tm, "$input", tmp); + Printv(f, "{\n", tm, "}\n", NIL); + fn = i + 1; + Printf(f, "if (!_v) goto check_%d;\n", fn); + } + } + if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { + /* we emit a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ + Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), + "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", + Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); + } + Parm *pj1 = Getattr(pj, "tmap:in:next"); + if (pj1) + pj = pj1; + else + pj = nextSibling(pj); + j++; + } + } + + /* close braces */ + for ( /* empty */ ; num_braces > 0; num_braces--) + Printf(f, "}\n"); + + + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + + Printf(f, "}\n"); /* braces closes "if" for this method */ + if (fn) + Printf(f, "check_%d:\n\n", fn); + + Delete(lfmt); + Delete(coll); + } + Delete(dispatch); + return f; +} + +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxargs) { + + if (fast_dispatch_mode || GetFlag(n, "feature:fastdispatch")) { + return Swig_overload_dispatch_fast(n, fmt, maxargs); + } + + int i, j; + + *maxargs = 1; + + String *f = NewString(""); + + /* Get a list of methods ranked by precedence values and argument count */ + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + + /* Loop over the functions */ + + for (i = 0; i < nfunc; i++) { + Node *ni = Getitem(dispatch, i); + Parm *pi = Getattr(ni, "wrap:parms"); + int num_required = emit_num_required(pi); + int num_arguments = emit_num_arguments(pi); + if (GetFlag(n, "wrap:this")) { + num_required++; + num_arguments++; + } + if (num_arguments > *maxargs) + *maxargs = num_arguments; + int varargs = emit_isvarargs(pi); + + if (!varargs) { + if (num_required == num_arguments) { + Printf(f, "if (%s == %d) {\n", argc_template_string, num_required); + } else { + Printf(f, "if ((%s >= %d) && (%s <= %d)) {\n", argc_template_string, num_required, argc_template_string, num_arguments); + } + } else { + Printf(f, "if (%s >= %d) {\n", argc_template_string, num_required); + } + + if (num_arguments) { + Printf(f, "int _v;\n"); + } + + int num_braces = 0; + j = 0; + Parm *pj = pi; + while (pj) { + if (checkAttribute(pj, "tmap:in:numinputs", "0")) { + pj = Getattr(pj, "tmap:in:next"); + continue; + } + if (j >= num_required) { + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(f, "if (%s <= %d) {\n", argc_template_string, j); + Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + Printf(f, "}\n"); + Delete(lfmt); + } + if (print_typecheck(f, (GetFlag(n, "wrap:this") ? j + 1 : j), pj)) { + Printf(f, "if (_v) {\n"); + num_braces++; + } + if (!Getattr(pj, "tmap:in:SWIGTYPE") && Getattr(pj, "tmap:typecheck:SWIGTYPE")) { + /* we emit a warning if the argument defines the 'in' typemap, but not the 'typecheck' one */ + Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni), + "Overloaded method %s with no explicit typecheck typemap for arg %d of type '%s'\n", + Swig_name_decl(n), j, SwigType_str(Getattr(pj, "type"), 0)); + } + Parm *pk = Getattr(pj, "tmap:in:next"); + if (pk) + pj = pk; + else + pj = nextSibling(pj); + j++; + } + String *lfmt = ReplaceFormat(fmt, num_arguments); + Printf(f, Char(lfmt), Getattr(ni, "wrap:name")); + Delete(lfmt); + /* close braces */ + for ( /* empty */ ; num_braces > 0; num_braces--) + Printf(f, "}\n"); + Printf(f, "}\n"); /* braces closes "if" for this method */ + } + Delete(dispatch); + return f; +} + +/* ----------------------------------------------------------------------------- + * Swig_overload_check() + * ----------------------------------------------------------------------------- */ +void Swig_overload_check(Node *n) { + Swig_overload_rank(n, false); +} diff --git a/Source/Modules/perl5.cxx b/Source/Modules/perl5.cxx new file mode 100644 index 0000000..34b2701 --- /dev/null +++ b/Source/Modules/perl5.cxx @@ -0,0 +1,1768 @@ +/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=2:tabstop=8:smarttab: + */ + +/* ---------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * perl5.cxx + * + * Perl5 language module for SWIG. + * ------------------------------------------------------------------------- */ + +char cvsroot_perl5_cxx[] = "$Id: perl5.cxx 11397 2009-07-15 07:43:16Z olly $"; + +#include "swigmod.h" +#include "cparse.h" +static int treduce = SWIG_cparse_template_reduce(0); + +#include <ctype.h> + +static const char *usage = (char *) "\ +Perl5 Options (available with -perl5)\n\ + -static - Omit code related to dynamic loading\n\ + -nopm - Do not generate the .pm file\n\ + -proxy - Create proxy classes\n\ + -noproxy - Don't create proxy classes\n\ + -const - Wrap constants as constants and not variables (implies -proxy)\n\ + -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ + -cppcast - Enable C++ casting operators\n\ + -compat - Compatibility mode\n\n"; + +static int compat = 0; + +static int no_pmfile = 0; + +static int export_all = 0; + +/* + * pmfile + * set by the -pm flag, overrides the name of the .pm file + */ +static String *pmfile = 0; + +/* + * module + * set by the %module directive, e.g. "Xerces". It will determine + * the name of the .pm file, and the dynamic library, and the name + * used by any module wanting to %import the module. + */ +static String *module = 0; + +/* + * namespace_module + * the fully namespace qualified name of the module. It will be used + * to set the package namespace in the .pm file, as well as the name + * of the initialization methods in the glue library. This will be + * the same as module, above, unless the %module directive is given + * the 'package' option, e.g. %module(package="Foo::Bar") "baz" + */ +static String *namespace_module = 0; + +/* + * cmodule + * the namespace of the internal glue code, set to the value of + * module with a 'c' appended + */ +static String *cmodule = 0; + +/* + * dest_package + * an optional namespace to put all classes into. Specified by using + * the %module(package="Foo::Bar") "baz" syntax + */ +static String *dest_package = 0; + +static String *command_tab = 0; +static String *constant_tab = 0; +static String *variable_tab = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; +static File *f_pm = 0; +static String *pm; /* Package initialization code */ +static String *magic; /* Magic variable wrappers */ + +static int staticoption = 0; + +// controlling verbose output +static int verbose = 0; + +/* The following variables are used to manage Perl5 classes */ + +static int blessed = 1; /* Enable object oriented features */ +static int do_constants = 0; /* Constant wrapping */ +static List *classlist = 0; /* List of classes */ +static int have_constructor = 0; +static int have_destructor = 0; +static int have_data_members = 0; +static String *class_name = 0; /* Name of the class (what Perl thinks it is) */ +static String *real_classname = 0; /* Real name of C/C++ class */ +static String *fullclassname = 0; + +static String *pcode = 0; /* Perl code associated with each class */ + /* static String *blessedmembers = 0; *//* Member data associated with each class */ +static int member_func = 0; /* Set to 1 when wrapping a member function */ +static String *func_stubs = 0; /* Function stubs */ +static String *const_stubs = 0; /* Constant stubs */ +static int num_consts = 0; /* Number of constants */ +static String *var_stubs = 0; /* Variable stubs */ +static String *exported = 0; /* Exported symbols */ +static String *pragma_include = 0; +static String *additional_perl_code = 0; /* Additional Perl code from %perlcode %{ ... %} */ +static Hash *operators = 0; +static int have_operators = 0; + +class PERL5:public Language { +public: + + PERL5():Language () { + Clear(argc_template_string); + Printv(argc_template_string, "items", NIL); + Clear(argv_template_string); + Printv(argv_template_string, "ST(%d)", NIL); + } + + /* Test to see if a type corresponds to something wrapped with a shadow class */ + Node *is_shadow(SwigType *t) { + Node *n; + n = classLookup(t); + /* Printf(stdout,"'%s' --> '%x'\n", t, n); */ + if (n) { + if (!Getattr(n, "perl5:proxy")) { + setclassname(n); + } + return Getattr(n, "perl5:proxy"); + } + return 0; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int i = 1; + int cppcast = 1; + + SWIG_library_directory("perl5"); + + for (i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-package") == 0) { + Printv(stderr, + "*** -package is no longer supported\n*** use the directive '%module A::B::C' in your interface file instead\n*** see the Perl section in the manual for details.\n", NIL); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-interface") == 0) { + Printv(stderr, + "*** -interface is no longer supported\n*** use the directive '%module A::B::C' in your interface file instead\n*** see the Perl section in the manual for details.\n", NIL); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-exportall") == 0) { + export_all = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-static") == 0) { + staticoption = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + blessed = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + blessed = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-const") == 0) { + do_constants = 1; + blessed = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nopm") == 0) { + no_pmfile = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-pm") == 0) { + Swig_mark_arg(i); + i++; + pmfile = NewString(argv[i]); + Swig_mark_arg(i); + } else if (strcmp(argv[i],"-v") == 0) { + Swig_mark_arg(i); + verbose++; + } else if (strcmp(argv[i], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-compat") == 0) { + compat = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + Preprocessor_define("SWIGPERL 1", 0); + // SWIGPERL5 is deprecated, and no longer documented. + Preprocessor_define("SWIGPERL5 1", 0); + SWIG_typemap_lang("perl5"); + SWIG_config_file("perl5.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + + classlist = NewList(); + + pm = NewString(""); + func_stubs = NewString(""); + var_stubs = NewString(""); + const_stubs = NewString(""); + exported = NewString(""); + magic = NewString(""); + pragma_include = NewString(""); + additional_perl_code = NewString(""); + + command_tab = NewString("static swig_command_info swig_commands[] = {\n"); + constant_tab = NewString("static swig_constant_info swig_constants[] = {\n"); + variable_tab = NewString("static swig_variable_info swig_variables[] = {\n"); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGPERL\n"); + Printf(f_runtime, "#define SWIG_CASTRANK_MODE\n"); + Printf(f_runtime, "\n"); + + // Is the imported module in another package? (IOW, does it use the + // %module(package="name") option and it's different than the package + // of this module.) + Node *mod = Getattr(n, "module"); + Node *options = Getattr(mod, "options"); + module = Copy(Getattr(n,"name")); + + if (verbose > 0) { + fprintf(stdout, "top: using module: %s\n", Char(module)); + } + + dest_package = options ? Getattr(options, "package") : 0; + if (dest_package) { + namespace_module = Copy(dest_package); + if (verbose > 0) { + fprintf(stdout, "top: Found package: %s\n",Char(dest_package)); + } + } else { + namespace_module = Copy(module); + if (verbose > 0) { + fprintf(stdout, "top: No package found\n"); + } + } + String *underscore_module = Copy(module); + Replaceall(underscore_module,":","_"); + + if (verbose > 0) { + fprintf(stdout, "top: using namespace_module: %s\n", Char(namespace_module)); + } + + /* If we're in blessed mode, change the package name to "packagec" */ + + if (blessed) { + cmodule = NewStringf("%sc",namespace_module); + } else { + cmodule = NewString(namespace_module); + } + + /* Create a .pm file + * Need to strip off any prefixes that might be found in + * the module name */ + + if (no_pmfile) { + f_pm = NewString(0); + } else { + if (pmfile == NULL) { + char *m = Char(module) + Len(module); + while (m != Char(module)) { + if (*m == ':') { + m++; + break; + } + m--; + } + pmfile = NewStringf("%s.pm", m); + } + String *filen = NewStringf("%s%s", SWIG_output_directory(), pmfile); + if ((f_pm = NewFile(filen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Delete(filen); + filen = NULL; + Swig_register_filebyname("pm", f_pm); + Swig_register_filebyname("perl", f_pm); + } + { + String *boot_name = NewStringf("boot_%s", underscore_module); + Printf(f_header,"#define SWIG_init %s\n\n", boot_name); + Printf(f_header,"#define SWIG_name \"%s::%s\"\n", cmodule, boot_name); + Printf(f_header,"#define SWIG_prefix \"%s::\"\n", cmodule); + Delete(boot_name); + } + + Swig_banner_target_lang(f_pm, "#"); + Printf(f_pm, "\n"); + + Printf(f_pm, "package %s;\n", module); + + /* + * If the package option has been given we are placing our + * symbols into some other packages namespace, so we do not + * mess with @ISA or require for that package + */ + if (dest_package) { + Printf(f_pm,"use base qw(DynaLoader);\n"); + } else { + Printf(f_pm,"use base qw(Exporter);\n"); + if (!staticoption) { + Printf(f_pm,"use base qw(DynaLoader);\n"); + } + } + + /* Start creating magic code */ + + Printv(magic, + "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n", + "#ifdef PERL_OBJECT\n", + "#define MAGIC_CLASS _wrap_", underscore_module, "_var::\n", + "class _wrap_", underscore_module, "_var : public CPerlObj {\n", + "public:\n", + "#else\n", + "#define MAGIC_CLASS\n", + "#endif\n", + "SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) {\n", + tab4, "MAGIC_PPERL\n", tab4, "croak(\"Value is read-only.\");\n", tab4, "return 0;\n", "}\n", NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* emit wrappers */ + Language::top(n); + + String *base = NewString(""); + + /* Dump out variable wrappers */ + + Printv(magic, "\n\n#ifdef PERL_OBJECT\n", "};\n", "#endif\n", NIL); + Printv(magic, "\n#ifdef __cplusplus\n}\n#endif\n", NIL); + + Printf(f_header, "%s\n", magic); + + String *type_table = NewString(""); + + /* Patch the type table to reflect the names used by shadow classes */ + if (blessed) { + Iterator cls; + for (cls = First(classlist); cls.item; cls = Next(cls)) { + String *pname = Getattr(cls.item, "perl5:proxy"); + if (pname) { + SwigType *type = Getattr(cls.item, "classtypeobj"); + if (!type) + continue; /* If unnamed class, no type will be found */ + type = Copy(type); + + SwigType_add_pointer(type); + String *mangled = SwigType_manglestr(type); + SwigType_remember_mangleddata(mangled, NewStringf("\"%s\"", pname)); + Delete(type); + Delete(mangled); + } + } + } + SwigType_emit_type_table(f_runtime, type_table); + + Printf(f_wrappers, "%s", type_table); + Delete(type_table); + + Printf(constant_tab, "{0,0,0,0,0,0}\n};\n"); + Printv(f_wrappers, constant_tab, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + Printf(f_init, "\t ST(0) = &PL_sv_yes;\n"); + Printf(f_init, "\t XSRETURN(1);\n"); + Printf(f_init, "}\n"); + + /* Finish off tables */ + Printf(variable_tab, "{0,0,0,0}\n};\n"); + Printv(f_wrappers, variable_tab, NIL); + + Printf(command_tab, "{0,0}\n};\n"); + Printv(f_wrappers, command_tab, NIL); + + + Printf(f_pm, "package %s;\n", cmodule); + + if (!staticoption) { + Printf(f_pm,"bootstrap %s;\n", module); + } else { + Printf(f_pm,"package %s;\n", cmodule); + Printf(f_pm,"boot_%s();\n", underscore_module); + } + + Printf(f_pm, "package %s;\n", module); + /* + * If the package option has been given we are placing our + * symbols into some other packages namespace, so we do not + * mess with @EXPORT + */ + if (!dest_package) { + Printf(f_pm,"@EXPORT = qw(%s);\n", exported); + } + + Printf(f_pm, "%s", pragma_include); + + if (blessed) { + + /* + * These methods will be duplicated if package + * has been specified, so we do not output them + */ + if (!dest_package) { + Printv(base, "\n# ---------- BASE METHODS -------------\n\n", "package ", namespace_module, ";\n\n", NIL); + + /* Write out the TIE method */ + + Printv(base, "sub TIEHASH {\n", tab4, "my ($classname,$obj) = @_;\n", tab4, "return bless $obj, $classname;\n", "}\n\n", NIL); + + /* Output a CLEAR method. This is just a place-holder, but by providing it we + * can make declarations such as + * %$u = ( x => 2, y=>3, z =>4 ); + * + * Where x,y,z are the members of some C/C++ object. */ + + Printf(base, "sub CLEAR { }\n\n"); + + /* Output default firstkey/nextkey methods */ + + Printf(base, "sub FIRSTKEY { }\n\n"); + Printf(base, "sub NEXTKEY { }\n\n"); + + /* Output a FETCH method. This is actually common to all classes */ + Printv(base, + "sub FETCH {\n", + tab4, "my ($self,$field) = @_;\n", tab4, "my $member_func = \"swig_${field}_get\";\n", tab4, "$self->$member_func();\n", "}\n\n", NIL); + + /* Output a STORE method. This is also common to all classes (might move to base class) */ + + Printv(base, + "sub STORE {\n", + tab4, "my ($self,$field,$newval) = @_;\n", + tab4, "my $member_func = \"swig_${field}_set\";\n", tab4, "$self->$member_func($newval);\n", "}\n\n", NIL); + + /* Output a 'this' method */ + + Printv(base, "sub this {\n", tab4, "my $ptr = shift;\n", tab4, "return tied(%$ptr);\n", "}\n\n", NIL); + + Printf(f_pm, "%s", base); + } + + /* Emit function stubs for stand-alone functions */ + Printf(f_pm, "\n# ------- FUNCTION WRAPPERS --------\n\n"); + Printf(f_pm, "package %s;\n\n", namespace_module); + Printf(f_pm, "%s", func_stubs); + + /* Emit package code for different classes */ + Printf(f_pm, "%s", pm); + + if (num_consts > 0) { + /* Emit constant stubs */ + Printf(f_pm, "\n# ------- CONSTANT STUBS -------\n\n"); + Printf(f_pm, "package %s;\n\n", namespace_module); + Printf(f_pm, "%s", const_stubs); + } + + /* Emit variable stubs */ + + Printf(f_pm, "\n# ------- VARIABLE STUBS --------\n\n"); + Printf(f_pm, "package %s;\n\n", namespace_module); + Printf(f_pm, "%s", var_stubs); + } + + /* Add additional Perl code at the end */ + Printf(f_pm, "%s", additional_perl_code); + + Printf(f_pm, "1;\n"); + Close(f_pm); + Delete(f_pm); + Delete(base); + Delete(dest_package); + Delete(underscore_module); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective(Node *n) + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + if (blessed) { + String *modname = Getattr(n, "module"); + if (modname) { + Printf(f_pm, "require %s;\n", modname); + } + } + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *overname = 0; + + Parm *p; + int i; + Wrapper *f; + char source[256], temp[256]; + String *tm; + String *cleanup, *outarg; + int num_saved = 0; + int num_arguments, num_required; + int varargs = 0; + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + cleanup = NewString(""); + outarg = NewString(""); + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + Printv(f->def, "XS(", wname, ") {\n", "{\n", /* scope to destroy C++ objects before croaking */ + NIL); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + varargs = emit_isvarargs(l); + + Wrapper_add_local(f, "argvi", "int argvi = 0"); + + /* Check the number of arguments */ + if (!varargs) { + Printf(f->code, " if ((items < %d) || (items > %d)) {\n", num_required, num_arguments); + } else { + Printf(f->code, " if (items < %d) {\n", num_required); + } + Printf(f->code, " SWIG_croak(\"Usage: %s\");\n", usage_func(Char(iname), d, l)); + Printf(f->code, "}\n"); + + /* Write code to extract parameters. */ + i = 0; + for (i = 0, p = l; i < num_arguments; i++) { + + /* Skip ignored arguments */ + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + + /* Produce string representation of source and target arguments */ + sprintf(source, "ST(%d)", i); + String *target = Getattr(p, "lname"); + + if (i >= num_required) { + Printf(f->code, " if (items > %d) {\n", i); + } + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$target", target); + Replaceall(tm, "$source", source); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); /* Save input location */ + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + if (i >= num_required) { + Printf(f->code, " }\n"); + } + } + + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + sprintf(source, "ST(%d)", i); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printf(f->code, "if (items >= %d) {\n", i); + Printv(f->code, tm, "\n", NIL); + Printf(f->code, "}\n"); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + num_saved = 0; + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:argout"))) { + SwigType *t = Getattr(p, "type"); + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "ST(argvi)"); + Replaceall(tm, "$result", "ST(argvi)"); + if (is_shadow(t)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + + String *in = Getattr(p, "emit:input"); + if (in) { + sprintf(temp, "_saved[%d]", num_saved); + Replaceall(tm, "$arg", temp); + Replaceall(tm, "$input", temp); + Printf(f->code, "_saved[%d] = %s;\n", num_saved, in); + num_saved++; + } + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* If there were any saved arguments, emit a local variable for them */ + if (num_saved) { + sprintf(temp, "_saved[%d]", num_saved); + Wrapper_add_localv(f, "_saved", "SV *", temp, NIL); + } + + /* Now write code to make the function call */ + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + SwigType *t = Getattr(n, "type"); + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "ST(argvi)"); + Replaceall(tm, "$result", "ST(argvi)"); + if (is_shadow(t)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "SWIG_OWNER"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* If there were any output args, take care of them. */ + + Printv(f->code, outarg, NIL); + + /* If there was any cleanup, do that. */ + + Printv(f->code, cleanup, NIL); + + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + Printv(f->code, "XSRETURN(argvi);\n", "fail:\n", cleanup, "SWIG_croak_null();\n" "}\n" "}\n", NIL); + + /* Add the dXSARGS last */ + + Wrapper_add_local(f, "dXSARGS", "dXSARGS"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + /* Dump the wrapper function */ + + Wrapper_print(f, f_wrappers); + + /* Now register the function */ + + if (!Getattr(n, "sym:overloaded")) { + Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, iname, wname); + } else if (!Getattr(n, "sym:nextSibling")) { + /* Generate overloaded dispatch function */ + int maxargs; + String *dispatch = Swig_overload_dispatch_cast(n, "++PL_markstack_ptr; SWIG_CALLXS(%s); return;", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "XS(", dname, ") {\n", NIL); + + Wrapper_add_local(df, "dXSARGS", "dXSARGS"); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "croak(\"No matching function for overloaded '%s'\");\n", iname); + Printf(df->code, "XSRETURN(0);\n"); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, iname, dname); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + if (!Getattr(n, "sym:nextSibling")) { + if (export_all) { + Printf(exported, "%s ", iname); + } + + /* -------------------------------------------------------------------- + * Create a stub for this function, provided it's not a member function + * -------------------------------------------------------------------- */ + + if ((blessed) && (!member_func)) { + Printv(func_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); + } + + } + Delete(cleanup); + Delete(outarg); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + virtual int variableWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + Wrapper *getf, *setf; + String *tm; + String *getname = Swig_name_get(iname); + String *setname = Swig_name_set(iname); + + String *get_name = Swig_name_wrapper(getname); + String *set_name = Swig_name_wrapper(setname); + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + getf = NewWrapper(); + setf = NewWrapper(); + + /* Create a Perl function for setting the variable value */ + + if (!GetFlag(n, "feature:immutable")) { + Setattr(n, "wrap:name", set_name); + Printf(setf->def, "SWIGCLASS_STATIC int %s(pTHX_ SV* sv, MAGIC * SWIGUNUSEDPARM(mg)) {\n", set_name); + Printv(setf->code, tab4, "MAGIC_PPERL\n", NIL); + + /* Check for a few typemaps */ + tm = Swig_typemap_lookup("varin", n, name, 0); + if (tm) { + Replaceall(tm, "$source", "sv"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "sv"); + /* Printf(setf->code,"%s\n", tm); */ + emit_action_code(n, setf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + return SWIG_NOWRAP; + } + Printf(setf->code, "fail:\n"); + Printf(setf->code, " return 1;\n}\n"); + Replaceall(setf->code, "$symname", iname); + Wrapper_print(setf, magic); + } + + /* Now write a function to evaluate the variable */ + Setattr(n, "wrap:name", get_name); + int addfail = 0; + Printf(getf->def, "SWIGCLASS_STATIC int %s(pTHX_ SV *sv, MAGIC *SWIGUNUSEDPARM(mg)) {\n", get_name); + Printv(getf->code, tab4, "MAGIC_PPERL\n", NIL); + + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$target", "sv"); + Replaceall(tm, "$result", "sv"); + Replaceall(tm, "$source", name); + if (is_shadow(t)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + /* Printf(getf->code,"%s\n", tm); */ + addfail = emit_action_code(n, getf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_NOWRAP; + } + Printf(getf->code, " return 1;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return 0;\n"); + } + Append(getf->code, "}\n"); + + + Replaceall(getf->code, "$symname", iname); + Wrapper_print(getf, magic); + + String *tt = Getattr(n, "tmap:varout:type"); + if (tt) { + String *tm = NewStringf("&SWIGTYPE%s", SwigType_manglestr(t)); + if (Replaceall(tt, "$1_descriptor", tm)) { + SwigType_remember(t); + } + Delete(tm); + SwigType *st = Copy(t); + SwigType_add_pointer(st); + tm = NewStringf("&SWIGTYPE%s", SwigType_manglestr(st)); + if (Replaceall(tt, "$&1_descriptor", tm)) { + SwigType_remember(st); + } + Delete(tm); + Delete(st); + } else { + tt = (String *) "0"; + } + /* Now add symbol to the PERL interpreter */ + if (GetFlag(n, "feature:immutable")) { + Printv(variable_tab, tab4, "{ \"", cmodule, "::", iname, "\", MAGIC_CLASS swig_magic_readonly, MAGIC_CLASS ", get_name, ",", tt, " },\n", NIL); + + } else { + Printv(variable_tab, tab4, "{ \"", cmodule, "::", iname, "\", MAGIC_CLASS ", set_name, ", MAGIC_CLASS ", get_name, ",", tt, " },\n", NIL); + } + + /* If we're blessed, try to figure out what to do with the variable + 1. If it's a Perl object of some sort, create a tied-hash + around it. + 2. Otherwise, just hack Perl's symbol table */ + + if (blessed) { + if (is_shadow(t)) { + Printv(var_stubs, + "\nmy %__", iname, "_hash;\n", + "tie %__", iname, "_hash,\"", is_shadow(t), "\", $", + cmodule, "::", iname, ";\n", "$", iname, "= \\%__", iname, "_hash;\n", "bless $", iname, ", ", is_shadow(t), ";\n", NIL); + } else { + Printv(var_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); + } + } + if (export_all) + Printf(exported, "$%s ", iname); + + DelWrapper(setf); + DelWrapper(getf); + Delete(getname); + Delete(setname); + Delete(set_name); + Delete(get_name); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + if (is_shadow(type)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + Printf(constant_tab, "%s,\n", tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + if (is_shadow(type)) { + Replaceall(tm, "$shadow", "SWIG_SHADOW"); + } else { + Replaceall(tm, "$shadow", "0"); + } + Printf(f_init, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + + if (blessed) { + if (is_shadow(type)) { + Printv(var_stubs, + "\nmy %__", iname, "_hash;\n", + "tie %__", iname, "_hash,\"", is_shadow(type), "\", $", + cmodule, "::", iname, ";\n", "$", iname, "= \\%__", iname, "_hash;\n", "bless $", iname, ", ", is_shadow(type), ";\n", NIL); + } else if (do_constants) { + Printv(const_stubs, "sub ", name, " () { $", cmodule, "::", name, " }\n", NIL); + num_consts++; + } else { + Printv(var_stubs, "*", iname, " = *", cmodule, "::", iname, ";\n", NIL); + } + } + if (export_all) { + if (do_constants && !is_shadow(type)) { + Printf(exported, "%s ", name); + } else { + Printf(exported, "$%s ", iname); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * usage_func() + * ------------------------------------------------------------ */ + char *usage_func(char *iname, SwigType *, ParmList *l) { + static String *temp = 0; + Parm *p; + int i; + + if (!temp) + temp = NewString(""); + Clear(temp); + Printf(temp, "%s(", iname); + + /* Now go through and print parameters */ + p = l; + i = 0; + while (p != 0) { + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + if (!checkAttribute(p,"tmap:in:numinputs","0")) { + /* If parameter has been named, use that. Otherwise, just print a type */ + if (SwigType_type(pt) != T_VOID) { + if (Len(pn) > 0) { + Printf(temp, "%s", pn); + } else { + Printf(temp, "%s", SwigType_str(pt, 0)); + } + } + i++; + p = nextSibling(p); + if (p) + if (!checkAttribute(p,"tmap:in:numinputs","0")) + Putc(',', temp); + } else { + p = nextSibling(p); + if (p) + if ((i > 0) && (!checkAttribute(p,"tmap:in:numinputs","0"))) + Putc(',', temp); + } + } + Printf(temp, ");"); + return Char(temp); + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + String *funcname = Getattr(n, "wrap:name"); + + if (!addSymbol(funcname, n)) + return SWIG_ERROR; + + Printf(command_tab, "{\"%s::%s\", %s},\n", cmodule, name, funcname); + if (export_all) + Printf(exported, "%s ", name); + if (blessed) { + Printv(func_stubs, "*", name, " = *", cmodule, "::", name, ";\n", NIL); + } + return SWIG_OK; + } + +/* ---------------------------------------------------------------------------- + * OBJECT-ORIENTED FEATURES + * + * These extensions provide a more object-oriented interface to C++ + * classes and structures. The code here is based on extensions + * provided by David Fletcher and Gary Holt. + * + * I have generalized these extensions to make them more general purpose + * and to resolve object-ownership problems. + * + * The approach here is very similar to the Python module : + * 1. All of the original methods are placed into a single + * package like before except that a 'c' is appended to the + * package name. + * + * 2. All methods and function calls are wrapped with a new + * perl function. While possibly inefficient this allows + * us to catch complex function arguments (which are hard to + * track otherwise). + * + * 3. Classes are represented as tied-hashes in a manner similar + * to Gary Holt's extension. This allows us to access + * member data. + * + * 4. Stand-alone (global) C functions are modified to take + * tied hashes as arguments for complex datatypes (if + * appropriate). + * + * 5. Global variables involving a class/struct is encapsulated + * in a tied hash. + * + * ------------------------------------------------------------------------- */ + + + void setclassname(Node *n) { + String *symname = Getattr(n, "sym:name"); + String *fullname; + String *actualpackage; + Node *clsmodule = Getattr(n, "module"); + + if (!clsmodule) { + /* imported module does not define a module name. Oh well */ + return; + } + + /* Do some work on the class name */ + if (verbose > 0) { + String *modulename = Getattr(clsmodule, "name"); + fprintf(stdout, "setclassname: Found sym:name: %s\n", Char(symname)); + fprintf(stdout, "setclassname: Found module: %s\n", Char(modulename)); + fprintf(stdout, "setclassname: No package found\n"); + } + + if (dest_package) { + fullname = NewStringf("%s::%s", namespace_module, symname); + } else { + actualpackage = Getattr(clsmodule,"name"); + + if (verbose > 0) { + fprintf(stdout, "setclassname: Found actualpackage: %s\n", Char(actualpackage)); + } + if ((!compat) && (!Strchr(symname,':'))) { + fullname = NewStringf("%s::%s",actualpackage,symname); + } else { + fullname = NewString(symname); + } + } + if (verbose > 0) { + fprintf(stdout, "setclassname: setting proxy: %s\n", Char(fullname)); + } + Setattr(n, "perl5:proxy", fullname); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + virtual int classDeclaration(Node *n) { + /* Do some work on the class name */ + if (!Getattr(n, "feature:onlychildren")) { + if (blessed) { + setclassname(n); + Append(classlist, n); + } + } + + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + + if (blessed) { + have_constructor = 0; + have_operators = 0; + have_destructor = 0; + have_data_members = 0; + operators = NewHash(); + + class_name = Getattr(n, "sym:name"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + /* Use the fully qualified name of the Perl class */ + if (!compat) { + fullclassname = NewStringf("%s::%s", namespace_module, class_name); + } else { + fullclassname = NewString(class_name); + } + real_classname = Getattr(n, "name"); + pcode = NewString(""); + // blessedmembers = NewString(""); + } + + /* Emit all of the members */ + Language::classHandler(n); + + + /* Finish the rest of the class */ + if (blessed) { + /* Generate a client-data entry */ + SwigType *ct = NewStringf("p.%s", real_classname); + Printv(f_init, "SWIG_TypeClientData(SWIGTYPE", SwigType_manglestr(ct), ", (void*) \"", fullclassname, "\");\n", NIL); + SwigType_remember(ct); + Delete(ct); + + Printv(pm, "\n############# Class : ", fullclassname, " ##############\n", "\npackage ", fullclassname, ";\n", NIL); + + if (have_operators) { + Printf(pm, "use overload\n"); + Iterator ki; + for (ki = First(operators); ki.key; ki = Next(ki)) { + char *name = Char(ki.key); + // fprintf(stderr,"found name: <%s>\n", name); + if (strstr(name, "__eq__")) { + Printv(pm, tab4, "\"==\" => sub { $_[0]->__eq__($_[1])},\n",NIL); + } else if (strstr(name, "__ne__")) { + Printv(pm, tab4, "\"!=\" => sub { $_[0]->__ne__($_[1])},\n",NIL); + // there are no tests for this in operator_overload_runme.pl + // it is likely to be broken + // } else if (strstr(name, "__assign__")) { + // Printv(pm, tab4, "\"=\" => sub { $_[0]->__assign__($_[1])},\n",NIL); + } else if (strstr(name, "__str__")) { + Printv(pm, tab4, "'\"\"' => sub { $_[0]->__str__()},\n",NIL); + } else if (strstr(name, "__plusplus__")) { + Printv(pm, tab4, "\"++\" => sub { $_[0]->__plusplus__()},\n",NIL); + } else if (strstr(name, "__minmin__")) { + Printv(pm, tab4, "\"--\" => sub { $_[0]->__minmin__()},\n",NIL); + } else if (strstr(name, "__add__")) { + Printv(pm, tab4, "\"+\" => sub { $_[0]->__add__($_[1])},\n",NIL); + } else if (strstr(name, "__sub__")) { + Printv(pm, tab4, "\"-\" => sub { if( not $_[2] ) { $_[0]->__sub__($_[1]) }\n",NIL); + Printv(pm, tab8, "elsif( $_[0]->can('__rsub__') ) { $_[0]->__rsub__($_[1]) }\n",NIL); + Printv(pm, tab8, "else { die(\"reverse subtraction not supported\") }\n",NIL); + Printv(pm, tab8, "},\n",NIL); + } else if (strstr(name, "__mul__")) { + Printv(pm, tab4, "\"*\" => sub { $_[0]->__mul__($_[1])},\n",NIL); + } else if (strstr(name, "__div__")) { + Printv(pm, tab4, "\"/\" => sub { $_[0]->__div__($_[1])},\n",NIL); + } else if (strstr(name, "__mod__")) { + Printv(pm, tab4, "\"%\" => sub { $_[0]->__mod__($_[1])},\n",NIL); + // there are no tests for this in operator_overload_runme.pl + // it is likely to be broken + // } else if (strstr(name, "__and__")) { + // Printv(pm, tab4, "\"&\" => sub { $_[0]->__and__($_[1])},\n",NIL); + + // there are no tests for this in operator_overload_runme.pl + // it is likely to be broken + // } else if (strstr(name, "__or__")) { + // Printv(pm, tab4, "\"|\" => sub { $_[0]->__or__($_[1])},\n",NIL); + } else if (strstr(name, "__gt__")) { + Printv(pm, tab4, "\">\" => sub { $_[0]->__gt__($_[1])},\n",NIL); + } else if (strstr(name, "__ge__")) { + Printv(pm, tab4, "\">=\" => sub { $_[0]->__ge__($_[1])},\n",NIL); + } else if (strstr(name, "__not__")) { + Printv(pm, tab4, "\"!\" => sub { $_[0]->__not__()},\n",NIL); + } else if (strstr(name, "__lt__")) { + Printv(pm, tab4, "\"<\" => sub { $_[0]->__lt__($_[1])},\n",NIL); + } else if (strstr(name, "__le__")) { + Printv(pm, tab4, "\"<=\" => sub { $_[0]->__le__($_[1])},\n",NIL); + } else if (strstr(name, "__pluseq__")) { + Printv(pm, tab4, "\"+=\" => sub { $_[0]->__pluseq__($_[1])},\n",NIL); + } else if (strstr(name, "__mineq__")) { + Printv(pm, tab4, "\"-=\" => sub { $_[0]->__mineq__($_[1])},\n",NIL); + } else if (strstr(name, "__neg__")) { + Printv(pm, tab4, "\"neg\" => sub { $_[0]->__neg__()},\n",NIL); + } else { + fprintf(stderr,"Unknown operator: %s\n", name); + } + } + Printv(pm, tab4, + "\"=\" => sub { my $class = ref($_[0]); $class->new($_[0]) },\n", NIL); + Printv(pm, tab4, "\"fallback\" => 1;\n", NIL); + } + // make use strict happy + Printv(pm, "use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);\n", NIL); + + /* If we are inheriting from a base class, set that up */ + + Printv(pm, "@ISA = qw(", NIL); + + /* Handle inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "perl5:proxy"); + if (!bname) { + b = Next(b); + continue; + } + Printv(pm, " ", bname, NIL); + b = Next(b); + } + } + + /* Module comes last */ + if (!compat || Cmp(namespace_module, fullclassname)) { + Printv(pm, " ", namespace_module, NIL); + } + + Printf(pm, " );\n"); + + /* Dump out a hash table containing the pointers that we own */ + Printf(pm, "%%OWNER = ();\n"); + if (have_data_members || have_destructor) + Printf(pm, "%%ITERATORS = ();\n"); + + /* Dump out the package methods */ + + Printv(pm, pcode, NIL); + Delete(pcode); + + /* Output methods for managing ownership */ + + Printv(pm, + "sub DISOWN {\n", + tab4, "my $self = shift;\n", + tab4, "my $ptr = tied(%$self);\n", + tab4, "delete $OWNER{$ptr};\n", + "}\n\n", "sub ACQUIRE {\n", tab4, "my $self = shift;\n", tab4, "my $ptr = tied(%$self);\n", tab4, "$OWNER{$ptr} = 1;\n", "}\n\n", NIL); + + /* Only output the following methods if a class has member data */ + + Delete(operators); + operators = 0; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + + member_func = 1; + Language::memberfunctionHandler(n); + member_func = 0; + + if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + + if (Strstr(symname, "__eq__")) { + DohSetInt(operators, "__eq__", 1); + have_operators = 1; + } else if (Strstr(symname, "__ne__")) { + DohSetInt(operators, "__ne__", 1); + have_operators = 1; + } else if (Strstr(symname, "__assign__")) { + DohSetInt(operators, "__assign__", 1); + have_operators = 1; + } else if (Strstr(symname, "__str__")) { + DohSetInt(operators, "__str__", 1); + have_operators = 1; + } else if (Strstr(symname, "__add__")) { + DohSetInt(operators, "__add__", 1); + have_operators = 1; + } else if (Strstr(symname, "__sub__")) { + DohSetInt(operators, "__sub__", 1); + have_operators = 1; + } else if (Strstr(symname, "__mul__")) { + DohSetInt(operators, "__mul__", 1); + have_operators = 1; + } else if (Strstr(symname, "__div__")) { + DohSetInt(operators, "__div__", 1); + have_operators = 1; + } else if (Strstr(symname, "__mod__")) { + DohSetInt(operators, "__mod__", 1); + have_operators = 1; + } else if (Strstr(symname, "__and__")) { + DohSetInt(operators, "__and__", 1); + have_operators = 1; + } else if (Strstr(symname, "__or__")) { + DohSetInt(operators, "__or__", 1); + have_operators = 1; + } else if (Strstr(symname, "__not__")) { + DohSetInt(operators, "__not__", 1); + have_operators = 1; + } else if (Strstr(symname, "__gt__")) { + DohSetInt(operators, "__gt__", 1); + have_operators = 1; + } else if (Strstr(symname, "__ge__")) { + DohSetInt(operators, "__ge__", 1); + have_operators = 1; + } else if (Strstr(symname, "__lt__")) { + DohSetInt(operators, "__lt__", 1); + have_operators = 1; + } else if (Strstr(symname, "__le__")) { + DohSetInt(operators, "__le__", 1); + have_operators = 1; + } else if (Strstr(symname, "__neg__")) { + DohSetInt(operators, "__neg__", 1); + have_operators = 1; + } else if (Strstr(symname, "__plusplus__")) { + DohSetInt(operators, "__plusplus__", 1); + have_operators = 1; + } else if (Strstr(symname, "__minmin__")) { + DohSetInt(operators, "__minmin__", 1); + have_operators = 1; + } else if (Strstr(symname, "__mineq__")) { + DohSetInt(operators, "__mineq__", 1); + have_operators = 1; + } else if (Strstr(symname, "__pluseq__")) { + DohSetInt(operators, "__pluseq__", 1); + have_operators = 1; + } + + if (Getattr(n, "feature:shadow")) { + String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); + String *plaction = NewStringf("%s::%s", cmodule, Swig_name_member(class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(class_name, symname), ";\n", NIL); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * + * Adds an instance member. + * ----------------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + + String *symname = Getattr(n, "sym:name"); + /* SwigType *t = Getattr(n,"type"); */ + + /* Emit a pair of get/set functions for the variable */ + + member_func = 1; + Language::membervariableHandler(n); + member_func = 0; + + if (blessed) { + + Printv(pcode, "*swig_", symname, "_get = *", cmodule, "::", Swig_name_get(Swig_name_member(class_name, symname)), ";\n", NIL); + Printv(pcode, "*swig_", symname, "_set = *", cmodule, "::", Swig_name_set(Swig_name_member(class_name, symname)), ";\n", NIL); + + /* Now we need to generate a little Perl code for this */ + + /* if (is_shadow(t)) { + + *//* This is a Perl object that we have already seen. Add an + entry to the members list *//* + Printv(blessedmembers, + tab4, symname, " => '", is_shadow(t), "',\n", + NIL); + + } + */ + } + have_data_members++; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorDeclaration() + * + * Emits a blessed constructor for our class. In addition to our construct + * we manage a Perl hash table containing all of the pointers created by + * the constructor. This prevents us from accidentally trying to free + * something that wasn't necessarily allocated by malloc or new + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + + String *symname = Getattr(n, "sym:name"); + + member_func = 1; + Language::constructorHandler(n); + + if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + if (Getattr(n, "feature:shadow")) { + String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); + String *plaction = NewStringf("%s::%s", module, Swig_name_member(class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + if ((Cmp(symname, class_name) == 0)) { + /* Emit a blessed constructor */ + Printf(pcode, "sub new {\n"); + } else { + /* Constructor doesn't match classname so we'll just use the normal name */ + Printv(pcode, "sub ", Swig_name_construct(symname), " {\n", NIL); + } + + Printv(pcode, + tab4, "my $pkg = shift;\n", + tab4, "my $self = ", cmodule, "::", Swig_name_construct(symname), "(@_);\n", tab4, "bless $self, $pkg if defined($self);\n", "}\n\n", NIL); + + have_constructor = 1; + } + } + member_func = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + member_func = 1; + Language::destructorHandler(n); + if (blessed) { + if (Getattr(n, "feature:shadow")) { + String *plcode = perlcode(Getattr(n, "feature:shadow"), 0); + String *plaction = NewStringf("%s::%s", module, Swig_name_member(class_name, symname)); + Replaceall(plcode, "$action", plaction); + Delete(plaction); + Printv(pcode, plcode, NIL); + } else { + Printv(pcode, + "sub DESTROY {\n", + tab4, "return unless $_[0]->isa('HASH');\n", + tab4, "my $self = tied(%{$_[0]});\n", + tab4, "return unless defined $self;\n", + tab4, "delete $ITERATORS{$self};\n", + tab4, "if (exists $OWNER{$self}) {\n", + tab8, cmodule, "::", Swig_name_destroy(symname), "($self);\n", tab8, "delete $OWNER{$self};\n", tab4, "}\n}\n\n", NIL); + have_destructor = 1; + } + } + member_func = 0; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + member_func = 1; + Language::staticmemberfunctionHandler(n); + member_func = 0; + if ((blessed) && (!Getattr(n, "sym:nextSibling"))) { + String *symname = Getattr(n, "sym:name"); + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(class_name, symname), ";\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + Language::staticmembervariableHandler(n); + if (blessed) { + String *symname = Getattr(n, "sym:name"); + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(class_name, symname), ";\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldblessed = blessed; + + /* Create a normal constant */ + blessed = 0; + Language::memberconstantHandler(n); + blessed = oldblessed; + + if (blessed) { + Printv(pcode, "*", symname, " = *", cmodule, "::", Swig_name_member(class_name, symname), ";\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * pragma() + * + * Pragma directive. + * + * %pragma(perl5) code="String" # Includes a string in the .pm file + * %pragma(perl5) include="file.pl" # Includes a file in the .pm file + * ------------------------------------------------------------ */ + + virtual int pragmaDirective(Node *n) { + String *lang; + String *code; + String *value; + if (!ImportMode) { + lang = Getattr(n, "lang"); + code = Getattr(n, "name"); + value = Getattr(n, "value"); + if (Strcmp(lang, "perl5") == 0) { + if (Strcmp(code, "code") == 0) { + /* Dump the value string into the .pm file */ + if (value) { + Printf(pragma_include, "%s\n", value); + } + } else if (Strcmp(code, "include") == 0) { + /* Include a file into the .pm file */ + if (value) { + FILE *f = Swig_include_open(value); + if (!f) { + Printf(stderr, "%s : Line %d. Unable to locate file %s\n", input_file, line_number, value); + } else { + char buffer[4096]; + while (fgets(buffer, 4095, f)) { + Printf(pragma_include, "%s", buffer); + } + } + fclose(f); + } + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + } + } + return Language::pragmaDirective(n); + } + + /* ------------------------------------------------------------ + * perlcode() - Output perlcode code into the shadow file + * ------------------------------------------------------------ */ + + String *perlcode(String *code, const String *indent) { + String *out = NewString(""); + String *temp; + char *t; + if (!indent) + indent = ""; + + temp = NewString(code); + + t = Char(temp); + if (*t == '{') { + Delitem(temp, 0); + Delitem(temp, DOH_END); + } + + /* Split the input text into lines */ + List *clist = DohSplitLines(temp); + Delete(temp); + int initial = 0; + String *s = 0; + Iterator si; + /* Get the initial indentation */ + + for (si = First(clist); si.item; si = Next(si)) { + s = si.item; + if (Len(s)) { + char *c = Char(s); + while (*c) { + if (!isspace(*c)) + break; + initial++; + c++; + } + if (*c && !isspace(*c)) + break; + else { + initial = 0; + } + } + } + while (si.item) { + s = si.item; + if (Len(s) > initial) { + char *c = Char(s); + c += initial; + Printv(out, indent, c, "\n", NIL); + } else { + Printv(out, "\n", NIL); + } + si = Next(si); + } + Delete(clist); + return out; + } + + /* ------------------------------------------------------------ + * insertDirective() + * + * Hook for %insert directive. + * ------------------------------------------------------------ */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + + if ((!ImportMode) && (Cmp(section, "perl") == 0)) { + Printv(additional_perl_code, code, NIL); + } else { + Language::insertDirective(n); + } + return SWIG_OK; + } + + String *runtimeCode() { + String *s = NewString(""); + String *shead = Swig_include_sys("perlhead.swg"); + if (!shead) { + Printf(stderr, "*** Unable to open 'perlhead.swg'\n"); + } else { + Append(s, shead); + Delete(shead); + } + String *serrors = Swig_include_sys("perlerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'perlerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *srun = Swig_include_sys("perlrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'perlrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigperlrun.h"); + } +}; + +/* ----------------------------------------------------------------------------- + * swig_perl5() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_perl5() { + return new PERL5(); +} +extern "C" Language *swig_perl5(void) { + return new_swig_perl5(); +} diff --git a/Source/Modules/php.cxx b/Source/Modules/php.cxx new file mode 100644 index 0000000..a0c9e24 --- /dev/null +++ b/Source/Modules/php.cxx @@ -0,0 +1,2739 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * php.cxx + * + * PHP language module for SWIG. + * ----------------------------------------------------------------------------- + */ + +/* FIXME: PHP5 OO wrapping TODO list: + * + * Medium term: + * + * Handle default parameters on overloaded methods in PHP where possible. + * (Mostly done - just need to handle cases of overloaded methods with + * default parameters...) + * This is an optimisation - we could handle this case using a PHP + * default value, but currently we treat it as we would for a default + * value which is a compound C++ expression (i.e. as if we had a + * method with two overloaded forms instead of a single method with + * a default parameter value). + * + * Long term: + * + * Sort out locale-dependent behaviour of strtod() - it's harmless unless + * SWIG ever sets the locale and DOH/base.c calls atof, so we're probably + * OK currently at least. + */ + +/* + * TODO: Replace remaining stderr messages with Swig_error or Swig_warning + * (may need to add more WARN_PHP_xxx codes...) + */ + +char cvsroot_php_cxx[] = "$Id: php.cxx 11637 2009-08-18 16:23:23Z vmiklos $"; + +#include "swigmod.h" + +#include <ctype.h> +#include <errno.h> + +static const char *usage = (char *) "\ +PHP Options (available with -php)\n\ + -cppext - cpp file extension (default to .cpp)\n\ + -noproxy - Don't generate proxy classes.\n\ + -prefix <prefix> - Prepend <prefix> to all class names in PHP wrappers\n\ +\n"; + +/* The original class wrappers for PHP stored the pointer to the C++ class in + * the object property _cPtr. If we use the same name for the member variable + * which we put the pointer to the C++ class in, then the flat function + * wrappers will automatically pull it out without any changes being required. + * FIXME: Isn't using a leading underscore a bit suspect here? + */ +#define SWIG_PTR "_cPtr" + +/* This is the name of the hash where the variables existing only in PHP + * classes are stored. + */ +#define SWIG_DATA "_pData" + +static int constructors = 0; +static String *NOTCLASS = NewString("Not a class"); +static Node *classnode = 0; +static String *module = 0; +static String *cap_module = 0; +static String *prefix = 0; + +static String *shadow_classname = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_h = 0; +static File *f_phpcode = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static String *phpfilename = 0; + +static String *s_header; +static String *s_wrappers; +static String *s_init; +static String *r_init; // RINIT user code +static String *s_shutdown; // MSHUTDOWN user code +static String *r_shutdown; // RSHUTDOWN user code +static String *s_vinit; // varinit initialization code. +static String *s_vdecl; +static String *s_cinit; // consttab initialization code. +static String *s_oinit; +static String *s_entry; +static String *cs_entry; +static String *all_cs_entry; +static String *pragma_incl; +static String *pragma_code; +static String *pragma_phpinfo; +static String *s_oowrappers; +static String *s_fakeoowrappers; +static String *s_phpclasses; + +/* Variables for using PHP classes */ +static Node *current_class = 0; + +static Hash *shadow_get_vars; +static Hash *shadow_set_vars; +static Hash *zend_types = 0; + +static int shadow = 1; + +static bool class_has_ctor = false; +static String *wrapping_member_constant = NULL; + +// These static variables are used to pass some state from Handlers into functionWrapper +static enum { + standard = 0, + memberfn, + staticmemberfn, + membervar, + staticmembervar, + constructor, + directorconstructor +} wrapperType = standard; + +extern "C" { + static void (*r_prevtracefunc) (SwigType *t, String *mangled, String *clientdata) = 0; +} + +static void SwigPHP_emit_resource_registrations() { + Iterator ki; + + if (!zend_types) + return; + + ki = First(zend_types); + if (ki.key) + Printf(s_oinit, "\n/* Register resource destructors for pointer types */\n"); + while (ki.key) { + DOH *key = ki.key; + Node *class_node = ki.item; + String *human_name = key; + + // Write out destructor function header + Printf(s_wrappers, "static ZEND_RSRC_DTOR_FUNC(_wrap_destroy%s) {\n", key); + + // write out body + if (class_node != NOTCLASS) { + String *destructor = Getattr(class_node, "destructor"); + human_name = Getattr(class_node, "sym:name"); + if (!human_name) + human_name = Getattr(class_node, "name"); + // Do we have a known destructor for this type? + if (destructor) { + Printf(s_wrappers, " %s(rsrc, SWIGTYPE%s->name TSRMLS_CC);\n", destructor, key); + } else { + Printf(s_wrappers, " /* No destructor for class %s */\n", human_name); + Printf(s_wrappers, " efree(rsrc->ptr);\n"); + } + } else { + Printf(s_wrappers, " /* No destructor for simple type %s */\n", key); + Printf(s_wrappers, " efree(rsrc->ptr);\n"); + } + + // close function + Printf(s_wrappers, "}\n"); + + // declare le_swig_<mangled> to store php registration + Printf(s_vdecl, "static int le_swig_%s=0; /* handle for %s */\n", key, human_name); + + // register with php + Printf(s_oinit, "le_swig_%s=zend_register_list_destructors_ex" + "(_wrap_destroy%s,NULL,(char *)(SWIGTYPE%s->name),module_number);\n", key, key, key); + + // store php type in class struct + Printf(s_oinit, "SWIG_TypeClientData(SWIGTYPE%s,&le_swig_%s);\n", key, key); + + ki = Next(ki); + } +} + +class PHP : public Language { +public: + PHP() { + director_language = 1; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + SWIG_library_directory("php"); + SWIG_config_cppext("cpp"); + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-cppext") == 0) { + if (argv[i + 1]) { + SWIG_config_cppext(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-noshadow") == 0) || (strcmp(argv[i], "-noproxy") == 0)) { + shadow = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } else if (strcmp(argv[i], "-make") == 0 || + strcmp(argv[i], "-withc") == 0 || + strcmp(argv[i], "-withcxx") == 0) { + Printf(stderr, "*** %s is no longer supported.\n", argv[i]); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-phpfull") == 0 || + strcmp(argv[i], "-withlibs") == 0 || + strcmp(argv[i], "-withincs") == 0) { + Printf(stderr, "*** %s is no longer supported.\n*** We recommend building as a dynamically loadable module.\n", argv[i]); + SWIG_exit(EXIT_FAILURE); + } else if (strcmp(argv[i], "-dlname") == 0) { + Printf(stderr, "*** -dlname is no longer supported.\n*** If you want to change the module name, use -module instead.\n"); + SWIG_exit(EXIT_FAILURE); + } + } + + Preprocessor_define("SWIGPHP 1", 0); + // SWIGPHP5 is deprecated, and no longer documented. + Preprocessor_define("SWIGPHP5 1", 0); + SWIG_typemap_lang("php"); + SWIG_config_file("php.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + String *filen; + String *s_type; + + /* Check if directors are enabled for this module. */ + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options && Getattr(options, "directors")) { + allow_directors(); + } + } + + /* Set comparison with null for ConstructorToFunction */ + setSubclassInstanceCheck(NewString("$arg->type != IS_NULL")); + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + /* main output file */ + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewStringEmpty(); + + /* sections of the output file */ + s_init = NewString("/* init section */\n"); + r_init = NewString("/* rinit section */\n"); + s_shutdown = NewString("/* shutdown section */\n"); + r_shutdown = NewString("/* rshutdown section */\n"); + s_header = NewString("/* header section */\n"); + s_wrappers = NewString("/* wrapper section */\n"); + s_type = NewStringEmpty(); + /* subsections of the init section */ + s_vinit = NewString("/* vinit subsection */\n"); + s_vdecl = NewString("/* vdecl subsection */\n"); + s_cinit = NewString("/* cinit subsection */\n"); + s_oinit = NewString("/* oinit subsection */\n"); + pragma_phpinfo = NewStringEmpty(); + s_phpclasses = NewString("/* PHP Proxy Classes */\n"); + f_directors_h = NewStringEmpty(); + f_directors = NewStringEmpty(); + + if (directorsEnabled()) { + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", s_init); + Swig_register_filebyname("rinit", r_init); + Swig_register_filebyname("shutdown", s_shutdown); + Swig_register_filebyname("rshutdown", r_shutdown); + Swig_register_filebyname("header", s_header); + Swig_register_filebyname("wrapper", s_wrappers); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGPHP\n"); + Printf(f_runtime, "\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + /* Set the module name */ + module = Copy(Getattr(n, "name")); + cap_module = NewStringf("%(upper)s", module); + if (!prefix) + prefix = NewStringEmpty(); + + if (directorsEnabled()) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", cap_module); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", cap_module); + + Printf(f_directors, "\n#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + /* PHP module file */ + filen = NewStringEmpty(); + Printv(filen, SWIG_output_directory(), module, ".php", NIL); + phpfilename = NewString(filen); + + f_phpcode = NewFile(filen, "w", SWIG_output_files()); + if (!f_phpcode) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_phpcode, "<?php\n\n"); + + Swig_banner(f_phpcode); + + Printf(f_phpcode, "\n"); + Printf(f_phpcode, "// Try to load our extension if it's not already loaded.\n"); + Printf(f_phpcode, "if (!extension_loaded('%s')) {\n", module); + Printf(f_phpcode, " if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {\n"); + Printf(f_phpcode, " if (!dl('php_%s.dll')) return;\n", module); + Printf(f_phpcode, " } else {\n"); + Printf(f_phpcode, " // PHP_SHLIB_SUFFIX gives 'dylib' on MacOS X but modules are 'so'.\n"); + Printf(f_phpcode, " if (PHP_SHLIB_SUFFIX === 'dylib') {\n"); + Printf(f_phpcode, " if (!dl('%s.so')) return;\n", module); + Printf(f_phpcode, " } else {\n"); + Printf(f_phpcode, " if (!dl('%s.'.PHP_SHLIB_SUFFIX)) return;\n", module); + Printf(f_phpcode, " }\n"); + Printf(f_phpcode, " }\n"); + Printf(f_phpcode, "}\n\n"); + + /* sub-sections of the php file */ + pragma_code = NewStringEmpty(); + pragma_incl = NewStringEmpty(); + + /* Initialize the rest of the module */ + + Printf(s_oinit, "ZEND_INIT_MODULE_GLOBALS(%s, %s_init_globals, %s_destroy_globals);\n", module, module, module); + + /* start the header section */ + Printf(s_header, "ZEND_BEGIN_MODULE_GLOBALS(%s)\n", module); + Printf(s_header, "const char *error_msg;\n"); + Printf(s_header, "int error_code;\n"); + Printf(s_header, "ZEND_END_MODULE_GLOBALS(%s)\n", module); + Printf(s_header, "ZEND_DECLARE_MODULE_GLOBALS(%s)\n", module); + Printf(s_header, "#ifdef ZTS\n"); + Printf(s_header, "#define SWIG_ErrorMsg() TSRMG(%s_globals_id, zend_%s_globals *, error_msg )\n", module, module); + Printf(s_header, "#define SWIG_ErrorCode() TSRMG(%s_globals_id, zend_%s_globals *, error_code )\n", module, module); + Printf(s_header, "#else\n"); + Printf(s_header, "#define SWIG_ErrorMsg() (%s_globals.error_msg)\n", module); + Printf(s_header, "#define SWIG_ErrorCode() (%s_globals.error_code)\n", module); + Printf(s_header, "#endif\n\n"); + + Printf(s_header, "static void %s_init_globals(zend_%s_globals *globals ) {\n", module, module); + Printf(s_header, " globals->error_msg = default_error_msg;\n"); + Printf(s_header, " globals->error_code = default_error_code;\n"); + Printf(s_header, "}\n"); + + Printf(s_header, "static void %s_destroy_globals(zend_%s_globals * globals) { (void)globals; }\n", module, module); + + Printf(s_header, "\n"); + Printf(s_header, "static void SWIG_ResetError() {\n"); + Printf(s_header, " TSRMLS_FETCH();\n"); + Printf(s_header, " SWIG_ErrorMsg() = default_error_msg;\n"); + Printf(s_header, " SWIG_ErrorCode() = default_error_code;\n"); + Printf(s_header, "}\n"); + + Append(s_header, "\n"); + Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_alter_newobject) {\n", module); + Append(s_header, " zval **args[2];\n"); + Append(s_header, " swig_object_wrapper *value;\n"); + Append(s_header, " int type;\n"); + Append(s_header, " int thisown;\n"); + Append(s_header, "\n"); + Append(s_header, " SWIG_ResetError();\n"); + Append(s_header, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n"); + Append(s_header, " WRONG_PARAM_COUNT;\n"); + Append(s_header, " }\n"); + Append(s_header, "\n"); + Append(s_header, " value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n"); + Append(s_header, " value->newobject = zval_is_true(*args[1]);\n"); + Append(s_header, "\n"); + Append(s_header, " return;\n"); + Append(s_header, "}\n"); + Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_get_newobject) {\n", module); + Append(s_header, " zval **args[1];\n"); + Append(s_header, " swig_object_wrapper *value;\n"); + Append(s_header, " int type;\n"); + Append(s_header, "\n"); + Append(s_header, " SWIG_ResetError();\n"); + Append(s_header, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n"); + Append(s_header, " WRONG_PARAM_COUNT;\n"); + Append(s_header, " }\n"); + Append(s_header, "\n"); + Append(s_header, " value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n"); + Append(s_header, " RETVAL_LONG(value->newobject);\n"); + Append(s_header, "\n"); + Append(s_header, " return;\n"); + Append(s_header, "}\n"); + + Printf(s_header, "#define SWIG_name \"%s\"\n", module); + /* Printf(s_header,"#ifdef HAVE_CONFIG_H\n"); + Printf(s_header,"#include \"config.h\"\n"); + Printf(s_header,"#endif\n\n"); + */ + Printf(s_header, "#ifdef __cplusplus\n"); + Printf(s_header, "extern \"C\" {\n"); + Printf(s_header, "#endif\n"); + Printf(s_header, "#include \"php.h\"\n"); + Printf(s_header, "#include \"php_ini.h\"\n"); + Printf(s_header, "#include \"ext/standard/info.h\"\n"); + Printf(s_header, "#include \"php_%s.h\"\n", module); + Printf(s_header, "#ifdef __cplusplus\n"); + Printf(s_header, "}\n"); + Printf(s_header, "#endif\n\n"); + + if (directorsEnabled()) { + // Insert director runtime + Swig_insert_file("director.swg", s_header); + } + + /* Create the .h file too */ + filen = NewStringEmpty(); + Printv(filen, SWIG_output_directory(), "php_", module, ".h", NIL); + f_h = NewFile(filen, "w", SWIG_output_files()); + if (!f_h) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(f_h); + + Printf(f_h, "\n"); + Printf(f_h, "#ifndef PHP_%s_H\n", cap_module); + Printf(f_h, "#define PHP_%s_H\n\n", cap_module); + Printf(f_h, "extern zend_module_entry %s_module_entry;\n", module); + Printf(f_h, "#define phpext_%s_ptr &%s_module_entry\n\n", module, module); + Printf(f_h, "#ifdef PHP_WIN32\n"); + Printf(f_h, "# define PHP_%s_API __declspec(dllexport)\n", cap_module); + Printf(f_h, "#else\n"); + Printf(f_h, "# define PHP_%s_API\n", cap_module); + Printf(f_h, "#endif\n\n"); + Printf(f_h, "#ifdef ZTS\n"); + Printf(f_h, "#include \"TSRM.h\"\n"); + Printf(f_h, "#endif\n\n"); + Printf(f_h, "PHP_MINIT_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_MSHUTDOWN_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_RINIT_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_RSHUTDOWN_FUNCTION(%s);\n", module); + Printf(f_h, "PHP_MINFO_FUNCTION(%s);\n\n", module); + + /* start the function entry section */ + s_entry = NewString("/* entry subsection */\n"); + + /* holds all the per-class function entry sections */ + all_cs_entry = NewString("/* class entry subsection */\n"); + cs_entry = NULL; + + Printf(s_entry, "/* Every non-class user visible function must have an entry here */\n"); + Printf(s_entry, "static zend_function_entry %s_functions[] = {\n", module); + + /* start the init section */ + Append(s_init, "#if ZEND_MODULE_API_NO <= 20090626\n"); + Append(s_init, "#undef ZEND_MODULE_BUILD_ID\n"); + Append(s_init, "#define ZEND_MODULE_BUILD_ID (char*)\"API\" ZEND_TOSTR(ZEND_MODULE_API_NO) ZEND_BUILD_TS ZEND_BUILD_DEBUG ZEND_BUILD_SYSTEM ZEND_BUILD_EXTRA\n"); + Append(s_init, "#endif\n"); + Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n" "#if ZEND_MODULE_API_NO > 20010900\n" " STANDARD_MODULE_HEADER,\n" "#endif\n", NIL); + Printf(s_init, " (char*)\"%s\",\n", module); + Printf(s_init, " %s_functions,\n", module); + Printf(s_init, " PHP_MINIT(%s),\n", module); + Printf(s_init, " PHP_MSHUTDOWN(%s),\n", module); + Printf(s_init, " PHP_RINIT(%s),\n", module); + Printf(s_init, " PHP_RSHUTDOWN(%s),\n", module); + Printf(s_init, " PHP_MINFO(%s),\n", module); + Printf(s_init, "#if ZEND_MODULE_API_NO > 20010900\n"); + Printf(s_init, " NO_VERSION_YET,\n"); + Printf(s_init, "#endif\n"); + Printf(s_init, " STANDARD_MODULE_PROPERTIES\n"); + Printf(s_init, "};\n"); + Printf(s_init, "zend_module_entry* SWIG_module_entry = &%s_module_entry;\n\n", module); + + Printf(s_init, "#ifdef __cplusplus\n"); + Printf(s_init, "extern \"C\" {\n"); + Printf(s_init, "#endif\n"); + // We want to write "SWIGEXPORT ZEND_GET_MODULE(%s)" but ZEND_GET_MODULE + // in PHP5 has "extern "C" { ... }" around it so we can't do that. + Printf(s_init, "SWIGEXPORT zend_module_entry *get_module(void) { return &%s_module_entry; }\n", module); + Printf(s_init, "#ifdef __cplusplus\n"); + Printf(s_init, "}\n"); + Printf(s_init, "#endif\n\n"); + + /* We have to register the constants before they are (possibly) used + * by the pointer typemaps. This all needs re-arranging really as + * things are being called in the wrong order + */ + Printf(s_init, "#define SWIG_php_minit PHP_MINIT_FUNCTION(%s)\n", module); + + /* Emit all of the code */ + Language::top(n); + + SwigPHP_emit_resource_registrations(); + // Printv(s_init,s_resourcetypes,NIL); + /* We need this after all classes written out by ::top */ + Printf(s_oinit, "CG(active_class_entry) = NULL;\n"); + Printf(s_oinit, "/* end oinit subsection */\n"); + Printf(s_init, "%s\n", s_oinit); + + /* Constants generated during top call */ + Printf(s_cinit, "/* end cinit subsection */\n"); + Printf(s_init, "%s\n", s_cinit); + Clear(s_cinit); + Delete(s_cinit); + + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + + // Now do REQUEST init which holds any user specified %rinit, and also vinit + Printf(s_init, "PHP_RINIT_FUNCTION(%s)\n{\n", module); + Printf(s_init, "%s\n", r_init); + + /* finish our init section which will have been used by class wrappers */ + Printf(s_vinit, "/* end vinit subsection */\n"); + Printf(s_init, "%s\n", s_vinit); + Clear(s_vinit); + Delete(s_vinit); + + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + + Printv(s_init, "PHP_MSHUTDOWN_FUNCTION(", module, ")\n" + "{\n", + s_shutdown, + "#ifdef ZTS\n" + " ts_free_id(", module, "_globals_id);\n" + "#endif\n" + " return SUCCESS;\n" + "}\n\n", NIL); + + Printf(s_init, "PHP_RSHUTDOWN_FUNCTION(%s)\n{\n", module); + Printf(s_init, "%s\n", r_shutdown); + Printf(s_init, " return SUCCESS;\n"); + Printf(s_init, "}\n\n"); + + Printf(s_init, "PHP_MINFO_FUNCTION(%s)\n{\n", module); + Printf(s_init, "%s", pragma_phpinfo); + Printf(s_init, "}\n"); + Printf(s_init, "/* end init section */\n"); + + Printf(f_h, "#endif /* PHP_%s_H */\n", cap_module); + + Close(f_h); + + String *type_table = NewStringEmpty(); + SwigType_emit_type_table(f_runtime, type_table); + Printf(s_header, "%s", type_table); + Delete(type_table); + + /* Oh dear, more things being called in the wrong order. This whole + * function really needs totally redoing. + */ + + if (directorsEnabled()) { + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + Close(f_runtime_h); + } + + Printf(s_header, "/* end header section */\n"); + Printf(s_wrappers, "/* end wrapper section */\n"); + Printf(s_vdecl, "/* end vdecl subsection */\n"); + + Dump(f_runtime, f_begin); + Printv(f_begin, s_header, NIL); + if (directorsEnabled()) { + Dump(f_directors, f_begin); + } + Printv(f_begin, s_vdecl, s_wrappers, NIL); + Printv(f_begin, all_cs_entry, "\n\n", s_entry, + " SWIG_ZEND_NAMED_FE(swig_", module, "_alter_newobject,_wrap_swig_", module, "_alter_newobject,NULL)\n" + " SWIG_ZEND_NAMED_FE(swig_", module, "_get_newobject,_wrap_swig_", module, "_get_newobject,NULL)\n" + "{NULL, NULL, NULL}\n};\n\n", NIL); + Printv(f_begin, s_init, NIL); + Delete(s_header); + Delete(s_wrappers); + Delete(s_init); + Delete(s_vdecl); + Delete(all_cs_entry); + Delete(s_entry); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + Printf(f_phpcode, "%s\n%s\n", pragma_incl, pragma_code); + if (s_fakeoowrappers) { + Printf(f_phpcode, "abstract class %s {", Len(prefix) ? prefix : module); + Printf(f_phpcode, "%s", s_fakeoowrappers); + Printf(f_phpcode, "}\n\n"); + Delete(s_fakeoowrappers); + s_fakeoowrappers = NULL; + } + Printf(f_phpcode, "%s\n?>\n", s_phpclasses); + Close(f_phpcode); + + return SWIG_OK; + } + + /* Just need to append function names to function table to register with PHP. */ + void create_command(String *cname, String *iname) { + // This is for the single main zend_function_entry record + Printf(f_h, "ZEND_NAMED_FUNCTION(%s);\n", iname); + String * s = cs_entry; + if (!s) s = s_entry; + Printf(s, " SWIG_ZEND_NAMED_FE(%(lower)s,%s,NULL)\n", cname, iname); + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewStringEmpty(); + if (Swig_directorclass(n) && wrapperType == directorconstructor) { + /* We have an extra 'this' parameter. */ + SetFlag(n, "wrap:this"); + } + String *dispatch = Swig_overload_dispatch(n, "return %s(INTERNAL_FUNCTION_PARAM_PASSTHRU);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + create_command(symname, wname); + Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + + Printf(tmp, "zval **argv[%d]", maxargs); + Wrapper_add_local(f, "argv", tmp); + + Printf(f->code, "argc = ZEND_NUM_ARGS();\n"); + + Printf(f->code, "zend_get_parameters_array_ex(argc,argv);\n"); + + Replaceall(dispatch, "$args", "self,args"); + + Printv(f->code, dispatch, "\n", NIL); + + Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n"); + Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname); + Printv(f->code, "zend_error(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n", NIL); + + Printv(f->code, "}\n", NIL); + Wrapper_print(f, s_wrappers); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + /* Helper method for PHP::functionWrapper */ + bool is_class(SwigType *t) { + Node *n = classLookup(t); + if (n) { + String *r = Getattr(n, "php:proxy"); // Set by classDeclaration() + if (!r) + r = Getattr(n, "sym:name"); // Not seen by classDeclaration yet, but this is the name + if (r) + return true; + } + return false; + } + + virtual int functionWrapper(Node *n) { + String *name = GetChar(n, "name"); + String *iname = GetChar(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *nodeType = Getattr(n, "nodeType"); + int newobject = GetFlag(n, "feature:new"); + int constructor = (Cmp(nodeType, "constructor") == 0); + + Parm *p; + int i; + int numopt; + String *tm; + Wrapper *f; + + String *wname; + int overloaded = 0; + String *overname = 0; + + if (Cmp(nodeType, "destructor") == 0) { + // We just generate the Zend List Destructor and let Zend manage the + // reference counting. There's no explicit destructor, but the user can + // just do `$obj = null;' to remove a reference to an object. + return CreateZendListDestructor(n); + } + // Test for overloading; + if (Getattr(n, "sym:overloaded")) { + overloaded = 1; + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + wname = Swig_name_wrapper(iname); + if (overname) { + Printf(wname, "%s", overname); + } + + f = NewWrapper(); + numopt = 0; + + String *outarg = NewStringEmpty(); + String *cleanup = NewStringEmpty(); + + // Not issued for overloaded functions. + if (!overloaded) { + create_command(iname, wname); + } + Printv(f->def, "ZEND_NAMED_FUNCTION(", wname, ") {\n", NIL); + + emit_parameter_variables(l, f); + /* Attach standard typemaps */ + + emit_attach_parmmaps(l, f); + + // wrap:parms is used by overload resolution. + Setattr(n, "wrap:parms", l); + + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + numopt = num_arguments - num_required; + + if (wrapperType == directorconstructor) + num_arguments++; + + if (num_arguments > 0) { + String *args = NewStringEmpty(); + if (wrapperType == directorconstructor) + Wrapper_add_local(f, "arg0", "zval *arg0"); + Printf(args, "zval **args[%d]", num_arguments); + Wrapper_add_local(f, "args", args); + Delete(args); + args = NULL; + } + if (is_member_director(n)) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director*>(arg1);\n"); + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Printf(f->code, "upcall = !director->is_overriden_method((char *)\"%s\", (char *)\"%s\");\n", + Swig_class_name(Swig_methodclass(n)), name); + } + + // This generated code may be called: + // 1) as an object method, or + // 2) as a class-method/function (without a "this_ptr") + // Option (1) has "this_ptr" for "this", option (2) needs it as + // first parameter + + // NOTE: possible we ignore this_ptr as a param for native constructor + + Printf(f->code, "SWIG_ResetError();\n"); + + if (numopt > 0) { // membervariable wrappers do not have optional args + Wrapper_add_local(f, "arg_count", "int arg_count"); + Printf(f->code, "arg_count = ZEND_NUM_ARGS();\n"); + Printf(f->code, "if(arg_count<%d || arg_count>%d ||\n", num_required, num_arguments); + Printf(f->code, " zend_get_parameters_array_ex(arg_count,args)!=SUCCESS)\n"); + Printf(f->code, "\tWRONG_PARAM_COUNT;\n\n"); + } else { + if (num_arguments == 0) { + Printf(f->code, "if(ZEND_NUM_ARGS() != 0) {\n"); + } else { + Printf(f->code, "if(ZEND_NUM_ARGS() != %d || zend_get_parameters_array_ex(%d, args) != SUCCESS) {\n", num_arguments, num_arguments); + } + Printf(f->code, "WRONG_PARAM_COUNT;\n}\n\n"); + } + if (wrapperType == directorconstructor) + Printf(f->code, "arg0 = *args[0];\n \n"); + + /* Now convert from PHP to C variables */ + // At this point, argcount if used is the number of deliberately passed args + // not including this_ptr even if it is used. + // It means error messages may be out by argbase with error + // reports. We can either take argbase into account when raising + // errors, or find a better way of dealing with _thisptr. + // I would like, if objects are wrapped, to assume _thisptr is always + // _this and not the first argument. + // This may mean looking at Language::memberfunctionHandler + + int limit = num_arguments; + if (wrapperType == directorconstructor) + limit--; + for (i = 0, p = l; i < limit; i++) { + String *source; + + /* Skip ignored arguments */ + //while (Getattr(p,"tmap:ignore")) { p = Getattr(p,"tmap:ignore:next");} + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + + if (wrapperType == directorconstructor) { + source = NewStringf("args[%d]", i+1); + } else { + source = NewStringf("args[%d]", i); + } + + String *ln = Getattr(p, "lname"); + + /* Check if optional */ + if (i >= num_required) { + Printf(f->code, "\tif(arg_count > %d) {\n", i); + } + + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printf(f->code, "%s\n", tm); + if (i == 0 && Getattr(p, "self")) { + Printf(f->code, "\tif(!arg1) SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");\n"); + } + p = Getattr(p, "tmap:in:next"); + if (i >= num_required) { + Printf(f->code, "}\n"); + } + continue; + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + } + if (i >= num_required) { + Printf(f->code, "\t}\n"); + } + Delete(source); + } + + Swig_director_emit_dynamic_cast(n, f); + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (i = 0, p = l; p; i++) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + // Replaceall(tm,"$input",Getattr(p,"lname")); + Replaceall(tm, "$target", "return_value"); + Replaceall(tm, "$result", "return_value"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + Setattr(n, "wrap:name", wname); + + /* emit function call */ + String *actioncode = emit_action(n); + + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$input", "result"); + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "return_value"); + Replaceall(tm, "$result", "return_value"); + Replaceall(tm, "$owner", newobject ? "1" : "0"); + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + if (outarg) { + Printv(f->code, outarg, NIL); + } + + if (cleanup) { + Printv(f->code, cleanup, NIL); + } + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + Printf(f->code, "return;\n"); + + /* Error handling code */ + Printf(f->code, "fail:\n"); + Printv(f->code, cleanup, NIL); + Printv(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());", NIL); + + Printf(f->code, "}\n"); + + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + Wrapper_print(f, s_wrappers); + DelWrapper(f); + f = NULL; + + if (overloaded && !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + Delete(wname); + wname = NULL; + + if (!shadow) { + return SWIG_OK; + } + + // Handle getters and setters. + if (wrapperType == membervar) { + const char *p = Char(iname); + if (strlen(p) > 4) { + p += strlen(p) - 4; + String *varname = Getattr(n, "membervariableHandler:sym:name"); + if (strcmp(p, "_get") == 0) { + Setattr(shadow_get_vars, varname, iname); + } else if (strcmp(p, "_set") == 0) { + Setattr(shadow_set_vars, varname, iname); + } + } + return SWIG_OK; + } + + // Only look at non-overloaded methods and the last entry in each overload + // chain (we check the last so that wrap:parms and wrap:name have been set + // for them all). + if (overloaded && Getattr(n, "sym:nextSibling") != 0) + return SWIG_OK; + + if (!s_oowrappers) + s_oowrappers = NewStringEmpty(); + + if (newobject || wrapperType == memberfn || wrapperType == staticmemberfn || wrapperType == standard || wrapperType == staticmembervar) { + bool handle_as_overload = false; + String **arg_names; + String **arg_values; + // Method or static method or plain function. + const char *methodname = 0; + String *output = s_oowrappers; + if (constructor) { + class_has_ctor = true; + // Skip the Foo:: prefix. + char *ptr = strrchr(GetChar(Swig_methodclass(n), "sym:name"), ':'); + if (ptr) { + ptr++; + } else { + ptr = GetChar(Swig_methodclass(n), "sym:name"); + } + if (strcmp(ptr, GetChar(n, "constructorHandler:sym:name")) == 0) { + methodname = "__construct"; + } else { + // The class has multiple constructors and this one is + // renamed, so this will be a static factory function + methodname = GetChar(n, "constructorHandler:sym:name"); + } + } else if (wrapperType == memberfn) { + methodname = Char(Getattr(n, "memberfunctionHandler:sym:name")); + } else if (wrapperType == staticmemberfn) { + methodname = Char(Getattr(n, "staticmemberfunctionHandler:sym:name")); + } else if (wrapperType == staticmembervar) { + // Static member variable, wrapped as a function due to PHP limitations. + methodname = Char(Getattr(n, "staticmembervariableHandler:sym:name")); + } else { // wrapperType == standard + methodname = Char(iname); + if (!s_fakeoowrappers) + s_fakeoowrappers = NewStringEmpty(); + output = s_fakeoowrappers; + } + + bool really_overloaded = overloaded ? true : false; + int min_num_of_arguments = emit_num_required(l); + int max_num_of_arguments = emit_num_arguments(l); + + // For a function with default arguments, we end up with the fullest + // parmlist in full_parmlist. + ParmList *full_parmlist = l; + Hash *ret_types = NewHash(); + Setattr(ret_types, d, d); + + if (overloaded) { + // Look at all the overloaded versions of this method in turn to + // decide if it's really an overloaded method, or just one where some + // parameters have default values. + Node *o = Getattr(n, "sym:overloaded"); + while (o) { + if (o == n) { + o = Getattr(o, "sym:nextSibling"); + continue; + } + + SwigType *d2 = Getattr(o, "type"); + if (!d2) { + assert(constructor); + } else if (!Getattr(ret_types, d2)) { + Setattr(ret_types, d2, d2); + } + + ParmList *l2 = Getattr(o, "wrap:parms"); + int num_arguments = emit_num_arguments(l2); + int num_required = emit_num_required(l2); + if (num_required < min_num_of_arguments) + min_num_of_arguments = num_required; + + if (num_arguments > max_num_of_arguments) { + max_num_of_arguments = num_arguments; + full_parmlist = l2; + } + o = Getattr(o, "sym:nextSibling"); + } + + o = Getattr(n, "sym:overloaded"); + while (o) { + if (o == n) { + o = Getattr(o, "sym:nextSibling"); + continue; + } + + ParmList *l2 = Getattr(o, "wrap:parms"); + Parm *p = l, *p2 = l2; + if (wrapperType == memberfn) { + p = nextSibling(p); + p2 = nextSibling(p2); + } + while (p && p2) { + if (Cmp(Getattr(p, "type"), Getattr(p2, "type")) != 0) + break; + if (Cmp(Getattr(p, "name"), Getattr(p2, "name")) != 0) + break; + String *value = Getattr(p, "value"); + String *value2 = Getattr(p2, "value"); + if (value && !value2) + break; + if (!value && value2) + break; + if (value) { + if (Cmp(value, value2) != 0) + break; + } + p = nextSibling(p); + p2 = nextSibling(p2); + } + if (p && p2) + break; + // One parameter list is a prefix of the other, so check that all + // remaining parameters of the longer list are optional. + if (p2) + p = p2; + while (p && Getattr(p, "value")) + p = nextSibling(p); + if (p) + break; + o = Getattr(o, "sym:nextSibling"); + } + if (!o) { + // This "overloaded method" is really just one with default args. + really_overloaded = false; + if (l != full_parmlist) { + l = full_parmlist; + if (wrapperType == memberfn) + l = nextSibling(l); + } + } + } + + if (wrapperType == memberfn) { + // Allow for the "this" pointer. + --min_num_of_arguments; + --max_num_of_arguments; + } + + arg_names = (String **) malloc(max_num_of_arguments * sizeof(String *)); + if (!arg_names) { + /* FIXME: How should this be handled? The rest of SWIG just seems + * to not bother checking for malloc failing! */ + fprintf(stderr, "Malloc failed!\n"); + exit(1); + } + for (i = 0; i < max_num_of_arguments; ++i) { + arg_names[i] = NULL; + } + + arg_values = (String **) malloc(max_num_of_arguments * sizeof(String *)); + if (!arg_values) { + /* FIXME: How should this be handled? The rest of SWIG just seems + * to not bother checking for malloc failing! */ + fprintf(stderr, "Malloc failed!\n"); + exit(1); + } + for (i = 0; i < max_num_of_arguments; ++i) { + arg_values[i] = NULL; + } + + Node *o; + if (overloaded) { + o = Getattr(n, "sym:overloaded"); + } else { + o = n; + } + while (o) { + int argno = 0; + Parm *p = Getattr(o, "wrap:parms"); + if (wrapperType == memberfn) + p = nextSibling(p); + while (p) { + if (GetInt(p, "tmap:in:numinputs") == 0) { + p = nextSibling(p); + continue; + } + assert(0 <= argno && argno < max_num_of_arguments); + String *&pname = arg_names[argno]; + const char *pname_cstr = GetChar(p, "name"); + // Just get rid of the C++ namespace part for now. + const char *ptr = NULL; + if (pname_cstr && (ptr = strrchr(pname_cstr, ':'))) { + pname_cstr = ptr + 1; + } + if (!pname_cstr) { + // Unnamed parameter, e.g. int foo(int); + } else if (pname == NULL) { + pname = NewString(pname_cstr); + } else { + size_t len = strlen(pname_cstr); + size_t spc = 0; + size_t len_pname = strlen(Char(pname)); + while (spc + len <= len_pname) { + if (strncmp(pname_cstr, Char(pname) + spc, len) == 0) { + char ch = ((char *) Char(pname))[spc + len]; + if (ch == '\0' || ch == ' ') { + // Already have this pname_cstr. + pname_cstr = NULL; + break; + } + } + char *p = strchr(Char(pname) + spc, ' '); + if (!p) + break; + spc = (p + 4) - Char(pname); + } + if (pname_cstr) { + Printf(pname, " or_%s", pname_cstr); + } + } + String *value = NewString(Getattr(p, "value")); + if (Len(value)) { + /* Check that value is a valid constant in PHP (and adjust it if + * necessary, or replace it with "?" if it's just not valid). */ + SwigType *type = Getattr(p, "type"); + switch (SwigType_type(type)) { + case T_BOOL: { + if (Strcmp(value, "true") == 0 || Strcmp(value, "false") == 0) + break; + char *p; + errno = 0; + int n = strtol(Char(value), &p, 0); + Clear(value); + if (errno || *p) { + Append(value, "?"); + } else if (n) { + Append(value, "true"); + } else { + Append(value, "false"); + } + break; + } + case T_CHAR: + case T_SCHAR: + case T_SHORT: + case T_INT: + case T_LONG: { + char *p; + errno = 0; + unsigned int n = strtol(Char(value), &p, 0); + (void) n; + if (errno || *p) { + Clear(value); + Append(value, "?"); + } + break; + } + case T_UCHAR: + case T_USHORT: + case T_UINT: + case T_ULONG: { + char *p; + errno = 0; + unsigned int n = strtoul(Char(value), &p, 0); + (void) n; + if (errno || *p) { + Clear(value); + Append(value, "?"); + } + break; + } + case T_FLOAT: + case T_DOUBLE:{ + char *p; + errno = 0; + /* FIXME: strtod is locale dependent... */ + double val = strtod(Char(value), &p); + if (errno || *p) { + Clear(value); + Append(value, "?"); + } else if (strchr(Char(value), '.') == NULL) { + // Ensure value is a double constant, not an integer one. + Append(value, ".0"); + double val2 = strtod(Char(value), &p); + if (errno || *p || val != val2) { + Clear(value); + Append(value, "?"); + } + } + break; + } + case T_REFERENCE: + case T_USER: + case T_ARRAY: + Clear(value); + Append(value, "?"); + break; + case T_STRING: + if (Len(value) < 2) { + // How can a string (including "" be less than 2 characters?) + Clear(value); + Append(value, "?"); + } else { + const char *v = Char(value); + if (v[0] != '"' || v[Len(value) - 1] != '"') { + Clear(value); + Append(value, "?"); + } + // Strings containing "$" require special handling, but we do + // that later. + } + break; + case T_VOID: + assert(false); + break; + case T_POINTER: { + const char *v = Char(value); + if (v[0] == '(') { + // Handle "(void*)0", "(TYPE*)0", "(char*)NULL", etc. + v += strcspn(v + 1, "*()") + 1; + if (*v == '*') { + do { + v++; + v += strspn(v, " \t"); + } while (*v == '*'); + if (*v++ == ')') { + v += strspn(v, " \t"); + String * old = value; + value = NewString(v); + Delete(old); + } + } + } + if (Strcmp(value, "NULL") == 0 || + Strcmp(value, "0") == 0 || + Strcmp(value, "0L") == 0) { + Clear(value); + Append(value, "null"); + } else { + Clear(value); + Append(value, "?"); + } + break; + } + } + + if (!arg_values[argno]) { + arg_values[argno] = value; + value = NULL; + } else if (Cmp(arg_values[argno], value) != 0) { + // If a parameter has two different default values in + // different overloaded forms of the function, we can't + // set its default in PHP. Flag this by setting its + // default to `?'. + Delete(arg_values[argno]); + arg_values[argno] = NewString("?"); + } + } else if (arg_values[argno]) { + // This argument already has a default value in another overloaded + // form, but doesn't in this form. So don't try to do anything + // clever, just let the C wrappers resolve the overload and set the + // default values. + // + // This handling is safe, but I'm wondering if it may be overly + // conservative (FIXME) in some cases. It seems it's only bad when + // there's an overloaded form with the appropriate number of + // parameters which doesn't want the default value, but I need to + // think about this more. + Delete(arg_values[argno]); + arg_values[argno] = NewString("?"); + } + Delete(value); + p = nextSibling(p); + ++argno; + } + if (!really_overloaded) + break; + o = Getattr(o, "sym:nextSibling"); + } + + /* Clean up any parameters which haven't yet got names, or whose + * names clash. */ + Hash *seen = NewHash(); + /* We need $this to refer to the current class, so can't allow it + * to be used as a parameter. */ + Setattr(seen, "this", seen); + /* We use $r to store the return value, so disallow that as a parameter + * name in case the user uses the "call-time pass-by-reference" feature + * (it's deprecated and off by default in PHP5, but we want to be + * maximally portable). Similarly we use $c for the classname or new + * stdClass object. + */ + Setattr(seen, "r", seen); + Setattr(seen, "c", seen); + + for (int argno = 0; argno < max_num_of_arguments; ++argno) { + String *&pname = arg_names[argno]; + if (pname) { + Replaceall(pname, " ", "_"); + } else { + /* We get here if the SWIG .i file has "int foo(int);" */ + pname = NewStringEmpty(); + Printf(pname, "arg%d", argno + 1); + } + // Check if we've already used this parameter name. + while (Getattr(seen, pname)) { + // Append "_" to clashing names until they stop clashing... + Printf(pname, "_"); + } + Setattr(seen, Char(pname), seen); + + if (arg_values[argno] && Cmp(arg_values[argno], "?") == 0) { + handle_as_overload = true; + } + } + Delete(seen); + seen = NULL; + + String *invoke = NewStringEmpty(); + String *prepare = NewStringEmpty(); + String *args = NewStringEmpty(); + + if (!handle_as_overload && !(really_overloaded && max_num_of_arguments > min_num_of_arguments)) { + Printf(invoke, "%s(", iname); + if (wrapperType == memberfn) { + Printf(invoke, "$this->%s", SWIG_PTR); + } + for (int i = 0; i < max_num_of_arguments; ++i) { + if (i) + Printf(args, ","); + if (i || wrapperType == memberfn) + Printf(invoke, ","); + String *value = arg_values[i]; + if (value) { + const char *v = Char(value); + if (v[0] == '"') { + /* In a PHP double quoted string, $ needs to be escaped as \$. */ + Replaceall(value, "$", "\\$"); + } + Printf(args, "$%s=%s", arg_names[i], value); + } else { + Printf(args, "$%s", arg_names[i]); + } + Printf(invoke, "$%s", arg_names[i]); + } + Printf(invoke, ")"); + } else { + int i; + for (i = 0; i < min_num_of_arguments; ++i) { + if (i) + Printf(args, ","); + Printf(args, "$%s", arg_names[i]); + } + String *invoke_args = NewStringEmpty(); + if (wrapperType == memberfn) { + Printf(invoke_args, "$this->%s", SWIG_PTR); + if (min_num_of_arguments > 0) + Printf(invoke_args, ","); + } + Printf(invoke_args, "%s", args); + bool had_a_case = false; + int last_handled_i = i - 1; + for (; i < max_num_of_arguments; ++i) { + if (i) + Printf(args, ","); + const char *value = Char(arg_values[i]); + // FIXME: (really_overloaded && handle_as_overload) is perhaps a + // little conservative, but it doesn't hit any cases that it + // shouldn't for Xapian at least (and we need it to handle + // "Enquire::get_mset()" correctly). + bool non_php_default = ((really_overloaded && handle_as_overload) || + !value || strcmp(value, "?") == 0); + if (non_php_default) + value = "null"; + Printf(args, "$%s=%s", arg_names[i], value); + if (non_php_default) { + if (!had_a_case) { + Printf(prepare, "\t\tswitch (func_num_args()) {\n"); + had_a_case = true; + } + Printf(prepare, "\t\t"); + while (last_handled_i < i) { + Printf(prepare, "case %d: ", ++last_handled_i); + } + if (Cmp(d, "void") != 0) { + if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) { + Append(prepare, "$r="); + } else { + Printf(prepare, "$this->%s=", SWIG_PTR); + } + } + if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) { + Printf(prepare, "%s(%s); break;\n", iname, invoke_args); + } else if (!i) { + Printf(prepare, "%s($_this%s); break;\n", iname, invoke_args); + } else { + Printf(prepare, "%s($_this, %s); break;\n", iname, invoke_args); + } + } + if (i || wrapperType == memberfn) + Printf(invoke_args, ","); + Printf(invoke_args, "$%s", arg_names[i]); + } + Printf(prepare, "\t\t"); + if (had_a_case) + Printf(prepare, "default: "); + if (Cmp(d, "void") != 0) { + if ((!directorsEnabled() || !Swig_directorclass(n)) && !newobject) { + Append(prepare, "$r="); + } else { + Printf(prepare, "$this->%s=", SWIG_PTR); + } + } + + if (!directorsEnabled() || !Swig_directorclass(n) || !newobject) { + Printf(prepare, "%s(%s);\n", iname, invoke_args); + } else { + Printf(prepare, "%s($_this, %s);\n", iname, invoke_args); + } + if (had_a_case) + Printf(prepare, "\t\t}\n"); + Delete(invoke_args); + Printf(invoke, "$r"); + } + + Printf(output, "\n"); + // If it's a member function or a class constructor... + if (wrapperType == memberfn || (constructor && current_class)) { + String *acc = NewString(Getattr(n, "access")); + // If a base has the same method with public access, then PHP + // requires to have it here as public as well + Node *bases = Getattr(Swig_methodclass(n), "bases"); + if (bases && Strcmp(acc, "public") != 0) { + String *warnmsg = 0; + int haspublicbase = 0; + Iterator i = First(bases); + while (i.item) { + Node *j = firstChild(i.item); + while (j) { + if (Strcmp(Getattr(j, "name"), Getattr(n, "name")) != 0) { + j = nextSibling(j); + continue; + } + if (Strcmp(nodeType(j), "cdecl") == 0) { + if (!Getattr(j, "access") || checkAttribute(j, "access", "public")) { + haspublicbase = 1; + } + } else if (Strcmp(nodeType(j), "using") == 0 && firstChild(j) && Strcmp(nodeType(firstChild(j)), "cdecl") == 0) { + if (!Getattr(firstChild(j), "access") || checkAttribute(firstChild(j), "access", "public")) { + haspublicbase = 1; + } + } + if (haspublicbase) { + warnmsg = NewStringf("Modifying the access of '%s::%s' to public, as the base '%s' has it as public as well.\n", Getattr(current_class, "classtype"), Getattr(n, "name"), Getattr(i.item, "classtype")); + break; + } + j = nextSibling(j); + } + i = Next(i); + if (haspublicbase) { + break; + } + } + if (Getattr(n, "access") && haspublicbase) { + Delete(acc); + acc = NewString("public"); + Swig_warning(WARN_PHP_PUBLIC_BASE, input_file, line_number, Char(warnmsg)); + Delete(warnmsg); + } + } + if (Cmp(acc, "") != 0) { + Append(acc, " "); + } + if (constructor) { + const char * arg0; + if (max_num_of_arguments > 0) { + arg0 = Char(arg_names[0]); + } else { + arg0 = "res"; + Delete(args); + args = NewString("$res=null"); + } + SwigType *t = Getattr(current_class, "classtype"); + String *mangled_type = SwigType_manglestr(SwigType_ltype(t)); + Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args); + Printf(output, "\t\tif (is_resource($%s) && get_resource_type($%s) === '_p%s') {\n", arg0, arg0, mangled_type); + Printf(output, "\t\t\t$this->%s=$%s;\n", SWIG_PTR, arg0); + Printf(output, "\t\t\treturn;\n"); + Printf(output, "\t\t}\n"); + } else { + Printf(output, "\t%sfunction %s(%s) {\n", acc, methodname, args); + } + Delete(acc); + } else if (wrapperType == staticmembervar) { + // We're called twice for a writable static member variable - first + // with "foo_set" and then with "foo_get" - so generate half the + // wrapper function each time. + // + // For a const static member, we only get called once. + static bool started = false; + if (!started) { + Printf(output, "\tstatic function %s() {\n", methodname); + if (max_num_of_arguments) { + // Setter. + Printf(output, "\t\tif (func_num_args()) {\n"); + Printf(output, "\t\t\t%s(func_get_arg(0));\n", iname); + Printf(output, "\t\t\treturn;\n"); + Printf(output, "\t\t}\n"); + started = true; + goto done; + } + } + started = false; + } else { + Printf(output, "\tstatic function %s(%s) {\n", methodname, args); + } + + if (!newobject) + Printf(output, "%s", prepare); + if (constructor) { + if (!directorsEnabled() || !Swig_directorclass(n)) { + if (strcmp(methodname, "__construct") == 0) { + Printf(output, "\t\t$this->%s=%s;\n", SWIG_PTR, invoke); + } else { + String *classname = Swig_class_name(current_class); + Printf(output, "\t\treturn new %s(%s);\n", classname, invoke); + } + } else { + Node *parent = Swig_methodclass(n); + String *classname = Swig_class_name(parent); + Printf(output, "\t\tif (get_class($this) === '%s%s') {\n", prefix, classname); + Printf(output, "\t\t\t$_this = null;\n"); + Printf(output, "\t\t} else {\n"); + Printf(output, "\t\t\t$_this = $this;\n"); + Printf(output, "\t\t}\n"); + if (!Len(prepare)) { + if (num_arguments > 1) { + Printf(output, "\t\t$this->%s=%s($_this, %s);\n", SWIG_PTR, iname, args); + } else { + Printf(output, "\t\t$this->%s=%s($_this);\n", SWIG_PTR, iname); + } + } + } + Printf(output, "%s", prepare); + } else if (Cmp(d, "void") == 0) { + if (Cmp(invoke, "$r") != 0) + Printf(output, "\t\t%s;\n", invoke); + } else if (is_class(d)) { + if (Cmp(invoke, "$r") != 0) + Printf(output, "\t\t$r=%s;\n", invoke); + if (Len(ret_types) == 1) { + /* If it has an abstract base, then we can't create a new + * base object. */ + int hasabstractbase = 0; + Node *bases = Getattr(Swig_methodclass(n), "bases"); + if (bases) { + Iterator i = First(bases); + while(i.item) { + if (Getattr(i.item, "abstract")) { + hasabstractbase = 1; + break; + } + i = Next(i); + } + } + if (newobject || !hasabstractbase) { + /* + * _p_Foo -> Foo, _p_ns__Bar -> Bar + * TODO: do this in a more elegant way + */ + Printf(output, "\t\tif (is_resource($r)) {\n"); + if (Getattr(classLookup(Getattr(n, "type")), "module")) { + if (Len(prefix) == 0) { + Printf(output, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n"); + } else { + Printf(output, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix); + } + Printf(output, "\t\t\tif (!class_exists($c)) {\n"); + Printf(output, "\t\t\t\treturn new %s($r);\n", Getattr(classLookup(d), "sym:name")); + Printf(output, "\t\t\t}\n"); + Printf(output, "\t\t\treturn new $c($r);\n"); + } else { + Printf(output, "\t\t\t$c = new stdClass();\n"); + Printf(output, "\t\t\t$c->_cPtr = $r;\n"); + Printf(output, "\t\t\treturn $c;\n"); + } + Printf(output, "\t\t}\n\t\treturn $r;\n"); + } else { + Printf(output, "\t\t$this->%s = $r;\n", SWIG_PTR); + Printf(output, "\t\treturn $this;\n"); + } + } else { + Printf(output, "\t\tif (!is_resource($r)) return $r;\n"); + Printf(output, "\t\tswitch (get_resource_type($r)) {\n"); + Iterator i = First(ret_types); + while (i.item) { + SwigType *ret_type = i.item; + i = Next(i); + Printf(output, "\t\t"); + String *mangled = NewString("_p"); + Printf(mangled, "%s", SwigType_manglestr(ret_type)); + Node *class_node = Getattr(zend_types, mangled); + if (!class_node) { + /* This is needed when we're returning a pointer to a type + * rather than returning the type by value or reference. */ + class_node = current_class; + Delete(mangled); + mangled = NewString(SwigType_manglestr(ret_type)); + class_node = Getattr(zend_types, mangled); + } + if (i.item) { + Printf(output, "case '%s': ", mangled); + } else { + Printf(output, "default: "); + } + const char *classname = GetChar(class_node, "sym:name"); + if (!classname) + classname = GetChar(class_node, "name"); + if (classname) + Printf(output, "return new %s%s($r);\n", prefix, classname); + else + Printf(output, "return $r;\n"); + Delete(mangled); + } + Printf(output, "\t\t}\n"); + } + } else { + Printf(output, "\t\treturn %s;\n", invoke); + } + Printf(output, "\t}\n"); + +done: + Delete(prepare); + Delete(invoke); + free(arg_values); + + Delete(args); + args = NULL; + + for (int i = 0; i < max_num_of_arguments; ++i) { + Delete(arg_names[i]); + } + free(arg_names); + arg_names = NULL; + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * globalvariableHandler() + * ------------------------------------------------------------ */ + + virtual int globalvariableHandler(Node *n) { + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + String *tm; + + /* First do the wrappers such as name_set(), name_get() + * as provided by the baseclass's implementation of variableWrapper + */ + if (Language::globalvariableHandler(n) == SWIG_NOWRAP) { + return SWIG_NOWRAP; + } + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + SwigType_remember(t); + + /* First link C variables to PHP */ + + tm = Swig_typemap_lookup("varinit", n, name, 0); + if (tm) { + Replaceall(tm, "$target", name); + Printf(s_vinit, "%s\n", tm); + } else { + Printf(stderr, "%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0)); + } + + /* Now generate PHP -> C sync blocks */ + /* + tm = Swig_typemap_lookup("varin", n, name, 0); + if(tm) { + Replaceall(tm, "$symname", iname); + Printf(f_c->code, "%s\n", tm); + } else { + Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0)); + } + */ + /* Now generate C -> PHP sync blocks */ + /* + if(!GetFlag(n,"feature:immutable")) { + + tm = Swig_typemap_lookup("varout", n, name, 0); + if(tm) { + Replaceall(tm, "$symname", iname); + Printf(f_php->code, "%s\n", tm); + } else { + Printf(stderr,"%s: Line %d, Unable to link with type %s\n", input_file, line_number, SwigType_str(t, 0)); + } + } + */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = GetChar(n, "name"); + String *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + SwigType_remember(type); + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Printf(s_cinit, "%s\n", tm); + } + + if (shadow) { + String *enumvalue = GetChar(n, "enumvalue"); + String *set_to = iname; + + if (!enumvalue) { + enumvalue = GetChar(n, "enumvalueex"); + } + + if (enumvalue) { + // Check for a simple constant expression which is valid in PHP. + // If we find one, initialise the const member with it; otherwise + // we initialise it using the C/C++ wrapped constant. + const char *p; + for (p = Char(enumvalue); *p; ++p) { + if (!isdigit((unsigned char)*p) && !strchr(" +-", *p)) { + // FIXME: enhance to handle `<previous_enum> + 1' which is what + // we get for enums that don't have an explicit value set. + break; + } + } + if (!*p) set_to = enumvalue; + } + + if (wrapping_member_constant) { + if (!s_oowrappers) + s_oowrappers = NewStringEmpty(); + Printf(s_oowrappers, "\n\tconst %s = %s;\n", wrapping_member_constant, set_to); + } else { + if (!s_fakeoowrappers) + s_fakeoowrappers = NewStringEmpty(); + Printf(s_fakeoowrappers, "\n\tconst %s = %s;\n", iname, set_to); + } + } + + return SWIG_OK; + } + + /* + * PHP::pragma() + * + * Pragma directive. + * + * %pragma(php) code="String" # Includes a string in the .php file + * %pragma(php) include="file.php" # Includes a file in the .php file + */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *type = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "php") == 0 || Strcmp(lang, "php4") == 0) { + if (Strcmp(type, "code") == 0) { + if (value) { + Printf(pragma_code, "%s\n", value); + } + } else if (Strcmp(type, "include") == 0) { + if (value) { + Printf(pragma_incl, "include '%s';\n", value); + } + } else if (Strcmp(type, "phpinfo") == 0) { + if (value) { + Printf(pragma_phpinfo, "%s\n", value); + } + } else { + Swig_warning(WARN_PHP_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", type); + } + } + } + return Language::pragmaDirective(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + if (!Getattr(n, "feature:onlychildren")) { + String *symname = Getattr(n, "sym:name"); + Setattr(n, "php:proxy", symname); + } + + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + constructors = 0; + //SwigType *t = Getattr(n, "classtype"); + current_class = n; + // String *use_class_name=SwigType_manglestr(SwigType_ltype(t)); + + if (shadow) { + char *rename = GetChar(n, "sym:name"); + + if (!addSymbol(rename, n)) + return SWIG_ERROR; + shadow_classname = NewString(rename); + + shadow_get_vars = NewHash(); + shadow_set_vars = NewHash(); + + /* Deal with inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + base = Next(base); + if (base.item) { + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_PHP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in PHP.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + classnode = n; + Language::classHandler(n); + classnode = 0; + + if (shadow) { + DOH *key; + List *baselist = Getattr(n, "bases"); + Iterator ki, base; + + if (baselist) { + base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + } else { + base.item = NULL; + } + + if (Getattr(n, "abstract") && !GetFlag(n, "feature:notabstract")) { + Printf(s_phpclasses, "abstract "); + } + + Printf(s_phpclasses, "class %s%s ", prefix, shadow_classname); + String *baseclass = NULL; + if (base.item && Getattr(base.item, "module")) { + baseclass = Getattr(base.item, "sym:name"); + if (!baseclass) + baseclass = Getattr(base.item, "name"); + Printf(s_phpclasses, "extends %s%s ", prefix, baseclass); + } else if (GetFlag(n, "feature:exceptionclass")) { + Append(s_phpclasses, "extends Exception "); + } + Printf(s_phpclasses, "{\n\tpublic $%s=null;\n", SWIG_PTR); + if (!baseclass) { + // Only store this in the base class (NB !baseclass means we *are* + // a base class...) + Printf(s_phpclasses, "\tprotected $%s=array();\n", SWIG_DATA); + } + + // Write property SET handlers + ki = First(shadow_set_vars); + + if (ki.key) { + // This class has setters. + Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n"); + // FIXME: tune this threshold... + if (Len(shadow_set_vars) <= 2) { + // Not many setters, so avoid call_user_func. + while (ki.key) { + key = ki.key; + Printf(s_phpclasses, "\t\tif ($var === '%s') return %s($this->%s,$value);\n", key, ki.item, SWIG_PTR); + ki = Next(ki); + } + } else { + Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_set';\n", shadow_classname); + Printf(s_phpclasses, "\t\tif (function_exists($func)) return call_user_func($func,$this->%s,$value);\n", SWIG_PTR); + } + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + + /* Create __isset for PHP 5.1 and later; PHP 5.0 will just ignore it. */ + Printf(s_phpclasses, "\n\tfunction __isset($var) {\n"); + Printf(s_phpclasses, "\t\tif (function_exists('%s_'.$var.'_set')) return true;\n", shadow_classname); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n"); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } else { + Printf(s_phpclasses, "\n\tfunction __set($var,$value) {\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_alter_newobject($this->%s,$value);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\t%s%s::__set($var,$value);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\t$this->%s[$var] = $value;\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + Printf(s_phpclasses, "\n\tfunction __isset($var) {\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return true;\n"); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__isset($var);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\treturn array_key_exists($var, $this->%s);\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } + // Write property GET handlers + ki = First(shadow_get_vars); + + if (ki.key) { + // This class has getters. + Printf(s_phpclasses, "\n\tfunction __get($var) {\n"); + // FIXME: Currently we always use call_user_func for __get, so we can + // check and wrap the result. This is needless if all the properties + // are primitive types. Also this doesn't handle all the cases which + // a method returning an object does. + Printf(s_phpclasses, "\t\t$func = '%s_'.$var.'_get';\n", shadow_classname); + Printf(s_phpclasses, "\t\tif (function_exists($func)) {\n"); + Printf(s_phpclasses, "\t\t\t$r = call_user_func($func,$this->%s);\n", SWIG_PTR); + Printf(s_phpclasses, "\t\t\tif (!is_resource($r)) return $r;\n"); + if (Len(prefix) == 0) { + Printf(s_phpclasses, "\t\t\t$c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n"); + } else { + Printf(s_phpclasses, "\t\t\t$c='%s'.substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3));\n", prefix); + } + Printf(s_phpclasses, "\t\t\treturn new $c($r);\n"); + Printf(s_phpclasses, "\t\t}\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass); + } else { + // Reading an unknown property name gives null in PHP. + Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } else { + Printf(s_phpclasses, "\n\tfunction __get($var) {\n"); + Printf(s_phpclasses, "\t\tif ($var === 'thisown') return swig_%s_get_newobject($this->%s);\n", module, SWIG_PTR); + if (baseclass) { + Printf(s_phpclasses, "\t\treturn %s%s::__get($var);\n", prefix, baseclass); + } else { + Printf(s_phpclasses, "\t\treturn $this->%s[$var];\n", SWIG_DATA); + } + Printf(s_phpclasses, "\t}\n"); + } + + if (!class_has_ctor) { + Printf(s_phpclasses, "\tfunction __construct($h) {\n"); + Printf(s_phpclasses, "\t\t$this->%s=$h;\n", SWIG_PTR); + Printf(s_phpclasses, "\t}\n"); + } + + if (s_oowrappers) { + Printf(s_phpclasses, "%s", s_oowrappers); + Delete(s_oowrappers); + s_oowrappers = NULL; + } + class_has_ctor = false; + + Printf(s_phpclasses, "}\n\n"); + + Delete(shadow_classname); + shadow_classname = NULL; + + Delete(shadow_set_vars); + shadow_set_vars = NULL; + Delete(shadow_get_vars); + shadow_get_vars = NULL; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + wrapperType = memberfn; + Language::memberfunctionHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + wrapperType = membervar; + Language::membervariableHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + wrapperType = staticmembervar; + Language::staticmembervariableHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + wrapperType = staticmemberfn; + Language::staticmemberfunctionHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + int abstractConstructorHandler(Node *) { + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + constructors++; + if (Swig_directorclass(n)) { + String *name = GetChar(Swig_methodclass(n), "name"); + String *ctype = GetChar(Swig_methodclass(n), "classtype"); + String *sname = GetChar(Swig_methodclass(n), "sym:name"); + String *args = NewStringEmpty(); + ParmList *p = Getattr(n, "parms"); + int i; + + for (i = 0; p; p = nextSibling(p), i++) { + if (i) { + Printf(args, ", "); + } + if (Strcmp(GetChar(p, "type"), SwigType_str(GetChar(p, "type"), 0))) { + SwigType *t = Getattr(p, "type"); + Printf(args, "%s", SwigType_rcaststr(t, 0)); + if (SwigType_isreference(t)) { + Append(args, "*"); + } + } + Printf(args, "arg%d", i+1); + } + + /* director ctor code is specific for each class */ + Delete(director_ctor_code); + director_ctor_code = NewStringEmpty(); + director_prot_ctor_code = NewStringEmpty(); + Printf(director_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n"); + Printf(director_prot_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n"); + Printf(director_ctor_code, " result = (%s *)new %s(%s);\n", ctype, ctype, args); + Printf(director_prot_ctor_code, " SWIG_PHP_Error(E_ERROR, \"accessing abstract class or protected constructor\");\n", name, name, args); + if (i) { + Insert(args, 0, ", "); + } + Printf(director_ctor_code, "} else {\n result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args); + Printf(director_prot_ctor_code, "} else {\n result = (%s *)new SwigDirector_%s(arg0%s);\n}\n", ctype, sname, args); + Delete(args); + + wrapperType = directorconstructor; + } else { + wrapperType = constructor; + } + Language::constructorHandler(n); + wrapperType = standard; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * CreateZendListDestructor() + * ------------------------------------------------------------ */ + //virtual int destructorHandler(Node *n) { + //} + int CreateZendListDestructor(Node *n) { + String *name = GetChar(Swig_methodclass(n), "name"); + String *iname = GetChar(n, "sym:name"); + ParmList *l = Getattr(n, "parms"); + + String *destructorname = NewStringEmpty(); + Printf(destructorname, "_%s", Swig_name_wrapper(iname)); + Setattr(classnode, "destructor", destructorname); + + Wrapper *f = NewWrapper(); + Printf(f->def, "/* This function is designed to be called by the zend list destructors */\n"); + Printf(f->def, "/* to typecast and do the actual destruction */\n"); + Printf(f->def, "static void %s(zend_rsrc_list_entry *rsrc, const char *type_name TSRMLS_DC) {\n", destructorname); + + Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) rsrc->ptr", NIL); + Wrapper_add_localv(f, "ptr", "void *ptr=value->ptr", NIL); + Wrapper_add_localv(f, "newobject", "int newobject=value->newobject", NIL); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l, f); + + // Get type of first arg, thing to be destructed + // Skip ignored arguments + Parm *p = l; + //while (Getattr(p,"tmap:ignore")) {p = Getattr(p,"tmap:ignore:next");} + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + SwigType *pt = Getattr(p, "type"); + + Printf(f->code, " efree(value);\n"); + Printf(f->code, " if (! newobject) return; /* can't delete it! */\n"); + Printf(f->code, " arg1 = (%s)SWIG_ZTS_ConvertResourceData(ptr,type_name,SWIGTYPE%s TSRMLS_CC);\n", SwigType_lstr(pt, 0), SwigType_manglestr(pt)); + Printf(f->code, " if (! arg1) zend_error(E_ERROR, \"%s resource already free'd\");\n", Char(name)); + + Setattr(n, "wrap:name", destructorname); + + String *actioncode = emit_action(n); + Append(f->code, actioncode); + Delete(actioncode); + + Append(f->code, "return;\n"); + Append(f->code, "fail:\n"); + Append(f->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); + Printf(f->code, "}\n"); + + Wrapper_print(f, s_wrappers); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + wrapping_member_constant = Getattr(n, "sym:name"); + Language::memberconstantHandler(n); + wrapping_member_constant = NULL; + return SWIG_OK; + } + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n"); + return Language::classDirectorEnd(n); + } + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewStringEmpty(); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("zval"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self")); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) {", classname, target, call); + Append(w->def, "}"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + return Language::classDirectorConstructor(n); + } + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewStringEmpty(); + String *return_type; + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewStringEmpty(); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (Cmp(type, "void") == 0 && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($result). + */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *cres = SwigType_lstr(return_type, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> PHP) */ + String *parse_args = NewStringEmpty(); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + char source[256]; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; + p = l; + int use_parse = 0; + while (p != NULL) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + String *parse = Getattr(p, "tmap:directorin:parse"); + if (!parse) { + sprintf(source, "obj%d", idx++); + String *input = NewStringf("&%s", source); + Replaceall(tm, "$input", input); + Delete(input); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, "zval ", source, ";\n", NIL); + Printf(wrap_args, "args[%d] = &%s;\n", idx - 1, source); + + Printv(wrap_args, tm, "\n", NIL); + Putc('O', parse_args); + } else { + use_parse = 1; + Append(parse_args, parse); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + } + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + p = nextSibling(p); + } + Append(w->code, "int error;\n"); + if (!idx) { + Printf(w->code, "zval **args = NULL;\n", idx); + } else { + Printf(w->code, "zval *args[%d];\n", idx); + } + Append(w->code, "zval *result, funcname;\n"); + Append(w->code, "MAKE_STD_ZVAL(result);\n"); + Printf(w->code, "ZVAL_STRING(&funcname, (char *)\"%s\", 0);\n", name); + Append(w->code, "if (!swig_self) {\n"); + Append(w->code, " SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");"); + Append(w->code, "}\n\n"); + + /* wrap complex arguments to zvals */ + Printv(w->code, wrap_args, NIL); + + Append(w->code, "call_user_function(EG(function_table), (zval**)&swig_self, &funcname,\n"); + Printf(w->code, " result, %d, args TSRMLS_CC);\n", idx); + + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Replaceall(tm, "$error", "error"); + Printv(w->code, Str(tm), "\n", NIL); + } + Delete(tm); + + /* marshal return value from PHP to C/C++ type */ + + String *cleanup = NewStringEmpty(); + String *outarg = NewStringEmpty(); + + idx = 0; + + /* marshal return value */ + if (!is_void) { + /* this seems really silly. the node's type excludes + * qualifier/pointer/reference markers, which have to be retrieved + * from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and + * out the correct type. it's not just me, similar silliness also + * occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + Replaceall(tm, "$input", "&result"); + char temp[24]; + sprintf(temp, "%d", idx); + Replaceall(tm, "$argnum", temp); + + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), SwigType_namestr(c_classname), + SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + Replaceall(tm, "$input", "result"); + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Append(w->code, "FREE_ZVAL(result);\n"); + + Delete(parse_args); + Delete(cleanup); + Delete(outarg); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(return_type, 0); + if (!SwigType_isreference(return_type)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } else { + Append(w->code, "return;\n"); + } + + Append(w->code, "fail:\n"); + Append(w->code, "zend_error_noreturn(SWIG_ErrorCode(),\"%s\",SWIG_ErrorMsg());\n"); + Append(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewStringEmpty(); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit the director method */ + if (status == SWIG_OK) { + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(return_type); + Delete(pclassname); + DelWrapper(w); + return status; + } + + int classDirectorDisown(Node *) { + return SWIG_OK; + } +}; /* class PHP */ + +static PHP *maininstance = 0; + +// We use this function to be able to write out zend_register_list_destructor_ex +// lines for most things in the type table +// NOTE: it's a function NOT A PHP::METHOD +extern "C" void typetrace(SwigType *ty, String *mangled, String *clientdata) { + Node *class_node; + if (!zend_types) { + zend_types = NewHash(); + } + // we want to know if the type which reduced to this has a constructor + if ((class_node = maininstance->classLookup(ty))) { + if (!Getattr(zend_types, mangled)) { + // OK it may have been set before by a different SwigType but it would + // have had the same underlying class node I think + // - it is certainly required not to have different originating class + // nodes for the same SwigType + Setattr(zend_types, mangled, class_node); + } + } else { // a non-class pointer + Setattr(zend_types, mangled, NOTCLASS); + } + if (r_prevtracefunc) + (*r_prevtracefunc) (ty, mangled, (String *) clientdata); +} + +/* ----------------------------------------------------------------------------- + * new_swig_php() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_php() { + maininstance = new PHP; + if (!r_prevtracefunc) { + r_prevtracefunc = SwigType_remember_trace(typetrace); + } else { + Printf(stderr, "php Typetrace vector already saved!\n"); + assert(0); + } + return maininstance; +} + +extern "C" Language *swig_php4(void) { + Printf(stderr, "*** -php4 is no longer supported.\n" + "*** Either upgrade to PHP5 or use SWIG 1.3.36 or earlier.\n"); + SWIG_exit(EXIT_FAILURE); + return NULL; // To avoid compiler warnings. +} + +extern "C" Language *swig_php(void) { + return new_swig_php(); +} diff --git a/Source/Modules/pike.cxx b/Source/Modules/pike.cxx new file mode 100644 index 0000000..00e7500 --- /dev/null +++ b/Source/Modules/pike.cxx @@ -0,0 +1,903 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * pike.cxx + * + * Pike language module for SWIG. + * ----------------------------------------------------------------------------- */ + +/* + * Notes: + * + * - The current approach used for "out" typemaps is inconsistent with + * how "out" typemaps are handled by other language modules. Instead + * of converting the C/C++ type ($1) to a Pike object type (e.g. a + * struct svalue), we're just calling the appropriate push_XXX + * (e.g. push_int) to push the return value onto the stack. + * + * - Pike classes can't have static member functions or data, so we need + * to find some other appropriate mapping for C++ static member functions + * and data. + * + * - Pike doesn't seem to provide any default way to print the memory + * address, etc. for extension objects. Should we do something here? + * + */ + +char cvsroot_pike_cxx[] = "$Id: pike.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +#include <ctype.h> // for isalnum() + +static const char *usage = (char *) "\ +Pike Options (available with -pike)\n\ + [None]\n\ +\n"; + +class PIKE:public Language { +private: + + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_classInit; + + String *PrefixPlusUnderscore; + int current; + + // Wrap modes + enum { + NO_CPP, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }; + +public: + + /* --------------------------------------------------------------------- + * PIKE() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + PIKE() { + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_classInit = 0; + PrefixPlusUnderscore = 0; + current = NO_CPP; + } + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + /* Set location of SWIG library */ + SWIG_library_directory("pike"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGPIKE 1", 0); + + /* Set language-specific configuration file */ + SWIG_config_file("pike.swg"); + + /* Set typemap language */ + SWIG_typemap_lang("pike"); + + /* Enable overloaded methods support */ + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + /* Get the module name */ + String *module = Getattr(n, "name"); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + /* Open the output file */ + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_classInit = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("classInit", f_classInit); + + /* Standard stuff for the SWIG runtime section */ + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGPIKE\n"); + Printf(f_runtime, "\n"); + + Printf(f_header, "#define SWIG_init pike_module_init\n"); + Printf(f_header, "#define SWIG_name \"%s\"\n\n", module); + + /* Change naming scheme for constructors and destructors */ + Swig_name_register("construct", "%c_create"); + Swig_name_register("destroy", "%c_destroy"); + + /* Current wrap type */ + current = NO_CPP; + + /* Emit code for children */ + Language::top(n); + + /* Close the initialization function */ + Printf(f_init, "}\n"); + SwigType_emit_type_table(f_runtime, f_wrappers); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_classInit); + + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + /* Done */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + const char *c0 = c; + const char *c1 = c0 + 1; + while (*c) { + if (*c == '`' && c == c0) { + c++; + continue; + } + if ((*c == '+' || *c == '-' || *c == '*' || *c == '/') && c == c1) { + c++; + continue; + } + if (!(isalnum(*c) || (*c == '_'))) + return 0; + c++; + } + return 1; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname) { + Printf(f_init, "pike_require(\"%s\");\n", modname); + } + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * strip() + * + * For names that begin with the current class prefix plus an + * underscore (e.g. "Foo_enum_test"), return the base function + * name (i.e. "enum_test"). + * ------------------------------------------------------------ */ + + String *strip(const DOHconst_String_or_char_ptr name) { + String *s = Copy(name); + if (Strncmp(name, PrefixPlusUnderscore, Len(PrefixPlusUnderscore)) != 0) { + return s; + } + Replaceall(s, PrefixPlusUnderscore, ""); + return s; + } + + /* ------------------------------------------------------------ + * add_method() + * ------------------------------------------------------------ */ + + void add_method(const DOHconst_String_or_char_ptr name, const DOHconst_String_or_char_ptr function, const DOHconst_String_or_char_ptr description) { + String *rename = NULL; + switch (current) { + case NO_CPP: + rename = NewString(name); + Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); + break; + case STATIC_FUNC: + case STATIC_VAR: + rename = NewString(name); + Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); + break; + case CONSTRUCTOR: + case DESTRUCTOR: + case MEMBER_FUNC: + case MEMBER_VAR: + rename = strip(name); + Printf(f_classInit, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); + break; + case CLASS_CONST: + assert(false); // shouldn't have gotten here for CLASS_CONST nodes + default: + assert(false); // what is this? + } + Delete(rename); + } + + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + + Parm *p; + String *tm; + int i; + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + Wrapper *f = NewWrapper(); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + int num_arguments = emit_num_arguments(l); + int varargs = emit_isvarargs(l); + + /* Which input argument to start with? */ + int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; + + /* Offset to skip over the attribute name */ + // int offset = (current == MEMBER_VAR) ? 1 : 0; + int offset = 0; + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + Printv(f->def, "static void ", wname, "(INT32 args) {", NIL); + + /* Generate code for argument marshalling */ + String *description = NewString(""); + char source[64]; + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + if (i < start) { + String *lstr = SwigType_lstr(pt, 0); + Printf(f->code, "%s = (%s) THIS;\n", ln, lstr); + Delete(lstr); + } else { + /* Look for an input typemap */ + sprintf(source, "Pike_sp[%d-args]", i - start + offset); + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + Printf(f->code, "%s\n", tm); + String *pikedesc = Getattr(p, "tmap:in:pikedesc"); + if (pikedesc) { + Printv(description, pikedesc, " ", NIL); + } + p = Getattr(p, "tmap:in:next"); + continue; + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + p = nextSibling(p); + } + + /* Check for trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + String *outarg = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* Clear the return stack */ + Printf(actioncode, "pop_n_elems(args);\n"); + + /* Return the function value */ + if (current == CONSTRUCTOR) { + Printv(actioncode, "THIS = (void *) result;\n", NIL); + Printv(description, ", tVoid", NIL); + } else if (current == DESTRUCTOR) { + Printv(description, ", tVoid", NIL); + } else { + Printv(description, ", ", NIL); + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + actioncode = 0; + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + String *pikedesc = Getattr(n, "tmap:out:pikedesc"); + if (pikedesc) { + Printv(description, pikedesc, NIL); + } + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + } + if (actioncode) { + Append(f->code, actioncode); + Delete(actioncode); + } + emit_return_variable(n, d, f); + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + /* Close the function */ + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", "resultobj"); + + /* Dump the function out */ + Wrapper_print(f, f_wrappers); + + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + add_method(iname, wname, description); + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + Delete(cleanup); + Delete(outarg); + Delete(description); + Delete(wname); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * + * Emit overloading dispatch function + * ------------------------------------------------------------ */ + + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "%s(args); return;", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + Printf(f->def, "static void %s(INT32 args) {", wname); + + Wrapper_add_local(f, "argc", "INT32 argc"); + Printf(tmp, "struct svalue argv[%d]", maxargs); + Wrapper_add_local(f, "argv", tmp); + Wrapper_add_local(f, "ii", "INT32 ii"); + + Printf(f->code, "argc = args;\n"); + Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs); + Printf(f->code, "argv[ii] = Pike_sp[ii-args];\n"); + Printf(f->code, "}\n"); + + Replaceall(dispatch, "$args", "self, args"); + Printv(f->code, dispatch, "\n", NIL); + Printf(f->code, "Pike_error(\"No matching function for overloaded '%s'.\");\n", symname); + Printv(f->code, "}\n", NIL); + + Wrapper_print(f, f_wrappers); + + String *description = NewString(""); + Printf(description, "tAny,"); + if (current == CONSTRUCTOR || current == DESTRUCTOR) { + Printf(description, " tVoid"); + } else { + String *pd = Getattr(n, "tmap:out:pikedesc"); + if (pd) + Printf(description, " %s", pd); + } + add_method(symname, wname, description); + Delete(description); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + return Language::variableWrapper(n); + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + + Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL); + + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(symname); + Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); + value = wname; + } + + /* Perform constant typemap substitution */ + String *tm = Swig_typemap_lookup("constant", n, value, 0); + if (tm) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", symname); + Replaceall(tm, "$symname", symname); + Replaceall(tm, "$value", value); + Printf(f_init, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value %s = %s\n", SwigType_str(type, 0), value); + } + + Swig_restore(n); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + // return Language::nativeWrapper(n); + String *name = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + add_method(name, wrapname, 0); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + + String *symname = Getattr(n, "sym:name"); + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + PrefixPlusUnderscore = NewStringf("%s_", getClassPrefix()); + + Printf(f_classInit, "start_new_program();\n"); + + /* Handle inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist) > 0) { + Iterator base = First(baselist); + while (base.item) { + String *basename = Getattr(base.item, "name"); + SwigType *basetype = NewString(basename); + SwigType_add_pointer(basetype); + SwigType_remember(basetype); + String *basemangle = SwigType_manglestr(basetype); + Printf(f_classInit, "low_inherit((struct program *) SWIGTYPE%s->clientdata, 0, 0, 0, 0, 0);\n", basemangle); + Delete(basemangle); + Delete(basetype); + base = Next(base); + } + } else { + Printf(f_classInit, "ADD_STORAGE(swig_object_wrapper);\n"); + } + + Language::classHandler(n); + + /* Accessors for member variables */ + /* + List *membervariables = Getattr(n,"membervariables"); + if (membervariables && Len(membervariables) > 0) { + membervariableAccessors(membervariables); + } + */ + + /* Done, close the class and dump its definition to the init function */ + Printf(f_classInit, "add_program_constant(\"%s\", pr = end_program(), 0);\n", symname); + Dump(f_classInit, f_init); + Clear(f_classInit); + + SwigType *tt = NewString(symname); + SwigType_add_pointer(tt); + SwigType_remember(tt); + String *tm = SwigType_manglestr(tt); + Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) pr);\n", tm); + Delete(tm); + Delete(tt); + + Delete(PrefixPlusUnderscore); + PrefixPlusUnderscore = 0; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * + * Method for adding C++ member function + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + current = MEMBER_FUNC; + Language::memberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * + * Method for adding C++ member constructor + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + current = CONSTRUCTOR; + Language::constructorHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + current = DESTRUCTOR; + Language::destructorHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableAccessors() + * ------------------------------------------------------------ */ + + void membervariableAccessors(List *membervariables) { + String *name; + Iterator i; + bool need_setter; + String *funcname; + + /* If at least one of them is mutable, we need a setter */ + need_setter = false; + i = First(membervariables); + while (i.item) { + if (!GetFlag(i.item, "feature:immutable")) { + need_setter = true; + break; + } + i = Next(i); + } + + /* Create a function to set the values of the (mutable) variables */ + if (need_setter) { + Wrapper *wrapper = NewWrapper(); + String *setter = Swig_name_member(getClassPrefix(), (char *) "`->="); + String *wname = Swig_name_wrapper(setter); + Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL); + Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n"); + + i = First(membervariables); + while (i.item) { + if (!GetFlag(i.item, "feature:immutable")) { + name = Getattr(i.item, "name"); + funcname = Swig_name_wrapper(Swig_name_set(Swig_name_member(getClassPrefix(), name))); + Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name); + Printf(wrapper->code, "%s(args);\n", funcname); + Printf(wrapper->code, "return;\n"); + Printf(wrapper->code, "}\n"); + Delete(funcname); + } + i = Next(i); + } + + /* Close the function */ + Printf(wrapper->code, "pop_n_elems(args);\n"); + Printf(wrapper->code, "}\n"); + + /* Dump wrapper code to the output file */ + Wrapper_print(wrapper, f_wrappers); + + /* Register it with Pike */ + String *description = NewString("tStr tFloat, tVoid"); + add_method("`->=", wname, description); + Delete(description); + + /* Clean up */ + Delete(wname); + Delete(setter); + DelWrapper(wrapper); + } + + /* Create a function to get the values of the (mutable) variables */ + Wrapper *wrapper = NewWrapper(); + String *getter = Swig_name_member(getClassPrefix(), (char *) "`->"); + String *wname = Swig_name_wrapper(getter); + Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL); + Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n"); + + i = First(membervariables); + while (i.item) { + name = Getattr(i.item, "name"); + funcname = Swig_name_wrapper(Swig_name_get(Swig_name_member(getClassPrefix(), name))); + Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name); + Printf(wrapper->code, "%s(args);\n", funcname); + Printf(wrapper->code, "return;\n"); + Printf(wrapper->code, "}\n"); + Delete(funcname); + i = Next(i); + } + + /* Close the function */ + Printf(wrapper->code, "pop_n_elems(args);\n"); + Printf(wrapper->code, "}\n"); + + /* Dump wrapper code to the output file */ + Wrapper_print(wrapper, f_wrappers); + + /* Register it with Pike */ + String *description = NewString("tStr, tMix"); + add_method("`->", wname, description); + Delete(description); + + /* Clean up */ + Delete(wname); + Delete(getter); + DelWrapper(wrapper); + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + List *membervariables = Getattr(getCurrentClass(), "membervariables"); + if (!membervariables) { + membervariables = NewList(); + Setattr(getCurrentClass(), "membervariables", membervariables); + } + Append(membervariables, n); + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + current = STATIC_FUNC; + Language::staticmemberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * + * Create a C++ constant + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + current = CLASS_CONST; + constantWrapper(n); + current = NO_CPP; + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + current = STATIC_VAR; + Language::staticmembervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } +}; + +/* ----------------------------------------------------------------------------- + * swig_pike() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_pike() { + return new PIKE(); +} +extern "C" Language *swig_pike(void) { + return new_swig_pike(); +} diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx new file mode 100644 index 0000000..83df3aa --- /dev/null +++ b/Source/Modules/python.cxx @@ -0,0 +1,4067 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * python.cxx + * + * Python language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_python_cxx[] = "$Id: python.cxx 11518 2009-08-08 22:56:10Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" + +static int treduce = SWIG_cparse_template_reduce(0); + +#include <ctype.h> + +#define PYSHADOW_MEMBER 0x2 + +static String *const_code = 0; +static String *module = 0; +static String *package = 0; +static String *mainmodule = 0; +static String *interface = 0; +static String *global_name = 0; +static int shadow = 1; +static int use_kw = 0; +static int director_method_index = 0; + +static File *f_begin = 0; +static File *f_runtime = 0; +static File *f_runtime_h = 0; +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; +static File *f_init = 0; +static File *f_shadow_py = 0; +static String *f_shadow = 0; +static String *f_shadow_imports = 0; +static String *f_shadow_stubs = 0; + +static String *methods; +static String *class_name; +static String *shadow_indent = 0; +static int in_class = 0; +static int classic = 0; +static int modern = 0; +static int new_repr = 1; +static int no_header_file = 0; + +static int py3 = 0; + +/* C++ Support + Shadow Classes */ + +static int have_constructor; +static int have_repr; +static String *real_classname; + +/* Thread Support */ +static int threads = 0; +static int nothreads = 0; +static int classptr = 0; +/* Other options */ +static int shadowimport = 1; +static int buildnone = 0; +static int nobuildnone = 0; +static int safecstrings = 0; +static int dirvtable = 0; +static int proxydel = 1; +static int fastunpack = 0; +static int fastproxy = 0; +static int fastquery = 0; +static int fastinit = 0; +static int olddefs = 0; +static int modernargs = 0; +static int aliasobj0 = 0; +static int castmode = 0; +static int extranative = 0; +static int outputtuple = 0; +static int nortti = 0; + +/* flags for the make_autodoc function */ +enum autodoc_t { + AUTODOC_CLASS, + AUTODOC_CTOR, + AUTODOC_DTOR, + AUTODOC_STATICFUNC, + AUTODOC_FUNC, + AUTODOC_METHOD +}; + + +static const char *usage1 = (char *) "\ +Python Options (available with -python)\n\ + -aliasobj0 - Alias obj0 when using fastunpack, needed for some old typemaps \n\ + -buildnone - Use Py_BuildValue(" ") to obtain Py_None (default in Windows)\n\ + -castmode - Enable the casting mode, which allows implicit cast between types in python\n\ + -classic - Use classic classes only\n\ + -classptr - Generate shadow 'ClassPtr' as in older swig versions\n\ + -cppcast - Enable C++ casting operators (default) \n\ + -dirvtable - Generate a pseudo virtual table for directors for faster dispatch \n\ + -extranative - Return extra native C++ wraps for std containers when possible \n\ + -fastinit - Use fast init mechanism for classes (default)\n\ + -fastunpack - Use fast unpack mechanism to parse the argument functions \n\ + -fastproxy - Use fast proxy mechanism for member methods \n\ + -fastquery - Use fast query mechanism for types \n\ + -globals <name> - Set <name> used to access C global variable [default: 'cvar']\n\ + -interface <lib>- Set the lib name to <lib>\n\ + -keyword - Use keyword arguments\n\ + -modern - Use modern python features only, without compatibility code\n\ + -modernargs - Use \"modern\" args mechanism to pack/unpack the function arguments\n"; +static const char *usage2 = (char *) "\ + -newrepr - Use more informative version of __repr__ in proxy classes (default) \n\ + -newvwm - New value wrapper mode, use only when everything else fails \n\ + -noaliasobj0 - Don't generate an obj0 alias when using fastunpack (default) \n\ + -nobuildnone - Access Py_None directly (default in non-Windows systems)\n\ + -nocastmode - Disable the casting mode (default)\n\ + -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ + -nodirvtable - Don't use the virtual table feature, resolve the python method each time (default)\n\ + -noexcept - No automatic exception handling\n\ + -noextranative - Don't use extra native C++ wraps for std containers when possible (default) \n\ + -nofastinit - Use traditional init mechanism for classes \n\ + -nofastunpack - Use traditional UnpackTuple method to parse the argument functions (default) \n\ + -nofastproxy - Use traditional proxy mechanism for member methods (default) \n\ + -nofastquery - Use traditional query mechanism for types (default) \n\ + -noh - Don't generate the output header file\n\ + -nomodern - Don't use modern python features which are not back compatible \n\ + -nomodernargs - Use classic ParseTuple/CallFunction methods to pack/unpack the function arguments (default) \n"; +static const char *usage3 = (char *) "\ + -noolddefs - Don't emit the old method definitions even when using fastproxy (default) \n\ + -nooutputtuple - Use a PyList for appending output values (default) \n\ + -noproxy - Don't generate proxy classes \n\ + -noproxydel - Don't generate the redundant __del__ method \n\ + -noproxyimport - Don't insert proxy import statements derived from the %import directive \n\ + -nortti - Disable the use of the native C++ RTTI with directors\n\ + -nosafecstrings - Avoid extra strings copies when possible (default)\n\ + -nothreads - Disable thread support for the entire interface\n\ + -olddefs - Keep the old method definitions even when using fastproxy\n\ + -oldrepr - Use shorter and old version of __repr__ in proxy classes\n\ + -outputtuple - Use a PyTuple for outputs instead of a PyList (use carefully with legacy interfaces) \n\ + -proxydel - Generate a __del__ method even though it is now redundant (default) \n\ + -safecstrings - Use safer (but slower) C string mapping, generating copies from Python -> C/C++\n\ + -threads - Add thread support for all the interface\n\ + -O - Enable all the optimization options: \n\ + -modern -fastdispatch -dirvtable -nosafecstrings -fvirtual -noproxydel \n\ + -fastproxy -fastinit -fastunpack -fastquery -modernargs -nobuildnone \n\ + -py3 - Generate code with Python 3 specific features:\n\ + Function annotation \n\ +\n"; + +class PYTHON:public Language { +public: + PYTHON() { + /* Add code to manage protected constructors and directors */ + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing abstract class or protected constructor\"); \n", " SWIG_fail;\n", "}\n", NIL); + director_multiple_inheritance = 1; + director_language = 1; + } + + /* ------------------------------------------------------------ + * Thread Implementation + * ------------------------------------------------------------ */ + + int threads_enable(Node *n) const { + return threads && !GetFlagAttr(n, "feature:nothread"); + } + + int initialize_threads(String *f_init) { + if (!threads) { + return SWIG_OK; + } + Printf(f_init, "\n"); + Printf(f_init, "/* Initialize threading */\n"); + Printf(f_init, "SWIG_PYTHON_INITIALIZE_THREADS;\n"); + + return SWIG_OK; + } + + virtual void thread_begin_block(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadblock")) { + String *bb = Getattr(n, "feature:threadbeginblock"); + if (bb) { + Append(f, bb); + } else { + Append(f, "SWIG_PYTHON_THREAD_BEGIN_BLOCK;\n"); + } + } + } + + virtual void thread_end_block(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadblock")) { + String *eb = Getattr(n, "feature:threadendblock"); + if (eb) { + Append(f, eb); + } else { + Append(f, "SWIG_PYTHON_THREAD_END_BLOCK;\n"); + } + } + } + + virtual void thread_begin_allow(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadallow")) { + String *bb = Getattr(n, "feature:threadbeginallow"); + if (bb) { + Append(f, bb); + } else { + Append(f, "SWIG_PYTHON_THREAD_BEGIN_ALLOW;\n"); + } + } + } + + virtual void thread_end_allow(Node *n, String *f) { + if (!GetFlag(n, "feature:nothreadallow")) { + String *eb = Getattr(n, "feature:threadendallow"); + if (eb) { + Append(f, eb); + } else { + Append(f, "SWIG_PYTHON_THREAD_END_ALLOW;\n"); + } + } + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int cppcast = 1; + + SWIG_library_directory("python"); + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-interface") == 0) { + if (argv[i + 1]) { + interface = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + /* end added */ + } else if (strcmp(argv[i], "-globals") == 0) { + if (argv[i + 1]) { + global_name = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-shadow") == 0) || ((strcmp(argv[i], "-proxy") == 0))) { + shadow = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-new_repr") == 0) || (strcmp(argv[i], "-newrepr") == 0)) { + new_repr = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-old_repr") == 0) || (strcmp(argv[i], "-oldrepr") == 0)) { + new_repr = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-classptr") == 0) { + classptr = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + shadow = 0; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-noproxyimport") == 0)) { + shadowimport = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-keyword") == 0) { + use_kw = 1; + SWIG_cparse_set_compact_default_args(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-classic") == 0) { + classic = 1; + modernargs = 0; + modern = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-outputtuple") == 0) { + outputtuple = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nooutputtuple") == 0) { + outputtuple = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nortti") == 0) { + nortti = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-threads") == 0) { + threads = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nothreads") == 0) { + /* Turn off thread suppor mode */ + nothreads = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-safecstrings") == 0) { + safecstrings = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nosafecstrings") == 0) { + safecstrings = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-buildnone") == 0) { + buildnone = 1; + nobuildnone = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nobuildnone") == 0) { + buildnone = 0; + nobuildnone = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-dirvtable") == 0) { + dirvtable = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nodirvtable") == 0) { + dirvtable = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastunpack") == 0) { + fastunpack = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastunpack") == 0) { + fastunpack = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastproxy") == 0) { + fastproxy = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastproxy") == 0) { + fastproxy = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastquery") == 0) { + fastquery = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastquery") == 0) { + fastquery = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fastinit") == 0) { + fastinit = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nofastinit") == 0) { + fastinit = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-olddefs") == 0) { + olddefs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noolddefs") == 0) { + olddefs = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-castmode") == 0) { + castmode = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocastmode") == 0) { + castmode = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-extranative") == 0) { + extranative = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noextranative") == 0) { + extranative = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-modernargs") == 0) { + modernargs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nomodernargs") == 0) { + modernargs = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-aliasobj0") == 0) { + aliasobj0 = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noaliasobj0") == 0) { + aliasobj0 = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-proxydel") == 0) { + proxydel = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noproxydel") == 0) { + proxydel = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-modern") == 0) { + classic = 0; + modern = 1; + modernargs = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nomodern") == 0) { + modern = 0; + modernargs = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noh") == 0) { + no_header_file = 1; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-new_vwm") == 0) || (strcmp(argv[i], "-newvwm") == 0)) { + /* Turn on new value wrapper mpde */ + Swig_value_wrapper_mode(1); + no_header_file = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-O") == 0) { + classic = 0; + modern = 1; + dirvtable = 1; + safecstrings = 0; + buildnone = 0; + nobuildnone = 1; + classptr = 0; + proxydel = 0; + fastunpack = 1; + fastproxy = 1; + fastinit = 1; + fastquery = 1; + modernargs = 1; + Wrapper_fast_dispatch_mode_set(1); + Wrapper_virtual_elimination_mode_set(1); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage1, stdout); + fputs(usage2, stdout); + fputs(usage3, stdout); + } else if (strcmp(argv[i], "-py3") == 0) { + py3 = 1; + Swig_mark_arg(i); + } + + } + } /* for */ + + if (py3) { + /* force disable features that not compatible with Python 3.x */ + classic = 0; + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + if (!global_name) + global_name = NewString("cvar"); + Preprocessor_define("SWIGPYTHON 1", 0); + SWIG_typemap_lang("python"); + SWIG_config_file("python.swg"); + allow_overloading(); + } + + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + String *mod_docstring = NULL; + { + Node *mod = Getattr(n, "module"); + if (mod) { + Node *options = Getattr(mod, "options"); + if (options) { + int dirprot = 0; + if (Getattr(options, "dirprot")) { + dirprot = 1; + } + if (Getattr(options, "nodirprot")) { + dirprot = 0; + } + if (Getattr(options, "directors")) { + allow_directors(); + if (dirprot) + allow_dirprot(); + } + if (Getattr(options, "threads")) { + threads = 1; + } + if (Getattr(options, "castmode")) { + castmode = 1; + } + if (Getattr(options, "nocastmode")) { + castmode = 0; + } + if (Getattr(options, "extranative")) { + extranative = 1; + } + if (Getattr(options, "noextranative")) { + extranative = 0; + } + if (Getattr(options, "outputtuple")) { + outputtuple = 1; + } + if (Getattr(options, "nooutputtuple")) { + outputtuple = 0; + } + mod_docstring = Getattr(options, "docstring"); + package = Getattr(options, "package"); + } + } + } + + /* Set comparison with none for ConstructorToFunction */ + setSubclassInstanceCheck(NewString("$arg != Py_None")); + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = !no_header_file ? Getattr(n, "outfile_h") : 0; + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + + if (directorsEnabled()) { + if (!no_header_file) { + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } else { + f_runtime_h = f_runtime; + } + } + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + const_code = NewString(""); + methods = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGPYTHON\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + if (nothreads) { + Printf(f_runtime, "#define SWIG_PYTHON_NO_THREADS\n"); + } else if (threads) { + Printf(f_runtime, "#define SWIG_PYTHON_THREADS\n"); + } + + if (safecstrings) { + Printf(f_runtime, "#define SWIG_PYTHON_SAFE_CSTRINGS\n"); + } + + if (buildnone) { + Printf(f_runtime, "#define SWIG_PYTHON_BUILD_NONE\n"); + } + + if (nobuildnone) { + Printf(f_runtime, "#define SWIG_PYTHON_NO_BUILD_NONE\n"); + } + + if (!dirvtable) { + Printf(f_runtime, "#define SWIG_PYTHON_DIRECTOR_NO_VTABLE\n"); + } + + if (outputtuple) { + Printf(f_runtime, "#define SWIG_PYTHON_OUTPUT_TUPLE\n"); + } + + if (nortti) { + Printf(f_runtime, "#ifndef SWIG_DIRECTOR_NORTTI\n"); + Printf(f_runtime, "#define SWIG_DIRECTOR_NORTTI\n"); + Printf(f_runtime, "#endif\n"); + } + + if (castmode) { + Printf(f_runtime, "#define SWIG_CASTRANK_MODE\n"); + Printf(f_runtime, "#define SWIG_PYTHON_CAST_MODE\n"); + } + + if (extranative) { + Printf(f_runtime, "#define SWIG_PYTHON_EXTRA_NATIVE_CONTAINERS\n"); + } + + if (classic) { + Printf(f_runtime, "#define SWIG_PYTHON_CLASSIC\n"); + } + + Printf(f_runtime, "\n"); + + Printf(f_header, "#if (PY_VERSION_HEX <= 0x02000000)\n"); + Printf(f_header, "# if !defined(SWIG_PYTHON_CLASSIC)\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-classic' option\"\n"); + Printf(f_header, "# endif\n"); + Printf(f_header, "#endif\n"); + + if (modern) { + Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodern' option\"\n"); + Printf(f_header, "#endif\n"); + } + + if (modernargs) { + Printf(f_header, "#if (PY_VERSION_HEX <= 0x02020000)\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-nomodernargs' option\"\n"); + Printf(f_header, "#endif\n"); + } + + if (fastunpack) { + Printf(f_header, "#ifndef METH_O\n"); + Printf(f_header, "# error \"This python version requires swig to be run with the '-nofastunpack' option\"\n"); + Printf(f_header, "#endif\n"); + } + + if (fastquery) { + Printf(f_header, "#ifdef SWIG_TypeQuery\n"); + Printf(f_header, "# undef SWIG_TypeQuery\n"); + Printf(f_header, "#endif\n"); + Printf(f_header, "#define SWIG_TypeQuery SWIG_Python_TypeQuery\n"); + } + + + /* Set module name */ + module = Copy(Getattr(n, "name")); + mainmodule = Getattr(n, "name"); + + if (directorsEnabled()) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module); + if (dirprot_mode()) { + Printf(f_directors_h, "#include <map>\n"); + Printf(f_directors_h, "#include <string>\n\n"); + } + + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + if (outfile_h) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + /* If shadow classing is enabled, we're going to change the module name to "_module" */ + if (shadow) { + String *filen = NewStringf("%s%s.py", SWIG_output_directory(), Char(module)); + // If we don't have an interface then change the module name X to _X + if (interface) + module = interface; + else + Insert(module, 0, "_"); + if ((f_shadow_py = NewFile(filen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Delete(filen); + filen = NULL; + + f_shadow = NewString(""); + f_shadow_imports = NewString(""); + f_shadow_stubs = NewString(""); + + Swig_register_filebyname("shadow", f_shadow); + Swig_register_filebyname("python", f_shadow); + + Swig_banner_target_lang(f_shadow, "#"); + + if (!modern) { + Printv(f_shadow, "# This file is compatible with both classic and new-style classes.\n", NIL); + } + + if (mod_docstring && Len(mod_docstring)) { + Printv(f_shadow, "\n\"\"\"\n", mod_docstring, "\n\"\"\"\n", NIL); + Delete(mod_docstring); + mod_docstring = NULL; + } + + Printv(f_shadow, "\nfrom sys import version_info\n", NULL); + + if(fastproxy) + { + Printv(f_shadow, "if version_info >= (3,0,0):\n", NULL); + Printf(f_shadow, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module); + Printv(f_shadow, "else:\n", NULL); + Printv(f_shadow, tab4, "from new import instancemethod as new_instancemethod\n", NULL); + } + /* Import the C-extension module. This should be a relative import, + * since the shadow module may also have been imported by a relative + * import, and there is thus no guarantee that the C-extension is on + * sys.path. Relative imports must be explicitly specified from 2.6.0 + * onwards (implicit relative imports will raise a DeprecationWarning + * in 2.6, and fail in 2.7 onwards), but the relative import syntax + * isn't available in python 2.4 or earlier, so we have to write some + * code conditional on the python version. + */ + Printv(f_shadow, "if version_info >= (2,6,0):\n", NULL); + Printv(f_shadow, tab4, "def swig_import_helper():\n", NULL); + Printv(f_shadow, tab8, "from os.path import dirname\n", NULL); + Printv(f_shadow, tab8, "import imp\n", NULL); + Printv(f_shadow, tab8, "fp = None\n", NULL); + Printv(f_shadow, tab8, "try:\n", NULL); + Printf(f_shadow, tab4 tab8 "fp, pathname, description = imp.find_module('%s', [dirname(__file__)])\n", module); + Printf(f_shadow, tab8 "except ImportError:\n"); + /* At here, the module may already loaded, so simply import it. */ + Printf(f_shadow, tab4 tab8 "import %s\n", module); + Printf(f_shadow, tab4 tab8 "return %s\n", module); + Printv(f_shadow, tab8 "if fp is not None:\n", NULL); + Printv(f_shadow, tab4 tab8 "try:\n", NULL); + Printf(f_shadow, tab8 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module); + Printv(f_shadow, tab4 tab8, "finally:\n", NULL); + Printv(f_shadow, tab8 tab8, "fp.close()\n", NULL); + Printv(f_shadow, tab4 tab8, "return _mod\n", NULL); + Printf(f_shadow, tab4 "%s = swig_import_helper()\n", module); + Printv(f_shadow, tab4, "del swig_import_helper\n", NULL); + Printv(f_shadow, "else:\n", NULL); + Printf(f_shadow, tab4 "import %s\n", module); + + /* Delete the version_info symbol since we don't use it elsewhere in the + * module. */ + Printv(f_shadow, "del version_info\n", NULL); + + if (modern || !classic) { + Printv(f_shadow, "try:\n", tab4, "_swig_property = property\n", "except NameError:\n", tab4, "pass # Python < 2.2 doesn't have 'property'.\n", NULL); + } + /* if (!modern) */ + /* always needed, a class can be forced to be no-modern, such as an exception */ + { + // Python-2.2 object hack + Printv(f_shadow, + "def _swig_setattr_nondynamic(self,class_type,name,value,static=1):\n", + tab4, "if (name == \"thisown\"): return self.this.own(value)\n", + tab4, "if (name == \"this\"):\n", tab4, tab4, "if type(value).__name__ == 'SwigPyObject':\n", tab4, tab8, "self.__dict__[name] = value\n", +#ifdef USE_THISOWN + tab4, tab8, "if hasattr(value,\"thisown\"): self.__dict__[\"thisown\"] = value.thisown\n", tab4, tab8, "del value.thisown\n", +#endif + tab4, tab8, "return\n", tab4, "method = class_type.__swig_setmethods__.get(name,None)\n", tab4, "if method: return method(self,value)\n", +#ifdef USE_THISOWN + tab4, "if (not static) or hasattr(self,name) or (name == \"thisown\"):\n", +#else + tab4, "if (not static) or hasattr(self,name):\n", +#endif + tab4, tab4, "self.__dict__[name] = value\n", + tab4, "else:\n", + tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n\n", + "def _swig_setattr(self,class_type,name,value):\n", tab4, "return _swig_setattr_nondynamic(self,class_type,name,value,0)\n\n", NIL); + + Printv(f_shadow, + "def _swig_getattr(self,class_type,name):\n", + tab4, "if (name == \"thisown\"): return self.this.own()\n", + tab4, "method = class_type.__swig_getmethods__.get(name,None)\n", + tab4, "if method: return method(self)\n", tab4, "raise AttributeError(name)\n\n", NIL); + + Printv(f_shadow, + "def _swig_repr(self):\n", + tab4, "try: strthis = \"proxy of \" + self.this.__repr__()\n", + tab4, "except: strthis = \"\"\n", tab4, "return \"<%s.%s; %s >\" % (self.__class__.__module__, self.__class__.__name__, strthis,)\n\n", NIL); + + if (!classic) { + /* Usage of types.ObjectType is deprecated. + * But don't sure wether this would broken old Python? + */ + Printv(f_shadow, +// "import types\n", + "try:\n", +// " _object = types.ObjectType\n", + " _object = object\n", + " _newclass = 1\n", "except AttributeError:\n", " class _object : pass\n", " _newclass = 0\n", +// "del types\n", + "\n\n", NIL); + } + } + if (modern) { + Printv(f_shadow, "def _swig_setattr_nondynamic_method(set):\n", tab4, "def set_attr(self,name,value):\n", +#ifdef USE_THISOWN + tab4, tab4, "if hasattr(self,name) or (name in (\"this\", \"thisown\")):\n", +#else + tab4, tab4, "if (name == \"thisown\"): return self.this.own(value)\n", tab4, tab4, "if hasattr(self,name) or (name == \"this\"):\n", +#endif + tab4, tab4, tab4, "set(self,name,value)\n", + tab4, tab4, "else:\n", + tab4, tab4, tab4, "raise AttributeError(\"You cannot add attributes to %s\" % self)\n", tab4, "return set_attr\n\n\n", NIL); + } + + if (directorsEnabled()) { + // Try loading weakref.proxy, which is only available in Python 2.1 and higher + Printv(f_shadow, + "try:\n", tab4, "import weakref\n", tab4, "weakref_proxy = weakref.proxy\n", "except:\n", tab4, "weakref_proxy = lambda x: x\n", "\n\n", NIL); + } + // Include some information in the code + Printf(f_header, "\n/*-----------------------------------------------\n @(target):= %s.so\n\ + ------------------------------------------------*/\n", module); + + } + + Printf(f_header, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_header, "# define SWIG_init PyInit_%s\n\n", module); + Printf(f_header, "#else\n"); + Printf(f_header, "# define SWIG_init init%s\n\n", module); + Printf(f_header, "#endif\n"); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n"); + Append(const_code, "static swig_const_info swig_const_table[] = {\n"); + Append(methods, "static PyMethodDef SwigMethods[] = {\n"); + + /* the method exported for replacement of new.instancemethod in Python 3 */ + add_pyinstancemethod_new(); + + /* emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director.swg", f_runtime); + } + + /* Close language module */ + Append(methods, "\t { NULL, NULL, 0, NULL }\n"); + Append(methods, "};\n"); + Printf(f_wrappers, "%s\n", methods); + + SwigType_emit_type_table(f_runtime, f_wrappers); + + Append(const_code, "{0, 0, 0, 0.0, 0, 0}};\n"); + Printf(f_wrappers, "%s\n", const_code); + initialize_threads(f_init); + + Printf(f_init, "#if PY_VERSION_HEX >= 0x03000000\n"); + Printf(f_init, " return m;\n"); + Printf(f_init, "#else\n"); + Printf(f_init, " return;\n"); + Printf(f_init, "#endif\n"); + Printf(f_init, "}\n"); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + if (shadow) { + Printv(f_shadow_py, f_shadow, "\n", NIL); + Printv(f_shadow_py, f_shadow_stubs, "\n", NIL); + + Close(f_shadow_py); + Delete(f_shadow_py); + } + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + if (f_runtime_h != f_begin) + Close(f_runtime_h); + Dump(f_directors, f_begin); + } + + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_directors); + Delete(f_directors_h); + + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * Emit the wrapper for PyInstanceMethod_New to MethodDef array. + * This wrapper is used to implement -fastproxy, + * as a replacement of new.instancemethod in Python 3. + * ------------------------------------------------------------ */ + int add_pyinstancemethod_new() + { + String* name = NewString("SWIG_PyInstanceMethod_New"); + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, NULL},\n", name, name); + Delete(name); + return 0; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + if (shadow) { + String *modname = Getattr(n, "module"); + + if (modname) { + String *import = NewString("import "); + + // Find the module node for this imported module. It should be the + // first child but search just in case. + Node *mod = firstChild(n); + while (mod && Strcmp(nodeType(mod), "module") != 0) + mod = nextSibling(mod); + + // Is the imported module in another package? (IOW, does it use the + // %module(package="name") option and it's different than the package + // of this module.) + Node *options = Getattr(mod, "options"); + String *pkg = options ? Getattr(options, "package") : 0; + if (pkg && (!package || Strcmp(pkg, package) != 0)) { + Printf(import, "%s.", pkg); + } + // finally, output the name of the imported module + if (shadowimport) { + if (!options || (!Getattr(options, "noshadow") && !Getattr(options, "noproxy"))) { + Printf(import, "_%s\n", modname); + if (!Strstr(f_shadow_imports, import)) { + if (pkg && (!package || Strcmp(pkg, package) != 0)) { + Printf(f_shadow, "import %s.%s\n", pkg, modname); + } else { + Printf(f_shadow, "import %s\n", modname); + } + Printv(f_shadow_imports, import, NULL); + } + } + } + + Delete(import); + } + } + return Language::importDirective(n); + } + + /* ------------------------------------------------------------ + * funcCall() + * Emit shadow code to call a function in the extension + * module. Using proper argument and calling style for + * given node n. + * ------------------------------------------------------------ */ + String *funcCall(String *name, String *parms) { + String *str = NewString(""); + + Printv(str, module, ".", name, "(", parms, ")", NIL); + return str; + } + + + /* ------------------------------------------------------------ + * pythoncode() - Output python code into the shadow file + * ------------------------------------------------------------ */ + + String *pythoncode(String *code, const_String_or_char_ptr indent) { + String *out = NewString(""); + String *temp; + char *t; + if (!indent) + indent = ""; + + temp = NewString(code); + + t = Char(temp); + if (*t == '{') { + Delitem(temp, 0); + Delitem(temp, DOH_END); + } + + /* Split the input text into lines */ + List *clist = DohSplitLines(temp); + Delete(temp); + int initial = 0; + String *s = 0; + Iterator si; + /* Get the initial indentation */ + + for (si = First(clist); si.item; si = Next(si)) { + s = si.item; + if (Len(s)) { + char *c = Char(s); + while (*c) { + if (!isspace(*c)) + break; + initial++; + c++; + } + if (*c && !isspace(*c)) + break; + else { + initial = 0; + } + } + } + while (si.item) { + s = si.item; + if (Len(s) > initial) { + char *c = Char(s); + c += initial; + Printv(out, indent, c, "\n", NIL); + } else { + Printv(out, "\n", NIL); + } + si = Next(si); + } + Delete(clist); + return out; + } + + + /* ------------------------------------------------------------ + * autodoc level declarations + * ------------------------------------------------------------ */ + + enum autodoc_l { + NO_AUTODOC = -2, // no autodoc + STRING_AUTODOC = -1, // use provided string + NAMES_AUTODOC = 0, // only parameter names + TYPES_AUTODOC = 1, // parameter names and types + EXTEND_AUTODOC = 2, // extended documentation and parameter names + EXTEND_TYPES_AUTODOC = 3 // extended documentation and parameter types + names + }; + + + autodoc_l autodoc_level(String *autodoc) { + autodoc_l dlevel = NO_AUTODOC; + if (autodoc) { + char *c = Char(autodoc); + if (c && isdigit(c[0])) { + dlevel = (autodoc_l) atoi(c); + } else { + if (strcmp(c, "extended") == 0) { + dlevel = EXTEND_AUTODOC; + } else { + dlevel = STRING_AUTODOC; + } + } + } + return dlevel; + } + + + /* ------------------------------------------------------------ + * have_docstring() + * Check if there is a docstring directive and it has text, + * or there is an autodoc flag set + * ------------------------------------------------------------ */ + + bool have_docstring(Node *n) { + String *str = Getattr(n, "feature:docstring"); + return (str != NULL && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + } + + /* ------------------------------------------------------------ + * docstring() + * Get the docstring text, stripping off {} if neccessary, + * and enclose in triple double quotes. If autodoc is also + * set then it will build a combined docstring. + * ------------------------------------------------------------ */ + + String *docstring(Node *n, autodoc_t ad_type, const String *indent, bool use_triple = true) { + String *str = Getattr(n, "feature:docstring"); + bool have_ds = (str != NULL && Len(str) > 0); + bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + const char *triple_double = use_triple ? "\"\"\"" : ""; + String *autodoc = NULL; + String *doc = NULL; + + if (have_ds) { + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + } + + if (have_auto) { + autodoc = make_autodoc(n, ad_type); + have_auto = (autodoc != NULL && Len(autodoc) > 0); + } + // If there is more than one line then make docstrings like this: + // + // """ + // This is line1 + // And here is line2 followed by the rest of them + // """ + // + // otherwise, put it all on a single line + // + if (have_auto && have_ds) { // Both autodoc and docstring are present + doc = NewString(""); + Printv(doc, triple_double, "\n", pythoncode(autodoc, indent), "\n", pythoncode(str, indent), indent, triple_double, NIL); + } else if (!have_auto && have_ds) { // only docstring + if (Strchr(str, '\n') == NULL) { + doc = NewStringf("%s%s%s", triple_double, str, triple_double); + } else { + doc = NewString(""); + Printv(doc, triple_double, "\n", pythoncode(str, indent), indent, triple_double, NIL); + } + } else if (have_auto && !have_ds) { // only autodoc + if (Strchr(autodoc, '\n') == NULL) { + doc = NewStringf("%s%s%s", triple_double, autodoc, triple_double); + } else { + doc = NewString(""); + Printv(doc, triple_double, "\n", pythoncode(autodoc, indent), indent, triple_double, NIL); + } + } else + doc = NewString(""); + + // Save the generated strings in the parse tree in case they are used later + // by post processing tools + Setattr(n, "python:docstring", doc); + Setattr(n, "python:autodoc", autodoc); + return doc; + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * Note: the generated name should consist with that in kwnames[] + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(ParmList *plist, Parm *p, int arg_num) { + String *arg = 0; + String *pn = Swig_name_make(p, 0, Getattr(p, "name"), 0, 0); + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + if ( SwigType_isvarargs(Getattr(p, "type")) ) { + return NewString("*args"); + } + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + arg = (!pn || !Len(pn) || (count > 1)) ? NewStringf("arg%d", arg_num) : Copy(pn); + return arg; + } + + + /* ------------------------------------------------------------ + * make_autodocParmList() + * Generate the documentation for the function parameters + * Parameters: + * func_annotation: Function annotation support + * ------------------------------------------------------------ */ + + String *make_autodocParmList(Node *n, bool showTypes, bool calling=false, bool func_annotation=false) { + + + String *doc = NewString(""); + String *pdocs = Copy(Getattr(n, "feature:pdocs")); + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + Node *lookup; + + + int lines = 0; + int arg_num = 0; + const int maxwidth = 50; + + if(calling) + func_annotation = false; + + if (pdocs) + Append(pdocs, "\n"); + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + if (Strcmp(ParmList_protostr(plist), "void")==0) { + //No parameters actually + return doc; + } + + for (p = plist; p; p = pnext) { + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + + String *name = 0; + String *type = 0; + String *value = 0; + String *ptype = 0; + String *pdoc = Getattr(p, "tmap:doc"); + if (pdoc) { + name = Getattr(p, "tmap:doc:name"); + type = Getattr(p, "tmap:doc:type"); + value = Getattr(p, "tmap:doc:value"); + ptype = Getattr(p, "tmap:doc:pytype"); + } + + name = name ? name : Getattr(p, "name"); + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + name = makeParameterName(plist, p, arg_num); + // Reset it for convinient in further use. (mainly for makeParameterName()) + // Since the plist is created by CopyParmList, + // we can hope that the set would have no side effect + Setattr(p, "name", name); + + arg_num++; + + + if (Len(doc)) { + // add a comma to the previous one if any + Append(doc, ", "); + + // Do we need to wrap a long line? + if ((Len(doc) - lines * maxwidth) > maxwidth) { + Printf(doc, "\n%s", tab4); + lines += 1; + } + } + + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + + // Do the param type too? + if (showTypes) + Printf(doc, "%s ", type); + + + Append(doc, name); + if (pdoc) { + if (!pdocs) + pdocs = NewString("Parameters:\n"); + Printf(pdocs, " %s\n", pdoc); + } + + // Write the function annoation + if (func_annotation) + Printf(doc, " : '%s'", type); + + // Write default value + if (value && !calling) { + String* pv = pyvalue(value, Getattr(p, "type")); + if (pv) + value = pv; + else { + lookup = Swig_symbol_clookup(value, 0); + if (lookup) { + value = Getattr(lookup, "sym:name"); + } + } + Printf(doc, " = %s", value); + } + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + return doc; + } + + /* ------------------------------------------------------------ + * make_autodoc() + * Build a docstring for the node, using parameter and other + * info in the parse tree. If the value of the autodoc + * attribute is "0" then do not include parameter types, if + * it is "1" (the default) then do. If it has some other + * value then assume it is supplied by the extension writer + * and use it directly. + * ------------------------------------------------------------ */ + + String *make_autodoc(Node *n, autodoc_t ad_type) { + int extended = 0; + // If the function is overloaded then this funciton is called + // for the last one. Rewind to the first so the docstrings are + // in order. + while (Getattr(n, "sym:previousSibling")) + n = Getattr(n, "sym:previousSibling"); + + String *doc = NewString(""); + while (n) { + bool showTypes = false; + bool skipAuto = false; + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + switch (dlevel) { + case NO_AUTODOC: + break; + case NAMES_AUTODOC: + showTypes = false; + break; + case TYPES_AUTODOC: + showTypes = true; + break; + case EXTEND_AUTODOC: + extended = 1; + showTypes = false; + break; + case EXTEND_TYPES_AUTODOC: + extended = 1; + showTypes = true; + break; + case STRING_AUTODOC: + Append(doc, autodoc); + skipAuto = true; + break; + } + + if (!skipAuto) { + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + + if (type) { + if (Strcmp(type, "void") == 0) + type = NULL; + else { + type = SwigType_base(type); + Node *lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + } + } + + switch (ad_type) { + case AUTODOC_CLASS: + { + // Only do the autodoc if there isn't a docstring for the class + String *str = Getattr(n, "feature:docstring"); + if (str == NULL || Len(str) == 0) { + if (CPlusPlus) { + Printf(doc, "Proxy of C++ %s class", real_classname); + } else { + Printf(doc, "Proxy of C %s struct", real_classname); + } + } + } + break; + case AUTODOC_CTOR: + if (Strcmp(class_name, symname) == 0) { + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, "__init__(self, %s) -> %s", paramList, class_name); + else + Printf(doc, "__init__(self) -> %s", class_name); + } else + Printf(doc, "%s(%s) -> %s", symname, make_autodocParmList(n, showTypes), class_name); + break; + + case AUTODOC_DTOR: + Append(doc, "__del__(self)"); + break; + + case AUTODOC_STATICFUNC: + Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); + if (type) + Printf(doc, " -> %s", type); + break; + + case AUTODOC_FUNC: + Printf(doc, "%s(%s)", symname, make_autodocParmList(n, showTypes)); + if (type) + Printf(doc, " -> %s", type); + break; + + case AUTODOC_METHOD: + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, "%s(self, %s)", symname, paramList); + else + Printf(doc, "%s(self)", symname); + if (type) + Printf(doc, " -> %s", type); + break; + } + } + if (extended) { + String *pdocs = Getattr(n, "feature:pdocs"); + if (pdocs) { + Printv(doc, "\n", pdocs, NULL); + } + } + + // if it's overloaded then get the next decl and loop around again + n = Getattr(n, "sym:nextSibling"); + if (n) + Append(doc, "\n"); + } + + return doc; + } + + /* ------------------------------------------------------------ + * pyvalue() + * Check if string v can be a Python value literal, + * (eg. number or string), or translate it to a Python literal. + * ------------------------------------------------------------ */ + String* pyvalue(String *v, SwigType *t) + { + if (v && Len(v)>0) { + char fc = (Char(v))[0]; + if (('0'<=fc && fc<='9') || '\''==fc || '"'==fc) { + /* number or string (or maybe NULL pointer)*/ + if (SwigType_ispointer(t) && Strcmp(v, "0")==0) + return NewString("None"); + else + return v; + } + if (Strcmp(v, "true")==0 || Strcmp(v, "FALSE")==0) + return NewString("True"); + if (Strcmp(v, "false")==0 || Strcmp(v, "FALSE")==0) + return NewString("False"); + if (Strcmp(v, "NULL")==0) + return NewString("None"); + } + return 0; + } + /* ------------------------------------------------------------ + * is_primitive_defaultargs() + * Check if all the default args have primitive type. + * (So we can generate proper parameter list with default + * values..) + * ------------------------------------------------------------ */ + bool is_primitive_defaultargs(Node *n) + { + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + + Swig_typemap_attach_parms("in", plist, 0); + for (p = plist; p; p = pnext) { + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + continue; + } + } else { + pnext = nextSibling(p); + } + String *type = Getattr(p, "type"); + String *value = Getattr(p, "value"); + if (!pyvalue(value, type)) + return false; + } + return true; + } + + + /* ------------------------------------------------------------ + * is_real_overloaded() + * Check if the function is overloaded, but not just have some + * siblings generated due to the original function have + * default arguments. + * ------------------------------------------------------------ */ + bool is_real_overloaded(Node *n) + { + Node *h = Getattr(n, "sym:overloaded"); + Node *i; + if (!h) + return false; + + i = Getattr(h, "sym:nextSibling"); + while (i) { + Node *nn = Getattr(i, "defaultargs"); + if (nn != h) { + /* Check if overloaded function has defaultargs and + * pointed to the first overloaded. */ + return true; + } + i = Getattr(i, "sym:nextSibling"); + } + + return false; + } + + /* ------------------------------------------------------------ + * make_pyParmList() + * Generate parameter list for Python functions or methods, + * reuse make_autodocParmList() to do so. + * ------------------------------------------------------------ */ + String* make_pyParmList(Node *n, bool in_class, bool is_calling, int kw) + { + /* Get the original function for a defaultargs copy, + * see default_arguments() in parser.y. */ + Node *nn = Getattr(n, "defaultargs"); + if (nn) n = nn; + + /* For overloaded function, just use *args */ + if (is_real_overloaded(n) || + GetFlag(n, "feature:compactdefaultargs") || + !is_primitive_defaultargs(n)) + { + String *parms = NewString(""); + if(in_class) + Printf(parms, "self, "); + Printf(parms, "*args"); + if (kw) + Printf(parms, ", **kwargs"); + return parms; + } + + bool funcanno = py3 ? true : false; + String *params = NewString(""); + String *_params = make_autodocParmList(n, false, is_calling, funcanno); + + if (in_class) + { + Printf(params, "self"); + if(Len(_params) > 0) + Printf(params, ", "); + } + + Printv(params, _params, NULL); + + return params; + } + + /* ------------------------------------------------------------ + * have_pythonprepend() + * Check if there is a %pythonprepend directive and it has text + * ------------------------------------------------------------ */ + + bool have_pythonprepend(Node *n) { + String *str = Getattr(n, "feature:pythonprepend"); + return (str != NULL && Len(str) > 0); + } + + /* ------------------------------------------------------------ + * pythonprepend() + * Get the %pythonprepend code, stripping off {} if neccessary + * ------------------------------------------------------------ */ + + String *pythonprepend(Node *n) { + String *str = Getattr(n, "feature:pythonprepend"); + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + return str; + } + + /* ------------------------------------------------------------ + * have_pythonappend() + * Check if there is a %pythonappend directive and it has text + * ------------------------------------------------------------ */ + + bool have_pythonappend(Node *n) { + String *str = Getattr(n, "feature:pythonappend"); + if (!str) + str = Getattr(n, "feature:addtofunc"); + return (str != NULL && Len(str) > 0); + } + + /* ------------------------------------------------------------ + * pythonappend() + * Get the %pythonappend code, stripping off {} if neccessary + * ------------------------------------------------------------ */ + + String *pythonappend(Node *n) { + String *str = Getattr(n, "feature:pythonappend"); + if (!str) + str = Getattr(n, "feature:addtofunc"); + + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + return str; + } + + /* ------------------------------------------------------------ + * have_addtofunc() + * Check if there is a %addtofunc directive and it has text + * ------------------------------------------------------------ */ + + bool have_addtofunc(Node *n) { + return have_pythonappend(n) || have_pythonprepend(n) || have_docstring(n); + } + + + /* ------------------------------------------------------------ + * returnTypeAnnotation() + * Helper function for constructing the function annotation + * of the returning type, return a empty string for Python 2.x + * ------------------------------------------------------------ */ + String* returnTypeAnnotation(Node *n) + { + String *ret=0; + Parm *p = Getattr(n, "parms"); + String *tm; + /* Try to guess the returning type by argout typemap, + * however the result may not accurate. */ + while (p) { + if ((tm=Getattr(p, "tmap:argout:match_type"))) { + tm = SwigType_str(tm, 0); + if (ret) + Printv(ret, ", ", tm, NULL); + else + ret = tm; + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + /* If no argout typemap, then get the returning type from + * the function prototype. */ + if (!ret) { + ret = Getattr(n, "type"); + if (ret) ret = SwigType_str(ret, 0); + } + return (ret && py3) ? NewStringf(" -> \"%s\" ", ret) + : NewString(""); + } + + /* ------------------------------------------------------------ + * emitFunctionShadowHelper() + * Refactoring some common code out of functionWrapper and + * dispatchFunction that writes the proxy code for non-member + * functions. + * ------------------------------------------------------------ */ + + void emitFunctionShadowHelper(Node *n, File *f_dest, String *name, int kw) { + String *parms = make_pyParmList(n, false, false, kw); + String *callParms = make_pyParmList(n, false, true, kw); + /* Make a wrapper function to insert the code into */ + Printv(f_dest, "\ndef ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_dest, " ", docstring(n, AUTODOC_FUNC, tab4), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_dest, pythoncode(pythonprepend(n), " "), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_dest, " val = ", funcCall(name, callParms), "\n", NIL); + Printv(f_dest, pythoncode(pythonappend(n), " "), "\n", NIL); + Printv(f_dest, " return val\n", NIL); + } else { + Printv(f_dest, " return ", funcCall(name, callParms), "\n", NIL); + } + + if (Getattr(n, "feature:python:callback") || !have_addtofunc(n)) { + /* If there is no addtofunc directive then just assign from the extension module (for speed up) */ + Printv(f_dest, name, " = ", module, ".", name, "\n", NIL); + } + } + + + /* ------------------------------------------------------------ + * check_kwargs() + * check if using kwargs is allowed for this Node + * ------------------------------------------------------------ */ + + int check_kwargs(Node *n) { + return (use_kw || GetFlag(n, "feature:kwargs")) + && !GetFlag(n, "memberset") && !GetFlag(n, "memberget"); + } + + + + /* ------------------------------------------------------------ + * add_method() + * ------------------------------------------------------------ */ + + void add_method(String *name, String *function, int kw, Node *n = 0, int funpack = 0, int num_required = -1, int num_arguments = -1) { + if (!kw) { + if (n && funpack) { + if (num_required == 0 && num_arguments == 0) { + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_NOARGS, ", name, function); + } else if (num_required == 1 && num_arguments == 1) { + Printf(methods, "\t { (char *)\"%s\", (PyCFunction)%s, METH_O, ", name, function); + } else { + Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function); + } + } else { + Printf(methods, "\t { (char *)\"%s\", %s, METH_VARARGS, ", name, function); + } + } else { + Printf(methods, "\t { (char *)\"%s\", (PyCFunction) %s, METH_VARARGS | METH_KEYWORDS, ", name, function); + } + + if (!n) { + Append(methods, "NULL"); + } else if (Getattr(n, "feature:callback")) { + if (have_docstring(n)) { + String *ds = docstring(n, AUTODOC_FUNC, "", false); + Replaceall(ds, "\\", "\\\\"); + Replaceall(ds, "\"", "\\\""); + Replaceall(ds, "\n", "\\n\"\n\t\t\""); + Printf(methods, "(char *)\"%s\\nswig_ptr: %s\"", ds, Getattr(n, "feature:callback:name")); + } else { + Printf(methods, "(char *)\"swig_ptr: %s\"", Getattr(n, "feature:callback:name")); + } + } else if (have_docstring(n)) { + String *ds = docstring(n, AUTODOC_FUNC, "", false); + Replaceall(ds, "\\", "\\\\"); + Replaceall(ds, "\"", "\\\""); + Replaceall(ds, "\n", "\\n\"\n\t\t\""); + Printf(methods, "(char *)\"%s\"", ds); + } else { + Append(methods, "NULL"); + } + + Append(methods, "},\n"); + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + void dispatchFunction(Node *n, int funpack = 0) { + /* Last node in overloaded chain */ + + int maxargs; + + String *tmp = NewString(""); + String *dispatch; + const char *dispatch_code = funpack ? "return %s(self, argc, argv);" : "return %s(self, args);"; + + if (castmode) { + dispatch = Swig_overload_dispatch_cast(n, dispatch_code, &maxargs); + } else { + dispatch = Swig_overload_dispatch(n, dispatch_code, &maxargs); + } + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "PyObject *argv[%d]", maxargs + 1); + Wrapper_add_local(f, "argv", tmp); + + if (!fastunpack) { + Wrapper_add_local(f, "ii", "int ii"); + Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n"); + Append(f->code, "argc = (int)PyObject_Length(args);\n"); + Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs); + Append(f->code, "argv[ii] = PyTuple_GET_ITEM(args,ii);\n"); + Append(f->code, "}\n"); + } else { + String *iname = Getattr(n, "sym:name"); + Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args,\"%s\",0,%d,argv))) SWIG_fail;\n", iname, maxargs); + Append(f->code, "--argc;\n"); + } + + Replaceall(dispatch, "$args", "self,args"); + + Printv(f->code, dispatch, "\n", NIL); + + if (GetFlag(n, "feature:python:maybecall")) { + Append(f->code, "fail:\n"); + Append(f->code, "Py_INCREF(Py_NotImplemented);\n"); + Append(f->code, "return Py_NotImplemented;\n"); + } else { + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + Printf(protoTypes, "\n\" %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms"))); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Append(f->code, "fail:\n"); + Printf(f->code, "SWIG_SetErrorMsg(PyExc_NotImplementedError," + "\"Wrong number of arguments for overloaded function '%s'.\\n\"" "\n\" Possible C/C++ prototypes are:\\n\"%s);\n", symname, protoTypes); + Append(f->code, "return NULL;\n"); + Delete(protoTypes); + } + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + Node *p = Getattr(n, "sym:previousSibling"); + add_method(symname, wname, 0, p); + + /* Create a shadow for this function (if enabled and not in a member function) */ + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + emitFunctionShadowHelper(n, f_shadow_stubs, symname, 0); + } + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + + const char *get_implicitconv_flag(Node *klass) { + int conv = 0; + if (klass && GetFlag(klass, "feature:implicitconv")) { + conv = 1; + } + return conv ? "SWIG_POINTER_IMPLICIT_CONV" : "0"; + } + + + virtual int functionWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + int director_method = 0; + + Parm *p; + int i; + char source[64]; + Wrapper *f; + String *parse_args; + String *arglist; + String *get_pointers; + String *cleanup; + String *outarg; + String *kwargs; + String *tm; + String *overname = 0; + + int num_required; + int num_arguments; + int varargs = 0; + int allow_kwargs = check_kwargs(n); + + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + int destructor = (!Cmp(nodeType, "destructor")); + String *storage = Getattr(n, "storage"); + /* Only the first constructor is handled as init method. Others + constructor can be emitted via %rename */ + int handled_as_init = 0; + if (!have_constructor && (constructor || Getattr(n, "handled_as_constructor")) + && ((shadow & PYSHADOW_MEMBER))) { + String *nname = Getattr(n, "sym:name"); + String *sname = Getattr(getCurrentClass(), "sym:name"); + String *cname = Swig_name_construct(sname); + handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); + Delete(cname); + } + + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + f = NewWrapper(); + parse_args = NewString(""); + arglist = NewString(""); + get_pointers = NewString(""); + cleanup = NewString(""); + outarg = NewString(""); + kwargs = NewString(""); + + int allow_thread = threads_enable(n); + + Wrapper_add_local(f, "resultobj", "PyObject *resultobj = 0"); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self"))) + allow_kwargs = 0; + varargs = emit_isvarargs(l); + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + + if (!allow_kwargs || Getattr(n, "sym:overloaded")) { + if (!varargs) { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + } else { + Printv(f->def, "SWIGINTERN PyObject *", wname, "__varargs__", "(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *varargs) {", NIL); + } + if (allow_kwargs) { + Swig_warning(WARN_LANG_OVERLOAD_KEYWORD, input_file, line_number, "Can't use keyword arguments with overloaded functions (%s).\n", Swig_name_decl(n)); + allow_kwargs = 0; + } + } else { + if (varargs) { + Swig_warning(WARN_LANG_VARARGS_KEYWORD, input_file, line_number, "Can't wrap varargs with keyword arguments enabled\n"); + varargs = 0; + } + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {", NIL); + } + if (!allow_kwargs) { + Append(parse_args, " if (!PyArg_ParseTuple(args,(char *)\""); + } else { + Append(parse_args, " if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)\""); + Append(arglist, ",kwnames"); + } + + int funpack = modernargs && fastunpack && !varargs && !allow_kwargs; + int noargs = funpack && (num_required == 0 && num_arguments == 0); + int onearg = funpack && (num_required == 1 && num_arguments == 1); + + /* Generate code for argument marshalling */ + if (funpack) { + if (overname) { + if (aliasobj0) { + Append(f->code, "#define obj0 (swig_obj[0])\n"); + } + } else if (num_arguments) { + sprintf(source, "PyObject *swig_obj[%d]", num_arguments); + Wrapper_add_localv(f, "swig_obj", source, NIL); + if (aliasobj0) { + Append(f->code, "#define obj0 (swig_obj[0])\n"); + } + } + } + + + if (constructor && num_arguments == 1 && num_required == 1) { + if (Cmp(storage, "explicit") == 0) { + Node *parent = Swig_methodclass(n); + if (GetFlag(parent, "feature:implicitconv")) { + String *desc = NewStringf("SWIGTYPE%s", SwigType_manglestr(Getattr(n, "type"))); + Printf(f->code, "if (SWIG_CheckImplicit(%s)) SWIG_fail;\n", desc); + Delete(desc); + } + } + } + + int use_parse = 0; + Append(kwargs, "{"); + for (i = 0, p = l; i < num_arguments; i++) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + String *ln = Getattr(p, "lname"); + if (funpack) { + sprintf(source, "swig_obj[%d]", i); + } else { + sprintf(source, "obj%d", i); + } + + + Putc(',', arglist); + if (i == num_required) + Putc('|', parse_args); /* Optional argument separator */ + + /* Keyword argument handling */ + if (allow_kwargs) { + if (Len(pn)) { + String *tmp = 0; + String *name = pn; + if (!Getattr(p,"hidden")) { + name = tmp = Swig_name_make(p, 0, pn, 0, 0); + } + Printf(kwargs, "(char *) \"%s\",", name); + if (tmp) + Delete(tmp); + } else { + Printf(kwargs, "(char *)\"arg%d\",", i + 1); + } + } + + /* Look for an input typemap */ + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + if (funpack) { + Replaceall(tm, "$self", "swig_obj[0]"); + } else { + Replaceall(tm, "$self", "obj0"); + } + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); /* Save the location of the object */ + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + if (Getattr(p, "tmap:in:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p,"hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + Replaceall(tm, "$implicitconv", convflag); + Setattr(p, "implicitconv", convflag); + } + + Putc('O', parse_args); + if (!funpack) { + Wrapper_add_localv(f, source, "PyObject *", source, "= 0", NIL); + Printf(arglist, "&%s", source); + } + if (i >= num_required) + Printv(get_pointers, "if (", source, ") {\n", NIL); + Printv(get_pointers, tm, "\n", NIL); + if (i >= num_required) + Printv(get_pointers, "}\n", NIL); + + } else { + use_parse = 1; + Append(parse_args, parse); + Printf(arglist, "&%s", ln); + } + p = Getattr(p, "tmap:in:next"); + continue; + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + + /* finish argument marshalling */ + Append(kwargs, " NULL }"); + if (allow_kwargs) { + Printv(f->locals, " char * kwnames[] = ", kwargs, ";\n", NIL); + } + + if (use_parse || allow_kwargs || !modernargs) { + Printf(parse_args, ":%s\"", iname); + Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + funpack = 0; + } else { + Clear(parse_args); + if (funpack) { + Clear(f->def); + if (overname) { + if (noargs) { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **SWIGUNUSEDPARM(swig_obj)) {", NIL); + } else { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), int nobjs, PyObject **swig_obj) {", NIL); + } + Printf(parse_args, "if ((nobjs < %d) || (nobjs > %d)) SWIG_fail;\n", num_required, num_arguments); + } else { + if (noargs) { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + } else { + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + } + if (onearg) { + Printf(parse_args, "if (!args) SWIG_fail;\n"); + Printf(parse_args, "swig_obj[0] = args;\n"); + } else if (!noargs) { + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args,\"%s\",%d,%d,swig_obj)) SWIG_fail;\n", iname, num_required, num_arguments); + } else if (noargs) { + Printf(parse_args, "if (!SWIG_Python_UnpackTuple(args,\"%s\",%d,%d,0)) SWIG_fail;\n", iname, num_required, num_arguments); + } + } + } else { + Printf(parse_args, "if(!PyArg_UnpackTuple(args,(char *)\"%s\",%d,%d", iname, num_required, num_arguments); + Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL); + } + } + + /* Now piece together the first part of the wrapper function */ + Printv(f->code, parse_args, get_pointers, NIL); + + /* Check for trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + // if (!checkAttribute(p,"tmap:in:numinputs","0") && !Getattr(p,"tmap:in:parse")) { + if (!Getattr(p, "tmap:in:parse") && (tm = Getattr(p, "tmap:freearg"))) { + if (Getattr(p, "tmap:freearg:implicitconv")) { + const char *convflag = "0"; + if (!Getattr(p,"hidden")) { + SwigType *ptype = Getattr(p, "type"); + convflag = get_implicitconv_flag(classLookup(ptype)); + } + if (strcmp(convflag, "0") == 0) { + tm = 0; + } + } + if (tm && (Len(tm) != 0)) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* if the object is a director, and the method call originated from its + * underlying python object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in python. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); + if (dirprot_mode() && !is_public(n)) { + Printf(f->code, "if (!director || !(director->swig_get_inner(\"%s\"))) {\n", name); + Printf(f->code, "SWIG_SetErrorMsg(PyExc_RuntimeError,\"accessing protected member %s\");\n", name); + Append(f->code, "SWIG_fail;\n"); + Append(f->code, "}\n"); + } + Wrapper_add_local(f, "upcall", "bool upcall = false"); + if (funpack) { + Append(f->code, "upcall = (director && (director->swig_get_self()==swig_obj[0]));\n"); + } else { + Append(f->code, "upcall = (director && (director->swig_get_self()==obj0));\n"); + } + } + + /* Emit the function call */ + if (director_method) { + Append(f->code, "try {\n"); + } else { + if (allow_thread) { + Append(f->code, "{\n"); + thread_begin_allow(n, f->code); + } + } + + Setattr(n, "wrap:name", wname); + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (director_method) { + Append(actioncode, "} catch (Swig::DirectorException&) {\n"); + Append(actioncode, " SWIG_fail;\n"); + Append(actioncode, "}\n"); + } else { + if (allow_thread) { + thread_end_allow(n, actioncode); + Append(actioncode, "}\n"); + } + } + + /* This part below still needs cleanup */ + + /* Return the function value */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + if (funpack) { + Replaceall(tm, "$self", "swig_obj[0]"); + } else { + Replaceall(tm, "$self", "obj0"); + } + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); + if (handled_as_init) { + Replaceall(tm, "$owner", "SWIG_POINTER_NEW"); + } else { + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm, "$owner", "0"); + } + } + // FIXME: this will not try to unwrap directors returned as non-director + // base class pointers! + + /* New addition to unwrap director return values so that the original + * python object is returned instead. + */ +#if 1 + int unwrap = 0; + String *decl = Getattr(n, "decl"); + int is_pointer = SwigType_ispointer_return(decl); + int is_reference = SwigType_isreference_return(decl); + if (is_pointer || is_reference) { + String *type = Getattr(n, "type"); + //Node *classNode = Swig_methodclass(n); + //Node *module = Getattr(classNode, "module"); + Node *parent = Swig_methodclass(n); + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, type); + if (target) + unwrap = 1; + } + if (unwrap) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Append(f->code, "director = SWIG_DIRECTOR_CAST(result);\n"); + Append(f->code, "if (director) {\n"); + Append(f->code, " resultobj = director->swig_get_self();\n"); + Append(f->code, " Py_INCREF(resultobj);\n"); + Append(f->code, "} else {\n"); + Printf(f->code, "%s\n", tm); + Append(f->code, "}\n"); + } else { + Printf(f->code, "%s\n", tm); + } +#else + Printf(f->code, "%s\n", tm); +#endif + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + int need_cleanup = Len(cleanup) != 0; + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, "result", 0))) { + Replaceall(tm, "$input", "result"); + Replaceall(tm, "$result", "resultobj"); + Printf(f->code, "%s\n", tm); + Delete(tm); + } + } + + Append(f->code, " return resultobj;\n"); + + /* Error handling code */ + + Append(f->code, "fail:\n"); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, " return NULL;\n", NIL); + + + if (funpack) { + if (aliasobj0) { + Append(f->code, "#if defined(obj0)\n"); + Append(f->code, "#undef obj0\n"); + Append(f->code, "#endif\n"); + } + } + + + Append(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", "resultobj"); + + if (funpack) { + Replaceall(f->code, "$self", "swig_obj[0]"); + } else { + Replaceall(f->code, "$self", "obj0"); + } + + /* Dump the function out */ + Wrapper_print(f, f_wrappers); + + /* If varargs. Need to emit a varargs stub */ + if (varargs) { + DelWrapper(f); + f = NewWrapper(); + Printv(f->def, "SWIGINTERN PyObject *", wname, "(PyObject *self, PyObject *args) {", NIL); + Wrapper_add_local(f, "resultobj", "PyObject *resultobj"); + Wrapper_add_local(f, "varargs", "PyObject *varargs"); + Wrapper_add_local(f, "newargs", "PyObject *newargs"); + Printf(f->code, "newargs = PyTuple_GetSlice(args,0,%d);\n", num_arguments); + Printf(f->code, "varargs = PyTuple_GetSlice(args,%d,PyTuple_Size(args)+1);\n", num_arguments); + Printf(f->code, "resultobj = %s__varargs__(self,newargs,varargs);\n", wname); + Append(f->code, "Py_XDECREF(newargs);\n"); + Append(f->code, "Py_XDECREF(varargs);\n"); + Append(f->code, "return resultobj;\n"); + Append(f->code, "}\n"); + Wrapper_print(f, f_wrappers); + } + + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + add_method(iname, wname, allow_kwargs, n, funpack, num_required, num_arguments); + + /* Create a shadow for this function (if enabled and not in a member function) */ + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + emitFunctionShadowHelper(n, in_class ? f_shadow_stubs : f_shadow, iname, allow_kwargs); + } + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n, funpack); + } + } + Delete(parse_args); + Delete(arglist); + Delete(get_pointers); + Delete(cleanup); + Delete(outarg); + Delete(kwargs); + Delete(wname); + DelWrapper(f); + return SWIG_OK; + } + + + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + static int have_globals = 0; + String *tm; + Wrapper *getf, *setf; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + getf = NewWrapper(); + setf = NewWrapper(); + + /* If this is our first call, add the globals variable to the + Python dictionary. */ + + if (!have_globals) { + Printf(f_init, "\t PyDict_SetItemString(d,(char*)\"%s\", SWIG_globals());\n", global_name); + have_globals = 1; + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + Printf(f_shadow_stubs, "%s = %s.%s\n", global_name, module, global_name); + } + } + int assignable = is_assignable(n); + + if ((shadow) && !assignable) { + if (!in_class) { + Printf(f_shadow_stubs, "%s = %s.%s\n", iname, global_name, iname); + } + } + + String *getname = Swig_name_get(iname); + String *setname = Swig_name_set(iname); + String *vargetname = NewStringf("Swig_var_%s", getname); + String *varsetname = NewStringf("Swig_var_%s", setname); + + /* Create a function for setting the value of the variable */ + if (assignable) { + Setattr(n, "wrap:name", varsetname); + Printf(setf->def, "SWIGINTERN int %s(PyObject *_val) {", varsetname); + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "_val"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "_val"); + if (Getattr(n, "tmap:varin:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + emit_action_code(n, setf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + } + Printv(setf->code, " return 0;\n", NULL); + Append(setf->code, "fail:\n"); + Printv(setf->code, " return 1;\n", NULL); + } else { + /* Is a readonly variable. Issue an error */ + if (CPlusPlus) { + Printf(setf->def, "SWIGINTERN int %s(PyObject *) {", varsetname); + } else { + Printf(setf->def, "SWIGINTERN int %s(PyObject *_val SWIGUNUSED) {", varsetname); + } + Printv(setf->code, " SWIG_Error(SWIG_AttributeError,\"Variable ", iname, " is read-only.\");\n", " return 1;\n", NIL); + } + + Append(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + + /* Create a function for getting the value of a variable */ + Setattr(n, "wrap:name", vargetname); + int addfail = 0; + Printf(getf->def, "SWIGINTERN PyObject *%s(void) {", vargetname); + Wrapper_add_local(getf, "pyobj", "PyObject *pyobj = 0"); + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "pyobj"); + Replaceall(tm, "$result", "pyobj"); + addfail = emit_action_code(n, getf->code, tm); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + Append(getf->code, " return pyobj;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return NULL;\n"); + } + Append(getf->code, "}\n"); + + Wrapper_print(getf, f_wrappers); + + /* Now add this to the variable linking mechanism */ + Printf(f_init, "\t SWIG_addvarlink(SWIG_globals(),(char*)\"%s\",%s, %s);\n", iname, vargetname, varsetname); + + Delete(vargetname); + Delete(varsetname); + Delete(getname); + Delete(setname); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + int have_tm = 0; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + String *str = SwigType_str(type, wname); + Printf(f_header, "static %s = %s;\n", str, value); + Delete(str); + value = wname; + } + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Printf(const_code, "%s,\n", tm); + Delete(tm); + have_tm = 1; + } + if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Printf(f_init, "%s\n", tm); + Delete(tm); + have_tm = 1; + } + if (!have_tm) { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + if ((shadow) && (!(shadow & PYSHADOW_MEMBER))) { + if (!in_class) { + Printv(f_shadow, iname, " = ", module, ".", iname, "\n", NIL); + } else { + if (!(Getattr(n, "feature:python:callback"))) { + Printv(f_shadow_stubs, iname, " = ", module, ".", iname, "\n", NIL); + } + } + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + add_method(name, wrapname, 0); + if (shadow) { + Printv(f_shadow_stubs, name, " = ", module, ".", name, "\n", NIL); + } + return SWIG_OK; + } + + + +/* ---------------------------------------------------------------------------- + * BEGIN C++ Director Class modifications + * ------------------------------------------------------------------------- */ + +/* C++/Python polymorphism demo code, copyright (C) 2002 Mark Rose <mrose@stm.lbl.gov> + * + * TODO + * + * Move some boilerplate code generation to Swig_...() functions. + * + */ + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * ** Moved down due to gcc-2.96 internal error ** + * --------------------------------------------------------------- */ + + int classDirectorMethods(Node *n); + + int classDirectorMethod(Node *n, Node *parent, String *super); + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("PyObject"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self")); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { \n", classname, target, call); + Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); + Append(w->def, "}\n"); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + { + Node *parent = Swig_methodclass(n); + String *basetype = Getattr(parent, "classtype"); + Wrapper *w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(PyObject* self) : Swig::Director(self) { \n", classname, classname); + Printf(w->def, " SWIG_DIRECTOR_RGTR((%s *)this, this); \n", basetype); + Append(w->def, "}\n"); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " SwigDirector_%s(PyObject* self);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + String *classname = Swig_class_name(n); + + if (dirprot_mode()) { + /* + This implementation uses a std::map<std::string,int>. + + It should be possible to rewrite it using a more elegant way, + like copying the Java approach for the 'override' array. + + But for now, this seems to be the least intrusive way. + */ + Printf(f_directors_h, "\n\n"); + Printf(f_directors_h, "/* Internal Director utilities */\n"); + Printf(f_directors_h, "public:\n"); + Printf(f_directors_h, " bool swig_get_inner(const char* name) const {\n"); + Printf(f_directors_h, " std::map<std::string, bool>::const_iterator iv = inner.find(name);\n"); + Printf(f_directors_h, " return (iv != inner.end() ? iv->second : false);\n"); + Printf(f_directors_h, " }\n\n"); + + Printf(f_directors_h, " void swig_set_inner(const char* name, bool val) const\n"); + Printf(f_directors_h, " { inner[name] = val;}\n\n"); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " mutable std::map<std::string, bool> inner;\n"); + + } + if (director_method_index) { + Printf(f_directors_h, "\n\n"); + Printf(f_directors_h, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); + Printf(f_directors_h, "/* VTable implementation */\n"); + Printf(f_directors_h, " PyObject *swig_get_method(size_t method_index, const char *method_name) const {\n"); + Printf(f_directors_h, " PyObject *method = vtable[method_index];\n"); + Printf(f_directors_h, " if (!method) {\n"); + Printf(f_directors_h, " swig::SwigVar_PyObject name = SWIG_Python_str_FromChar(method_name);\n"); + Printf(f_directors_h, " method = PyObject_GetAttr(swig_get_self(), name);\n"); + Printf(f_directors_h, " if (method == NULL) {\n"); + Printf(f_directors_h, " std::string msg = \"Method in class %s doesn't exist, undefined \";\n", classname); + Printf(f_directors_h, " msg += method_name;\n"); + Printf(f_directors_h, " Swig::DirectorMethodException::raise(msg.c_str());\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, " vtable[method_index] = method;\n"); + Printf(f_directors_h, " };\n"); + Printf(f_directors_h, " return method;\n"); + Printf(f_directors_h, " }\n"); + Printf(f_directors_h, "private:\n"); + Printf(f_directors_h, " mutable swig::SwigVar_PyObject vtable[%d];\n", director_method_index); + Printf(f_directors_h, "#endif\n\n"); + } + + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + + /* ------------------------------------------------------------ + * classDirectorDisown() + * ------------------------------------------------------------ */ + + int classDirectorDisown(Node *n) { + int result; + int oldshadow = shadow; + /* disable shadowing */ + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + result = Language::classDirectorDisown(n); + shadow = oldshadow; + if (shadow) { + String *symname = Getattr(n, "sym:name"); + String *mrename = Swig_name_disown(symname); //Getattr(n, "name")); + Printv(f_shadow, tab4, "def __disown__(self):\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow, tab8, "self.thisown = 0\n", NIL); +#else + Printv(f_shadow, tab8, "self.this.disown()\n", NIL); +#endif + Printv(f_shadow, tab8, module, ".", mrename, "(self)\n", NIL); + Printv(f_shadow, tab8, "return weakref_proxy(self)\n", NIL); + Delete(mrename); + } + return result; + } + +/* ---------------------------------------------------------------------------- + * END of C++ Director Class modifications + * ------------------------------------------------------------------------- */ + + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + if (shadow && !Getattr(n, "feature:onlychildren")) { + Node *mod = Getattr(n, "module"); + if (mod) { + String *importname = NewString(""); + String *modname = Getattr(mod, "name"); + if (Strcmp(modname, mainmodule) != 0) { + // check if the module has a package option + Node *options = Getattr(mod, "options"); + String *pkg = options ? Getattr(options, "package") : 0; + if (pkg && (!package || Strcmp(pkg, package) != 0)) { + Printf(importname, "%s.", pkg); + } + Printf(importname, "%s.", modname); + } + Append(importname, Getattr(n, "sym:name")); + Setattr(n, "python:proxy", importname); + } + } + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + int oldclassic = classic; + int oldmodern = modern; + File *f_shadow_file = f_shadow; + + if (shadow) { + + /* Create new strings for building up a wrapper function */ + have_constructor = 0; + have_repr = 0; + + if (GetFlag(n, "feature:classic")) { + classic = 1; + modern = 0; + } + if (GetFlag(n, "feature:modern")) { + classic = 0; + modern = 1; + } + if (GetFlag(n, "feature:exceptionclass")) { + classic = 1; + modern = 0; + } + + shadow_indent = (String *) tab4; + + class_name = Getattr(n, "sym:name"); + real_classname = Getattr(n, "name"); + + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + /* Handle inheritance */ + String *base_class = NewString(""); + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "python:proxy"); + bool ignore = GetFlag(b.item, "feature:ignore") ? true : false; + if (!bname || ignore) { + if (!bname && !ignore) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, input_file, line_number, + "Base class '%s' ignored - unknown module name for base. Either import the appropriate module interface file or specify the name of the module in the %%import directive.\n", SwigType_namestr(Getattr(b.item, "name"))); + } + b = Next(b); + continue; + } + Printv(base_class, bname, NIL); + b = Next(b); + if (b.item) { + Putc(',', base_class); + } + } + } + + /* dealing with abstract base class */ + String *abcs = Getattr(n, "feature:python:abc"); + if (py3 && abcs) { + if (Len(base_class)) { + Putc(',', base_class); + } + Printv(base_class, abcs, NIL); + } + + Printv(f_shadow, "class ", class_name, NIL); + + if (Len(base_class)) { + Printf(f_shadow, "(%s)", base_class); + } else { + if (!classic) { + Printf(f_shadow, modern ? "(object)" : "(_object)"); + } + if (GetFlag(n, "feature:exceptionclass") ) { + Printf(f_shadow, "(Exception)"); + } + } + Printf(f_shadow, ":\n"); + if (have_docstring(n)) { + String *str = docstring(n, AUTODOC_CLASS, tab4); + if (str != NULL && Len(str)) + Printv(f_shadow, tab4, str, "\n", NIL); + } + if (!modern) { + Printv(f_shadow, tab4, "__swig_setmethods__ = {}\n", NIL); + if (Len(base_class)) { + Printf(f_shadow, "%sfor _s in [%s]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))\n", tab4, base_class); + } + + if (!GetFlag(n, "feature:python:nondynamic")) { + Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr(self, ", class_name, ", name, value)\n", NIL); + } else { + Printv(f_shadow, tab4, "__setattr__ = lambda self, name, value: _swig_setattr_nondynamic(self, ", class_name, ", name, value)\n", NIL); + } + + Printv(f_shadow, tab4, "__swig_getmethods__ = {}\n", NIL); + if (Len(base_class)) { + Printf(f_shadow, "%sfor _s in [%s]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))\n", tab4, base_class); + } + + Printv(f_shadow, tab4, "__getattr__ = lambda self, name: _swig_getattr(self, ", class_name, ", name)\n", NIL); + } else { + Printv(f_shadow, tab4, "thisown = _swig_property(lambda x: x.this.own(), ", "lambda x, v: x.this.own(v), doc='The membership flag')\n", NIL); + /* Add static attribute */ + if (GetFlag(n, "feature:python:nondynamic")) { + Printv(f_shadow_file, + tab4, "__setattr__ = _swig_setattr_nondynamic_method(object.__setattr__)\n", + tab4, "class __metaclass__(type):\n", tab4, tab4, "__setattr__ = _swig_setattr_nondynamic_method(type.__setattr__)\n", NIL); + } + } + } + + /* Emit all of the members */ + + in_class = 1; + + /* Overide the shadow file so we can capture its methods */ + f_shadow = NewString(""); + + Language::classHandler(n); + in_class = 0; + + /* Complete the class */ + if (shadow) { + /* Generate a class registration function */ + { + String *smartptr = Getattr(n, "feature:smartptr"); // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) + SwigType *smart = 0; + if (smartptr) { + SwigType *cpt = Swig_cparse_type(smartptr); + if (cpt) { + smart = SwigType_typedef_resolve_all(cpt); + Delete(cpt); + } else { + // TODO: report line number of where the feature comes from + Swig_error(Getfile(n), Getline(n), "Invalid type (%s) in 'smartptr' feature for class %s.\n", smartptr, real_classname); + } + } + SwigType *ct = Copy(smart ? smart : real_classname); + SwigType_add_pointer(ct); + SwigType *realct = Copy(real_classname); + SwigType_add_pointer(realct); + SwigType_remember(realct); + Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); + Printv(f_wrappers, " PyObject *obj;\n", NIL); + if (modernargs) { + if (fastunpack) { + Printv(f_wrappers, " if (!SWIG_Python_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); + } else { + Printv(f_wrappers, " if (!PyArg_UnpackTuple(args,(char*)\"swigregister\", 1, 1,&obj)) return NULL;\n", NIL); + } + } else { + Printv(f_wrappers, " if (!PyArg_ParseTuple(args,(char*)\"O:swigregister\", &obj)) return NULL;\n", NIL); + } + + Printv(f_wrappers, + " SWIG_TypeNewClientData(SWIGTYPE", SwigType_manglestr(ct), ", SWIG_NewClientData(obj));\n", + " return SWIG_Py_Void();\n", "}\n\n", NIL); + String *cname = NewStringf("%s_swigregister", class_name); + add_method(cname, cname, 0); + Delete(smart); + Delete(cname); + Delete(ct); + Delete(realct); + } + if (!have_constructor) { + Printv(f_shadow_file, tab4, "def __init__(self, *args, **kwargs): raise AttributeError(\"", "No constructor defined", (Getattr(n, "abstract") ? " - class is abstract" : ""), "\")\n", NIL); + } else if (fastinit) { + + Printv(f_wrappers, "SWIGINTERN PyObject *", class_name, "_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {\n", NIL); + Printv(f_wrappers, " return SWIG_Python_InitShadowInstance(args);\n", "}\n\n", NIL); + String *cname = NewStringf("%s_swiginit", class_name); + add_method(cname, cname, 0); + Delete(cname); + } + if (!have_repr) { + /* Supply a repr method for this class */ + String *rname = SwigType_namestr(real_classname); + if (new_repr) { + Printv(f_shadow_file, tab4, "__repr__ = _swig_repr\n", NIL); + } else { + Printv(f_shadow_file, tab4, "def __repr__(self):\n", tab8, "return \"<C ", rname, " instance at 0x%x>\" % (self.this,)\n", NIL); + } + Delete(rname); + } + + + /* Now emit methods */ + Printv(f_shadow_file, f_shadow, NIL); + + /* Now the Ptr class */ + if (classptr) { + Printv(f_shadow_file, "\nclass ", class_name, "Ptr(", class_name, "):\n", tab4, "def __init__(self, this):\n", NIL); + if (!modern) { + Printv(f_shadow_file, + tab8, "try: self.this.append(this)\n", + tab8, "except: self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL); + } else { + Printv(f_shadow_file, + tab8, "try: self.this.append(this)\n", + tab8, "except: self.this = this\n", tab8, "self.this.own(0)\n", tab8, "self.__class__ = ", class_name, "\n\n", NIL); + } + } + + if (fastproxy) { + List *shadow_list = Getattr(n, "shadow_methods"); + for (int i = 0; i < Len(shadow_list); ++i) { + String *symname = Getitem(shadow_list, i); + Printf(f_shadow_file, "%s.%s = new_instancemethod(%s.%s,None,%s)\n", class_name, symname, module, Swig_name_member(class_name, symname), class_name); + } + } + Printf(f_shadow_file, "%s_swigregister = %s.%s_swigregister\n", class_name, module, class_name); + Printf(f_shadow_file, "%s_swigregister(%s)\n", class_name, class_name); + + shadow_indent = 0; + Printf(f_shadow_file, "%s\n", f_shadow_stubs); + Clear(f_shadow_stubs); + } + classic = oldclassic; + modern = oldmodern; + + /* Restore shadow file back to original version */ + Delete(f_shadow); + f_shadow = f_shadow_file; + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * functionHandler() - Mainly overloaded for callback handling + * ------------------------------------------------------------ */ + + virtual int functionHandler(Node *n) { + String *pcb = GetFlagAttr(n, "feature:python:callback"); + if (pcb) { + if (Strcmp(pcb, "1") == 0) { + SetFlagAttr(n, "feature:callback", "%s_cb_ptr"); + } else { + SetFlagAttr(n, "feature:callback", pcb); + } + autodoc_l dlevel = autodoc_level(Getattr(n, "feature:autodoc")); + if (dlevel != NO_AUTODOC && dlevel > TYPES_AUTODOC) { + Setattr(n, "feature:autodoc", "1"); + } + } + return Language::functionHandler(n); + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow; + + /* Create the default member function */ + oldshadow = shadow; /* Disable shadowing when wrapping member functions */ + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::memberfunctionHandler(n); + shadow = oldshadow; + + if (!Getattr(n, "sym:nextSibling")) { + if (shadow) { + int allow_kwargs = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; + int fproxy = fastproxy; + if (Strcmp(symname, "__repr__") == 0) { + have_repr = 1; + } + if (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4); + String *pyaction = NewStringf("%s.%s", module, Swig_name_member(class_name, symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + fproxy = 0; + } else { + String *parms = make_pyParmList(n, true, false, allow_kwargs); + String *callParms = make_pyParmList(n, true, true, allow_kwargs); + if (!have_addtofunc(n)) { + if (!fastproxy || olddefs) { + Printv(f_shadow, tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":", NIL); + Printv(f_shadow, " return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); + } + } else { + Printv(f_shadow, tab4, "def ", symname, "(",parms , ")", returnTypeAnnotation(n), ":", NIL); + Printv(f_shadow, "\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_METHOD, tab8), "\n", NIL); + if (have_pythonprepend(n)) { + fproxy = 0; + Printv(f_shadow, pythoncode(pythonprepend(n), tab8), "\n", NIL); + } + if (have_pythonappend(n)) { + fproxy = 0; + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n", NIL); + Printv(f_shadow, tab8, "return val\n\n", NIL); + } else { + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n\n", NIL); + } + } + } + if (fproxy) { + List *shadow_list = Getattr(getCurrentClass(), "shadow_methods"); + if (!shadow_list) { + shadow_list = NewList(); + Setattr(getCurrentClass(), "shadow_methods", shadow_list); + Delete(shadow_list); + } + Append(shadow_list, symname); + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmemberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int staticmemberfunctionHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + Language::staticmemberfunctionHandler(n); + + if (Getattr(n, "sym:nextSibling")) { + return SWIG_OK; + } + + if (shadow) { + if (!classic && !Getattr(n, "feature:python:callback") && have_addtofunc(n)) { + int kw = (check_kwargs(n) && !Getattr(n, "sym:overloaded")) ? 1 : 0; + String *parms = make_pyParmList(n, false, false, kw); + String *callParms = make_pyParmList(n, false, true, kw); + Printv(f_shadow, tab4, "def ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_STATICFUNC, tab8), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow, pythoncode(pythonprepend(n), tab8), "\n", NIL); + if (have_pythonappend(n)) { + Printv(f_shadow, tab8, "val = ", funcCall(Swig_name_member(class_name, symname), callParms), "\n", NIL); + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n", NIL); + Printv(f_shadow, tab8, "return val\n\n", NIL); + } else { + Printv(f_shadow, tab8, "return ", funcCall(Swig_name_member(class_name, symname), callParms), "\n\n", NIL); + } + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", symname, ")\n", NIL); + + if (!modern) { + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", symname, "\n", NIL); + } + + } else { + if (!modern) { + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = lambda x: ", module, ".", Swig_name_member(class_name, symname), "\n", NIL); + } + if (!classic) { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = staticmethod(", module, ".", Swig_name_member(class_name, symname), ")\n", NIL); + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow = shadow; + int use_director = Swig_directorclass(n); + + /* + * If we're wrapping the constructor of a C++ director class, prepend a new parameter + * to receive the scripting language object (e.g. 'self') + * + */ + Swig_save("python:constructorHandler", n, "parms", NIL); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("PyObject"); + SwigType_add_pointer(type); + self = NewParm(type, name); + Delete(type); + Delete(name); + Setattr(self, "lname", "O"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Setattr(n, "hidden", "1"); + Delete(self); + } + + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::constructorHandler(n); + shadow = oldshadow; + + Delattr(n, "wrap:self"); + Swig_restore(n); + + if (!Getattr(n, "sym:nextSibling")) { + if (shadow) { + int allow_kwargs = (check_kwargs(n) && (!Getattr(n, "sym:overloaded"))) ? 1 : 0; + int handled_as_init = 0; + if (!have_constructor) { + String *nname = Getattr(n, "sym:name"); + String *sname = Getattr(getCurrentClass(), "sym:name"); + String *cname = Swig_name_construct(sname); + handled_as_init = (Strcmp(nname, sname) == 0) || (Strcmp(nname, cname) == 0); + Delete(cname); + } + + if (!have_constructor && handled_as_init) { + if (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4); + String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + } else { + String *pass_self = NewString(""); + Node *parent = Swig_methodclass(n); + String *classname = Swig_class_name(parent); + String *rclassname = Swig_class_name(getCurrentClass()); + assert(rclassname); + + String *parms = make_pyParmList(n, true, false, allow_kwargs); + /* Pass 'self' only if using director */ + String *callParms = make_pyParmList(n, false, true, allow_kwargs); + + if (use_director) { + Insert(callParms, 0, "_self, "); + Printv(pass_self, tab8, NIL); + Printf(pass_self, "if self.__class__ == %s:\n", classname); + //Printv(pass_self, tab8, tab4, "args = (None,) + args\n", tab8, "else:\n", tab8, tab4, "args = (self,) + args\n", NIL); + Printv(pass_self, tab8, tab4, "_self = None\n", tab8, "else:\n", tab8, tab4, "_self = self\n", NIL); + } + + Printv(f_shadow, tab4, "def __init__(", parms, ")", returnTypeAnnotation(n), ": \n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_CTOR, tab8), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow, pythoncode(pythonprepend(n), tab8), "\n", NIL); + Printv(f_shadow, pass_self, NIL); + if (fastinit) { + Printv(f_shadow, tab8, module, ".", class_name, "_swiginit(self,", funcCall(Swig_name_construct(symname), callParms), ")\n", NIL); + } else { + Printv(f_shadow, + tab8, "this = ", funcCall(Swig_name_construct(symname), callParms), "\n", + tab8, "try: self.this.append(this)\n", tab8, "except: self.this = this\n", NIL); + } + if (have_pythonappend(n)) + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n\n", NIL); + Delete(pass_self); + } + have_constructor = 1; + } else { + /* Hmmm. We seem to be creating a different constructor. We're just going to create a + function for it. */ + + if (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), ""); + String *pyaction = NewStringf("%s.%s", module, Swig_name_construct(symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow_stubs, pycode, "\n", NIL); + Delete(pycode); + } else { + String *parms = make_pyParmList(n, true, false, allow_kwargs); + String *callParms = make_pyParmList(n, true, true, allow_kwargs); + + Printv(f_shadow_stubs, "\ndef ", symname, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL); + if (have_docstring(n)) + Printv(f_shadow_stubs, tab4, docstring(n, AUTODOC_CTOR, tab4), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow_stubs, pythoncode(pythonprepend(n), tab4), "\n", NIL); + Printv(f_shadow_stubs, tab4, "val = ", funcCall(Swig_name_construct(symname), callParms), "\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow_stubs, tab4, "val.thisown = 1\n", NIL); +#endif + if (have_pythonappend(n)) + Printv(f_shadow_stubs, pythoncode(pythonappend(n), tab4), "\n", NIL); + Printv(f_shadow_stubs, tab4, "return val\n", NIL); + } + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow = shadow; + + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + //Setattr(n,"emit:dealloc","1"); + Language::destructorHandler(n); + shadow = oldshadow; + if (shadow) { + if (Getattr(n, "feature:shadow")) { + String *pycode = pythoncode(Getattr(n, "feature:shadow"), tab4); + String *pyaction = NewStringf("%s.%s", module, Swig_name_destroy(symname)); + Replaceall(pycode, "$action", pyaction); + Delete(pyaction); + Printv(f_shadow, pycode, "\n", NIL); + Delete(pycode); + } else { + Printv(f_shadow, tab4, "__swig_destroy__ = ", module, ".", Swig_name_destroy(symname), "\n", NIL); + if (!have_pythonprepend(n) && !have_pythonappend(n)) { + if (proxydel) { + Printv(f_shadow, tab4, "__del__ = lambda self : None;\n", NIL); + } + return SWIG_OK; + } + Printv(f_shadow, tab4, "def __del__(self):\n", NIL); + if (have_docstring(n)) + Printv(f_shadow, tab8, docstring(n, AUTODOC_DTOR, tab8), "\n", NIL); + if (have_pythonprepend(n)) + Printv(f_shadow, pythoncode(pythonprepend(n), tab8), "\n", NIL); +#ifdef USE_THISOWN + Printv(f_shadow, tab8, "try:\n", NIL); + Printv(f_shadow, tab8, tab4, "if self.thisown: ", module, ".", Swig_name_destroy(symname), "(self)\n", NIL); + Printv(f_shadow, tab8, "except: pass\n", NIL); +#else +#endif + if (have_pythonappend(n)) + Printv(f_shadow, pythoncode(pythonappend(n), tab8), "\n", NIL); + Printv(f_shadow, tab8, "pass\n", NIL); + Printv(f_shadow, "\n", NIL); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + + int oldshadow = shadow; + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::membervariableHandler(n); + shadow = oldshadow; + + if (shadow) { + String *mname = Swig_name_member(class_name, symname); + String *setname = Swig_name_set(mname); + String *getname = Swig_name_get(mname); + if (shadow) { + int assignable = is_assignable(n); + if (!modern) { + if (assignable) { + Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL); + } + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL); + } + if (!classic) { + if (!assignable) { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ")\n", NIL); + } else { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ", ", module, ".", setname, ")\n", NIL); + } + } + } + Delete(mname); + Delete(setname); + Delete(getname); + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * staticmembervariableHandler() + * ------------------------------------------------------------ */ + + virtual int staticmembervariableHandler(Node *n) { + Language::staticmembervariableHandler(n); + + if (shadow && !GetFlag(n, "wrappedasconstant")) { + String *symname = Getattr(n, "sym:name"); + if (GetFlag(n, "hasconsttype")) { + String *mname = Swig_name_member(class_name, symname); + Printf(f_shadow_stubs, "%s.%s = %s.%s.%s\n", class_name, symname, module, global_name, mname); + Delete(mname); + } else { + String *mname = Swig_name_member(class_name, symname); + String *getname = Swig_name_get(mname); + String *wrapgetname = Swig_name_wrapper(getname); + String *vargetname = NewStringf("Swig_var_%s", getname); + String *setname = Swig_name_set(mname); + String *wrapsetname = Swig_name_wrapper(setname); + String *varsetname = NewStringf("Swig_var_%s", setname); + + Wrapper *f = NewWrapper(); + Printv(f->def, "SWIGINTERN PyObject *", wrapgetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *SWIGUNUSEDPARM(args)) {", NIL); + Printv(f->code, " return ", vargetname, "();\n", NIL); + Append(f->code, "}\n"); + add_method(getname, wrapgetname, 0); + Wrapper_print(f, f_wrappers); + DelWrapper(f); + int assignable = is_assignable(n); + if (assignable) { + Wrapper *f = NewWrapper(); + Printv(f->def, "SWIGINTERN PyObject *", wrapsetname, "(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {", NIL); + Wrapper_add_local(f, "value", "PyObject *value"); + Wrapper_add_local(f, "res", "int res"); + Append(f->code, "if (!PyArg_ParseTuple(args,(char *)\"O:set\",&value)) return NULL;\n"); + Printv(f->code, "res = ", varsetname, "(value);\n", NIL); + Append(f->code, "return !res ? SWIG_Py_Void() : NULL;\n"); + Append(f->code, "}\n"); + Wrapper_print(f, f_wrappers); + add_method(setname, wrapsetname, 0); + DelWrapper(f); + } + if (!modern) { + if (assignable) { + Printv(f_shadow, tab4, "__swig_setmethods__[\"", symname, "\"] = ", module, ".", setname, "\n", NIL); + } + Printv(f_shadow, tab4, "__swig_getmethods__[\"", symname, "\"] = ", module, ".", getname, "\n", NIL); + } + if (!classic) { + if (!assignable) { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ")\n", NIL); + } else { + Printv(f_shadow, tab4, modern ? "" : "if _newclass:", symname, " = _swig_property(", module, ".", getname, ", ", module, ".", setname, ")\n", NIL); + } + } + Delete(mname); + Delete(getname); + Delete(wrapgetname); + Delete(vargetname); + Delete(setname); + Delete(wrapsetname); + Delete(varsetname); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + int oldshadow = shadow; + if (shadow) + shadow = shadow | PYSHADOW_MEMBER; + Language::memberconstantHandler(n); + shadow = oldshadow; + + if (shadow) { + Printv(f_shadow, tab4, symname, " = ", module, ".", Swig_name_member(class_name, symname), "\n", NIL); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * insertDirective() + * + * Hook for %insert directive. We're going to look for special %shadow inserts + * as a special case so we can do indenting correctly + * ------------------------------------------------------------ */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + String *section = Getattr(n, "section"); + + if ((!ImportMode) && ((Cmp(section, "python") == 0) || (Cmp(section, "shadow") == 0))) { + if (shadow) { + String *pycode = pythoncode(code, shadow_indent); + Printv(f_shadow, pycode, NIL); + Delete(pycode); + } + } else { + Language::insertDirective(n); + } + return SWIG_OK; + } + + virtual String *runtimeCode() { + String *s = NewString(""); + String *shead = Swig_include_sys("pyhead.swg"); + if (!shead) { + Printf(stderr, "*** Unable to open 'pyhead.swg'\n"); + } else { + Append(s, shead); + Delete(shead); + } + String *serrors = Swig_include_sys("pyerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'pyerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *sthread = Swig_include_sys("pythreads.swg"); + if (!sthread) { + Printf(stderr, "*** Unable to open 'pythreads.swg'\n"); + } else { + Append(s, sthread); + Delete(sthread); + } + String *sapi = Swig_include_sys("pyapi.swg"); + if (!sapi) { + Printf(stderr, "*** Unable to open 'pyapi.swg'\n"); + } else { + Append(s, sapi); + Delete(sapi); + } + String *srun = Swig_include_sys("pyrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'pyrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + virtual String *defaultExternalRuntimeFilename() { + return NewString("swigpyrun.h"); + } + +}; + +/* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * + * ** Moved it here due to internal error on gcc-2.96 ** + * --------------------------------------------------------------- */ +int PYTHON::classDirectorMethods(Node *n) { + director_method_index = 0; + return Language::classDirectorMethods(n); +} + + +int PYTHON::classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_type; + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + String *str = SwigType_str(Getattr(p, "type"), 0); + Append(w->def, str); + Append(declaration, str); + Delete(str); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($result). + */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *cres = SwigType_lstr(return_type, "c_result"); + Printf(w->code, "%s;\n", cres); + Delete(cres); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> Python) */ + String *arglist = NewString(""); + String *parse_args = NewString(""); + + /* remove the wrapper 'w' since it was producing spurious temps */ + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorargout", l, w); + + Parm *p; + char source[256]; + + int outputs = 0; + if (!is_void) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; + p = l; + int use_parse = 0; + while (p != NULL) { + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* old style? caused segfaults without the p!=0 check + in the for() condition, and seems dangerous in the + while loop as well. + while (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + } + */ + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + String *pname = Getattr(p, "name"); + String *ptype = Getattr(p, "type"); + + Putc(',', arglist); + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + String *parse = Getattr(p, "tmap:directorin:parse"); + if (!parse) { + sprintf(source, "obj%d", idx++); + String *input = NewString(source); + Replaceall(tm, "$input", input); + Delete(input); + Replaceall(tm, "$owner", "0"); + /* Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); */ + Printv(wrap_args, "swig::SwigVar_PyObject ", source, ";\n", NIL); + + Printv(wrap_args, tm, "\n", NIL); + Printv(arglist, "(PyObject *)", source, NIL); + Putc('O', parse_args); + } else { + use_parse = 1; + Append(parse_args, parse); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) + Append(tm, pname); + Append(arglist, tm); + } + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(ptype, "void")) { + /* special handling for pointers to other C++ director classes. + * ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. in other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. we avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, ptype); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(ptype) + 2); + /* name as pointer */ + String *ppname = Copy(pname); + if (SwigType_isreference(ptype)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Python doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", pname); + String *nonconst_i = NewStringf("= const_cast<%s>(%s)", SwigType_lstr(ptype, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", + SwigType_str(ptype, pname), SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(ptype); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_DIRECTOR_CAST(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Append(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "Py_INCREF((PyObject *)%s);\n", source); + Append(wrap_args, "}\n"); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "swig::SwigVar_PyObject", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Putc('O', parse_args); + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + /* add the method name as a PyString */ + String *pyname = Getattr(n, "sym:name"); + + int allow_thread = threads_enable(n); + + if (allow_thread) { + thread_begin_block(n, w->code); + Append(w->code, "{\n"); + } + + /* wrap complex arguments to PyObjects */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Python object */ + if (dirprot_mode() && !is_public(n)) { + Printf(w->code, "swig_set_inner(\"%s\", true);\n", name); + } + + + Append(w->code, "if (!swig_get_self()) {\n"); + Printf(w->code, " Swig::DirectorException::raise(\"'self' uninitialized, maybe you forgot to call %s.__init__.\");\n", classname); + Append(w->code, "}\n"); + Append(w->code, "#if defined(SWIG_PYTHON_DIRECTOR_VTABLE)\n"); + Printf(w->code, "const size_t swig_method_index = %d;\n", director_method_index++); + Printf(w->code, "const char * const swig_method_name = \"%s\";\n", pyname); + + Append(w->code, "PyObject* method = swig_get_method(swig_method_index, swig_method_name);\n"); + if (Len(parse_args) > 0) { + if (use_parse || !modernargs) { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunction(method, (char *)\"(%s)\" %s);\n", parse_args, arglist); + } else { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunctionObjArgs(method %s, NULL);\n", arglist); + } + } else { + if (modernargs) { + Append(w->code, "swig::SwigVar_PyObject args = PyTuple_New(0);\n"); + Append(w->code, "swig::SwigVar_PyObject result = PyObject_Call(method, (PyObject*) args, NULL);\n"); + } else { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallFunction(method, NULL, NULL);\n"); + } + } + Append(w->code, "#else\n"); + if (Len(parse_args) > 0) { + if (use_parse || !modernargs) { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *)\"%s\", (char *)\"(%s)\" %s);\n", + pyname, parse_args, arglist); + } else { + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name %s, NULL);\n", arglist); + } + } else { + if (!modernargs) { + Printf(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethod(swig_get_self(), (char *) \"%s\", NULL);\n", pyname); + } else { + Printf(w->code, "swig::SwigVar_PyObject swig_method_name = SWIG_Python_str_FromChar((char *)\"%s\");\n", pyname); + Append(w->code, "swig::SwigVar_PyObject result = PyObject_CallMethodObjArgs(swig_get_self(), (PyObject *) swig_method_name, NULL);\n"); + } + } + Append(w->code, "#endif\n"); + + if (dirprot_mode() && !is_public(n)) + Printf(w->code, "swig_set_inner(\"%s\", false);\n", name); + + /* exception handling */ + tm = Swig_typemap_lookup("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + if (tm) + tm = Copy(tm); + } + Append(w->code, "if (result == NULL) {\n"); + Append(w->code, " PyObject *error = PyErr_Occurred();\n"); + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Replaceall(tm, "$error", "error"); + Printv(w->code, Str(tm), "\n", NIL); + } else { + Append(w->code, " if (error != NULL) {\n"); + Printf(w->code, " Swig::DirectorMethodException::raise(\"Error detected when calling '%s.%s'\");\n", classname, pyname); + Append(w->code, " }\n"); + } + Append(w->code, "}\n"); + Delete(tm); + + /* + * Python method may return a simple object, or a tuple. + * for in/out aruments, we have to extract the appropriate PyObjects from the tuple, + * then marshal everything back to C/C++ (return value and output arguments). + * + */ + + /* marshal return value and other outputs (if any) from PyObject to C/C++ type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + if (outputs > 1) { + Wrapper_add_local(w, "output", "PyObject *output"); + Append(w->code, "if (!PyTuple_Check(result)) {\n"); + Printf(w->code, " Swig::DirectorTypeMismatchException::raise(\"Python method %s.%sfailed to return a tuple.\");\n", classname, pyname); + Append(w->code, "}\n"); + } + + idx = 0; + + /* marshal return value */ + if (!is_void) { + /* this seems really silly. the node's type excludes + * qualifier/pointer/reference markers, which have to be retrieved + * from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and + * out the correct type. it's not just me, similar silliness also + * occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + char temp[24]; + sprintf(temp, "%d", idx); + Replaceall(tm, "$argnum", temp); + + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + if (Getattr(n, "tmap:directorout:implicitconv")) { + Replaceall(tm, "$implicitconv", get_implicitconv_flag(n)); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), SwigType_namestr(c_classname), + SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + /* any existing helper functions to handle this? */ + if (allow_thread) { + Append(w->code, "}\n"); + thread_end_block(n, w->code); + } + + Delete(parse_args); + Delete(arglist); + Delete(cleanup); + Delete(outarg); + } + + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(return_type, 0); + if (!SwigType_isreference(return_type)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Append(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit the director method */ + if (status == SWIG_OK) { + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(return_type); + Delete(pclassname); + DelWrapper(w); + return status; +} + +/* ----------------------------------------------------------------------------- + * swig_python() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_python() { + return new PYTHON(); +} +extern "C" Language *swig_python(void) { + return new_swig_python(); +} diff --git a/Source/Modules/r.cxx b/Source/Modules/r.cxx new file mode 100644 index 0000000..966feb7 --- /dev/null +++ b/Source/Modules/r.cxx @@ -0,0 +1,2745 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * r.cxx + * + * R language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_r_cxx[] = "$Id: r.cxx 11454 2009-07-26 21:21:26Z wsfulton $"; + +#include "swigmod.h" + +#define UNUSED(a) (void)a + +static const double DEFAULT_NUMBER = .0000123456712312312323; +static const int MAX_OVERLOAD_ARGS = 5; + +static String* replaceInitialDash(const String *name) +{ + String *retval; + if (!Strncmp(name, "_", 1)) { + retval = Copy(name); + Insert(retval, 0, "s"); + } else { + retval = Copy(name); + } + return retval; +} + +static String * getRTypeName(SwigType *t, int *outCount = NULL) { + String *b = SwigType_base(t); + List *els = SwigType_split(t); + int count = 0; + int i; + + if(Strncmp(b, "struct ", 7) == 0) + Replace(b, "struct ", "", DOH_REPLACE_FIRST); + + /* Printf(stderr, "<getRTypeName> %s,base = %s\n", t, b); + for(i = 0; i < Len(els); i++) + Printf(stderr, "%d) %s, ", i, Getitem(els,i)); + Printf(stderr, "\n"); */ + + for(i = 0; i < Len(els); i++) { + String *el = Getitem(els, i); + if(Strcmp(el, "p.") == 0 || Strncmp(el, "a(", 2) == 0) { + count++; + Append(b, "Ref"); + } + } + if(outCount) + *outCount = count; + + String *tmp = NewString(""); + char *retName = Char(SwigType_manglestr(t)); + Insert(tmp, 0, retName); + return tmp; + + /* + if(count) + return(b); + + Delete(b); + return(NewString("")); + */ +} + +#if 0 +static String * getRType(Node *n) { + SwigType *elType = Getattr(n, "type"); + SwigType *elDecl = Getattr(n, "decl"); + //XXX How can we tell if this is already done. + SwigType_push(elType, elDecl); + String *ans; + + String *rtype = Swig_typemap_lookup("rtype", n, "", 0); + String *i = getRTypeName(elType); + + if(Len(i) == 0) { + SwigType *td = SwigType_typedef_resolve(elType); + if(td) { + // Printf(stderr, "Resolving typedef %s -> %s\n", elType, td); + i = getRTypeName(td); + } + } + // Printf(stderr, "<getRType> i = %s, rtype = %s (for %s)\n", + // i, rtype, elType); + if(rtype) { + ans = NewString(""); + Printf(ans, "%s", rtype); + Replaceall(ans, "$R_class", Char(i)); + // Printf(stderr, "Found r type in typemap for %s (for %s) => %s (%s) => %s\n", + // SwigType_str(elType, 0), Getattr(n, "name"), rtype, i, ans); + } else { + ans = i; + } + + return(ans); +} +#endif + +/********************* + Tries to get the name of the R class corresponding to the given type + e.g. struct A * is ARef, struct A** is ARefRef. + Now handles arrays, i.e. struct A[2] +****************/ + +static String *getRClassName(String *retType, int /*addRef*/ = 1, int upRef=0) { + String *tmp = NewString(""); + SwigType *resolved = SwigType_typedef_resolve_all(retType); + char *retName = Char(SwigType_manglestr(resolved)); + if (upRef) { + Printf(tmp, "_p%s", retName); + } else{ + Insert(tmp, 0, retName); + } + + return tmp; +/* +#if 1 + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + if (debugMode) + Printf(stderr, "SwigType_split return an empty list for %s\n", + retType); +#endif + return(tmp); + } + + + String *el = Getitem(l, n-1); + char *ptr = Char(el); + if(strncmp(ptr, "struct ", 7) == 0) + ptr += 7; + + Printf(tmp, "%s", ptr); + + if(addRef) { + for(int i = 0; i < n; i++) { + if(Strcmp(Getitem(l, i), "p.") == 0 || + Strncmp(Getitem(l, i), "a(", 2) == 0) + Printf(tmp, "Ref"); + } + } + +#else + char *retName = Char(SwigType_manglestr(retType)); + if(!retName) + return(tmp); + + if(addRef) { + while(retName && strlen(retName) > 1 && strncmp(retName, "_p", 2) == 0) { + retName += 2; + Printf(tmp, "Ref"); + } + } + if(retName[0] == '_') + retName ++; + Insert(tmp, 0, retName); +#endif + + return tmp; +*/ +} + +/********************* + Tries to get the name of the R class corresponding to the given type + e.g. struct A * is ARef, struct A** is ARefRef. + Now handles arrays, i.e. struct A[2] +****************/ + +static String * getRClassNameCopyStruct(String *retType, int addRef) { + String *tmp = NewString(""); + +#if 1 + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + Printf(stderr, "SwigType_split return an empty list for %s\n", retType); +#endif + return(tmp); + } + + + String *el = Getitem(l, n-1); + char *ptr = Char(el); + if(strncmp(ptr, "struct ", 7) == 0) + ptr += 7; + + Printf(tmp, "%s", ptr); + + if(addRef) { + for(int i = 0; i < n; i++) { + if(Strcmp(Getitem(l, i), "p.") == 0 || + Strncmp(Getitem(l, i), "a(", 2) == 0) + Printf(tmp, "Ref"); + } + } + +#else + char *retName = Char(SwigType_manglestr(retType)); + if(!retName) + return(tmp); + + if(addRef) { + while(retName && strlen(retName) > 1 && + strncmp(retName, "_p", 2) == 0) { + retName += 2; + Printf(tmp, "Ref"); + } + } + + if(retName[0] == '_') + retName ++; + Insert(tmp, 0, retName); +#endif + + return tmp; +} + + +/********************************* + Write the elements of a list to the File*, one element per line. + If quote is true, surround the element with "element". + This takes care of inserting a tab in front of each line and also + a comma after each element, except the last one. +**********************************/ + +static void writeListByLine(List *l, File *out, bool quote = 0) { + int i, n = Len(l); + for(i = 0; i < n; i++) + Printf(out, "%s%s%s%s%s\n", tab8, + quote ? "\"" :"", + Getitem(l, i), + quote ? "\"" :"", i < n-1 ? "," : ""); +} + + +static const char *usage = (char *)"\ +R Options (available with -r)\n\ + -copystruct - Emit R code to copy C structs (on by default)\n\ + -cppcast - Enable C++ casting operators (default) \n\ + -debug - Output debug\n\ + -dll <name> - Name of the DLL (without the .dll or .so suffix). Default is the module name.\n\ + -gc - Aggressive garbage collection\n\ + -memoryprof - Add memory profile\n\ + -namespace - Output NAMESPACE file\n\ + -no-init-code - Turn off the generation of the R_init_<pkgname> code (registration information still generated)\n\ + -package <name> - Package name for the PACKAGE argument of the R .Call() invocations. Default is the module name.\n\ +"; + + + +/************ + Display the help for this module on the screen/console. +*************/ +static void showUsage() { + fputs(usage, stdout); +} + +static bool expandTypedef(SwigType *t) { + if (SwigType_isenum(t)) return false; + String *prefix = SwigType_prefix(t); + if (Strncmp(prefix, "f", 1)) return false; + if (Strncmp(prefix, "p.f", 3)) return false; + return true; +} + + +/***** + Determine whether we should add a .copy argument to the S function + that wraps/interfaces to the routine that returns the given type. +*****/ +static int addCopyParameter(SwigType *type) { + int ok = 0; + ok = Strncmp(type, "struct ", 7) == 0 || Strncmp(type, "p.struct ", 9) == 0; + if(!ok) { + ok = Strncmp(type, "p.", 2); + } + + return(ok); +} + +static void replaceRClass(String *tm, SwigType *type) { + String *tmp = getRClassName(type); + String *tmp_base = getRClassName(type, 0); + String *tmp_ref = getRClassName(type, 1, 1); + Replaceall(tm, "$R_class", tmp); + Replaceall(tm, "$*R_class", tmp_base); + Replaceall(tm, "$&R_class", tmp_ref); + Delete(tmp); Delete(tmp_base); Delete(tmp_ref); +} + +static double getNumber(String *value, String *type) { + UNUSED(type); + + double d = DEFAULT_NUMBER; + if(Char(value)) { + // Printf(stderr, "getNumber %s %s\n", Char(value), type); + if(sscanf(Char(value), "%lf", &d) != 1) + return(DEFAULT_NUMBER); + } + return(d); +} + +class R : public Language { +public: + R(); + void registerClass(Node *n); + void main(int argc, char *argv[]); + int top(Node *n); + + void dispatchFunction(Node *n); + int functionWrapper(Node *n); + int variableWrapper(Node *n); + + int classDeclaration(Node *n); + int enumDeclaration(Node *n); + + int membervariableHandler(Node *n); + + int typedefHandler(Node *n); + + int memberfunctionHandler(Node *n) { + if (debugMode) + Printf(stderr, "<memberfunctionHandler> %s %s\n", + Getattr(n, "name"), + Getattr(n, "type")); + member_name = Getattr(n, "name"); + processing_class_member_function = 1; + int status = Language::memberfunctionHandler(n); + processing_class_member_function = 0; + return status; + } + + /* Grab the name of the current class being processed so that we can + deal with members of that class. */ + int classHandler(Node *n){ + if(!ClassMemberTable) + ClassMemberTable = NewHash(); + + class_name = Getattr(n, "name"); + int status = Language::classHandler(n); + + class_name = NULL; + return status; + } + + // Not used: + String *runtimeCode(); + +protected: + int addRegistrationRoutine(String *rname, int nargs); + int outputRegistrationRoutines(File *out); + + int outputCommandLineArguments(File *out); + int generateCopyRoutines(Node *n); + int DumpCode(Node *n); + + int OutputMemberReferenceMethod(String *className, int isSet, List *el, File *out); + int OutputArrayMethod(String *className, List *el, File *out); + int OutputClassMemberTable(Hash *tb, File *out); + int OutputClassMethodsTable(File *out); + int OutputClassAccessInfo(Hash *tb, File *out); + + int defineArrayAccessors(SwigType *type); + + void addNamespaceFunction(String *name) { + if(!namespaceFunctions) + namespaceFunctions = NewList(); + Append(namespaceFunctions, name); + } + + void addNamespaceMethod(String *name) { + if(!namespaceMethods) + namespaceMethods = NewList(); + Append(namespaceMethods, name); + } + + String* processType(SwigType *t, Node *n, int *nargs = NULL); + String *createFunctionPointerHandler(SwigType *t, Node *n, int *nargs); + int addFunctionPointerProxy(String *name, Node *n, SwigType *t, String *s_paramTypes) { + /*XXX Do we need to put the t in there to get the return type later. */ + if(!functionPointerProxyTable) + functionPointerProxyTable = NewHash(); + + Setattr(functionPointerProxyTable, name, n); + + Setattr(SClassDefs, name, name); + Printv(s_classes, "setClass('", + name, + "',\n", tab8, + "prototype = list(parameterTypes = c(", s_paramTypes, "),\n", + tab8, tab8, tab8, + "returnType = '", SwigType_manglestr(t), "'),\n", tab8, + "contains = 'CRoutinePointer')\n\n##\n", NIL); + + return SWIG_OK; + } + + + void addSMethodInfo(String *name, + String *argType, int nargs); + // Simple initialization such as constant strings that can be reused. + void init(); + + + void addAccessor(String *memberName, Wrapper *f, + String *name, int isSet = -1); + + static int getFunctionPointerNumArgs(Node *n, SwigType *tt); + +protected: + bool copyStruct; + bool memoryProfile; + bool aggressiveGc; + + // Strings into which we cumulate the generated code that is to be written + //vto the files. + String *sfile; + String *f_init; + String *s_classes; + String *f_begin; + String *f_runtime; + String *f_wrapper; + String *s_header; + String *f_wrappers; + String *s_init; + String *s_init_routine; + String *s_namespace; + + // State variables that carry information across calls to functionWrapper() + // from member accessors and class declarations. + String *opaqueClassDeclaration; + int processing_variable; + int processing_member_access_function; + String *member_name; + String *class_name; + + + int processing_class_member_function; + List *class_member_functions; + List *class_member_set_functions; + + /* */ + Hash *ClassMemberTable; + Hash *ClassMethodsTable; + Hash *SClassDefs; + Hash *SMethodInfo; + + // Information about routines that are generated and to be registered with + // R for dynamic lookup. + Hash *registrationTable; + Hash *functionPointerProxyTable; + + List *namespaceFunctions; + List *namespaceMethods; + List *namespaceClasses; // Probably can do this from ClassMemberTable. + + + // Store a copy of the command line. + // Need only keep a string that has it formatted. + char **Argv; + int Argc; + bool inCPlusMode; + + // State variables that we remember from the command line settings + // potentially that govern the code we generate. + String *DllName; + String *Rpackage; + bool noInitializationCode; + bool outputNamespaceInfo; + + String *UnProtectWrapupCode; + + // Static members + static bool debugMode; +}; + +R::R() : + copyStruct(false), + memoryProfile(false), + aggressiveGc(false), + sfile(0), + f_init(0), + s_classes(0), + f_begin(0), + f_runtime(0), + f_wrapper(0), + s_header(0), + f_wrappers(0), + s_init(0), + s_init_routine(0), + s_namespace(0), + opaqueClassDeclaration(0), + processing_variable(0), + processing_member_access_function(0), + member_name(0), + class_name(0), + processing_class_member_function(0), + class_member_functions(0), + class_member_set_functions(0), + ClassMemberTable(0), + ClassMethodsTable(0), + SClassDefs(0), + SMethodInfo(0), + registrationTable(0), + functionPointerProxyTable(0), + namespaceFunctions(0), + namespaceMethods(0), + namespaceClasses(0), + Argv(0), + Argc(0), + inCPlusMode(false), + DllName(0), + Rpackage(0), + noInitializationCode(false), + outputNamespaceInfo(false), + UnProtectWrapupCode(0) { +} + +bool R::debugMode = false; + +int R::getFunctionPointerNumArgs(Node *n, SwigType *tt) { + (void) tt; + n = Getattr(n, "type"); + if (debugMode) + Printf(stderr, "type: %s\n", n); +#if 0 + SwigType *tmp = SwigType_typedef_resolve(tt); + + n = SwigType_typedef_resolve(tt); +#endif + + ParmList *parms = Getattr(n, "parms"); + if (debugMode) + Printf(stderr, "parms = %p\n", parms); + return ParmList_len(parms); +} + + +void R::addSMethodInfo(String *name, String *argType, int nargs) { + (void) argType; + + if(!SMethodInfo) + SMethodInfo = NewHash(); + if (debugMode) + Printf(stderr, "[addMethodInfo] %s\n", name); + + Hash *tb = Getattr(SMethodInfo, name); + + if(!tb) { + tb = NewHash(); + Setattr(SMethodInfo, name, tb); + } + + String *str = Getattr(tb, "max"); + int max = -1; + if(str) + max = atoi(Char(str)); + if(max < nargs) { + if(str) Delete(str); + str = NewStringf("%d", max); + Setattr(tb, "max", str); + } +} + +/* +Returns the name of the new routine. +*/ +String * R::createFunctionPointerHandler(SwigType *t, Node *n, int *numArgs) { + String *funName = SwigType_manglestr(t); + + /* See if we have already processed this one. */ + if(functionPointerProxyTable && Getattr(functionPointerProxyTable, funName)) + return funName; + + if (debugMode) + Printf(stderr, "<createFunctionPointerHandler> Defining %s\n", t); + + SwigType *rettype = Copy(Getattr(n, "type")); + SwigType *funcparams = SwigType_functionpointer_decompose(rettype); + String *rtype = SwigType_str(rettype, 0); + + // ParmList *parms = Getattr(n, "parms"); + // memory leak + ParmList *parms = SwigType_function_parms(SwigType_del_pointer(Copy(t))); + + + // if (debugMode) { + Printf(stderr, "Type: %s\n", t); + Printf(stderr, "Return type: %s\n", SwigType_base(t)); + //} + + bool isVoidType = Strcmp(rettype, "void") == 0; + if (debugMode) + Printf(stderr, "%s is void ? %s (%s)\n", funName, isVoidType ? "yes" : "no", rettype); + + Wrapper *f = NewWrapper(); + + /* Go through argument list, attach lnames for arguments */ + int i = 0; + Parm *p = parms; + for (i = 0; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("s_arg%d", i+1); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + Swig_typemap_attach_parms("out", parms, f); + Swig_typemap_attach_parms("scoerceout", parms, f); + Swig_typemap_attach_parms("scheck", parms, f); + + Printf(f->def, "%s %s(", rtype, funName); + + emit_parameter_variables(parms, f); + emit_return_variable(n, rettype, f); +// emit_attach_parmmaps(parms,f); + + /* Using weird name and struct to avoid potential conflicts. */ + Wrapper_add_local(f, "r_swig_cb_data", "RCallbackFunctionData *r_swig_cb_data = R_SWIG_getCallbackFunctionData()"); + String *lvar = NewString("r_swig_cb_data"); + + Wrapper_add_local(f, "r_tmp", "SEXP r_tmp"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_nprotect", "int r_nprotect = 0"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_vmax", "char * r_vmax= 0"); // for use in converting arguments to R objects for call. + + // Add local for error code in return value. This is not in emit_return_variable because that assumes an out typemap + // whereas the type makes are reverse + Wrapper_add_local(f, "ecode", "int ecode = 0"); + + p = parms; + int nargs = ParmList_len(parms); + if(numArgs) { + *numArgs = nargs; + if (debugMode) + Printf(stderr, "Setting number of parameters to %d\n", *numArgs); + } + String *setExprElements = NewString(""); + + String *s_paramTypes = NewString(""); + for(i = 0; p; i++) { + SwigType *tt = Getattr(p, "type"); + SwigType *name = Getattr(p, "name"); + // String *lname = Getattr(p,"lname"); + Printf(f->def, "%s %s", SwigType_str(tt, 0), name); + String *tm = Getattr(p, "tmap:out"); + if(tm) { + Replaceall(tm, "$1", name); + Replaceall(tm, "$result", "r_tmp"); + replaceRClass(tm, Getattr(p,"type")); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + } + + Printf(setExprElements, "%s\n", tm); + Printf(setExprElements, "SETCAR(r_swig_cb_data->el, %s);\n", "r_tmp"); + Printf(setExprElements, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + + Printf(s_paramTypes, "'%s'", SwigType_manglestr(tt)); + + + p = nextSibling(p); + if(p) { + Printf(f->def, ", "); + Printf(s_paramTypes, ", "); + } + } + + Printf(f->def, ") {\n"); + + Printf(f->code, "Rf_protect(%s->expr = Rf_allocVector(LANGSXP, %d));\n", lvar, nargs + 1); + Printf(f->code, "r_nprotect++;\n"); + Printf(f->code, "r_swig_cb_data->el = r_swig_cb_data->expr;\n\n"); + + Printf(f->code, "SETCAR(r_swig_cb_data->el, r_swig_cb_data->fun);\n"); + Printf(f->code, "r_swig_cb_data->el = CDR(r_swig_cb_data->el);\n\n"); + + Printf(f->code, "%s\n\n", setExprElements); + + Printv(f->code, "r_swig_cb_data->retValue = R_tryEval(", + "r_swig_cb_data->expr,", + " R_GlobalEnv,", + " &r_swig_cb_data->errorOccurred", + ");\n", + NIL); + + Printv(f->code, "\n", + "if(r_swig_cb_data->errorOccurred) {\n", + "R_SWIG_popCallbackFunctionData(1);\n", + "Rf_error(\"error in calling R function as a function pointer (", + funName, + ")\");\n", + "}\n", + NIL); + + + + if(!isVoidType) { + /* Need to deal with the return type of the function pointer, not the function pointer itself. + So build a new node that has the relevant pieces. + XXX Have to be a little more clever so that we can deal with struct A * - the * is getting lost. + Is this still true? If so, will a SwigType_push() solve things? + */ + Node *bbase = NewHash(); + + Setattr(bbase, "type", rettype); + Setattr(bbase, "name", NewString("result")); + String *returnTM = Swig_typemap_lookup("in", bbase, "result", f); + if(returnTM) { + String *tm = returnTM; + Replaceall(tm,"$input", "r_swig_cb_data->retValue"); + Replaceall(tm,"$target", "result"); + replaceRClass(tm, rettype); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + Replaceall(tm,"$disown","0"); + Printf(f->code, "%s\n", tm); + } + Delete(bbase); + } + + Printv(f->code, "R_SWIG_popCallbackFunctionData(1);\n", NIL); + Printv(f->code, "\n", UnProtectWrapupCode, NIL); + + if(!isVoidType) + Printv(f->code, "return result;\n", NIL); + + Printv(f->code, "\n}\n", NIL); + + /* To coerce correctly in S, we really want to have an extra/intermediate + function that handles the scoerceout. + We need to check if any of the argument types have an entry in + that map. If none do, the ignore and call the function straight. + Otherwise, generate the a marshalling function. + Need to be able to find it in S. Or use an entirely generic one + that evaluates the expressions. + Handle errors in the evaluation of the function by restoring + the stack, if there is one in use for this function (i.e. no + userData). + */ + + Wrapper_print(f, f_wrapper); + + addFunctionPointerProxy(funName, n, t, s_paramTypes); + Delete(s_paramTypes); + Delete(rtype); + Delete(rettype); + Delete(funcparams); + + return funName; +} + +void R::init() { + UnProtectWrapupCode = + NewStringf("%s", "vmaxset(r_vmax);\nif(r_nprotect) Rf_unprotect(r_nprotect);\n\n"); + + SClassDefs = NewHash(); + + sfile = NewString(""); + f_init = NewString(""); + s_header = NewString(""); + f_begin = NewString(""); + f_runtime = NewString(""); + f_wrapper = NewString(""); + s_classes = NewString(""); + s_init = NewString(""); + s_init_routine = NewString(""); +} + + + +#if 0 +int R::cDeclaration(Node *n) { + SwigType *t = Getattr(n, "type"); + SwigType *name = Getattr(n, "name"); + if (debugMode) + Printf(stderr, "cDeclaration (%s): %s\n", name, SwigType_lstr(t, 0)); + return Language::cDeclaration(n); +} +#endif + + +/** + Method from Language that is called to start the entire + processing off, i.e. the generation of the code. + It is called after the input has been read and parsed. + Here we open the output streams and generate the code. +***/ +int R::top(Node *n) { + String *module = Getattr(n, "name"); + if(!Rpackage) + Rpackage = Copy(module); + if(!DllName) + DllName = Copy(module); + + if(outputNamespaceInfo) { + s_namespace = NewString(""); + Swig_register_filebyname("snamespace", s_namespace); + Printf(s_namespace, "useDynLib(%s)\n", DllName); + } + + /* Associate the different streams with names so that they can be used in %insert directives by the + typemap code. */ + Swig_register_filebyname("sinit", s_init); + Swig_register_filebyname("sinitroutine", s_init_routine); + + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("header", s_header); + Swig_register_filebyname("wrapper", f_wrapper); + Swig_register_filebyname("s", sfile); + Swig_register_filebyname("sclasses", s_classes); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGR\n"); + Printf(f_runtime, "\n"); + + + Swig_banner_target_lang(s_init, "#"); + outputCommandLineArguments(s_init); + + Printf(f_wrapper, "#ifdef __cplusplus\n"); + Printf(f_wrapper, "extern \"C\" {\n"); + Printf(f_wrapper, "#endif\n\n"); + + Language::top(n); + + Printf(f_wrapper, "#ifdef __cplusplus\n"); + Printf(f_wrapper, "}\n"); + Printf(f_wrapper, "#endif\n"); + + String *type_table = NewString(""); + SwigType_emit_type_table(f_runtime,f_wrapper); + Delete(type_table); + + if(ClassMemberTable) { + //XXX OutputClassAccessInfo(ClassMemberTable, sfile); + Delete(ClassMemberTable); + ClassMemberTable = NULL; + } + + Printf(f_init,"}\n"); + if(registrationTable) + outputRegistrationRoutines(f_init); + + /* Now arrange to write the 2 files - .S and .c. */ + + DumpCode(n); + + Delete(sfile); + Delete(s_classes); + Delete(s_init); + Delete(f_wrapper); + Delete(f_init); + + Delete(s_header); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; +} + + +/***************************************************** + Write the generated code to the .S and the .c files. +****************************************************/ +int R::DumpCode(Node *n) { + String *output_filename = NewString(""); + + + /* The name of the file in which we will generate the S code. */ + Printf(output_filename, "%s%s.R", SWIG_output_directory(), Rpackage); + +#ifdef R_SWIG_VERBOSE + Printf(stderr, "Writing S code to %s\n", output_filename); +#endif + + File *scode = NewFile(output_filename, "w", SWIG_output_files()); + if (!scode) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(output_filename); + + + Printf(scode, "%s\n\n", s_init); + Printf(scode, "%s\n\n", s_classes); + Printf(scode, "%s\n", sfile); + + Close(scode); + // Delete(scode); + String *outfile = Getattr(n,"outfile"); + File *runtime = NewFile(outfile,"w", SWIG_output_files()); + if (!runtime) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + Printf(runtime, "%s", f_begin); + Printf(runtime, "%s\n", f_runtime); + Printf(runtime, "%s\n", s_header); + Printf(runtime, "%s\n", f_wrapper); + Printf(runtime, "%s\n", f_init); + + Close(runtime); + Delete(runtime); + + if(outputNamespaceInfo) { + output_filename = NewString(""); + Printf(output_filename, "%sNAMESPACE", SWIG_output_directory()); + File *ns = NewFile(output_filename, "w", SWIG_output_files()); + if (!ns) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(output_filename); + + Printf(ns, "%s\n", s_namespace); + + Printf(ns, "\nexport(\n"); + writeListByLine(namespaceFunctions, ns); + Printf(ns, ")\n"); + Printf(ns, "\nexportMethods(\n"); + writeListByLine(namespaceFunctions, ns, 1); + Printf(ns, ")\n"); + Close(ns); + Delete(ns); + Delete(s_namespace); + } + + return SWIG_OK; +} + + + +/* + We may need to do more.... so this is left as a + stub for the moment. +*/ +int R::OutputClassAccessInfo(Hash *tb, File *out) { + int n = OutputClassMemberTable(tb, out); + OutputClassMethodsTable(out); + return n; +} + +/************************************************************************ + Currently this just writes the information collected about the + different methods of the C++ classes that have been processed + to the console. + This will be used later to define S4 generics and methods. +**************************************************************************/ +int R::OutputClassMethodsTable(File *) { + Hash *tb = ClassMethodsTable; + + if(!tb) + return SWIG_OK; + + List *keys = Keys(tb); + String *key; + int i, n = Len(keys); + if (debugMode) { + for(i = 0; i < n ; i++ ) { + key = Getitem(keys, i); + Printf(stderr, "%d) %s\n", i, key); + List *els = Getattr(tb, key); + int nels = Len(els); + Printf(stderr, "\t"); + for(int j = 0; j < nels; j+=2) { + Printf(stderr, "%s%s", Getitem(els, j), j < nels - 1 ? ", " : ""); + Printf(stderr, "%s\n", Getitem(els, j+1)); + } + Printf(stderr, "\n"); + } + } + + return SWIG_OK; +} + + +/* + Iterate over the <class name>_set and <>_get + elements and generate the $ and $<- functions + that provide constrained access to the member + fields in these elements. + + tb - a hash table that is built up in functionWrapper + as we process each membervalueHandler. + The entries are indexed by <class name>_set and + <class_name>_get. Each entry is a List *. + + out - the stram where the code is to be written. This is the S + code stream as we generate only S code here.. +*/ +int R::OutputClassMemberTable(Hash *tb, File *out) { + List *keys = Keys(tb), *el; + + String *key; + int i, n = Len(keys); + /* Loop over all the <Class>_set and <Class>_get entries in the table. */ + + if(n && outputNamespaceInfo) { + Printf(s_namespace, "exportClasses("); + } + for(i = 0; i < n; i++) { + key = Getitem(keys, i); + el = Getattr(tb, key); + + String *className = Getitem(el, 0); + char *ptr = Char(key); + ptr = &ptr[Len(key) - 3]; + int isSet = strcmp(ptr, "set") == 0; + + // OutputArrayMethod(className, el, out); + OutputMemberReferenceMethod(className, isSet, el, out); + + if(outputNamespaceInfo) + Printf(s_namespace, "\"%s\"%s", className, i < n-1 ? "," : ""); + } + if(n && outputNamespaceInfo) { + Printf(s_namespace, ")\n"); + } + + return n; +} + +/******************************************************************* + Write the methods for $ or $<- for accessing a member field in an + struct or union (or class). + className - the name of the struct or union (e.g. Bar for struct Bar) + isSet - a logical value indicating whether the method is for + modifying ($<-) or accessing ($) the member field. + el - a list of length 2 * # accessible member elements + 1. + The first element is the name of the class. + The other pairs are member name and the name of the R function to access it. + out - the stream where we write the code. +********************************************************************/ +int R::OutputMemberReferenceMethod(String *className, int isSet, + List *el, File *out) { + int numMems = Len(el), j; + int has_getitem = 0, has_setitem = 0, has_str = 0; + int varaccessor = 0; + if (numMems == 0) + return SWIG_OK; + + Wrapper *f = NewWrapper(), *attr = NewWrapper(); + + Printf(f->def, "function(x, name%s)", isSet ? ", value" : ""); + Printf(attr->def, "function(x, i, j, ...%s)", isSet ? ", value" : ""); + + Printf(f->code, "{\n"); + Printf(f->code, "%saccessorFuns = list(", tab8); + + Node *itemList = NewHash(); + bool has_prev = false; + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + if (Getattr(itemList, item)) + continue; + Setattr(itemList, item, "1"); + if (!Strcmp(item, "__getitem__")) has_getitem = 1; + if (!Strcmp(item, "__setitem__")) has_setitem = 1; + if (!Strcmp(item, "__str__")) has_str = 1; + + String *dup = Getitem(el, j + 1); + char *ptr = Char(dup); + ptr = &ptr[Len(dup) - 3]; + + if (!strcmp(ptr, "get")) + varaccessor++; + + String *pitem; + if (!Strcmp(item, "operator ()")) { + pitem = NewString("call"); + } else if (!Strcmp(item, "operator ->")) { + pitem = NewString("deref"); + } else if (!Strcmp(item, "operator +")) { + pitem = NewString("add"); + } else if (!Strcmp(item, "operator -")) { + pitem = NewString("sub"); + } else { + pitem = Copy(item); + } + if (has_prev) + Printf(f->code, ", "); + Printf(f->code, "'%s' = %s", pitem, dup); + has_prev = true; + Delete(pitem); + } + Delete(itemList); + Printf(f->code, ")\n"); + + if (!isSet && varaccessor > 0) { + Printf(f->code, "%svaccessors = c(", tab8); + int vcount = 0; + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + String *dup = Getitem(el, j + 1); + char *ptr = Char(dup); + ptr = &ptr[Len(dup) - 3]; + + if (!strcmp(ptr, "get")) { + vcount++; + Printf(f->code, "'%s'%s", item, vcount < varaccessor ? ", " : ""); + } + } + Printf(f->code, ")\n"); + } + + + /* Printv(f->code, tab8, + "idx = pmatch(name, names(accessorFuns))\n", + tab8, + "if(is.na(idx)) {\n", + tab8, tab4, + "stop(\"No ", (isSet ? "modifiable" : "accessible"), " field named \", name, \" in ", className, + ": fields are \", paste(names(accessorFuns), sep = \", \")", + ")", "\n}\n", NIL); */ + Printv(f->code, tab8, + "idx = pmatch(name, names(accessorFuns))\n", + tab8, + "if(is.na(idx)) \n", + tab8, tab4, NIL); + Printf(f->code, "return(callNextMethod(x, name%s))\n", + isSet ? ", value" : ""); + Printv(f->code, tab8, "f = accessorFuns[[idx]]\n", NIL); + if(isSet) { + Printv(f->code, tab8, "f(x, value)\n", NIL); + Printv(f->code, tab8, "x\n", NIL); // make certain to return the S value. + } else { + Printv(f->code, tab8, "formals(f)[[1]] = x\n", NIL); + if (varaccessor) { + Printv(f->code, tab8, + "if (is.na(match(name, vaccessors))) f else f(x)\n", NIL); + } else { + Printv(f->code, tab8, "f\n", NIL); + } + } + Printf(f->code, "}\n"); + + + Printf(out, "# Start of accessor method for %s\n", className); + Printf(out, "setMethod('$%s', '_p%s', ", + isSet ? "<-" : "", + getRClassName(className)); + Wrapper_print(f, out); + Printf(out, ")\n"); + + if(isSet) { + Printf(out, "setMethod('[[<-', c('_p%s', 'character'),", + getRClassName(className)); + Insert(f->code, 2, "name = i\n"); + Printf(attr->code, "%s", f->code); + Wrapper_print(attr, out); + Printf(out, ")\n"); + } + + DelWrapper(attr); + DelWrapper(f); + + Printf(out, "# end of accessor method for %s\n", className); + + return SWIG_OK; +} + +/******************************************************************* + Write the methods for [ or [<- for accessing a member field in an + struct or union (or class). + className - the name of the struct or union (e.g. Bar for struct Bar) + el - a list of length 2 * # accessible member elements + 1. + The first element is the name of the class. + The other pairs are member name and the name of the R function to access it. + out - the stream where we write the code. +********************************************************************/ +int R::OutputArrayMethod(String *className, List *el, File *out) { + int numMems = Len(el), j; + + if(!el || numMems == 0) + return(0); + + Printf(out, "# start of array methods for %s\n", className); + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + String *dup = Getitem(el, j + 1); + if (!Strcmp(item, "__getitem__")) { + Printf(out, + "setMethod('[', '_p%s', function(x, i, j, ..., drop =TRUE) ", + getRClassName(className)); + Printf(out, " sapply(i, function (n) %s(x, as.integer(n-1))))\n\n", dup); + } + if (!Strcmp(item, "__setitem__")) { + Printf(out, "setMethod('[<-', '_p%s', function(x, i, j, ..., value)", + getRClassName(className)); + Printf(out, " sapply(1:length(i), function(n) %s(x, as.integer(i[n]-1), value[n])))\n\n", dup); + } + + } + + Printf(out, "# end of array methods for %s\n", className); + + return SWIG_OK; +} + + +/************************************************************ + Called when a enumeration is to be processed. + We want to call the R function defineEnumeration(). + tdname is the typedef of the enumeration, i.e. giving its name. +*************************************************************/ +int R::enumDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + + /* Using name if tdname is empty. */ + + if(Len(tdname) == 0) + tdname = name; + + + if(!tdname || Strcmp(tdname, "") == 0) { + Language::enumDeclaration(n); + return SWIG_OK; + } + + String *mangled_tdname = SwigType_manglestr(tdname); + String *scode = NewString(""); + + Printv(scode, "defineEnumeration('", mangled_tdname, "'", + ",\n", tab8, tab8, tab4, ".values = c(\n", NIL); + + Node *c; + int value = -1; // First number is zero + for (c = firstChild(n); c; c = nextSibling(c)) { + // const char *tag = Char(nodeType(c)); + // if (Strcmp(tag,"cdecl") == 0) { + name = Getattr(c, "name"); + String *type = Getattr(c, "type"); + String *val = Getattr(c, "enumvalue"); + if(val && Char(val)) { + int inval = (int) getNumber(val, type); + if(inval == DEFAULT_NUMBER) + value++; + else + value = inval; + } else + value++; + + Printf(scode, "%s%s%s'%s' = %d%s\n", tab8, tab8, tab8, name, value, + nextSibling(c) ? ", " : ""); + // } + } + + Printv(scode, "))", NIL); + Printf(sfile, "%s\n", scode); + + Delete(scode); + Delete(mangled_tdname); + + return SWIG_OK; +} + + +/************************************************************* +**************************************************************/ +int R::variableWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + + processing_variable = 1; + Language::variableWrapper(n); // Force the emission of the _set and _get function wrappers. + processing_variable = 0; + + + SwigType *ty = Getattr(n, "type"); + int addCopyParam = addCopyParameter(ty); + + //XXX + processType(ty, n); + + if(!SwigType_isconst(ty)) { + Wrapper *f = NewWrapper(); + Printf(f->def, "%s = \nfunction(value%s)\n{\n", + name, addCopyParam ? ", .copy = FALSE" : ""); + Printv(f->code, "if(missing(value)) {\n", + name, "_get(", addCopyParam ? ".copy" : "", ")\n}", NIL); + Printv(f->code, " else {\n", + name, "_set(value)\n}\n}", NIL); + + Wrapper_print(f, sfile); + DelWrapper(f); + } else { + Printf(sfile, "%s = %s_get\n", name, name); + } + + return SWIG_OK; +} + + +void R::addAccessor(String *memberName, Wrapper *wrapper, String *name, + int isSet) { + if(isSet < 0) { + int n = Len(name); + char *ptr = Char(name); + isSet = Strcmp(NewString(&ptr[n-3]), "set") == 0; + } + + List *l = isSet ? class_member_set_functions : class_member_functions; + + if(!l) { + l = NewList(); + if(isSet) + class_member_set_functions = l; + else + class_member_functions = l; + } + + Append(l, memberName); + Append(l, name); + + String *tmp = NewString(""); + Wrapper_print(wrapper, tmp); + Append(l, tmp); + // if we could put the wrapper in directly: Append(l, Copy(sfun)); + if (debugMode) + Printf(stderr, "Adding accessor: %s (%s) => %s\n", memberName, name, tmp); +} + +#define MAX_OVERLOAD 256 + +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ +}; + + +static List * Swig_overload_rank(Node *n, + bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n,"sym:overloaded"); + + + if (!o) return 0; + + Node *c = o; + while (c) { + if (Getattr(c,"error")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } + /* if (SmartPointer && Getattr(c,"cplus:staticbase")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } */ + + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + + if (Getattr(c,"wrap:name")) { + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c,"wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nnodes++; + } + c = Getattr(c,"sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i,j; + for (i = 0; i < nnodes; i++) { + for (j = i+1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i,j; + for (i = 0; i < nnodes-1; i++) { + if (nodes[i].argc == nodes[i+1].argc) { + for (j = i+1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + // Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + if (checkAttribute(p1,"tmap:in:numinputs","0")) { + p1 = Getattr(p1,"tmap:in:next"); + continue; + } + if (checkAttribute(p2,"tmap:in:numinputs","0")) { + p2 = Getattr(p2,"tmap:in:next"); + continue; + } + String *t1 = Getattr(p1,"tmap:typecheck:precedence"); + String *t2 = Getattr(p2,"tmap:typecheck:precedence"); + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded method %s not supported (no type checking rule for '%s').\n", + Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "xx Overloaded method %s not supported (no type checking rule for '%s').\n", + Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v-t2v; + } + else if (!t1 && t2) differ = 1; + else if (t1 && !t2) differ = -1; + else if (!t1 && !t2) differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1,"0") == 0)) { + t1 = Getattr(p1,"ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1,"type")); + if (Getattr(p1,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1,"ltype",t1); + } + t2 = Getattr(p2,"ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2,"type")); + if (Getattr(p2,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2,"ltype",t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2,t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1,t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1,"tmap:in:next")) { + p1 = Getattr(p1,"tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2,"tmap:in:next")) { + p2 = Getattr(p2,"tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *d1 = Getattr(nodes[i].n,"decl"); + String *d2 = Getattr(nodes[j].n,"decl"); + if (d1 && d2) { + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1,dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s) ignored. Method %s(%s) const at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n,"name"), ParmList_errorstr(nodes[i].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s) const ignored. Method %s(%s) at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms), + Getattr(nodes[i].n,"name"), ParmList_errorstr(nodes[i].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s is shadowed by %s at %s:%d.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s ignored. Method %s at %s:%d used.\n", + Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result,nodes[i].n); + // Printf(stdout,"[ %d ] %s\n", i, ParmList_errorstr(nodes[i].parms)); + // Swig_print_node(nodes[i].n); + } + } + return result; +} + +void R::dispatchFunction(Node *n) { + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + + String *sfname = NewString(symname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + Printf(f->def, + "`%s` <- function(...) {", sfname); + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + Printv(f->code, + "argtypes <- mapply(class, list(...))\n", + "argv <- list(...)\n", + "argc <- length(argtypes)\n", NIL ); + + Printf(f->code, "# dispatch functions %d\n", nfunc); + int cur_args = -1; + bool first_compare = true; + for (int i=0; i < nfunc; i++) { + Node *ni = Getitem(dispatch,i); + Parm *pi = Getattr(ni,"wrap:parms"); + int num_arguments = emit_num_arguments(pi); + + String *overname = Getattr(ni,"sym:overname"); + if (cur_args != num_arguments) { + if (cur_args != -1) { + Printv(f->code, "} else ", NIL); + } + Printf(f->code, "if (argc == %d) {", num_arguments); + cur_args = num_arguments; + first_compare = true; + } + Parm *p; + int j; + if (num_arguments > 0) { + if (!first_compare) { + Printv(f->code, " else ", NIL); + } else { + first_compare = false; + } + Printv(f->code, "if (", NIL); + for (p =pi, j = 0 ; j < num_arguments ; j++) { + String *tm = Swig_typemap_lookup("rtype", p, "", 0); + if(tm) { + replaceRClass(tm, Getattr(p, "type")); + } + if (DohStrcmp(tm,"numeric")==0) { + Printf(f->code, "%sis.numeric(argv[[%d]])", + j == 0 ? "" : " && ", + j+1); + } + else { + Printf(f->code, "%sextends(argtypes[%d], '%s')", + j == 0 ? "" : " && ", + j+1, + tm); + } + p = Getattr(p, "tmap:in:next"); + } + Printf(f->code, ") { f <- %s%s }\n", sfname, overname); + } else { + Printf(f->code, "f <- %s%s", sfname, overname); + } + } + if (cur_args != -1) { + Printv(f->code, "}", NIL); + } + Printv(f->code, "\nf(...)", NIL); + Printv(f->code, "\n}", NIL); + Wrapper_print(f, sfile); + Printv(sfile, "# Dispatch function\n", NIL); + DelWrapper(f); +} + +/****************************************************************** + +*******************************************************************/ +int R::functionWrapper(Node *n) { + String *fname = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *type = Getattr(n, "type"); + + if (debugMode) { + Printf(stderr, + "<functionWrapper> %s %s %s\n", fname, iname, type); + } + String *overname = 0; + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + bool destructor = (!Cmp(nodeType, "destructor")); + + String *sfname = NewString(iname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + if (Getattr(n,"sym:overloaded")) { + overname = Getattr(n,"sym:overname"); + Append(sfname, overname); + } + + if (debugMode) + Printf(stderr, + "<functionWrapper> processing parameters\n"); + + + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *tm; + + p = l; + while(p) { + SwigType *resultType = Getattr(p, "type"); + if (expandTypedef(resultType) && + SwigType_istypedef(resultType)) { + SwigType *resolved = + SwigType_typedef_resolve_all(resultType); + if (expandTypedef(resolved)) { + Setattr(p, "type", Copy(resolved)); + } + } + p = nextSibling(p); + } + + String *unresolved_return_type = + Copy(type); + if (expandTypedef(type) && + SwigType_istypedef(type)) { + SwigType *resolved = + SwigType_typedef_resolve_all(type); + if (expandTypedef(resolved)) { + type = Copy(resolved); + Setattr(n, "type", type); + } + } + if (debugMode) + Printf(stderr, "<functionWrapper> unresolved_return_type %s\n", + unresolved_return_type); + if(processing_member_access_function) { + if (debugMode) + Printf(stderr, "<functionWrapper memberAccess> '%s' '%s' '%s' '%s'\n", + fname, iname, member_name, class_name); + + if(opaqueClassDeclaration) + return SWIG_OK; + + + /* Add the name of this member to a list for this class_name. + We will dump all these at the end. */ + + int n = Len(iname); + char *ptr = Char(iname); + bool isSet(Strcmp(NewString(&ptr[n-3]), "set") == 0); + + + String *tmp = NewString(""); + Printf(tmp, "%s_%s", class_name, isSet ? "set" : "get"); + + List *memList = Getattr(ClassMemberTable, tmp); + if(!memList) { + memList = NewList(); + Append(memList, class_name); + Setattr(ClassMemberTable, tmp, memList); + } + Delete(tmp); + Append(memList, member_name); + Append(memList, iname); + } + + int i; + int nargs, num_required, varargs; + UNUSED(varargs); + + String *wname = Swig_name_wrapper(iname); + Replace(wname, "_wrap", "R_swig", DOH_REPLACE_FIRST); + if(overname) + Append(wname, overname); + Setattr(n,"wrap:name", wname); + + Wrapper *f = NewWrapper(); + Wrapper *sfun = NewWrapper(); + + int isVoidReturnType = (Strcmp(type, "void") == 0); + // Need to use the unresolved return type since + // typedef resolution removes the const which causes a + // mismatch with the function action + emit_return_variable(n, unresolved_return_type, f); + + SwigType *rtype = Getattr(n, "type"); + int addCopyParam = 0; + + if(!isVoidReturnType) + addCopyParam = addCopyParameter(rtype); + + + // Can we get the nodeType() of the type node! and see if it is a struct. + // int addCopyParam = SwigType_isclass(rtype); + + // if(addCopyParam) + if (debugMode) + Printf(stderr, "Adding a .copy argument to %s for %s = %s\n", + iname, type, addCopyParam ? "yes" : "no"); + + Printv(f->def, "SWIGEXPORT SEXP\n", wname, " ( ", NIL); + + Printf(sfun->def, "# Start of %s\n", iname); + Printv(sfun->def, "\n`", sfname, "` = function(", NIL); + + if(outputNamespaceInfo) //XXX Need to be a little more discriminating + addNamespaceFunction(iname); + + Swig_typemap_attach_parms("scoercein", l, f); + Swig_typemap_attach_parms("scoerceout", l, f); + Swig_typemap_attach_parms("scheck", l, f); + + emit_parameter_variables(l, f); + emit_attach_parmmaps(l,f); + Setattr(n,"wrap:parms",l); + + nargs = emit_num_arguments(l); + num_required = emit_num_required(l); + varargs = emit_isvarargs(l); + + Wrapper_add_local(f, "r_nprotect", "unsigned int r_nprotect = 0"); + Wrapper_add_localv(f, "r_ans", "SEXP", "r_ans = R_NilValue", NIL); + Wrapper_add_localv(f, "r_vmax", "VMAXTYPE", "r_vmax = vmaxget()", NIL); + + String *sargs = NewString(""); + + + String *s_inputTypes = NewString(""); + String *s_inputMap = NewString(""); + bool inFirstArg = true; + bool inFirstType = true; + Parm *curP; + for (p =l, i = 0 ; i < nargs ; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *tt = Getattr(p, "type"); + int nargs = -1; + String *funcptr_name = processType(tt, p, &nargs); + + // SwigType *tp = Getattr(p, "type"); + String *name = Getattr(p,"name"); + String *lname = Getattr(p,"lname"); + + // R keyword renaming + if (name && Swig_name_warning(p, 0, name, 0)) + name = 0; + + /* If we have a :: in the parameter name because we are accessing a static member of a class, say, then + we need to remove that prefix. */ + while (Strstr(name, "::")) { + //XXX need to free. + name = NewStringf("%s", Strchr(name, ':') + 2); + if (debugMode) + Printf(stderr, "+++ parameter name with :: in it %s\n", name); + } + if (Len(name) == 0) + name = NewStringf("s_arg%d", i+1); + + name = replaceInitialDash(name); + + if (!Strncmp(name, "arg", 3)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(processing_variable) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(!Strcmp(name, fname)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + Printf(sargs, "%s, ", name); + + String *tm; + if((tm = Getattr(p, "tmap:scoercein"))) { + Replaceall(tm, "$input", name); + replaceRClass(tm, Getattr(p, "type")); + + if(funcptr_name) { + //XXX need to get this to return non-zero + if(nargs == -1) + nargs = getFunctionPointerNumArgs(p, tt); + + String *snargs = NewStringf("%d", nargs); + Printv(sfun->code, "if(is.function(", name, ")) {", "\n", + "assert('...' %in% names(formals(", name, + ")) || length(formals(", name, ")) >= ", snargs, ")\n} ", NIL); + Delete(snargs); + + Printv(sfun->code, "else {\n", + "if(is.character(", name, ")) {\n", + name, " = getNativeSymbolInfo(", name, ")", + "\n}\n", + "if(is(", name, ", \"NativeSymbolInfo\")) {\n", + name, " = ", name, "$address", "\n}\n", + "}\n", + NIL); + } else { + Printf(sfun->code, "%s\n", tm); + } + } + + Printv(sfun->def, inFirstArg ? "" : ", ", name, NIL); + + if ((tm = Getattr(p,"tmap:scheck"))) { + + Replaceall(tm,"$target", lname); + Replaceall(tm,"$source", name); + Replaceall(tm,"$input", name); + replaceRClass(tm, Getattr(p, "type")); + Printf(sfun->code,"%s\n",tm); + } + + + + curP = p; + if ((tm = Getattr(p,"tmap:in"))) { + + Replaceall(tm,"$target", lname); + Replaceall(tm,"$source", name); + Replaceall(tm,"$input", name); + + if (Getattr(p,"wrap:disown") || (Getattr(p,"tmap:in:disown"))) { + Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm,"$disown","0"); + } + + if(funcptr_name) { + /* have us a function pointer */ + Printf(f->code, "if(TYPEOF(%s) != CLOSXP) {\n", name); + Replaceall(tm,"$R_class", ""); + } else { + replaceRClass(tm, Getattr(p, "type")); + } + + + Printf(f->code,"%s\n",tm); + if(funcptr_name) + Printf(f->code, "} else {\n%s = %s;\nR_SWIG_pushCallbackFunctionData(%s, NULL);\n}\n", + lname, funcptr_name, name); + Printv(f->def, inFirstArg ? "" : ", ", "SEXP ", name, NIL); + if (Len(name) != 0) + inFirstArg = false; + p = Getattr(p,"tmap:in:next"); + + } else { + p = nextSibling(p); + } + + + tm = Swig_typemap_lookup("rtype", curP, "", 0); + if(tm) { + replaceRClass(tm, Getattr(curP, "type")); + } + Printf(s_inputTypes, "%s'%s'", inFirstType ? "" : ", ", tm); + Printf(s_inputMap, "%s%s='%s'", inFirstType ? "" : ", ", name, tm); + inFirstType = false; + + if(funcptr_name) + Delete(funcptr_name); + } /* end of looping over parameters. */ + + if(addCopyParam) { + Printf(sfun->def, "%s.copy = FALSE", nargs > 0 ? ", " : ""); + Printf(f->def, "%sSEXP s_swig_copy", nargs > 0 ? ", " : ""); + + Printf(sargs, "as.logical(.copy), "); + } + + Printv(f->def, ")\n{\n", NIL); + Printv(sfun->def, ")\n{\n", NIL); + + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + String *outargs = NewString(""); + int numOutArgs = isVoidReturnType ? -1 : 0; + for(p = l, i = 0; p; i++) { + if((tm = Getattr(p, "tmap:argout"))) { + // String *lname = Getattr(p, "lname"); + numOutArgs++; + String *pos = NewStringf("%d", numOutArgs); + Replaceall(tm,"$source", Getattr(p, "lname")); + Replaceall(tm,"$result", "r_ans"); + Replaceall(tm,"$n", pos); // The position into which to store the answer. + Replaceall(tm,"$arg", Getattr(p, "emit:input")); + Replaceall(tm,"$input", Getattr(p, "emit:input")); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + + + Printf(outargs, "%s\n", tm); + p = Getattr(p,"tmap:argout:next"); + } else + p = nextSibling(p); + } + + String *actioncode = emit_action(n); + + /* Deal with the explicit return value. */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + SwigType *retType = Getattr(n, "type"); + //Printf(stderr, "Return Value for %s, array? %s\n", retType, SwigType_isarray(retType) ? "yes" : "no"); + /* if(SwigType_isarray(retType)) { + defineArrayAccessors(retType); + } */ + + + Replaceall(tm,"$1", "result"); + Replaceall(tm,"$result", "r_ans"); + replaceRClass(tm, retType); + + if (GetFlag(n,"feature:new")) { + Replaceall(tm, "$owner", "R_SWIG_OWNER"); + } else { + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + } + +#if 0 + if(addCopyParam) { + Printf(f->code, "if(LOGICAL(s_swig_copy)[0]) {\n"); + Printf(f->code, "/* Deal with returning a reference. */\nr_ans = R_NilValue;\n"); + Printf(f->code, "}\n else {\n"); + } +#endif + Printf(f->code, "%s\n", tm); +#if 0 + if(addCopyParam) + Printf(f->code, "}\n"); /* end of if(s_swig_copy) ... else { ... } */ +#endif + + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, + "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), fname); + } + + + if(Len(outargs)) { + Wrapper_add_local(f, "R_OutputValues", "SEXP R_OutputValues"); + + String *tmp = NewString(""); + if(!isVoidReturnType) + Printf(tmp, "Rf_protect(r_ans);\n"); + + Printf(tmp, "Rf_protect(R_OutputValues = Rf_allocVector(VECSXP,%d));\nr_nprotect += %d;\n", + numOutArgs + !isVoidReturnType, + isVoidReturnType ? 1 : 2); + + if(!isVoidReturnType) + Printf(tmp, "SET_VECTOR_ELT(R_OutputValues, 0, r_ans);\n"); + Printf(tmp, "r_ans = R_OutputValues;\n"); + + Insert(outargs, 0, tmp); + Delete(tmp); + + + + Printv(f->code, outargs, NIL); + Delete(outargs); + + } + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + Delete(cleanup); + + + + Printv(f->code, UnProtectWrapupCode, NIL); + + /*If the user gave us something to convert the result in */ + if ((tm = Swig_typemap_lookup("scoerceout", n, + "result", sfun))) { + Replaceall(tm,"$source","ans"); + Replaceall(tm,"$result","ans"); + replaceRClass(tm, Getattr(n, "type")); + Chop(tm); + } + + + Printv(sfun->code, (Len(tm) ? "ans = " : ""), ".Call('", wname, + "', ", sargs, "PACKAGE='", Rpackage, "')\n", NIL); + if(Len(tm)) + Printf(sfun->code, "%s\n\nans\n", tm); + if (destructor) + Printv(f->code, "R_ClearExternalPtr(self);\n", NIL); + + Printv(f->code, "return r_ans;\n}\n", NIL); + Printv(sfun->code, "\n}", NIL); + + /* Substitute the function name */ + Replaceall(f->code,"$symname",iname); + + Wrapper_print(f, f_wrapper); + Wrapper_print(sfun, sfile); + + Printf(sfun->code, "\n# End of %s\n", iname); + tm = Swig_typemap_lookup("rtype", n, "", 0); + if(tm) { + SwigType *retType = Getattr(n, "type"); + replaceRClass(tm, retType); + } + + Printv(sfile, "attr(`", sfname, "`, 'returnType') = '", + isVoidReturnType ? "void" : (tm ? tm : ""), + "'\n", NIL); + + if(nargs > 0) + Printv(sfile, "attr(`", sfname, "`, \"inputTypes\") = c(", + s_inputTypes, ")\n", NIL); + Printv(sfile, "class(`", sfname, "`) = c(\"SWIGFunction\", class('", + sfname, "'))\n\n", NIL); + + if (memoryProfile) { + Printv(sfile, "memory.profile()\n", NIL); + } + if (aggressiveGc) { + Printv(sfile, "gc()\n", NIL); + } + + // Printv(sfile, "setMethod('", name, "', '", name, "', ", iname, ")\n\n\n"); + + + + /* If we are dealing with a method in an C++ class, then + add the name of the R function and its definition. + XXX need to figure out how to store the Wrapper if possible in the hash/list. + Would like to be able to do this so that we can potentialy insert + */ + if(processing_member_access_function || processing_class_member_function) { + String *tmp; + if(member_name) + tmp = member_name; + else + tmp = Getattr(n, "memberfunctionHandler:name"); + addAccessor(member_name, sfun, iname); + } + + if (Getattr(n, "sym:overloaded") && + !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + addRegistrationRoutine(wname, addCopyParam ? nargs +1 : nargs); + + DelWrapper(f); + DelWrapper(sfun); + + Delete(sargs); + Delete(sfname); + return SWIG_OK; +} + +/***************************************************** + Add the specified routine name to the collection of + generated routines that are called from R functions. + This is used to register the routines with R for + resolving symbols. + + rname - the name of the routine + nargs - the number of arguments it expects. +******************************************************/ +int R::addRegistrationRoutine(String *rname, int nargs) { + if(!registrationTable) + registrationTable = NewHash(); + + String *el = + NewStringf("{\"%s\", (DL_FUNC) &%s, %d}", rname, rname, nargs); + + Setattr(registrationTable, rname, el); + + return SWIG_OK; +} + +/***************************************************** + Write the registration information to an array and + create the initialization routine for registering + these. +******************************************************/ +int R::outputRegistrationRoutines(File *out) { + int i, n; + if(!registrationTable) + return(0); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + + Printf(out, "#include <R_ext/Rdynload.h>\n\n"); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\n}\n#endif\n\n"); + + Printf(out, "SWIGINTERN R_CallMethodDef CallEntries[] = {\n"); + + List *keys = Keys(registrationTable); + n = Len(keys); + for(i = 0; i < n; i++) + Printf(out, " %s,\n", Getattr(registrationTable, Getitem(keys, i))); + + Printf(out, " {NULL, NULL, 0}\n};\n\n"); + + if(!noInitializationCode) { + if (inCPlusMode) + Printv(out, "extern \"C\" ", NIL); + Printf(out, "SWIGEXPORT void R_init_%s(DllInfo *dll) {\n", Rpackage); + Printf(out, "%sR_registerRoutines(dll, NULL, CallEntries, NULL, NULL);\n", tab4); + if(Len(s_init_routine)) { + Printf(out, "\n%s\n", s_init_routine); + } + Printf(out, "}\n"); + } + + return n; +} + + + +/**************************************************************************** + Process a struct, union or class declaration in the source code, + or an anonymous typedef struct + +*****************************************************************************/ +//XXX What do we need to do here - +// Define an S4 class to refer to this. + +void R::registerClass(Node *n) { + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + String *sname = NewStringf("_p%s", SwigType_manglestr(name)); + if(!Getattr(SClassDefs, sname)) { + Setattr(SClassDefs, sname, sname); + String *base; + + if(Strcmp(kind, "class") == 0) { + base = NewString(""); + List *l = Getattr(n, "bases"); + if(Len(l)) { + Printf(base, "c("); + for(int i = 0; i < Len(l); i++) { + registerClass(Getitem(l, i)); + Printf(base, "'_p%s'%s", + SwigType_manglestr(Getattr(Getitem(l, i), "name")), + i < Len(l)-1 ? ", " : ""); + } + Printf(base, ")"); + } else { + base = NewString("'C++Reference'"); + } + } else + base = NewString("'ExternalReference'"); + + Printf(s_classes, "setClass('%s', contains = %s)\n", sname, base); + Delete(base); + } + +} + +int R::classDeclaration(Node *n) { + + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + registerClass(n); + + + /* If we have a typedef union { ... } U, then we never get to see the typedef + via a regular call to typedefHandler. Instead, */ + if(Getattr(n, "unnamed") && Strcmp(Getattr(n, "storage"), "typedef") == 0 + && Getattr(n, "tdname") && Strcmp(Getattr(n, "tdname"), name) == 0) { + if (debugMode) + Printf(stderr, "Typedef in the class declaration for %s\n", name); + // typedefHandler(n); + } + + bool opaque = GetFlag(n, "feature:opaque") ? true : false; + + if(opaque) + opaqueClassDeclaration = name; + + int status = Language::classDeclaration(n); + + opaqueClassDeclaration = NULL; + + + // OutputArrayMethod(name, class_member_functions, sfile); + if (class_member_functions) + OutputMemberReferenceMethod(name, 0, class_member_functions, sfile); + if (class_member_set_functions) + OutputMemberReferenceMethod(name, 1, class_member_set_functions, sfile); + + if(class_member_functions) { + Delete(class_member_functions); + class_member_functions = NULL; + } + if(class_member_set_functions) { + Delete(class_member_set_functions); + class_member_set_functions = NULL; + } + if (Getattr(n, "has_destructor")) { + Printf(sfile, "setMethod('delete', '_p%s', function(obj) {delete%s(obj)})\n", + getRClassName(Getattr(n, "name")), + getRClassName(Getattr(n, "name"))); + + } + if(!opaque && !Strcmp(kind, "struct") && copyStruct) { + + String *def = + NewStringf("setClass(\"%s\",\n%srepresentation(\n", name, tab4); + bool firstItem = true; + + for(Node *c = firstChild(n); c; ) { + String *elName; + String *tp; + + elName = Getattr(c, "name"); + + String *elKind = Getattr(c, "kind"); + if (Strcmp(elKind, "variable") != 0) { + c = nextSibling(c); + continue; + } + if (!Len(elName)) { + c = nextSibling(c); + continue; + } +#if 0 + tp = getRType(c); +#else + tp = Swig_typemap_lookup("rtype", c, "", 0); + if(!tp) { + c = nextSibling(c); + continue; + } + if (Strstr(tp, "R_class")) { + c = nextSibling(c); + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + c = nextSibling(c); + continue; + } + + if (!firstItem) { + Printf(def, ",\n"); + } + // else + //XXX How can we tell if this is already done. + // SwigType_push(elType, elDecl); + + + // returns "" tp = processType(elType, c, NULL); + // Printf(stderr, "<classDeclaration> elType %p\n", elType); + // tp = getRClassNameCopyStruct(Getattr(c, "type"), 1); +#endif + String *elNameT = replaceInitialDash(elName); + Printf(def, "%s%s = \"%s\"", tab8, elNameT, tp); + firstItem = false; + Delete(tp); + Delete(elNameT); + c = nextSibling(c); + } + Printf(def, "),\n%scontains = \"RSWIGStruct\")\n", tab8); + Printf(s_classes, "%s\n\n# End class %s\n\n", def, name); + + generateCopyRoutines(n); + + Delete(def); + } + + return status; +} + + + +/*************************************************************** + Create the C routines that copy an S object of the class given + by the given struct definition in Node *n to the C value + and also the routine that goes from the C routine to an object + of this S class. +****************************************************************/ +/*XXX + Clean up the toCRef - make certain the names are correct for the types, etc. + in all cases. +*/ + +int R::generateCopyRoutines(Node *n) { + Wrapper *copyToR = NewWrapper(); + Wrapper *copyToC = NewWrapper(); + + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *kind = Getattr(n, "kind"); + String *type; + + if(Len(tdname)) { + type = Copy(tdname); + } else { + type = NewStringf("%s %s", kind, name); + } + + String *mangledName = SwigType_manglestr(name); + + if (debugMode) + Printf(stderr, "generateCopyRoutines: name = %s, %s\n", name, type); + + Printf(copyToR->def, "CopyToR%s = function(value, obj = new(\"%s\"))\n{\n", + mangledName, name); + Printf(copyToC->def, "CopyToC%s = function(value, obj)\n{\n", + mangledName); + + Node *c = firstChild(n); + + for(; c; c = nextSibling(c)) { + String *elName = Getattr(c, "name"); + if (!Len(elName)) { + continue; + } + String *elKind = Getattr(c, "kind"); + if (Strcmp(elKind, "variable") != 0) { + Delete(elKind); + continue; + } + + String *tp = Swig_typemap_lookup("rtype", c, "", 0); + if(!tp) { + continue; + } + if (Strstr(tp, "R_class")) { + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + continue; + } + + + /* The S functions to get and set the member value. */ + String *elNameT = replaceInitialDash(elName); + Printf(copyToR->code, "obj@%s = value$%s\n", elNameT, elNameT); + Printf(copyToC->code, "obj$%s = value@%s\n", elNameT, elNameT); + Delete(elNameT); + } + Printf(copyToR->code, "obj\n}\n\n"); + String *rclassName = getRClassNameCopyStruct(type, 0); // without the Ref. + Printf(sfile, "# Start definition of copy functions & methods for %s\n", rclassName); + + Wrapper_print(copyToR, sfile); + Printf(copyToC->code, "obj\n}\n\n"); + Wrapper_print(copyToC, sfile); + + + Printf(sfile, "# Start definition of copy methods for %s\n", rclassName); + Printf(sfile, "setMethod('copyToR', '_p_%s', CopyToR%s)\n", rclassName, + mangledName); + Printf(sfile, "setMethod('copyToC', '%s', CopyToC%s)\n\n", rclassName, + mangledName); + + Printf(sfile, "# End definition of copy methods for %s\n", rclassName); + Printf(sfile, "# End definition of copy functions & methods for %s\n", rclassName); + + String *m = NewStringf("%sCopyToR", name); + addNamespaceMethod(m); + char *tt = Char(m); tt[Len(m)-1] = 'C'; + addNamespaceMethod(m); + Delete(m); + Delete(rclassName); + Delete(mangledName); + DelWrapper(copyToR); + DelWrapper(copyToC); + + return SWIG_OK; +} + + + +/***** + Called when there is a typedef to be invoked. + + XXX Needs to be enhanced or split to handle the case where we have a + typedef within a classDeclaration emission because the struct/union/etc. + is anonymous. +******/ +int R::typedefHandler(Node *n) { + SwigType *tp = Getattr(n, "type"); + String *type = Getattr(n, "type"); + if (debugMode) + Printf(stderr, "<typedefHandler> %s\n", Getattr(n, "name")); + + processType(tp, n); + + if(Strncmp(type, "struct ", 7) == 0) { + String *name = Getattr(n, "name"); + char *trueName = Char(type); + trueName += 7; + if (debugMode) + Printf(stderr, "<typedefHandler> Defining S class %s\n", trueName); + Printf(s_classes, "setClass('_p%s', contains = 'ExternalReference')\n", + SwigType_manglestr(name)); + } + + return Language::typedefHandler(n); +} + + + +/********************* + Called when processing a field in a "class", i.e. struct, union or + actual class. We set a state variable so that we can correctly + interpret the resulting functionWrapper() call and understand that + it is for a field element. +**********************/ +int R::membervariableHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + processType(t, n, NULL); + processing_member_access_function = 1; + member_name = Getattr(n,"sym:name"); + if (debugMode) + Printf(stderr, "<membervariableHandler> name = %s, sym:name = %s\n", + Getattr(n, "name"), member_name); + + int status(Language::membervariableHandler(n)); + + if(opaqueClassDeclaration == NULL && debugMode) + Printf(stderr, "<membervariableHandler> %s %s\n", Getattr(n, "name"), Getattr(n, "type")); + + processing_member_access_function = 0; + member_name = NULL; + + return status; +} + + +/* + This doesn't seem to get used so leave it out for the moment. +*/ +String * R::runtimeCode() { + String *s = Swig_include_sys("rrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'rrun.swg'\n"); + s = NewString(""); + } + return s; +} + + +/** + Called when SWIG wants to initialize this + We initialize anythin we want here. + Most importantly, tell SWIG where to find the files (e.g. r.swg) for this module. + Use Swig_mark_arg() to tell SWIG that it is understood and not to throw an error. +**/ +void R::main(int argc, char *argv[]) { + bool cppcast = true; + init(); + Preprocessor_define("SWIGR 1", 0); + SWIG_library_directory("r"); + SWIG_config_file("r.swg"); + debugMode = false; + copyStruct = true; + memoryProfile = false; + aggressiveGc = false; + inCPlusMode = false; + outputNamespaceInfo = false; + noInitializationCode = false; + + this->Argc = argc; + this->Argv = argv; + + allow_overloading();// can we support this? + + for(int i = 0; i < argc; i++) { + if(strcmp(argv[i], "-package") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + Rpackage = argv[i]; + } else if(strcmp(argv[i], "-dll") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + DllName = argv[i]; + } else if(strcmp(argv[i], "-help") == 0) { + showUsage(); + } else if(strcmp(argv[i], "-namespace") == 0) { + outputNamespaceInfo = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-no-init-code")) { + noInitializationCode = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-c++")) { + inCPlusMode = true; + Swig_mark_arg(i); + Printf(s_classes, "setClass('C++Reference', contains = 'ExternalReference')\n"); + } else if(!strcmp(argv[i], "-debug")) { + debugMode = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-cppcast")) { + cppcast = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-nocppcast")) { + cppcast = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-copystruct")) { + copyStruct = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocopystruct")) { + copyStruct = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-memoryprof")) { + memoryProfile = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nomemoryprof")) { + memoryProfile = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-aggressivegc")) { + aggressiveGc = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-noaggressivegc")) { + aggressiveGc = false; + Swig_mark_arg(i); + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + /// copyToR copyToC functions. + + } +} + +/* + Could make this work for String or File and then just store the resulting string + rather than the collection of arguments and argc. +*/ +int R::outputCommandLineArguments(File *out) +{ + if(Argc < 1 || !Argv || !Argv[0]) + return(-1); + + Printf(out, "\n## Generated via the command line invocation:\n##\t"); + for(int i = 0; i < Argc ; i++) { + Printf(out, " %s", Argv[i]); + } + Printf(out, "\n\n\n"); + + return Argc; +} + + + +/* How SWIG instantiates an object from this module. + See swigmain.cxx */ +extern "C" +Language *swig_r(void) { + return new R(); +} + + + +/*************************************************************************************/ + +/* + Needs to be reworked. +*/ +String * R::processType(SwigType *t, Node *n, int *nargs) { + //XXX Need to handle typedefs, e.g. + // a type which is a typedef to a function pointer. + + SwigType *tmp = Getattr(n, "tdname"); + if (debugMode) + Printf(stderr, "processType %s (tdname = %s)\n", Getattr(n, "name"), tmp); + + SwigType *td = t; + if (expandTypedef(t) && + SwigType_istypedef(t)) { + SwigType *resolved = + SwigType_typedef_resolve_all(t); + if (expandTypedef(resolved)) { + td = Copy(resolved); + } + } + + if(!td) { + int count = 0; + String *b = getRTypeName(t, &count); + if(count && b && !Getattr(SClassDefs, b)) { + if (debugMode) + Printf(stderr, "<processType> Defining class %s\n", b); + + Printf(s_classes, "setClass('%s', contains = 'ExternalReference')\n", b); + Setattr(SClassDefs, b, b); + } + + } + + + if(td) + t = td; + + if(SwigType_isfunctionpointer(t)) { + if (debugMode) + Printf(stderr, + "<processType> Defining pointer handler %s\n", t); + + String *tmp = createFunctionPointerHandler(t, n, nargs); + return tmp; + } + +#if 0 + SwigType_isfunction(t) && SwigType_ispointer(t) +#endif + + return NULL; +} + + + + + + + + + +/*************************************************************************************/ + + + + + diff --git a/Source/Modules/ruby.cxx b/Source/Modules/ruby.cxx new file mode 100644 index 0000000..c9e935e --- /dev/null +++ b/Source/Modules/ruby.cxx @@ -0,0 +1,3427 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * ruby.cxx + * + * Ruby language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_ruby_cxx[] = "$Id: ruby.cxx 11246 2009-06-05 17:19:29Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +static int treduce = SWIG_cparse_template_reduce(0); + +#define SWIG_PROTECTED_TARGET_METHODS 1 + +#include <ctype.h> +#include <string.h> +#include <limits.h> /* for INT_MAX */ + +class RClass { +private: + String *temp; + +public: + String *name; /* class name (renamed) */ + String *cname; /* original C class/struct name */ + String *mname; /* Mangled name */ + + /** + * The C variable name used in the SWIG-generated wrapper code to refer to + * this class; usually it is of the form "SwigClassXXX.klass", where SwigClassXXX + * is a swig_class struct instance and klass is a member of that struct. + */ + String *vname; + + /** + * The C variable name used in the SWIG-generated wrapper code to refer to + * the module that implements this class's methods (when we're trying to + * support C++ multiple inheritance). Usually it is of the form + * "SwigClassClassName.mImpl", where SwigClassXXX is a swig_class struct instance + * and mImpl is a member of that struct. + */ + String *mImpl; + + String *type; + String *prefix; + String *init; + + + int constructor_defined; + int destructor_defined; + + RClass() { + temp = NewString(""); + name = NewString(""); + cname = NewString(""); + mname = NewString(""); + vname = NewString(""); + mImpl = NewString(""); + type = NewString(""); + prefix = NewString(""); + init = NewString(""); + constructor_defined = 0; + destructor_defined = 0; + } + + ~RClass() { + Delete(name); + Delete(cname); + Delete(vname); + Delete(mImpl); + Delete(mname); + Delete(type); + Delete(prefix); + Delete(init); + Delete(temp); + } + + void set_name(const_String_or_char_ptr cn, const_String_or_char_ptr rn, const_String_or_char_ptr valn) { + /* Original C/C++ class (or struct) name */ + Clear(cname); + Append(cname, cn); + + /* Mangled name */ + Delete(mname); + mname = Swig_name_mangle(cname); + + /* Renamed class name */ + Clear(name); + Append(name, valn); + + /* Variable name for the VALUE that refers to the Ruby Class object */ + Clear(vname); + Printf(vname, "SwigClass%s.klass", name); + + /* Variable name for the VALUE that refers to the Ruby Class object */ + Clear(mImpl); + Printf(mImpl, "SwigClass%s.mImpl", name); + + /* Prefix */ + Clear(prefix); + Printv(prefix, (rn ? rn : cn), "_", NIL); + } + + char *strip(const_String_or_char_ptr s) { + Clear(temp); + Append(temp, s); + if (Strncmp(s, prefix, Len(prefix)) == 0) { + Replaceall(temp, prefix, ""); + } + return Char(temp); + } +}; + + +/* flags for the make_autodoc function */ +enum autodoc_t { + AUTODOC_CLASS, + AUTODOC_CTOR, + AUTODOC_DTOR, + AUTODOC_STATICFUNC, + AUTODOC_FUNC, + AUTODOC_METHOD, + AUTODOC_GETTER, + AUTODOC_SETTER +}; + +static const char *usage = "\ +Ruby Options (available with -ruby)\n\ + -globalmodule - Wrap everything into the global module\n\ + -minherit - Attempt to support multiple inheritance\n\ + -nocppcast - Disable C++ casting operators, useful for generating bugs\n\ + -cppcast - Enable C++ casting operators (default)\n\ + -autorename - Enable renaming of classes and methods to follow Ruby coding standards\n\ + -noautorename - Disable renaming of classes and methods (default)\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -initname <name> - Set entry function to Init_<name> (used by `require')\n"; + + +#define RCLASS(hash, name) (RClass*)(Getattr(hash, name) ? Data(Getattr(hash, name)) : 0) +#define SET_RCLASS(hash, name, klass) Setattr(hash, name, NewVoid(klass, 0)) + + +class RUBY:public Language { +private: + + String *module; + String *modvar; + String *feature; + String *prefix; + int current; + Hash *classes; /* key=cname val=RClass */ + RClass *klass; /* Currently processing class */ + Hash *special_methods; /* Python style special method name table */ + + File *f_directors; + File *f_directors_h; + File *f_directors_helpers; + File *f_begin; + File *f_runtime; + File *f_runtime_h; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + + bool useGlobalModule; + bool multipleInheritance; + + // Wrap modes + enum WrapperMode { + NO_CPP, + MEMBER_FUNC, + CONSTRUCTOR_ALLOCATE, + CONSTRUCTOR_INITIALIZE, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }; + + /* ------------------------------------------------------------ + * autodoc level declarations + * ------------------------------------------------------------ */ + + enum autodoc_l { + NO_AUTODOC = -2, // no autodoc + STRING_AUTODOC = -1, // use provided string + NAMES_AUTODOC = 0, // only parameter names + TYPES_AUTODOC = 1, // parameter names and types + EXTEND_AUTODOC = 2, // extended documentation and parameter names + EXTEND_TYPES_AUTODOC = 3 // extended documentation and parameter types + names + }; + + autodoc_t last_mode; + String* last_autodoc; + + + + autodoc_l autodoc_level(String *autodoc) { + autodoc_l dlevel = NO_AUTODOC; + if (autodoc) { + char *c = Char(autodoc); + if (c && isdigit(c[0])) { + dlevel = (autodoc_l) atoi(c); + } else { + if (strcmp(c, "extended") == 0) { + dlevel = EXTEND_AUTODOC; + } else { + dlevel = STRING_AUTODOC; + } + } + } + return dlevel; + } + + + + /* ------------------------------------------------------------ + * have_docstring() + * Check if there is a docstring directive and it has text, + * or there is an autodoc flag set + * ------------------------------------------------------------ */ + + bool have_docstring(Node *n) { + String *str = Getattr(n, "feature:docstring"); + return (str != NULL && Len(str) > 0) || (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + } + + /* ------------------------------------------------------------ + * docstring() + * Get the docstring text, stripping off {} if neccessary, + * and enclose in triple double quotes. If autodoc is also + * set then it will build a combined docstring. + * ------------------------------------------------------------ */ + + String *docstring(Node *n, autodoc_t ad_type) { + + String *str = Getattr(n, "feature:docstring"); + bool have_ds = (str != NULL && Len(str) > 0); + bool have_auto = (Getattr(n, "feature:autodoc") && !GetFlag(n, "feature:noautodoc")); + String *autodoc = NULL; + String *doc = NULL; + + if (have_ds) { + char *t = Char(str); + if (*t == '{') { + Delitem(str, 0); + Delitem(str, DOH_END); + } + } + + if (have_auto) { + autodoc = make_autodoc(n, ad_type); + have_auto = (autodoc != NULL && Len(autodoc) > 0); + } + // If there is more than one line then make docstrings like this: + // + // This is line1 + // And here is line2 followed by the rest of them + // + // otherwise, put it all on a single line + // + if (have_auto && have_ds) { // Both autodoc and docstring are present + doc = NewString(""); + Printv(doc, "\n", autodoc, "\n", str, NIL); + } else if (!have_auto && have_ds) { // only docstring + if (Strchr(str, '\n') == NULL) { + doc = NewString(str); + } else { + doc = NewString(""); + Printv(doc, str, NIL); + } + } else if (have_auto && !have_ds) { // only autodoc + if (Strchr(autodoc, '\n') == NULL) { + doc = NewStringf("%s", autodoc); + } else { + doc = NewString(""); + Printv(doc, "\n", autodoc, NIL); + } + } else + doc = NewString(""); + + // Save the generated strings in the parse tree in case they are used later + // by post processing tools + Setattr(n, "ruby:docstring", doc); + Setattr(n, "ruby:autodoc", autodoc); + return doc; + } + + /* ------------------------------------------------------------ + * make_autodocParmList() + * Generate the documentation for the function parameters + * ------------------------------------------------------------ */ + + String *make_autodocParmList(Node *n, bool showTypes) { + String *doc = NewString(""); + String *pdocs = Copy(Getattr(n, "feature:pdocs")); + ParmList *plist = CopyParmList(Getattr(n, "parms")); + Parm *p; + Parm *pnext; + Node *lookup; + int lines = 0; + const int maxwidth = 50; + + if (pdocs) + Append(pdocs, ".\n"); + + + Swig_typemap_attach_parms("in", plist, 0); + Swig_typemap_attach_parms("doc", plist, 0); + + for (p = plist; p; p = pnext) { + String *name = 0; + String *type = 0; + String *value = 0; + String *ptype = 0; + String *pdoc = Getattr(p, "tmap:doc"); + if (pdoc) { + name = Getattr(p, "tmap:doc:name"); + type = Getattr(p, "tmap:doc:type"); + value = Getattr(p, "tmap:doc:value"); + ptype = Getattr(p, "tmap:doc:pytype"); + } + + name = name ? name : Getattr(p, "name"); + type = type ? type : Getattr(p, "type"); + value = value ? value : Getattr(p, "value"); + + + String *tm = Getattr(p, "tmap:in"); + if (tm) { + pnext = Getattr(p, "tmap:in:next"); + } else { + pnext = nextSibling(p); + } + + // Skip ignored input attributes + if (checkAttribute(p, "tmap:in:numinputs", "0")) + continue; + + // Skip the 'self' parameter which in ruby is implicit + if ( Cmp(name, "self") == 0 ) + continue; + + // Make __p parameters just p (as used in STL) + Replace( name, "__", "", DOH_REPLACE_FIRST ); + + if (Len(doc)) { + // add a comma to the previous one if any + Append(doc, ", "); + + // Do we need to wrap a long line? + if ((Len(doc) - lines * maxwidth) > maxwidth) { + Printf(doc, "\n%s", tab4); + lines += 1; + } + } + // Do the param type too? + if (showTypes) { + type = SwigType_base(type); + lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + Printf(doc, "%s ", type); + } + + if (name) { + Append(doc, name); + if (pdoc) { + if (!pdocs) + pdocs = NewString("Parameters:\n"); + Printf(pdocs, " %s.\n", pdoc); + } + } else { + Append(doc, "?"); + } + + if (value) { + if (Strcmp(value, "NULL") == 0) + value = NewString("nil"); + else if (Strcmp(value, "true") == 0 || Strcmp(value, "TRUE") == 0) + value = NewString("true"); + else if (Strcmp(value, "false") == 0 || Strcmp(value, "FALSE") == 0) + value = NewString("false"); + else { + lookup = Swig_symbol_clookup(value, 0); + if (lookup) + value = Getattr(lookup, "sym:name"); + } + Printf(doc, "=%s", value); + } + } + if (pdocs) + Setattr(n, "feature:pdocs", pdocs); + Delete(plist); + return doc; + } + + /* ------------------------------------------------------------ + * make_autodoc() + * Build a docstring for the node, using parameter and other + * info in the parse tree. If the value of the autodoc + * attribute is "0" then do not include parameter types, if + * it is "1" (the default) then do. If it has some other + * value then assume it is supplied by the extension writer + * and use it directly. + * ------------------------------------------------------------ */ + + String *make_autodoc(Node *n, autodoc_t ad_type) { + int extended = 0; + // If the function is overloaded then this funciton is called + // for the last one. Rewind to the first so the docstrings are + // in order. + while (Getattr(n, "sym:previousSibling")) + n = Getattr(n, "sym:previousSibling"); + + Node *pn = Swig_methodclass(n); + String* super_names = NewString(""); + String* class_name = Getattr(pn, "sym:name") ; + + if ( !class_name ) class_name = NewString(""); + else + { + class_name = Copy(class_name); + List *baselist = Getattr(pn, "bases"); + if (baselist && Len(baselist)) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + + int count = 0; + for ( ;base.item; ++count) { + if ( count ) Append(super_names, ", "); + String *basename = Getattr(base.item, "sym:name"); + + String* basenamestr = NewString(basename); + Node* parent = parentNode(base.item); + while (parent) + { + String *parent_name = Copy( Getattr(parent, "sym:name") ); + if ( !parent_name ) { + Node* mod = Getattr(parent, "module"); + if ( mod ) + parent_name = Copy( Getattr(mod, "name") ); + if ( parent_name ) + { + (Char(parent_name))[0] = (char)toupper((Char(parent_name))[0]); + } + } + if ( parent_name ) + { + Insert(basenamestr, 0, "::"); + Insert(basenamestr, 0, parent_name); + Delete(parent_name); + } + parent = parentNode(parent); + } + + Append(super_names, basenamestr ); + Delete(basenamestr); + base = Next(base); + } + } + } + String* full_name; + if ( module ) { + full_name = NewString(module); + if (class_name && Len(class_name) > 0) Append(full_name, "::"); + } + else + full_name = NewString(""); + Append(full_name, class_name); + + String* symname = Getattr(n, "sym:name"); + if ( Getattr( special_methods, symname ) ) + symname = Getattr( special_methods, symname ); + + String* methodName = NewString(full_name); + Append(methodName, symname); + + + // Each overloaded function will try to get documented, + // so we keep the name of the last overloaded function and its type. + // Documenting just from functionWrapper() is not possible as + // sym:name has already been changed to include the class name + if ( last_mode == ad_type && Cmp(methodName, last_autodoc) == 0 ) { + Delete(full_name); + Delete(class_name); + Delete(super_names); + Delete(methodName); + return NewString(""); + } + + + last_mode = ad_type; + last_autodoc = Copy(methodName); + + String *doc = NewString("/*\n"); + int counter = 0; + bool skipAuto = false; + Node* on = n; + for ( ; n; ++counter ) { + skipAuto = false; + bool showTypes = false; + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + switch (dlevel) { + case NO_AUTODOC: + break; + case NAMES_AUTODOC: + showTypes = false; + break; + case TYPES_AUTODOC: + showTypes = true; + break; + case EXTEND_AUTODOC: + extended = 1; + showTypes = false; + break; + case EXTEND_TYPES_AUTODOC: + extended = 1; + showTypes = true; + break; + case STRING_AUTODOC: + skipAuto = true; + break; + } + + SwigType *type = Getattr(n, "type"); + + if (type) { + if (Strcmp(type, "void") == 0) + type = NULL; + else { + SwigType *qt = SwigType_typedef_resolve_all(type); + if (SwigType_isenum(qt)) + type = NewString("int"); + else { + type = SwigType_base(type); + Node *lookup = Swig_symbol_clookup(type, 0); + if (lookup) + type = Getattr(lookup, "sym:name"); + } + } + } + + if (counter == 0) { + switch (ad_type) { + case AUTODOC_CLASS: + Printf(doc, " Document-class: %s", full_name); + if ( Len(super_names) > 0 ) + Printf( doc, " < %s", super_names); + Append(doc, "\n\n"); + break; + case AUTODOC_CTOR: + Printf(doc, " Document-method: %s.new\n\n", full_name); + break; + + case AUTODOC_DTOR: + break; + + case AUTODOC_STATICFUNC: + Printf(doc, " Document-method: %s.%s\n\n", full_name, symname); + break; + + case AUTODOC_FUNC: + case AUTODOC_METHOD: + case AUTODOC_GETTER: + Printf(doc, " Document-method: %s.%s\n\n", full_name, symname); + break; + case AUTODOC_SETTER: + Printf(doc, " Document-method: %s.%s=\n\n", full_name, symname); + break; + } + } + + + if (skipAuto) { + if ( counter == 0 ) Printf(doc, " call-seq:\n"); + switch( ad_type ) + { + case AUTODOC_STATICFUNC: + case AUTODOC_FUNC: + case AUTODOC_METHOD: + case AUTODOC_GETTER: + { + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, " %s(%s)", symname, paramList); + else + Printf(doc, " %s", symname); + if (type) + Printf(doc, " -> %s", type); + break; + } + case AUTODOC_SETTER: + { + Printf(doc, " %s=(x)", symname); + if (type) Printf(doc, " -> %s", type); + break; + } + default: + break; + } + } + else { + switch (ad_type) { + case AUTODOC_CLASS: + { + // Only do the autodoc if there isn't a docstring for the class + String *str = Getattr(n, "feature:docstring"); + if (counter == 0 && (str == NULL || Len(str) == 0)) { + if (CPlusPlus) { + Printf(doc, " Proxy of C++ %s class", full_name); + } else { + Printf(doc, " Proxy of C %s struct", full_name); + } + } + } + break; + case AUTODOC_CTOR: + if (counter == 0) Printf(doc, " call-seq:\n"); + if (Strcmp(class_name, symname) == 0) { + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, " %s.new(%s)", class_name, paramList); + else + Printf(doc, " %s.new", class_name); + } else + Printf(doc, " %s.new(%s)", class_name, + make_autodocParmList(n, showTypes)); + break; + + case AUTODOC_DTOR: + break; + + case AUTODOC_STATICFUNC: + case AUTODOC_FUNC: + case AUTODOC_METHOD: + case AUTODOC_GETTER: + { + if (counter == 0) Printf(doc, " call-seq:\n"); + String *paramList = make_autodocParmList(n, showTypes); + if (Len(paramList)) + Printf(doc, " %s(%s)", symname, paramList); + else + Printf(doc, " %s", symname); + if (type) + Printf(doc, " -> %s", type); + break; + } + case AUTODOC_SETTER: + { + Printf(doc, " call-seq:\n"); + Printf(doc, " %s=(x)", symname); + if (type) Printf(doc, " -> %s", type); + break; + } + } + } + + // if it's overloaded then get the next decl and loop around again + n = Getattr(n, "sym:nextSibling"); + if (n) + Append(doc, "\n"); + } + + Printf(doc, "\n\n"); + if (!skipAuto) { + switch (ad_type) { + case AUTODOC_CLASS: + case AUTODOC_DTOR: + break; + case AUTODOC_CTOR: + Printf(doc, "Class constructor.\n"); + break; + case AUTODOC_STATICFUNC: + Printf(doc, "A class method.\n"); + break; + case AUTODOC_FUNC: + Printf(doc, "A module function.\n"); + break; + case AUTODOC_METHOD: + Printf(doc, "An instance method.\n"); + break; + case AUTODOC_GETTER: + Printf(doc, "Get value of attribute.\n"); + break; + case AUTODOC_SETTER: + Printf(doc, "Set new value for attribute.\n"); + break; + } + } + + + n = on; + while ( n ) { + String *autodoc = Getattr(n, "feature:autodoc"); + autodoc_l dlevel = autodoc_level(autodoc); + + symname = Getattr(n, "sym:name"); + if ( Getattr( special_methods, symname ) ) + symname = Getattr( special_methods, symname ); + + switch (dlevel) { + case NO_AUTODOC: + case NAMES_AUTODOC: + case TYPES_AUTODOC: + extended = 0; + break; + case STRING_AUTODOC: + extended = 2; + Replaceall( autodoc, "$class", class_name ); + Printv(doc, autodoc, ".", NIL); + break; + case EXTEND_AUTODOC: + case EXTEND_TYPES_AUTODOC: + extended = 1; + break; + } + + + if (extended) { + String *pdocs = Getattr(n, "feature:pdocs"); + if (pdocs) { + Printv(doc, "\n\n", pdocs, NULL); + break; + } + if ( extended == 2 ) break; + } + n = Getattr(n, "sym:nextSibling"); + } + + Append(doc, "\n*/\n"); + Delete(full_name); + Delete(class_name); + Delete(super_names); + Delete(methodName); + + return doc; + } + +public: + + /* --------------------------------------------------------------------- + * RUBY() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + RUBY() { + module = 0; + modvar = 0; + feature = 0; + prefix = 0; + last_autodoc = NewString(""); + current = NO_CPP; + classes = 0; + klass = 0; + special_methods = 0; + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_initbeforefunc = 0; + useGlobalModule = false; + multipleInheritance = false; + director_prot_ctor_code = NewString(""); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " rb_raise(rb_eRuntimeError,\"accessing abstract class or protected constructor\"); \n", " return Qnil;\n", "}\n", NIL); + director_multiple_inheritance = 0; + director_language = 1; + } + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + int cppcast = 1; + int autorename = 0; + + /* Set location of SWIG library */ + SWIG_library_directory("ruby"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-initname") == 0) { + if (argv[i + 1]) { + char *name = argv[i + 1]; + feature = NewString(name); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } + else if (strcmp(argv[i], "-feature") == 0) { + fprintf( stderr, "Warning: Ruby -feature option is deprecated, " + "please use -initname instead.\n"); + if (argv[i + 1]) { + char *name = argv[i + 1]; + feature = NewString(name); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-globalmodule") == 0) { + useGlobalModule = true; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-minherit") == 0) { + multipleInheritance = true; + director_multiple_inheritance = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-autorename") == 0) { + autorename = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-noautorename") == 0) { + autorename = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + char *name = argv[i + 1]; + prefix = NewString(name); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + if (cppcast) { + /* Turn on cppcast mode */ + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + if (autorename) { + /* Turn on the autorename mode */ + Preprocessor_define((DOH *) "SWIG_RUBY_AUTORENAME", 0); + } + + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGRUBY 1", 0); + + /* Add typemap definitions */ + SWIG_typemap_lang("ruby"); + SWIG_config_file("ruby.swg"); + allow_overloading(); + } + + /** + * Generate initialization code to define the Ruby module(s), + * accounting for nested modules as necessary. + */ + void defineRubyModule() { + List *modules = Split(module, ':', INT_MAX); + if (modules != 0 && Len(modules) > 0) { + String *mv = 0; + Iterator m; + m = First(modules); + while (m.item) { + if (Len(m.item) > 0) { + if (mv != 0) { + Printv(f_init, tab4, modvar, " = rb_define_module_under(", modvar, ", \"", m.item, "\");\n", NIL); + } else { + Printv(f_init, tab4, modvar, " = rb_define_module(\"", m.item, "\");\n", NIL); + mv = NewString(modvar); + } + } + m = Next(m); + } + Delete(mv); + Delete(modules); + } + } + + void registerMagicMethods() { + + special_methods = NewHash(); + + /* Python->Ruby style special method name. */ + /* Basic */ + Setattr(special_methods, "__repr__", "inspect"); + Setattr(special_methods, "__str__", "to_s"); + Setattr(special_methods, "__cmp__", "<=>"); + Setattr(special_methods, "__hash__", "hash"); + Setattr(special_methods, "__nonzero__", "nonzero?"); + + /* Callable */ + Setattr(special_methods, "__call__", "call"); + + /* Collection */ + Setattr(special_methods, "__len__", "length"); + Setattr(special_methods, "__getitem__", "[]"); + Setattr(special_methods, "__setitem__", "[]="); + + /* Operators */ + Setattr(special_methods, "__add__", "+"); + Setattr(special_methods, "__pos__", "+@"); + Setattr(special_methods, "__sub__", "-"); + Setattr(special_methods, "__neg__", "-@"); + Setattr(special_methods, "__mul__", "*"); + Setattr(special_methods, "__div__", "/"); + Setattr(special_methods, "__mod__", "%"); + Setattr(special_methods, "__lshift__", "<<"); + Setattr(special_methods, "__rshift__", ">>"); + Setattr(special_methods, "__and__", "&"); + Setattr(special_methods, "__or__", "|"); + Setattr(special_methods, "__xor__", "^"); + Setattr(special_methods, "__invert__", "~"); + Setattr(special_methods, "__lt__", "<"); + Setattr(special_methods, "__le__", "<="); + Setattr(special_methods, "__gt__", ">"); + Setattr(special_methods, "__ge__", ">="); + Setattr(special_methods, "__eq__", "=="); + + /* Other numeric */ + Setattr(special_methods, "__divmod__", "divmod"); + Setattr(special_methods, "__pow__", "**"); + Setattr(special_methods, "__abs__", "abs"); + Setattr(special_methods, "__int__", "to_i"); + Setattr(special_methods, "__float__", "to_f"); + Setattr(special_methods, "__coerce__", "coerce"); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + + /** + * See if any Ruby module options have been specified as options + * to the %module directive. + */ + Node *swigModule = Getattr(n, "module"); + if (swigModule) { + Node *options = Getattr(swigModule, "options"); + if (options) { + if (Getattr(options, "directors")) { + allow_directors(); + } + if (Getattr(options, "dirprot")) { + allow_dirprot(); + } + if (Getattr(options, "ruby_globalmodule")) { + useGlobalModule = true; + } + if (Getattr(options, "ruby_minherit")) { + multipleInheritance = true; + director_multiple_inheritance = 1; + } + } + } + + /* Set comparison with none for ConstructorToFunction */ + + + setSubclassInstanceCheck(NewStringf("strcmp(rb_obj_classname(self), classname) != 0")); + // setSubclassInstanceCheck(NewString("CLASS_OF(self) != cFoo.klass")); + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + if (!outfile) { + Printf(stderr, "Unable to determine outfile\n"); + SWIG_exit(EXIT_FAILURE); + } + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + f_directors_helpers = NewString(""); + f_initbeforefunc = NewString(""); + + if (directorsEnabled()) { + if (!outfile_h) { + Printf(stderr, "Unable to determine outfile_h\n"); + SWIG_exit(EXIT_FAILURE); + } + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + Swig_register_filebyname("director_helpers", f_directors_helpers); + Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + + modvar = 0; + current = NO_CPP; + klass = 0; + classes = NewHash(); + + registerMagicMethods(); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGRUBY\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + } + + Printf(f_runtime, "\n"); + + /* typedef void *VALUE */ + SwigType *value = NewSwigType(T_VOID); + SwigType_add_pointer(value); + SwigType_typedef(value, (char *) "VALUE"); + Delete(value); + + /* Set module name */ + set_module(Char(Getattr(n, "name"))); + + if (directorsEnabled()) { + /* Build a version of the module name for use in a C macro name. */ + String *module_macro = Copy(module); + Replaceall(module_macro, "::", "__"); + + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_macro); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_macro); + Printf(f_directors_h, "namespace Swig {\n"); + Printf(f_directors_h, " class Director;\n"); + Printf(f_directors_h, "}\n\n"); + + Printf(f_directors_helpers, "/* ---------------------------------------------------\n"); + Printf(f_directors_helpers, " * C++ director class helpers\n"); + Printf(f_directors_helpers, " * --------------------------------------------------- */\n\n"); + + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + if (outfile_h) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + + Delete(module_macro); + } + + Printf(f_header, "#define SWIG_init Init_%s\n", feature); + Printf(f_header, "#define SWIG_name \"%s\"\n\n", module); + Printf(f_header, "static VALUE %s;\n", modvar); + + /* Start generating the initialization function */ + String* docs = docstring(n, AUTODOC_CLASS); + Printf(f_init, "/*\n%s\n*/", docs ); + Printv(f_init, "\n", "#ifdef __cplusplus\n", "extern \"C\"\n", "#endif\n", "SWIGEXPORT void Init_", feature, "(void) {\n", "size_t i;\n", "\n", NIL); + + Printv(f_init, tab4, "SWIG_InitRuntime();\n", NIL); + + if (!useGlobalModule) + defineRubyModule(); + + Printv(f_init, "\n", "SWIG_InitializeModule(0);\n", "for (i = 0; i < swig_module.size; i++) {\n", "SWIG_define_class(swig_module.types[i]);\n", "}\n", NIL); + Printf(f_init, "\n"); + + /* Initialize code to keep track of objects */ + Printf(f_init, "SWIG_RubyInitializeTrackings();\n"); + + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director.swg", f_runtime); + } + + /* Finish off our init function */ + Printf(f_init, "}\n"); + SwigType_emit_type_table(f_runtime, f_wrappers); + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors_helpers, f_begin); + Dump(f_directors, f_begin); + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + Close(f_runtime_h); + } + + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + Wrapper_pretty_print(f_init, f_begin); + + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_initbeforefunc); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * importDirective() + * ----------------------------------------------------------------------------- */ + + virtual int importDirective(Node *n) { + String *modname = Getattr(n, "module"); + if (modname) { + if (prefix) { + Insert(modname, 0, prefix); + } + + List *modules = Split(modname, ':', INT_MAX); + if (modules && Len(modules) > 0) { + modname = NewString(""); + String *last = NULL; + Iterator m = First(modules); + while (m.item) { + if (Len(m.item) > 0) { + if (last) { + Append(modname, "/"); + } + Append(modname, m.item); + last = m.item; + } + m = Next(m); + } + Printf(f_init, "rb_require(\"%s\");\n", modname); + Delete(modname); + } + Delete(modules); + } + return Language::importDirective(n); + } + + /* --------------------------------------------------------------------- + * set_module(const char *mod_name) + * + * Sets the module name. Does nothing if it's already set (so it can + * be overridden as a command line option). + *---------------------------------------------------------------------- */ + + void set_module(const char *s) { + String *mod_name = NewString(s); + if (module == 0) { + /* Start with the empty string */ + module = NewString(""); + + if (prefix) { + Insert(mod_name, 0, prefix); + } + + /* Account for nested modules */ + List *modules = Split(mod_name, ':', INT_MAX); + if (modules != 0 && Len(modules) > 0) { + String *last = 0; + Iterator m = First(modules); + while (m.item) { + if (Len(m.item) > 0) { + String *cap = NewString(m.item); + (Char(cap))[0] = (char)toupper((Char(cap))[0]); + if (last != 0) { + Append(module, "::"); + } + Append(module, cap); + last = m.item; + } + m = Next(m); + } + if (feature == 0) { + feature = Copy(last); + } + (Char(last))[0] = (char)toupper((Char(last))[0]); + modvar = NewStringf("m%s", last); + Delete(modules); + } + } + Delete(mod_name); + } + + /* -------------------------------------------------------------------------- + * nativeWrapper() + * -------------------------------------------------------------------------- */ + virtual int nativeWrapper(Node *n) { + String *funcname = Getattr(n, "wrap:name"); + Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, "Adding native function %s not supported (ignored).\n", funcname); + return SWIG_NOWRAP; + } + + /** + * Process the comma-separated list of aliases (if any). + */ + void defineAliases(Node *n, const_String_or_char_ptr iname) { + String *aliasv = Getattr(n, "feature:alias"); + if (aliasv) { + List *aliases = Split(aliasv, ',', INT_MAX); + if (aliases && Len(aliases) > 0) { + Iterator alias = First(aliases); + while (alias.item) { + if (Len(alias.item) > 0) { + Printv(klass->init, tab4, "rb_define_alias(", klass->vname, ", \"", alias.item, "\", \"", iname, "\");\n", NIL); + } + alias = Next(alias); + } + } + Delete(aliases); + } + } + + /* --------------------------------------------------------------------- + * create_command(Node *n, char *iname) + * + * Creates a new command from a C function. + * iname = Name of function in scripting language + * + * A note about what "protected" and "private" mean in Ruby: + * + * A private method is accessible only within the class or its subclasses, + * and it is callable only in "function form", with 'self' (implicit or + * explicit) as a receiver. + * + * A protected method is callable only from within its class, but unlike + * a private method, it can be called with a receiver other than self, such + * as another instance of the same class. + * --------------------------------------------------------------------- */ + + void create_command(Node *n, const_String_or_char_ptr iname) { + + String *alloc_func = Swig_name_wrapper(iname); + String *wname = Swig_name_wrapper(iname); + if (CPlusPlus) { + Insert(wname, 0, "VALUEFUNC("); + Append(wname, ")"); + } + if (current != NO_CPP) + iname = klass->strip(iname); + if (Getattr(special_methods, iname)) { + iname = GetChar(special_methods, iname); + } + + String *s = NewString(""); + String *temp = NewString(""); + +#ifdef SWIG_PROTECTED_TARGET_METHODS + const char *rb_define_method = is_public(n) ? "rb_define_method" : "rb_define_protected_method"; +#else + const char *rb_define_method = "rb_define_method"; +#endif + switch (current) { + case MEMBER_FUNC: + { + if (multipleInheritance) { + Printv(klass->init, tab4, rb_define_method, "(", klass->mImpl, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + } else { + Printv(klass->init, tab4, rb_define_method, "(", klass->vname, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + } + } + break; + case CONSTRUCTOR_ALLOCATE: + Printv(s, tab4, "rb_define_alloc_func(", klass->vname, ", ", alloc_func, ");\n", NIL); + Replaceall(klass->init, "$allocator", s); + break; + case CONSTRUCTOR_INITIALIZE: + Printv(s, tab4, rb_define_method, "(", klass->vname, ", \"initialize\", ", wname, ", -1);\n", NIL); + Replaceall(klass->init, "$initializer", s); + break; + case MEMBER_VAR: + Append(temp, iname); + /* Check for _set or _get at the end of the name. */ + if (Len(temp) > 4) { + const char *p = Char(temp) + (Len(temp) - 4); + if (strcmp(p, "_set") == 0) { + Delslice(temp, Len(temp) - 4, DOH_END); + Append(temp, "="); + } else if (strcmp(p, "_get") == 0) { + Delslice(temp, Len(temp) - 4, DOH_END); + } + } + if (multipleInheritance) { + Printv(klass->init, tab4, "rb_define_method(", klass->mImpl, ", \"", temp, "\", ", wname, ", -1);\n", NIL); + } else { + Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"", temp, "\", ", wname, ", -1);\n", NIL); + } + break; + case STATIC_FUNC: + Printv(klass->init, tab4, "rb_define_singleton_method(", klass->vname, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + break; + case NO_CPP: + if (!useGlobalModule) { + Printv(s, tab4, "rb_define_module_function(", modvar, ", \"", iname, "\", ", wname, ", -1);\n", NIL); + Printv(f_init, s, NIL); + } else { + Printv(s, tab4, "rb_define_global_function(\"", iname, "\", ", wname, ", -1);\n", NIL); + Printv(f_init, s, NIL); + } + break; + case DESTRUCTOR: + case CLASS_CONST: + case STATIC_VAR: + assert(false); // Should not have gotten here for these types + default: + assert(false); + } + + defineAliases(n, iname); + + Delete(temp); + Delete(s); + Delete(wname); + Delete(alloc_func); + } + + /* --------------------------------------------------------------------- + * applyInputTypemap() + * + * Look up the appropriate "in" typemap for this parameter (p), + * substitute the correct strings for the $target and $input typemap + * parameters, and dump the resulting code to the wrapper file. + * --------------------------------------------------------------------- */ + + Parm *applyInputTypemap(Parm *p, String *ln, String *source, Wrapper *f, String *symname) { + String *tm; + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$target", ln); + Replaceall(tm, "$source", source); + Replaceall(tm, "$input", source); + Replaceall(tm, "$symname", symname); + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + Setattr(p, "emit:input", Copy(source)); + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + return p; + } + + Parm *skipIgnoredArgs(Parm *p) { + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + return p; + } + + /* --------------------------------------------------------------------- + * marshalInputArgs() + * + * Process all of the arguments passed into the scripting language + * method and convert them into C/C++ function arguments using the + * supplied typemaps. + * --------------------------------------------------------------------- */ + + void marshalInputArgs(Node *n, ParmList *l, int numarg, int numreq, String *kwargs, bool allow_kwargs, Wrapper *f) { + int i; + Parm *p; + String *tm; + String *source; + String *target; + + source = NewString(""); + target = NewString(""); + + bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + + /** + * The 'start' value indicates which of the C/C++ function arguments + * produced here corresponds to the first value in Ruby's argv[] array. + * The value of start is either zero or one. If start is zero, then + * the first argument (with name arg1) is based on the value of argv[0]. + * If start is one, then arg1 is based on the value of argv[1]. + */ + int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; + + int varargs = emit_isvarargs(l); + + Printf(kwargs, "{ "); + for (i = 0, p = l; i < numarg; i++) { + + p = skipIgnoredArgs(p); + + String *pn = Getattr(p, "name"); + String *ln = Getattr(p, "lname"); + + /* Produce string representation of source argument */ + Clear(source); + + /* First argument is a special case */ + if (i == 0) { + Printv(source, (start == 0) ? "argv[0]" : "self", NIL); + } else { + Printf(source, "argv[%d]", i - start); + } + + /* Produce string representation of target argument */ + Clear(target); + Printf(target, "%s", Char(ln)); + + if (i >= (numreq)) { /* Check if parsing an optional argument */ + Printf(f->code, " if (argc > %d) {\n", i - start); + } + + /* Record argument name for keyword argument handling */ + if (Len(pn)) { + Printf(kwargs, "\"%s\",", pn); + } else { + Printf(kwargs, "\"arg%d\",", i + 1); + } + + /* Look for an input typemap */ + p = applyInputTypemap(p, ln, source, f, Getattr(n, "name")); + if (i >= numreq) { + Printf(f->code, "}\n"); + } + } + + /* Finish argument marshalling */ + Printf(kwargs, " NULL }"); + if (allow_kwargs) { + Printv(f->locals, tab4, "char *kwnames[] = ", kwargs, ";\n", NIL); + } + + /* Trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Clear(source); + Printf(source, "argv[%d]", i - start); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", Copy(source)); + Printf(f->code, "if (argc > %d) {\n", i - start); + Printv(f->code, tm, "\n", NIL); + Printf(f->code, "}\n"); + } + } + + Delete(source); + Delete(target); + } + + /* --------------------------------------------------------------------- + * insertConstraintCheckingCode(ParmList *l, Wrapper *f) + * + * Checks each of the parameters in the parameter list for a "check" + * typemap and (if it finds one) inserts the typemapping code into + * the function wrapper. + * --------------------------------------------------------------------- */ + + void insertConstraintCheckingCode(ParmList *l, Wrapper *f) { + Parm *p; + String *tm; + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + } + + /* --------------------------------------------------------------------- + * insertCleanupCode(ParmList *l, String *cleanup) + * + * Checks each of the parameters in the parameter list for a "freearg" + * typemap and (if it finds one) inserts the typemapping code into + * the function wrapper. + * --------------------------------------------------------------------- */ + + void insertCleanupCode(ParmList *l, String *cleanup) { + String *tm; + for (Parm *p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + if (Len(tm) != 0) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + } + + /* --------------------------------------------------------------------- + * insertArgOutputCode(ParmList *l, String *outarg, int& need_result) + * + * Checks each of the parameters in the parameter list for a "argout" + * typemap and (if it finds one) inserts the typemapping code into + * the function wrapper. + * --------------------------------------------------------------------- */ + + void insertArgOutputCode(ParmList *l, String *outarg, int &need_result) { + String *tm; + for (Parm *p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "vresult"); + Replaceall(tm, "$result", "vresult"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + + Printv(outarg, tm, "\n", NIL); + need_result += 1; + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + } + + /* --------------------------------------------------------------------- + * validIdentifier() + * + * Is this a valid identifier in the scripting language? + * Ruby method names can include any combination of letters, numbers + * and underscores. A Ruby method name may optionally end with + * a question mark ("?"), exclamation point ("!") or equals sign ("="). + * + * Methods whose names end with question marks are, by convention, + * predicate methods that return true or false (e.g. Array#empty?). + * + * Methods whose names end with exclamation points are, by convention, + * called bang methods that modify the instance in place (e.g. Array#sort!). + * + * Methods whose names end with an equals sign are attribute setters + * (e.g. Thread#critical=). + * --------------------------------------------------------------------- */ + + virtual int validIdentifier(String *s) { + char *c = Char(s); + while (*c) { + if (!(isalnum(*c) || (*c == '_') || (*c == '?') || (*c == '!') || (*c == '='))) + return 0; + c++; + } + return 1; + } + + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + + String *nodeType; + bool constructor; + bool destructor; + String *storage; + + String *symname = Copy(Getattr(n, "sym:name")); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + int director_method = 0; + String *tm; + + int need_result = 0; + + /* Ruby needs no destructor wrapper */ + if (current == DESTRUCTOR) + return SWIG_NOWRAP; + + nodeType = Getattr(n, "nodeType"); + constructor = (!Cmp(nodeType, "constructor")); + destructor = (!Cmp(nodeType, "destructor")); + storage = Getattr(n, "storage"); + + /* If the C++ class constructor is overloaded, we only want to + * write out the "new" singleton method once since it is always + * the same. (It's the "initialize" method that will handle the + * overloading). */ + + if (current == CONSTRUCTOR_ALLOCATE && Swig_symbol_isoverloaded(n) && Getattr(n, "sym:nextSibling") != 0) + return SWIG_OK; + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(symname, n)) + return SWIG_ERROR; + } + + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *kwargs = NewString(""); + Wrapper *f = NewWrapper(); + + /* Rename predicate methods */ + if (GetFlag(n, "feature:predicate")) { + Append(symname, "?"); + } + + /* Rename bang methods */ + if (GetFlag(n, "feature:bang")) { + Append(symname, "!"); + } + + /* Determine the name of the SWIG wrapper function */ + String *wname = Swig_name_wrapper(symname); + if (overname && current != CONSTRUCTOR_ALLOCATE) { + Append(wname, overname); + } + + /* Emit arguments */ + if (current != CONSTRUCTOR_ALLOCATE) { + emit_parameter_variables(l, f); + } + + /* Attach standard typemaps */ + if (current != CONSTRUCTOR_ALLOCATE) { + emit_attach_parmmaps(l, f); + } + Setattr(n, "wrap:parms", l); + + /* Get number of arguments */ + int numarg = emit_num_arguments(l); + int numreq = emit_num_required(l); + int varargs = emit_isvarargs(l); + bool allow_kwargs = GetFlag(n, "feature:kwargs") ? true : false; + + bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; + + /* Now write the wrapper function itself */ + if (current == CONSTRUCTOR_ALLOCATE) { + Printf(f->def, "#ifdef HAVE_RB_DEFINE_ALLOC_FUNC\n"); + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(VALUE self) {", NIL); + Printf(f->def, "#else\n"); + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); + Printf(f->def, "#endif\n"); + } else if (current == CONSTRUCTOR_INITIALIZE) { + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); + if (!varargs) { + Printf(f->code, "if ((argc < %d) || (argc > %d)) ", numreq - start, numarg - start); + } else { + Printf(f->code, "if (argc < %d) ", numreq - start); + } + Printf(f->code, "{rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc); SWIG_fail;}\n", numreq - start); + } else { + + if ( current == NO_CPP ) + { + String* docs = docstring(n, AUTODOC_FUNC); + Printf(f_wrappers, "%s", docs); + Delete(docs); + } + + Printv(f->def, "SWIGINTERN VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); + if (!varargs) { + Printf(f->code, "if ((argc < %d) || (argc > %d)) ", numreq - start, numarg - start); + } else { + Printf(f->code, "if (argc < %d) ", numreq - start); + } + Printf(f->code, "{rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc); SWIG_fail;}\n", numreq - start); + } + + /* Now walk the function parameter list and generate code */ + /* to get arguments */ + if (current != CONSTRUCTOR_ALLOCATE) { + marshalInputArgs(n, l, numarg, numreq, kwargs, allow_kwargs, f); + } + // FIXME? + if (ctor_director) { + numarg--; + numreq--; + } + + /* Insert constraint checking code */ + insertConstraintCheckingCode(l, f); + + /* Insert cleanup code */ + insertCleanupCode(l, cleanup); + + /* Insert argument output code */ + insertArgOutputCode(l, outarg, need_result); + + /* if the object is a director, and the method call originated from its + * underlying Ruby object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in python. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + director_method = is_member_director(n) && !is_smart_pointer() && !destructor; + if (director_method) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); + Wrapper_add_local(f, "upcall", "bool upcall = false"); + Append(f->code, "upcall = (director && (director->swig_get_self() == self));\n"); + } + + /* Now write code to make the function call */ + if (current != CONSTRUCTOR_ALLOCATE) { + if (current == CONSTRUCTOR_INITIALIZE) { + Node *pn = Swig_methodclass(n); + String *symname = Getattr(pn, "sym:name"); + String *action = Getattr(n, "wrap:action"); + if (directorsEnabled()) { + String *classname = NewStringf("const char *classname SWIGUNUSED = \"%s::%s\"", module, symname); + Wrapper_add_local(f, "classname", classname); + } + if (action) { + Append(action, "\nDATA_PTR(self) = result;"); + if (GetFlag(pn, "feature:trackobjects")) { + Append(action, "\nSWIG_RubyAddTracking(result, self);"); + } + } + } + + /* Emit the function call */ + if (director_method) { + Printf(f->code, "try {\n"); + } + + Setattr(n, "wrap:name", wname); + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (director_method) { + Printf(actioncode, "} catch (Swig::DirectorException& e) {\n"); + Printf(actioncode, " rb_exc_raise(e.getError());\n"); + Printf(actioncode, " SWIG_fail;\n"); + Printf(actioncode, "}\n"); + } + + /* Return value if necessary */ + if (SwigType_type(t) != T_VOID && current != CONSTRUCTOR_INITIALIZE) { + need_result = 1; + if (GetFlag(n, "feature:predicate")) { + Printv(actioncode, tab4, "vresult = (result ? Qtrue : Qfalse);\n", NIL); + } else { + tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode); + actioncode = 0; + if (tm) { + Replaceall(tm, "$result", "vresult"); + Replaceall(tm, "$source", "result"); + Replaceall(tm, "$target", "vresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + else + Replaceall(tm, "$owner", "0"); + +#if 1 + // FIXME: this will not try to unwrap directors returned as non-director + // base class pointers! + + /* New addition to unwrap director return values so that the original + * Ruby object is returned instead. + */ + bool unwrap = false; + String *decl = Getattr(n, "decl"); + int is_pointer = SwigType_ispointer_return(decl); + int is_reference = SwigType_isreference_return(decl); + if (is_pointer || is_reference) { + String *type = Getattr(n, "type"); + Node *parent = Swig_methodclass(n); + Node *modname = Getattr(parent, "module"); + Node *target = Swig_directormap(modname, type); + if (target) + unwrap = true; + } + if (unwrap) { + Wrapper_add_local(f, "director", "Swig::Director *director = 0"); + Printf(f->code, "director = dynamic_cast<Swig::Director *>(result);\n"); + Printf(f->code, "if (director) {\n"); + Printf(f->code, " vresult = director->swig_get_self();\n"); + Printf(f->code, "} else {\n"); + Printf(f->code, "%s\n", tm); + Printf(f->code, "}\n"); + director_method = 0; + } else { + Printf(f->code, "%s\n", tm); + } +#else + Printf(f->code, "%s\n", tm); +#endif + Delete(tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s.\n", SwigType_str(t, 0)); + } + } + } + if (actioncode) { + Append(f->code, actioncode); + Delete(actioncode); + } + emit_return_variable(n, t, f); + } + + /* Extra code needed for new and initialize methods */ + if (current == CONSTRUCTOR_ALLOCATE) { + need_result = 1; + Printf(f->code, "VALUE vresult = SWIG_NewClassInstance(self, SWIGTYPE%s);\n", Char(SwigType_manglestr(t))); + Printf(f->code, "#ifndef HAVE_RB_DEFINE_ALLOC_FUNC\n"); + Printf(f->code, "rb_obj_call_init(vresult, argc, argv);\n"); + Printf(f->code, "#endif\n"); + } else if (current == CONSTRUCTOR_INITIALIZE) { + need_result = 1; + // Printf(f->code, "DATA_PTR(self) = result;\n"); + } + else + { + if ( need_result > 1 ) { + if ( SwigType_type(t) == T_VOID ) + Printf(f->code, "vresult = rb_ary_new();\n"); + else + { + Printf(f->code, "if (vresult == Qnil) vresult = rb_ary_new();\n"); + Printf(f->code, "else vresult = SWIG_Ruby_AppendOutput( " + "rb_ary_new(), vresult);\n"); + } + } + } + + /* Dump argument output code; */ + Printv(f->code, outarg, NIL); + + /* Dump the argument cleanup code */ + int need_cleanup = (current != CONSTRUCTOR_ALLOCATE) && (Len(cleanup) != 0); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + + + /* Look for any remaining cleanup. This processes the %new directive */ + if (current != CONSTRUCTOR_ALLOCATE && GetFlag(n, "feature:new")) { + tm = Swig_typemap_lookup("newfree", n, "result", 0); + if (tm) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, "\n", NIL); + Delete(tm); + } + } + + /* Special processing on return value. */ + tm = Swig_typemap_lookup("ret", n, "result", 0); + if (tm) { + Replaceall(tm, "$source", "result"); + Printv(f->code, tm, NIL); + Delete(tm); + } + + if (director_method) { + if ((tm = Swig_typemap_lookup("directorfree", n, "result", 0))) { + Replaceall(tm, "$input", "result"); + Replaceall(tm, "$result", "vresult"); + Printf(f->code, "%s\n", tm); + } + } + + + /* Wrap things up (in a manner of speaking) */ + if (need_result) { + if (current == CONSTRUCTOR_ALLOCATE) { + Printv(f->code, tab4, "return vresult;\n", NIL); + } else if (current == CONSTRUCTOR_INITIALIZE) { + Printv(f->code, tab4, "return self;\n", NIL); + Printv(f->code, "fail:\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, tab4, "return Qnil;\n", NIL); + } else { + Wrapper_add_local(f, "vresult", "VALUE vresult = Qnil"); + Printv(f->code, tab4, "return vresult;\n", NIL); + Printv(f->code, "fail:\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, tab4, "return Qnil;\n", NIL); + } + } else { + Printv(f->code, tab4, "return Qnil;\n", NIL); + Printv(f->code, "fail:\n", NIL); + if (need_cleanup) { + Printv(f->code, cleanup, NIL); + } + Printv(f->code, tab4, "return Qnil;\n", NIL); + } + + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + /* Emit the function */ + Wrapper_print(f, f_wrappers); + + /* Now register the function with the interpreter */ + if (!Swig_symbol_isoverloaded(n)) { + create_command(n, symname); + } else { + if (current == CONSTRUCTOR_ALLOCATE) { + create_command(n, symname); + } else { + if (!Getattr(n, "sym:nextSibling")) + dispatchFunction(n); + } + } + + Delete(kwargs); + Delete(cleanup); + Delete(outarg); + DelWrapper(f); + Delete(symname); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * ------------------------------------------------------------ */ + + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "return %s(nargs, args, self);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + Printv(f->def, "SWIGINTERN VALUE ", wname, "(int nargs, VALUE *args, VALUE self) {", NIL); + + Wrapper_add_local(f, "argc", "int argc"); + bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); + if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { + Printf(tmp, "VALUE argv[%d]", maxargs + 1); + } else { + Printf(tmp, "VALUE argv[%d]", maxargs); + } + Wrapper_add_local(f, "argv", tmp); + Wrapper_add_local(f, "ii", "int ii"); + + if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { + maxargs += 1; + Printf(f->code, "argc = nargs + 1;\n"); + Printf(f->code, "argv[0] = self;\n"); + Printf(f->code, "if (argc > %d) SWIG_fail;\n", maxargs); + Printf(f->code, "for (ii = 1; (ii < argc); ++ii) {\n"); + Printf(f->code, "argv[ii] = args[ii-1];\n"); + Printf(f->code, "}\n"); + } else { + Printf(f->code, "argc = nargs;\n"); + Printf(f->code, "if (argc > %d) SWIG_fail;\n", maxargs); + Printf(f->code, "for (ii = 0; (ii < argc); ++ii) {\n"); + Printf(f->code, "argv[ii] = args[ii];\n"); + Printf(f->code, "}\n"); + } + + Replaceall(dispatch, "$args", "nargs, args, self"); + Printv(f->code, dispatch, "\n", NIL); + + + + // Generate prototype list, go to first node + Node *sibl = n; + + String* type = SwigType_str(Getattr(sibl,"type"),NULL); + + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + + // Constructors will be treated specially + const bool isCtor = Cmp(Getattr(sibl,"feature:new"), "1") == 0; + const bool isMethod = ( Cmp(Getattr(sibl, "ismember"), "1") == 0 && + (!isCtor) ); + + // Construct real method name + String* methodName = NewString(""); + if ( isMethod ) + Printv( methodName, Getattr(parentNode(sibl),"sym:name"), ".", NIL ); + Append( methodName, Getattr(sibl,"sym:name" ) ); + if ( isCtor ) Append( methodName, ".new" ); + + // Generate prototype list + String *protoTypes = NewString(""); + do { + Append( protoTypes, "\n\" "); + if ( !isCtor ) Printv( protoTypes, type, " ", NIL ); + Printv(protoTypes, methodName, NIL ); + Parm* p = Getattr(sibl, "wrap:parms"); + if (p && (current == MEMBER_FUNC || current == MEMBER_VAR || + ctor_director) ) + p = nextSibling(p); // skip self + Append( protoTypes, "(" ); + while(p) + { + Append( protoTypes, SwigType_str(Getattr(p,"type"), Getattr(p,"name")) ); + if ( ( p = nextSibling(p)) ) Append(protoTypes, ", "); + } + Append( protoTypes, ")\\n\"" ); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + + Append(f->code, "fail:\n"); + Printf(f->code, "Ruby_Format_OverloadedError( argc, %d, \"%s\", %s);\n", + maxargs, methodName, protoTypes); + Append(f->code, "\nreturn Qnil;\n"); + + Delete(methodName); + Delete(type); + Delete(protoTypes); + + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + create_command(n, Char(symname)); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + /* --------------------------------------------------------------------- + * variableWrapper() + * --------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + String* docs = docstring(n, AUTODOC_GETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + + char *name = GetChar(n, "name"); + char *iname = GetChar(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + String *tm; + String *getfname, *setfname; + Wrapper *getf, *setf; + + getf = NewWrapper(); + setf = NewWrapper(); + + /* create getter */ + int addfail = 0; + String *getname = Swig_name_get(iname); + getfname = Swig_name_wrapper(getname); + Setattr(n, "wrap:name", getfname); + Printv(getf->def, "SWIGINTERN VALUE\n", getfname, "(", NIL); + Printf(getf->def, "VALUE self"); + Printf(getf->def, ") {"); + Wrapper_add_local(getf, "_val", "VALUE _val"); + + tm = Swig_typemap_lookup("varout", n, name, 0); + if (tm) { + Replaceall(tm, "$result", "_val"); + Replaceall(tm, "$target", "_val"); + Replaceall(tm, "$source", name); + /* Printv(getf->code,tm, NIL); */ + addfail = emit_action_code(n, getf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + } + Printv(getf->code, tab4, "return _val;\n", NIL); + if (addfail) { + Append(getf->code, "fail:\n"); + Append(getf->code, " return Qnil;\n"); + } + Append(getf->code, "}\n"); + + Wrapper_print(getf, f_wrappers); + + if (!is_assignable(n)) { + setfname = NewString("NULL"); + } else { + /* create setter */ + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + String *setname = Swig_name_set(iname); + setfname = Swig_name_wrapper(setname); + Setattr(n, "wrap:name", setfname); + Printv(setf->def, "SWIGINTERN VALUE\n", setfname, "(VALUE self, ", NIL); + Printf(setf->def, "VALUE _val) {"); + tm = Swig_typemap_lookup("varin", n, name, 0); + if (tm) { + Replaceall(tm, "$input", "_val"); + Replaceall(tm, "$source", "_val"); + Replaceall(tm, "$target", name); + /* Printv(setf->code,tm,"\n",NIL); */ + emit_action_code(n, setf->code, tm); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s\n", SwigType_str(t, 0)); + } + Printv(setf->code, tab4, "return _val;\n", NIL); + Printf(setf->code, "fail:\n"); + Printv(setf->code, tab4, "return Qnil;\n", NIL); + Printf(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + Delete(setname); + } + + /* define accessor method */ + if (CPlusPlus) { + Insert(getfname, 0, "VALUEFUNC("); + Append(getfname, ")"); + Insert(setfname, 0, "VALUEFUNC("); + Append(setfname, ")"); + } + + String *s = NewString(""); + switch (current) { + case STATIC_VAR: + /* C++ class variable */ + Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "\", ", getfname, ", 0);\n", NIL); + if (!GetFlag(n, "feature:immutable")) { + Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "=\", ", setfname, ", 1);\n", NIL); + } + Printv(klass->init, s, NIL); + break; + default: + /* C global variable */ + /* wrapped in Ruby module attribute */ + assert(current == NO_CPP); + if (!useGlobalModule) { + Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "\", ", getfname, ", 0);\n", NIL); + if (!GetFlag(n, "feature:immutable")) { + Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "=\", ", setfname, ", 1);\n", NIL); + } + } else { + Printv(s, tab4, "rb_define_global_method(\"", iname, "\", ", getfname, ", 0);\n", NIL); + if (!GetFlag(n, "feature:immutable")) { + Printv(s, tab4, "rb_define_global_method(\"", iname, "=\", ", setfname, ", 1);\n", NIL); + } + } + Printv(f_init, s, NIL); + Delete(s); + break; + } + Delete(getname); + Delete(getfname); + Delete(setfname); + DelWrapper(setf); + DelWrapper(getf); + return SWIG_OK; + } + + + /* --------------------------------------------------------------------- + * validate_const_name(char *name) + * + * Validate constant name. + * --------------------------------------------------------------------- */ + + char *validate_const_name(char *name, const char *reason) { + if (!name || name[0] == '\0') + return name; + + if (isupper(name[0])) + return name; + + if (islower(name[0])) { + name[0] = (char)toupper(name[0]); + Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, "Wrong %s name (corrected to `%s')\n", reason, name); + return name; + } + + Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, "Wrong %s name %s\n", reason, name); + + return name; + } + + /* --------------------------------------------------------------------- + * constantWrapper() + * --------------------------------------------------------------------- */ + + virtual int constantWrapper(Node *n) { + Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL); + + char *iname = GetChar(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + + if (current == CLASS_CONST) { + iname = klass->strip(iname); + } + validate_const_name(iname, "constant"); + SetChar(n, "sym:name", iname); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + String *tm = Swig_typemap_lookup("constant", n, value, 0); + if (!tm) + tm = Swig_typemap_lookup("constcode", n, value, 0); + if (tm) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", iname); + Replaceall(tm, "$symname", iname); + Replaceall(tm, "$value", value); + if (current == CLASS_CONST) { + if (multipleInheritance) { + Replaceall(tm, "$module", klass->mImpl); + Printv(klass->init, tm, "\n", NIL); + } else { + Replaceall(tm, "$module", klass->vname); + Printv(klass->init, tm, "\n", NIL); + } + } else { + if (!useGlobalModule) { + Replaceall(tm, "$module", modvar); + } else { + Replaceall(tm, "$module", "rb_cObject"); + } + Printf(f_init, "%s\n", tm); + } + } else { + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value %s = %s\n", SwigType_str(type, 0), value); + } + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * classDeclaration() + * + * Records information about classes---even classes that might be defined in + * other modules referenced by %import. + * ----------------------------------------------------------------------------- */ + + virtual int classDeclaration(Node *n) { + if (!Getattr(n, "feature:onlychildren")) { + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *tdname = Getattr(n, "tdname"); + + name = tdname ? tdname : name; + String *namestr = SwigType_namestr(name); + klass = RCLASS(classes, Char(namestr)); + if (!klass) { + klass = new RClass(); + String *valid_name = NewString(symname ? symname : namestr); + validate_const_name(Char(valid_name), "class"); + klass->set_name(namestr, symname, valid_name); + SET_RCLASS(classes, Char(namestr), klass); + Delete(valid_name); + } + Delete(namestr); + } + return Language::classDeclaration(n); + } + + /** + * Process the comma-separated list of mixed-in module names (if any). + */ + void includeRubyModules(Node *n) { + String *mixin = Getattr(n, "feature:mixin"); + if (mixin) { + List *modules = Split(mixin, ',', INT_MAX); + if (modules && Len(modules) > 0) { + Iterator mod = First(modules); + while (mod.item) { + if (Len(mod.item) > 0) { + Printf(klass->init, "rb_include_module(%s, rb_eval_string(\"%s\"));\n", klass->vname, mod.item); + } + mod = Next(mod); + } + } + Delete(modules); + } + } + + void handleBaseClasses(Node *n) { + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + while (base.item) { + String *basename = Getattr(base.item, "name"); + String *basenamestr = SwigType_namestr(basename); + RClass *super = RCLASS(classes, Char(basenamestr)); + Delete(basenamestr); + if (super) { + SwigType *btype = NewString(basename); + SwigType_add_pointer(btype); + SwigType_remember(btype); + if (multipleInheritance) { + String *bmangle = SwigType_manglestr(btype); + Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); + Append(bmangle, "->clientdata)->mImpl"); + Printv(klass->init, "rb_include_module(", klass->mImpl, ", ", bmangle, ");\n", NIL); + Delete(bmangle); + } else { + String *bmangle = SwigType_manglestr(btype); + Insert(bmangle, 0, "((swig_class *) SWIGTYPE"); + Append(bmangle, "->clientdata)->klass"); + Replaceall(klass->init, "$super", bmangle); + Delete(bmangle); + } + Delete(btype); + } + base = Next(base); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (!multipleInheritance) { + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Ruby.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + } + + /** + * Check to see if a %markfunc was specified. + */ + void handleMarkFuncDirective(Node *n) { + String *markfunc = Getattr(n, "feature:markfunc"); + if (markfunc) { + Printf(klass->init, "SwigClass%s.mark = (void (*)(void *)) %s;\n", klass->name, markfunc); + } else { + Printf(klass->init, "SwigClass%s.mark = 0;\n", klass->name); + } + } + + /** + * Check to see if a %freefunc was specified. + */ + void handleFreeFuncDirective(Node *n) { + String *freefunc = Getattr(n, "feature:freefunc"); + if (freefunc) { + Printf(klass->init, "SwigClass%s.destroy = (void (*)(void *)) %s;\n", klass->name, freefunc); + } else { + if (klass->destructor_defined) { + Printf(klass->init, "SwigClass%s.destroy = (void (*)(void *)) free_%s;\n", klass->name, klass->mname); + } + } + } + + /** + * Check to see if tracking is enabled for this class. + */ + void handleTrackDirective(Node *n) { + int trackObjects = GetFlag(n, "feature:trackobjects"); + if (trackObjects) { + Printf(klass->init, "SwigClass%s.trackObjects = 1;\n", klass->name); + } else { + Printf(klass->init, "SwigClass%s.trackObjects = 0;\n", klass->name); + } + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + String* docs = docstring(n, AUTODOC_CLASS); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + String *namestr = SwigType_namestr(name); // does template expansion + + klass = RCLASS(classes, Char(namestr)); + assert(klass != 0); + Delete(namestr); + String *valid_name = NewString(symname); + validate_const_name(Char(valid_name), "class"); + + Clear(klass->type); + Printv(klass->type, Getattr(n, "classtype"), NIL); + Printv(f_wrappers, "swig_class SwigClass", valid_name, ";\n\n", NIL); + Printv(klass->init, "\n", tab4, NIL); + + if (!useGlobalModule) { + Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar, ", \"", klass->name, "\", $super);\n", NIL); + } else { + Printv(klass->init, klass->vname, " = rb_define_class(\"", klass->name, + "\", $super);\n", NIL); + } + + if (multipleInheritance) { + Printv(klass->init, klass->mImpl, " = rb_define_module_under(", klass->vname, ", \"Impl\");\n", NIL); + } + + SwigType *tt = NewString(name); + SwigType_add_pointer(tt); + SwigType_remember(tt); + String *tm = SwigType_manglestr(tt); + Printf(klass->init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) &SwigClass%s);\n", tm, valid_name); + Delete(tm); + Delete(tt); + Delete(valid_name); + + includeRubyModules(n); + + Printv(klass->init, "$allocator", NIL); + Printv(klass->init, "$initializer", NIL); + + Language::classHandler(n); + + handleBaseClasses(n); + handleMarkFuncDirective(n); + handleFreeFuncDirective(n); + handleTrackDirective(n); + + if (multipleInheritance) { + Printv(klass->init, "rb_include_module(", klass->vname, ", ", klass->mImpl, ");\n", NIL); + } + + String *s = NewString(""); + Printv(s, tab4, "rb_undef_alloc_func(", klass->vname, ");\n", NIL); + Replaceall(klass->init, "$allocator", s); + Replaceall(klass->init, "$initializer", ""); + + if (GetFlag(n, "feature:exceptionclass")) { + Replaceall(klass->init, "$super", "rb_eRuntimeError"); + } else { + Replaceall(klass->init, "$super", "rb_cObject"); + } + Delete(s); + + Printv(f_init, klass->init, NIL); + klass = 0; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * + * Method for adding C++ member function + * + * By default, we're going to create a function of the form : + * + * Foo_bar(this,args) + * + * Where Foo is the classname, bar is the member name and the this pointer + * is explicitly attached to the beginning. + * + * The renaming only applies to the member function part, not the full + * classname. + * + * --------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + current = MEMBER_FUNC; + + String* docs = docstring(n, AUTODOC_METHOD); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + Language::memberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * constructorHandler() + * + * Method for adding C++ member constructor + * -------------------------------------------------------------------- */ + + void set_director_ctor_code(Node *n) { + /* director ctor code is specific for each class */ + Delete(director_prot_ctor_code); + director_prot_ctor_code = NewString(""); + Node *pn = Swig_methodclass(n); + String *symname = Getattr(pn, "sym:name"); + String *name = Copy(symname); + char *cname = Char(name); + if (cname) + cname[0] = (char)toupper(cname[0]); + Printv(director_prot_ctor_code, + "if ( $comparison ) { /* subclassed */\n", + " $director_new \n", + "} else {\n", " rb_raise(rb_eNameError,\"accessing abstract class or protected constructor\"); \n", " return Qnil;\n", "}\n", NIL); + Delete(director_ctor_code); + director_ctor_code = NewString(""); + Printv(director_ctor_code, "if ( $comparison ) { /* subclassed */\n", " $director_new \n", "} else {\n", " $nondirector_new \n", "}\n", NIL); + Delete(name); + } + + virtual int constructorHandler(Node *n) { + int use_director = Swig_directorclass(n); + if (use_director) { + set_director_ctor_code(n); + } + + /* First wrap the allocate method */ + current = CONSTRUCTOR_ALLOCATE; + Swig_name_register((const_String_or_char_ptr ) "construct", (const_String_or_char_ptr ) "%c_allocate"); + + + Language::constructorHandler(n); + + /* + * If we're wrapping the constructor of a C++ director class, prepend a new parameter + * to receive the scripting language object (e.g. 'self') + * + */ + Swig_save("ruby:constructorHandler", n, "parms", NIL); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("VALUE"); + self = NewParm(type, name); + Delete(type); + Delete(name); + Setattr(self, "lname", "Qnil"); + if (parms) + set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Delete(self); + } + + + + /* Now do the instance initialize method */ + String* docs = docstring(n, AUTODOC_CTOR); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + current = CONSTRUCTOR_INITIALIZE; + Swig_name_register((const_String_or_char_ptr ) "construct", (const_String_or_char_ptr ) "new_%c"); + Language::constructorHandler(n); + + /* Restore original parameter list */ + Delattr(n, "wrap:self"); + Swig_restore(n); + + /* Done */ + Swig_name_unregister((const_String_or_char_ptr ) "construct"); + current = NO_CPP; + klass->constructor_defined = 1; + return SWIG_OK; + } + + virtual int copyconstructorHandler(Node *n) { + int use_director = Swig_directorclass(n); + if (use_director) { + set_director_ctor_code(n); + } + + /* First wrap the allocate method */ + current = CONSTRUCTOR_ALLOCATE; + Swig_name_register((const_String_or_char_ptr ) "construct", (const_String_or_char_ptr ) "%c_allocate"); + + return Language::copyconstructorHandler(n); + } + + + /* --------------------------------------------------------------------- + * destructorHandler() + * -------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + + /* Do no spit free function if user defined his own for this class */ + Node *pn = Swig_methodclass(n); + String *freefunc = Getattr(pn, "feature:freefunc"); + if (freefunc) return SWIG_OK; + + current = DESTRUCTOR; + Language::destructorHandler(n); + + freefunc = NewString(""); + String *freebody = NewString(""); + String *pname0 = Swig_cparm_name(0, 0); + + Printv(freefunc, "free_", klass->mname, NIL); + Printv(freebody, "SWIGINTERN void\n", freefunc, "(", klass->type, " *", pname0, ") {\n", tab4, NIL); + + /* Check to see if object tracking is activated for the class + that owns this destructor. */ + if (GetFlag(pn, "feature:trackobjects")) { + Printf(freebody, "SWIG_RubyRemoveTracking(%s);\n", pname0); + Printv(freebody, tab4, NIL); + } + + if (Extend) { + String *wrap = Getattr(n, "wrap:code"); + if (wrap) { + Printv(f_wrappers, wrap, NIL); + } + /* Printv(freebody, Swig_name_destroy(name), "(", pname0, ")", NIL); */ + Printv(freebody, Getattr(n, "wrap:action"), "\n", NIL); + } else { + String *action = Getattr(n, "wrap:action"); + if (action) { + Printv(freebody, action, "\n", NIL); + } else { + /* In the case swig emits no destroy function. */ + if (CPlusPlus) + Printf(freebody, "delete %s;\n", pname0); + else + Printf(freebody, "free((char*) %s);\n", pname0); + } + } + + Printv(freebody, "}\n\n", NIL); + + Printv(f_wrappers, freebody, NIL); + + klass->destructor_defined = 1; + current = NO_CPP; + Delete(freefunc); + Delete(freebody); + Delete(pname0); + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * membervariableHandler() + * + * This creates a pair of functions to set/get the variable of a member. + * -------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + String* docs = docstring(n, AUTODOC_GETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + if (is_assignable(n)) { + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + } + + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + String* docs = docstring(n, AUTODOC_STATICFUNC); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + current = STATIC_FUNC; + Language::staticmemberfunctionHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * + * Create a C++ constant + * --------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + String* docs = docstring(n, AUTODOC_STATICFUNC); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + current = CLASS_CONST; + Language::memberconstantHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + String* docs = docstring(n, AUTODOC_GETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + + if (is_assignable(n)) { + String* docs = docstring(n, AUTODOC_SETTER); + Printf(f_wrappers, "%s", docs); + Delete(docs); + } + + current = STATIC_VAR; + Language::staticmembervariableHandler(n); + current = NO_CPP; + return SWIG_OK; + } + + /* C++ director class generation */ + virtual int classDirector(Node *n) { + return Language::classDirector(n); + } + + virtual int classDirectorInit(Node *n) { + String *declaration; + declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + virtual int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + virtual int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "SwigDirector_%s", supername); + + /* insert self parameter */ + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("VALUE"); + p = NewParm(type, NewString("self")); + set_nextSibling(p, parms); + parms = p; + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + virtual int classDirectorDefaultConstructor(Node *n) { + String *classname; + Wrapper *w; + classname = Swig_class_name(n); + w = NewWrapper(); + Printf(w->def, "SwigDirector_%s::SwigDirector_%s(VALUE self) : Swig::Director(self) { }", classname, classname); + Wrapper_print(w, f_directors); + DelWrapper(w); + Printf(f_directors_h, " SwigDirector_%s(VALUE self);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + /* --------------------------------------------------------------- + * exceptionSafeMethodCall() + * + * Emit a virtual director method to pass a method call on to the + * underlying Ruby instance. + * + * --------------------------------------------------------------- */ + + void exceptionSafeMethodCall(String *className, Node *n, Wrapper *w, int argc, String *args, bool initstack) { + Wrapper *body = NewWrapper(); + Wrapper *rescue = NewWrapper(); + + String *methodName = Getattr(n, "sym:name"); + + String *bodyName = NewStringf("%s_%s_body", className, methodName); + String *rescueName = NewStringf("%s_%s_rescue", className, methodName); + String *depthCountName = NewStringf("%s_%s_call_depth", className, methodName); + + // Check for an exception typemap of some kind + String *tm = Swig_typemap_lookup("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + } + + if ((tm != 0) && (Len(tm) > 0) && (Strcmp(tm, "1") != 0)) { + // Declare a global to hold the depth count + if (!Getattr(n, "sym:nextSibling")) { + Printf(body->def, "static int %s = 0;\n", depthCountName); + + // Function body + Printf(body->def, "VALUE %s(VALUE data) {\n", bodyName); + Wrapper_add_localv(body, "args", "Swig::body_args *", "args", "= reinterpret_cast<Swig::body_args *>(data)", NIL); + Wrapper_add_localv(body, "result", "VALUE", "result", "= Qnil", NIL); + Printf(body->code, "%s++;\n", depthCountName); + Printv(body->code, "result = rb_funcall2(args->recv, args->id, args->argc, args->argv);\n", NIL); + Printf(body->code, "%s--;\n", depthCountName); + Printv(body->code, "return result;\n", NIL); + Printv(body->code, "}", NIL); + + // Exception handler + Printf(rescue->def, "VALUE %s(VALUE args, VALUE error) {\n", rescueName); + Replaceall(tm, "$error", "error"); + Printf(rescue->code, "%s--;\n", depthCountName); + Printf(rescue->code, "if (%s == 0) ", depthCountName); + Printv(rescue->code, Str(tm), "\n", NIL); + Printv(rescue->code, "rb_exc_raise(error);\n", NIL); + Printv(rescue->code, "}", NIL); + } + + // Main code + Wrapper_add_localv(w, "args", "Swig::body_args", "args", NIL); + Wrapper_add_localv(w, "status", "int", "status", NIL); + Printv(w->code, "args.recv = swig_get_self();\n", NIL); + Printf(w->code, "args.id = rb_intern(\"%s\");\n", methodName); + Printf(w->code, "args.argc = %d;\n", argc); + if (argc > 0) { + Printf(w->code, "args.argv = new VALUE[%d];\n", argc); + for (int i = 0; i < argc; i++) { + Printf(w->code, "args.argv[%d] = obj%d;\n", i, i); + } + } else { + Printv(w->code, "args.argv = 0;\n", NIL); + } + Printf(w->code, "result = rb_protect(PROTECTFUNC(%s), reinterpret_cast<VALUE>(&args), &status);\n", bodyName); + if ( initstack ) Printf(w->code, "SWIG_RELEASE_STACK;\n"); + Printf(w->code, "if (status) {\n"); + Printf(w->code, "VALUE lastErr = rb_gv_get(\"$!\");\n"); + Printf(w->code, "%s(reinterpret_cast<VALUE>(&args), lastErr);\n", rescueName); + Printf(w->code, "}\n"); + if (argc > 0) { + Printv(w->code, "delete [] args.argv;\n", NIL); + } + // Dump wrapper code + Wrapper_print(body, f_directors_helpers); + Wrapper_print(rescue, f_directors_helpers); + } else { + if (argc > 0) { + Printf(w->code, "result = rb_funcall(swig_get_self(), rb_intern(\"%s\"), %d%s);\n", methodName, argc, args); + } else { + Printf(w->code, "result = rb_funcall(swig_get_self(), rb_intern(\"%s\"), 0, NULL);\n", methodName); + } + if ( initstack ) Printf(w->code, "SWIG_RELEASE_STACK;\n"); + } + + // Clean up + Delete(bodyName); + Delete(rescueName); + Delete(depthCountName); + DelWrapper(body); + DelWrapper(rescue); + } + + virtual int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl; + String *type; + String *name; + String *classname; + String *c_classname = Getattr(parent, "name"); + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args = NewString(""); + String *return_type; + Parm *p; + String *value = Getattr(n, "value"); + String *storage = Getattr(n, "storage"); + bool pure_virtual = false; + int status = SWIG_OK; + int idx; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + bool asvoid = checkAttribute( n, "feature:numoutputs", "0") ? true : false; + bool initstack = checkAttribute( n, "feature:initstack", "1") ? true : false; + + if (Cmp(storage, "virtual") == 0) { + if (Cmp(value, "0") == 0) { + pure_virtual = true; + } + } + String *overnametmp = NewString(Getattr(n, "sym:name")); + if (Getattr(n, "sym:overloaded")) { + Printf(overnametmp, "::%s", Getattr(n, "sym:overname")); + } + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("SwigDirector_%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Get any exception classes in the throws typemap + ParmList *throw_parm_list = 0; + + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + Parm *p; + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + if (initstack && !(ignored_method && !pure_virtual)) { + Append(w->def, "\nSWIG_INIT_STACK;\n"); + } + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($result). + */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), NIL); + } + } + + if (ignored_method) { + if (!pure_virtual) { + if (!is_void) + Printf(w->code, "return "); + String *super_call = Swig_method_call(super, l); + Printf(w->code, "%s;\n", super_call); + Delete(super_call); + } else { + Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname), + SwigType_namestr(name)); + } + } else { + /* attach typemaps to arguments (C/C++ -> Ruby) */ + String *arglist = NewString(""); + + /** + * For each parameter to the C++ member function, copy the parameter name + * to its "lname"; this ensures that Swig_typemap_attach_parms() will do + * the right thing when it sees strings like "$1" in your "directorin" typemaps. + * Not sure if it's OK to leave it like this, but seems OK so far. + */ + typemap_copy_pname_to_lname(l); + + Swig_typemap_attach_parms("in", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("directorargout", l, w); + + char source[256]; + + int outputs = 0; + if (!is_void && !asvoid) + outputs++; + + /* build argument list and type conversion string */ + idx = 0; p = l; + while ( p ) { + + if (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + continue; + } + + if (Getattr(p, "tmap:directorargout") != 0) + outputs++; + + if ( checkAttribute( p, "tmap:in:numinputs", "0") ) + { + p = Getattr(p, "tmap:in:next"); + continue; + } + + String *parameterName = Getattr(p, "name"); + String *parameterType = Getattr(p, "type"); + + Putc(',', arglist); + if ((tm = Getattr(p, "tmap:directorin")) != 0) { + sprintf(source, "obj%d", idx++); + Replaceall(tm, "$input", source); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, tm, "\n", NIL); + Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); + Printv(arglist, source, NIL); + p = Getattr(p, "tmap:directorin:next"); + continue; + } else if (Cmp(parameterType, "void")) { + /** + * Special handling for pointers to other C++ director classes. + * Ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. In other words, the type "SwigDirector_$1_lname" only exists + * for classes with directors. We avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. Perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(parameterType) || SwigType_isreference(parameterType)) { + Node *modname = Getattr(parent, "module"); + Node *target = Swig_directormap(modname, parameterType); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(parameterType) + 2); + /* name as pointer */ + String *ppname = Copy(parameterName); + if (SwigType_isreference(parameterType)) { + Insert(ppname, 0, "&"); + } + /* if necessary, cast away const since Ruby doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", parameterName); + String *nonconst_i = NewStringf("= const_cast<%s>(%s)", SwigType_lstr(parameterType, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(parameterType, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(parameterType, parameterName), + SwigType_namestr(c_classname), SwigType_namestr(name)); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(parameterType); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); + Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Printf(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); + Printf(wrap_args, "}\n"); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(parameterType, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + /* declare Ruby return value */ + Wrapper_add_local(w, "result", "VALUE result"); + + /* wrap complex arguments to VALUEs */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Ruby object */ + exceptionSafeMethodCall(classname, n, w, idx, arglist, initstack); + + /* + * Ruby method may return a simple object, or an Array of objects. + * For in/out arguments, we have to extract the appropriate VALUEs from the Array, + * then marshal everything back to C/C++ (return value and output arguments). + */ + + /* Marshal return value and other outputs (if any) from VALUE to C/C++ type */ + + String *cleanup = NewString(""); + String *outarg = NewString(""); + + if (outputs > 1) { + Wrapper_add_local(w, "output", "VALUE output"); + Printf(w->code, "if (TYPE(result) != T_ARRAY) {\n"); + Printf(w->code, "Ruby_DirectorTypeMismatchException(\"Ruby method failed to return an array.\");\n"); + Printf(w->code, "}\n"); + } + + idx = 0; + + /* Marshal return value */ + if (!is_void) { + /* This seems really silly. The node's type excludes qualifier/pointer/reference markers, + * which have to be retrieved from the decl field to construct return_type. But the typemap + * lookup routine uses the node's type, so we have to swap in and out the correct type. + * It's not just me, similar silliness also occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup("directorout", n, "result", w); + Setattr(n, "type", type); + if (tm != 0) { + if (outputs > 1 && !asvoid ) { + Printf(w->code, "output = rb_ary_entry(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + /* TODO check this */ + if (Getattr(n, "wrap:disown")) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), + SwigType_namestr(c_classname), SwigType_namestr(name)); + status = SWIG_ERROR; + } + } + + /* Marshal outputs */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:directorargout")) != 0) { + if (outputs > 1) { + Printf(w->code, "output = rb_ary_entry(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:directorargout:next"); + } else { + p = nextSibling(p); + } + } + + Delete(arglist); + Delete(cleanup); + Delete(outarg); + } + + /* any existing helper functions to handle this? */ + if (!is_void) { + if (!(ignored_method && !pure_virtual)) { + String *rettype = SwigType_str(return_type, 0); + if (!SwigType_isreference(return_type)) { + Printf(w->code, "return (%s) c_result;\n", rettype); + } else { + Printf(w->code, "return (%s) *c_result;\n", rettype); + } + Delete(rettype); + } + } + + Printf(w->code, "}\n"); + + // We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit the director method */ + if (status == SWIG_OK) { + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + /* clean up */ + Delete(wrap_args); + Delete(return_type); + Delete(pclassname); + DelWrapper(w); + return status; + } + + virtual int classDirectorConstructors(Node *n) { + return Language::classDirectorConstructors(n); + } + + virtual int classDirectorMethods(Node *n) { + return Language::classDirectorMethods(n); + } + + virtual int classDirectorDisown(Node *n) { + return Language::classDirectorDisown(n); + } + + void typemap_copy_pname_to_lname(ParmList *parms) { + Parm *p; + String *pname; + String *lname; + + p = parms; + while (p) { + pname = Getattr(p, "name"); + lname = Copy(pname); + Setattr(p, "lname", lname); + p = nextSibling(p); + } + } + + String *runtimeCode() { + String *s = NewString(""); + String *shead = Swig_include_sys("rubyhead.swg"); + if (!shead) { + Printf(stderr, "*** Unable to open 'rubyhead.swg'\n"); + } else { + Append(s, shead); + Delete(shead); + } + String *serrors = Swig_include_sys("rubyerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'rubyerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *strack = Swig_include_sys("rubytracking.swg"); + if (!strack) { + Printf(stderr, "*** Unable to open 'rubytracking.swg'\n"); + } else { + Append(s, strack); + Delete(strack); + } + String *sapi = Swig_include_sys("rubyapi.swg"); + if (!sapi) { + Printf(stderr, "*** Unable to open 'rubyapi.swg'\n"); + } else { + Append(s, sapi); + Delete(sapi); + } + String *srun = Swig_include_sys("rubyrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'rubyrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigrubyrun.h"); + } +}; /* class RUBY */ + +/* ----------------------------------------------------------------------------- + * swig_ruby() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_ruby() { + return new RUBY(); +} +extern "C" Language *swig_ruby(void) { + return new_swig_ruby(); +} + + +/* + * Local Variables: + * c-basic-offset: 2 + * End: + */ diff --git a/Source/Modules/s-exp.cxx b/Source/Modules/s-exp.cxx new file mode 100644 index 0000000..c87d18c --- /dev/null +++ b/Source/Modules/s-exp.cxx @@ -0,0 +1,394 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * s-exp.cxx + * + * A parse tree represented as Lisp s-expressions. + * ----------------------------------------------------------------------------- */ + +char cvsroot_s_exp_cxx[] = "$Id: s-exp.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" +#include "dohint.h" + +static const char *usage = "\ +S-Exp Options (available with -sexp)\n\ + -typemaplang <lang> - Typemap language\n\n"; + +//static Node *view_top = 0; +static File *out = 0; + +class Sexp:public Language { +public: + int indent_level; + Sexp():indent_level(0) { + } + + virtual ~ Sexp() { + } + + virtual void main(int argc, char *argv[]) { + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGSEXP 1", 0); + + SWIG_typemap_lang("sexp"); + for (int iX = 0; iX < argc; iX++) { + if (strcmp(argv[iX], "-typemaplang") == 0) { + Swig_mark_arg(iX); + iX++; + SWIG_typemap_lang(argv[iX]); + Swig_mark_arg(iX); + continue; + } + if (strcmp(argv[iX], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + DOHHash *print_circle_hash; + int print_circle_count; + int hanging_parens; + bool need_whitespace; + bool need_newline; + + /* Top of the parse tree */ + virtual int top(Node *n) { + if (out == 0) { + String *outfile = Getattr(n, "outfile"); + Replaceall(outfile, "_wrap.cxx", ".lisp"); + Replaceall(outfile, "_wrap.c", ".lisp"); + out = NewFile(outfile, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + } + String *f_sink = NewString(""); + Swig_register_filebyname("header", f_sink); + Swig_register_filebyname("wrapper", f_sink); + Swig_register_filebyname("begin", f_sink); + Swig_register_filebyname("runtime", f_sink); + Swig_register_filebyname("init", f_sink); + + Swig_banner_target_lang(out, ";;;"); + + Language::top(n); + Printf(out, "\n"); + Printf(out, ";;; Lisp parse tree produced by SWIG\n"); + print_circle_hash = DohNewHash(); + print_circle_count = 0; + hanging_parens = 0; + need_whitespace = 0; + need_newline = 0; + Sexp_print_node(n); + flush_parens(); + return SWIG_OK; + } + + void print_indent() { + int i; + for (i = 0; i < indent_level; i++) { + Printf(out, " "); + } + } + + void open_paren(const String *oper) { + flush_parens(); + Printf(out, "("); + if (oper) + Printf(out, "%s ", oper); + indent_level += 2; + } + + void close_paren(bool neednewline = false) { + hanging_parens++; + if (neednewline) + print_lazy_whitespace(); + indent_level -= 2; + } + + void flush_parens() { + int i; + if (hanging_parens) { + for (i = 0; i < hanging_parens; i++) + Printf(out, ")"); + hanging_parens = 0; + need_newline = true; + need_whitespace = true; + } + if (need_newline) { + Printf(out, "\n"); + print_indent(); + need_newline = false; + need_whitespace = false; + } else if (need_whitespace) { + Printf(out, " "); + need_whitespace = false; + } + } + + void print_lazy_whitespace() { + need_whitespace = 1; + } + + void print_lazy_newline() { + need_newline = 1; + } + + bool internal_key_p(DOH *key) { + return ((Cmp(key, "nodeType") == 0) + || (Cmp(key, "firstChild") == 0) + || (Cmp(key, "lastChild") == 0) + || (Cmp(key, "parentNode") == 0) + || (Cmp(key, "nextSibling") == 0) + || (Cmp(key, "previousSibling") == 0) + || (Cmp(key, "csym:nextSibling") == 0) + || (Cmp(key, "csym:previousSibling") == 0) + || (Cmp(key, "typepass:visit") == 0) + || (Cmp(key, "allocate:visit") == 0) + || (*(Char(key)) == '$')); + } + + bool boolean_key_p(DOH *key) { + return ((Cmp(key, "allocate:default_constructor") == 0) + || (Cmp(key, "allocate:default_destructor") == 0) + || (Cmp(key, "allows_typedef") == 0) + || (Cmp(key, "feature:immutable") == 0)); + } + + bool list_key_p(DOH *key) { + return ((Cmp(key, "parms") == 0) + || (Cmp(key, "baselist") == 0)); + } + + bool plist_key_p(DOH *key) + // true if KEY is the name of data that is a mapping from keys to + // values, which should be printed as a plist. + { + return ((Cmp(key, "typescope") == 0)); + } + + bool maybe_plist_key_p(DOH *key) { + return (Strncmp(key, "tmap:", 5) == 0); + } + + bool print_circle(DOH *obj, bool list_p) + // We have a complex object, which might be referenced several + // times, or even recursively. Use Lisp's reader notation for + // circular structures (#n#, #n=). + // + // An object can be printed in list-mode or object-mode; LIST_P toggles. + // return TRUE if OBJ still needs to be printed + { + flush_parens(); + // Following is a silly hack. It works around the limitation of + // DOH's hash tables that only work with string keys! + char address[32]; + sprintf(address, "%p%c", obj, list_p ? 'L' : 'O'); + DOH *placeholder = Getattr(print_circle_hash, address); + if (placeholder) { + Printv(out, placeholder, NIL); + return false; + } else { + String *placeholder = NewStringf("#%d#", ++print_circle_count); + Setattr(print_circle_hash, address, placeholder); + Printf(out, "#%d=", print_circle_count); + return true; + } + } + + void Sexp_print_value_of_key(DOH *value, DOH *key) { + if ((Cmp(key, "parms") == 0) || (Cmp(key, "wrap:parms") == 0) + || (Cmp(key, "kwargs") == 0) || (Cmp(key, "pattern") == 0)) + Sexp_print_parms(value); + else if (plist_key_p(key)) + Sexp_print_plist(value); + else if (maybe_plist_key_p(key)) { + if (DohIsMapping(value)) + Sexp_print_plist(value); + else + Sexp_print_doh(value); + } else if (list_key_p(key)) + Sexp_print_list(value); + else if (boolean_key_p(key)) + Sexp_print_boolean(value); + else + Sexp_print_doh(value); + } + + void Sexp_print_boolean(DOH *obj) { + flush_parens(); + /* See DOH/Doh/base.c, DohGetInt() */ + if (DohIsString(obj)) { + if (atoi(Char(obj)) != 0) + Printf(out, "t"); + else + Printf(out, "nil"); + } else + Printf(out, "nil"); + } + + void Sexp_print_list(DOH *obj) { + if (print_circle(obj, true)) { + open_paren(NIL); + for (; obj; obj = nextSibling(obj)) { + Sexp_print_doh(obj); + print_lazy_whitespace(); + } + close_paren(true); + } + } + + void Sexp_print_parms(DOH *obj) { + // print it as a list of plists + if (print_circle(obj, true)) { + open_paren(NIL); + for (; obj; obj = nextSibling(obj)) { + if (DohIsMapping(obj)) { + Iterator k; + open_paren(NIL); + for (k = First(obj); k.key; k = Next(k)) { + if (!internal_key_p(k.key)) { + DOH *value = Getattr(obj, k.key); + Sexp_print_as_keyword(k.key); + Sexp_print_value_of_key(value, k.key); + print_lazy_whitespace(); + } + } + close_paren(true); + } else + Sexp_print_doh(obj); + print_lazy_whitespace(); + } + close_paren(true); + } + } + + void Sexp_print_doh(DOH *obj) { + flush_parens(); + if (DohIsString(obj)) { + String *o = Str(obj); + Replaceall(o, "\\", "\\\\"); + Replaceall(o, "\"", "\\\""); + Printf(out, "\"%s\"", o); + Delete(o); + } else { + if (print_circle(obj, false)) { + // Dispatch type + if (nodeType(obj)) { + Sexp_print_node(obj); + } + + else if (DohIsMapping(obj)) { + Iterator k; + open_paren(NIL); + for (k = First(obj); k.key; k = Next(k)) { + if (!internal_key_p(k.key)) { + DOH *value = Getattr(obj, k.key); + flush_parens(); + open_paren(NIL); + Sexp_print_doh(k.key); + Printf(out, " . "); + Sexp_print_value_of_key(value, k.key); + close_paren(); + } + } + close_paren(); + } else if (strcmp(ObjType(obj)->objname, "List") == 0) { + int i; + open_paren(NIL); + for (i = 0; i < Len(obj); i++) { + DOH *item = Getitem(obj, i); + Sexp_print_doh(item); + } + close_paren(); + } else { + // What is it? + Printf(out, "#<DOH %s %x>", ObjType(obj)->objname, obj); + } + } + } + } + + void Sexp_print_as_keyword(const DOH *k) { + /* Print key, replacing ":" with "-" because : is CL's package prefix */ + flush_parens(); + String *key = NewString(k); + Replaceall(key, ":", "-"); + Replaceall(key, "_", "-"); + Printf(out, ":%s ", key); + Delete(key); + } + + void Sexp_print_plist_noparens(DOH *obj) { + /* attributes map names to objects */ + Iterator k; + bool first; + for (k = First(obj), first = true; k.key; k = Next(k), first = false) { + if (!internal_key_p(k.key)) { + DOH *value = Getattr(obj, k.key); + flush_parens(); + if (!first) { + Printf(out, " "); + } + Sexp_print_as_keyword(k.key); + /* Print value */ + Sexp_print_value_of_key(value, k.key); + } + } + } + + void Sexp_print_plist(DOH *obj) { + flush_parens(); + if (print_circle(obj, true)) { + open_paren(NIL); + Sexp_print_plist_noparens(obj); + close_paren(); + } + } + + void Sexp_print_attributes(Node *obj) { + Sexp_print_plist_noparens(obj); + } + + void Sexp_print_node(Node *obj) { + Node *cobj; + open_paren(nodeType(obj)); + /* A node has an attribute list... */ + Sexp_print_attributes(obj); + /* ... and child nodes. */ + cobj = firstChild(obj); + if (cobj) { + print_lazy_newline(); + flush_parens(); + Sexp_print_as_keyword("children"); + open_paren(NIL); + for (; cobj; cobj = nextSibling(cobj)) { + Sexp_print_node(cobj); + } + close_paren(); + } + close_paren(); + } + + + virtual int functionWrapper(Node *n) { + ParmList *l = Getattr(n, "parms"); + Wrapper *f = NewWrapper(); + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + DelWrapper(f); + return SWIG_OK; + } + +}; + + +static Language *new_swig_sexp() { + return new Sexp(); +} +extern "C" Language *swig_sexp(void) { + return new_swig_sexp(); +} diff --git a/Source/Modules/swigmain.cxx b/Source/Modules/swigmain.cxx new file mode 100644 index 0000000..aed915d --- /dev/null +++ b/Source/Modules/swigmain.cxx @@ -0,0 +1,202 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * Simplified Wrapper and Interface Generator (SWIG) + * + * swigmain.cxx + * + * This file is the main entry point to SWIG. It collects the command + * line options, registers built-in language modules, and instantiates + * a module for code generation. If adding new language modules + * to SWIG, you would modify this file. + * ----------------------------------------------------------------------------- */ + +char cvsroot_swigmain_cxx[] = "$Id: swigmain.cxx 10969 2008-12-06 23:15:20Z wsfulton $"; + +#include "swigmod.h" +#include <ctype.h> + +/* Module factories. These functions are used to instantiate + the built-in language modules. If adding a new language + module to SWIG, place a similar function here. Make sure + the function has "C" linkage. This is required so that modules + can be dynamically loaded in future versions. */ + +extern "C" { + Language *swig_tcl(void); + Language *swig_python(void); + Language *swig_perl5(void); + Language *swig_ruby(void); + Language *swig_guile(void); + Language *swig_modula3(void); + Language *swig_mzscheme(void); + Language *swig_java(void); + Language *swig_php(void); + Language *swig_php4(void); + Language *swig_ocaml(void); + Language *swig_octave(void); + Language *swig_pike(void); + Language *swig_sexp(void); + Language *swig_xml(void); + Language *swig_chicken(void); + Language *swig_csharp(void); + Language *swig_allegrocl(void); + Language *swig_lua(void); + Language *swig_clisp(void); + Language *swig_cffi(void); + Language *swig_uffi(void); + Language *swig_r(void); +} + +struct swig_module { + const char *name; + ModuleFactory fac; + const char *help; +}; + +/* Association of command line options to language modules. + Place an entry for new language modules here, keeping the + list sorted alphabetically. */ + +static swig_module modules[] = { + {"-allegrocl", swig_allegrocl, "ALLEGROCL"}, + {"-chicken", swig_chicken, "CHICKEN"}, + {"-clisp", swig_clisp, "CLISP"}, + {"-cffi", swig_cffi, "CFFI"}, + {"-csharp", swig_csharp, "C#"}, + {"-guile", swig_guile, "Guile"}, + {"-java", swig_java, "Java"}, + {"-lua", swig_lua, "Lua"}, + {"-modula3", swig_modula3, "Modula 3"}, + {"-mzscheme", swig_mzscheme, "Mzscheme"}, + {"-ocaml", swig_ocaml, "Ocaml"}, + {"-octave", swig_octave, "Octave"}, + {"-perl", swig_perl5, "Perl"}, + {"-perl5", swig_perl5, 0}, + {"-php", swig_php, "PHP"}, + {"-php4", swig_php4, 0}, + {"-php5", swig_php, 0}, + {"-pike", swig_pike, "Pike"}, + {"-python", swig_python, "Python"}, + {"-r", swig_r, "R (aka GNU S)"}, + {"-ruby", swig_ruby, "Ruby"}, + {"-sexp", swig_sexp, "Lisp S-Expressions"}, + {"-tcl", swig_tcl, "Tcl"}, + {"-tcl8", swig_tcl, 0}, + {"-uffi", swig_uffi, "Common Lisp / UFFI"}, + {"-xml", swig_xml, "XML"}, + {NULL, NULL, NULL} +}; + +#ifdef MACSWIG +#include <console.h> +#include <SIOUX.h> +#endif + +#ifndef SWIG_LANG +#define SWIG_LANG "-python" +#endif + +//----------------------------------------------------------------- +// main() +// +// Main program. Initializes the files and starts the parser. +//----------------------------------------------------------------- + +void SWIG_merge_envopt(const char *env, int oargc, char *oargv[], int *nargc, char ***nargv) { + if (!env) { + *nargc = oargc; + *nargv = oargv; + return; + } + + int argc = 1; + int arge = oargc + 1024; + char **argv = (char **) malloc(sizeof(char *) * (arge)); + char *buffer = (char *) malloc(2048); + char *b = buffer; + char *be = b + 1023; + const char *c = env; + while ((b != be) && *c && (argc < arge)) { + while (isspace(*c) && *c) + ++c; + if (*c) { + argv[argc] = b; + ++argc; + } + while ((b != be) && *c && !isspace(*c)) { + *(b++) = *(c++); + } + *b++ = 0; + } + + argv[0] = oargv[0]; + for (int i = 1; (i < oargc) && (argc < arge); ++i, ++argc) { + argv[argc] = oargv[i]; + } + + *nargc = argc; + *nargv = argv; +} + +int main(int margc, char **margv) { + int i; + Language *dl = 0; + ModuleFactory fac = 0; + + int argc; + char **argv; + + SWIG_merge_envopt(getenv("SWIG_FEATURES"), margc, margv, &argc, &argv); + +#ifdef MACSWIG + SIOUXSettings.asktosaveonclose = false; + argc = ccommand(&argv); +#endif + + /* Register built-in modules */ + for (i = 0; modules[i].name; i++) { + Swig_register_module(modules[i].name, modules[i].fac); + } + + Swig_init_args(argc, argv); + + /* Get options */ + for (i = 1; i < argc; i++) { + if (argv[i]) { + fac = Swig_find_module(argv[i]); + if (fac) { + dl = (fac) (); + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nolang") == 0) { + dl = new Language; + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-dnone") == 0) || + (strcmp(argv[i], "-dhtml") == 0) || + (strcmp(argv[i], "-dlatex") == 0) || (strcmp(argv[i], "-dascii") == 0) || (strcmp(argv[i], "-stat") == 0)) { + Printf(stderr, "swig: Warning. %s option deprecated.\n", argv[i]); + Swig_mark_arg(i); + } else if ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0)) { + if (strcmp(argv[i], "--help") == 0) + strcpy(argv[i], "-help"); + Printf(stdout, "Target Language Options\n"); + for (int j = 0; modules[j].name; j++) { + if (modules[j].help) { + Printf(stdout, " %-15s - Generate %s wrappers\n", modules[j].name, modules[j].help); + } + } + // Swig_mark_arg not called as the general -help options also need to be displayed later on + } + } + } + if (!dl) { + fac = Swig_find_module(SWIG_LANG); + if (fac) { + dl = (fac) (); + } + } + int res = SWIG_main(argc, argv, dl); + delete dl; + return res; +} diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h new file mode 100644 index 0000000..dbb62b2 --- /dev/null +++ b/Source/Modules/swigmod.h @@ -0,0 +1,391 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigmod.h + * + * Main header file for SWIG modules. + * ----------------------------------------------------------------------------- */ + +/* $Id: swigmod.h 11470 2009-07-29 20:50:39Z wsfulton $ */ + +#ifndef SWIG_SWIGMOD_H_ +#define SWIG_SWIGMOD_H_ + +#include "swig.h" +#include "preprocessor.h" +#include "swigwarn.h" + +#if !defined(HAVE_BOOL) +typedef int bool; +#define true ((bool)1) +#define false ((bool)0) +#endif + +#define NOT_VIRTUAL 0 +#define PLAIN_VIRTUAL 1 +#define PURE_VIRTUAL 2 + +extern String *input_file; +extern int line_number; +extern int start_line; +extern int CPlusPlus; // C++ mode +extern int Extend; // Extend mode +extern int Verbose; +extern int IsVirtual; +extern int ImportMode; +extern int NoExcept; // -no_except option +extern int Abstract; // abstract base class +extern int SmartPointer; // smart pointer methods being emitted +extern int SwigRuntime; + +/* Overload "argc" and "argv" */ +extern String *argv_template_string; +extern String *argc_template_string; + +/* Miscellaneous stuff */ + +#define tab2 " " +#define tab4 " " +#define tab8 " " + +class Dispatcher { +public: + + Dispatcher ():cplus_mode(PUBLIC) { + } + virtual ~ Dispatcher () { + } + + virtual int emit_one(Node *n); + virtual int emit_children(Node *n); + virtual int defaultHandler(Node *n); + + /* Top of the parse tree */ + virtual int top(Node *n) = 0; + + /* SWIG directives */ + + virtual int applyDirective(Node *n); + virtual int clearDirective(Node *n); + virtual int constantDirective(Node *n); + virtual int extendDirective(Node *n); + virtual int fragmentDirective(Node *n); + virtual int importDirective(Node *n); + virtual int includeDirective(Node *n); + virtual int insertDirective(Node *n); + virtual int moduleDirective(Node *n); + virtual int nativeDirective(Node *n); + virtual int pragmaDirective(Node *n); + virtual int typemapDirective(Node *n); + virtual int typemapitemDirective(Node *n); + virtual int typemapcopyDirective(Node *n); + virtual int typesDirective(Node *n); + + /* C/C++ parsing */ + + virtual int cDeclaration(Node *n); + virtual int externDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int enumvalueDeclaration(Node *n); + virtual int enumforwardDeclaration(Node *n); + virtual int classDeclaration(Node *n); + virtual int classforwardDeclaration(Node *n); + virtual int constructorDeclaration(Node *n); + virtual int destructorDeclaration(Node *n); + virtual int accessDeclaration(Node *n); + virtual int usingDeclaration(Node *n); + virtual int namespaceDeclaration(Node *n); + virtual int templateDeclaration(Node *n); + + enum AccessMode { PUBLIC, PRIVATE, PROTECTED }; + +protected: + AccessMode cplus_mode; +}; + +/* ---------------------------------------------------------------------------- + * class language: + * + * This class defines the functions that need to be supported by the + * scripting language being used. The translator calls these virtual + * functions to output different types of code for different languages. + * ------------------------------------------------------------------------- */ + +class Language:public Dispatcher { +public: + Language(); + virtual ~Language(); + virtual int emit_one(Node *n); + + /* Parse command line options */ + + virtual void main(int argc, char *argv[]); + + /* Top of the parse tree */ + + virtual int top(Node *n); + + /* SWIG directives */ + + + virtual int applyDirective(Node *n); + virtual int clearDirective(Node *n); + virtual int constantDirective(Node *n); + virtual int extendDirective(Node *n); + virtual int fragmentDirective(Node *n); + virtual int importDirective(Node *n); + virtual int includeDirective(Node *n); + virtual int insertDirective(Node *n); + virtual int moduleDirective(Node *n); + virtual int nativeDirective(Node *n); + virtual int pragmaDirective(Node *n); + virtual int typemapDirective(Node *n); + virtual int typemapcopyDirective(Node *n); + virtual int typesDirective(Node *n); + + /* C/C++ parsing */ + + virtual int cDeclaration(Node *n); + virtual int externDeclaration(Node *n); + virtual int enumDeclaration(Node *n); + virtual int enumvalueDeclaration(Node *n); + virtual int enumforwardDeclaration(Node *n); + virtual int classDeclaration(Node *n); + virtual int classforwardDeclaration(Node *n); + virtual int constructorDeclaration(Node *n); + virtual int destructorDeclaration(Node *n); + virtual int accessDeclaration(Node *n); + virtual int namespaceDeclaration(Node *n); + virtual int usingDeclaration(Node *n); + + /* Function handlers */ + + virtual int functionHandler(Node *n); + virtual int globalfunctionHandler(Node *n); + virtual int memberfunctionHandler(Node *n); + virtual int staticmemberfunctionHandler(Node *n); + virtual int callbackfunctionHandler(Node *n); + + /* Variable handlers */ + + virtual int variableHandler(Node *n); + virtual int globalvariableHandler(Node *n); + virtual int membervariableHandler(Node *n); + virtual int staticmembervariableHandler(Node *n); + + /* C++ handlers */ + + virtual int memberconstantHandler(Node *n); + virtual int constructorHandler(Node *n); + virtual int copyconstructorHandler(Node *n); + virtual int destructorHandler(Node *n); + virtual int classHandler(Node *n); + + /* Miscellaneous */ + + virtual int typedefHandler(Node *n); + + /* Low-level code generation */ + + virtual int constantWrapper(Node *n); + virtual int variableWrapper(Node *n); + virtual int functionWrapper(Node *n); + virtual int nativeWrapper(Node *n); + + /* C++ director class generation */ + virtual int classDirector(Node *n); + virtual int classDirectorInit(Node *n); + virtual int classDirectorEnd(Node *n); + virtual int unrollVirtualMethods(Node *n, Node *parent, List *vm, int default_director, int &virtual_destructor, int protectedbase = 0); + virtual int classDirectorConstructor(Node *n); + virtual int classDirectorDefaultConstructor(Node *n); + virtual int classDirectorMethod(Node *n, Node *parent, String *super); + virtual int classDirectorConstructors(Node *n); + virtual int classDirectorDestructor(Node *n); + virtual int classDirectorMethods(Node *n); + virtual int classDirectorDisown(Node *n); + + /* Miscellaneous */ + virtual int validIdentifier(String *s); /* valid identifier? */ + virtual int addSymbol(const String *s, const Node *n); /* Add symbol */ + virtual Node *symbolLookup(String *s); /* Symbol lookup */ + virtual Node *classLookup(SwigType *s); /* Class lookup */ + virtual Node *enumLookup(SwigType *s); /* Enum lookup */ + virtual int abstractClassTest(Node *n); /* Is class really abstract? */ + virtual int is_assignable(Node *n); /* Is variable assignable? */ + virtual String *runtimeCode(); /* returns the language specific runtime code */ + virtual String *defaultExternalRuntimeFilename(); /* the default filename for the external runtime */ + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm); /* Language specific special variable substitutions for $typemap() */ + + /* Runtime is C++ based, so extern "C" header section */ + void enable_cplus_runtime_mode(); + + /* Returns the cplus_runtime mode */ + int cplus_runtime_mode(); + + /* Allow director related code generation */ + void allow_directors(int val = 1); + + /* Return true if directors are enabled */ + int directorsEnabled() const; + + /* Allow director protected members related code generation */ + void allow_dirprot(int val = 1); + + /* Allow all protected members code generation (for directors) */ + void allow_allprotected(int val = 0); + + /* Returns the dirprot mode */ + int dirprot_mode() const; + + /* Check if the non public constructor is needed (for directors) */ + int need_nonpublic_ctor(Node *n); + + /* Check if the non public member is needed (for directors) */ + int need_nonpublic_member(Node *n); + + /* Set none comparison string */ + void setSubclassInstanceCheck(String *s); + + /* Set overload variable templates argc and argv */ + void setOverloadResolutionTemplates(String *argc, String *argv); + + /* Language instance is a singleton - get instance */ + static Language* instance(); + +protected: + /* Allow multiple-input typemaps */ + void allow_multiple_input(int val = 1); + + /* Allow overloaded functions */ + void allow_overloading(int val = 1); + + /* Wrapping class query */ + int is_wrapping_class(); + + /* Return the node for the current class */ + Node *getCurrentClass() const; + + /* Return C++ mode */ + int getCPlusMode() const; + + /* Return the real name of the current class */ + String *getClassName() const; + + /* Return the classes hash */ + Hash *getClassHash() const; + + /* Return the current class prefix */ + String *getClassPrefix() const; + + /* Fully qualified type name to use */ + String *getClassType() const; + + /* Return true if the current method is part of a smart-pointer */ + int is_smart_pointer() const; + + /* Some language modules require additional wrappers for virtual methods not declared in sub-classes */ + virtual bool extraDirectorProtectedCPPMethodsRequired() const; + + /* Director subclass comparison test */ + String *none_comparison; + + /* Director constructor "template" code */ + String *director_ctor_code; + + /* Director 'protected' constructor "template" code */ + String *director_prot_ctor_code; + + /* Director allows multiple inheritance */ + int director_multiple_inheritance; + + /* Director language module */ + int director_language; + +private: + Hash *symbols; + Hash *classtypes; + Hash *enumtypes; + int overloading; + int multiinput; + int cplus_runtime; + int directors; + static Language *this_; +}; + +int SWIG_main(int, char **, Language *); +void emit_parameter_variables(ParmList *l, Wrapper *f); +void emit_return_variable(Node *n, SwigType *rt, Wrapper *f); +void SWIG_exit(int); /* use EXIT_{SUCCESS,FAILURE} */ +void SWIG_config_file(const_String_or_char_ptr ); +const String *SWIG_output_directory(); +void SWIG_config_cppext(const char *ext); + +/* get the list of generated files */ +List *SWIG_output_files(); + +void SWIG_library_directory(const char *); +int emit_num_arguments(ParmList *); +int emit_num_required(ParmList *); +int emit_isvarargs(ParmList *); +void emit_attach_parmmaps(ParmList *, Wrapper *f); +void emit_mark_varargs(ParmList *l); +String *emit_action(Node *n); +int emit_action_code(Node *n, String *wrappercode, String *action); +void Swig_overload_check(Node *n); +String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *); +String *Swig_overload_dispatch_cast(Node *n, const_String_or_char_ptr fmt, int *); +String *Swig_overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *); +SwigType *cplus_value_type(SwigType *t); + +/* directors.cxx start */ +String *Swig_csuperclass_call(String *base, String *method, ParmList *l); +String *Swig_class_declaration(Node *n, String *name); +String *Swig_class_name(Node *n); +String *Swig_method_call(const_String_or_char_ptr name, ParmList *parms); +String *Swig_method_decl(SwigType *rtype, SwigType *decl, const_String_or_char_ptr id, List *args, int strip, int values); +String *Swig_director_declaration(Node *n); +void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f); +/* directors.cxx end */ + +extern "C" { + void SWIG_typemap_lang(const char *); + typedef Language *(*ModuleFactory) (void); +} + +void Swig_register_module(const char *name, ModuleFactory fac); +ModuleFactory Swig_find_module(const char *name); + +/* Utilities */ + +int is_public(Node *n); +int is_private(Node *n); +int is_protected(Node *n); +int is_member_director(Node *parentnode, Node *member); +int is_member_director(Node *member); +int is_non_virtual_protected_access(Node *n); /* Check if the non-virtual protected members are required (for directors) */ +int use_naturalvar_mode(Node *n); + +void Wrapper_virtual_elimination_mode_set(int); +void Wrapper_fast_dispatch_mode_set(int); +void Wrapper_cast_dispatch_mode_set(int); +void Wrapper_naturalvar_mode_set(int); + + +void clean_overloaded(Node *n); + +/* Contracts */ + +void Swig_contracts(Node *n); +void Swig_contract_mode_set(int flag); +int Swig_contract_mode_get(); + +/* Browser */ + +void Swig_browser(Node *n, int); +void Swig_default_allocators(Node *n); +void Swig_process_types(Node *n); + + +#endif diff --git a/Source/Modules/tcl8.cxx b/Source/Modules/tcl8.cxx new file mode 100644 index 0000000..3ff69fe --- /dev/null +++ b/Source/Modules/tcl8.cxx @@ -0,0 +1,1306 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * tcl8.cxx + * + * Tcl8 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_tcl8_cxx[] = "$Id: tcl8.cxx 11518 2009-08-08 22:56:10Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" +static int treduce = SWIG_cparse_template_reduce(0); + +static const char *usage = (char *) "\ +Tcl 8 Options (available with -tcl)\n\ + -itcl - Enable ITcl support\n\ + -nosafe - Leave out SafeInit module function.\n\ + -prefix <name> - Set a prefix <name> to be prepended to all names\n\ + -namespace - Build module into a Tcl 8 namespace\n\ + -pkgversion - Set package version\n\n"; + +static String *cmd_tab = 0; /* Table of command names */ +static String *var_tab = 0; /* Table of global variables */ +static String *const_tab = 0; /* Constant table */ +static String *methods_tab = 0; /* Methods table */ +static String *attr_tab = 0; /* Attribute table */ +static String *prefix = 0; +static String *module = 0; +static int nspace = 0; +static String *init_name = 0; +static String *ns_name = 0; +static int have_constructor; +static String *constructor_name; +static int have_destructor; +static int have_base_classes; +static String *destructor_action = 0; +static String *version = (String *) "0.0"; +static String *class_name = 0; + +static int have_attributes; +static int have_methods; +static int nosafe = 0; + +static File *f_header = 0; +static File *f_wrappers = 0; +static File *f_init = 0; +static File *f_begin = 0; +static File *f_runtime = 0; + + +// Itcl support +static int itcl = 0; +static File *f_shadow = 0; +static File *f_shadow_stubs = 0; + +static String *constructor = 0; +static String *destructor = 0; +static String *base_classes = 0; +static String *base_class_init = 0; +static String *methods = 0; +static String *imethods = 0; +static String *attributes = 0; +static String *attribute_traces = 0; +static String *iattribute_traces = 0; + + + +class TCL8:public Language { +public: + + /* ------------------------------------------------------------ + * TCL8::main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + int cppcast = 1; + + SWIG_library_directory("tcl"); + + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-prefix") == 0) { + if (argv[i + 1]) { + prefix = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else + Swig_arg_error(); + } else if (strcmp(argv[i], "-pkgversion") == 0) { + if (argv[i + 1]) { + version = NewString(argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } + } else if (strcmp(argv[i], "-namespace") == 0) { + nspace = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-itcl") == 0) { + itcl = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nosafe") == 0) { + nosafe = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-cppcast") == 0) { + cppcast = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-nocppcast") == 0) { + cppcast = 0; + Swig_mark_arg(i); + } else if (strcmp(argv[i], "-help") == 0) { + fputs(usage, stdout); + } + } + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + + Preprocessor_define("SWIGTCL 1", 0); + // SWIGTCL8 is deprecated, and no longer documented. + Preprocessor_define("SWIGTCL8 1", 0); + SWIG_typemap_lang("tcl8"); + SWIG_config_file("tcl8.swg"); + allow_overloading(); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + + /* Initialize some variables for the object interface */ + + cmd_tab = NewString(""); + var_tab = NewString(""); + methods_tab = NewString(""); + const_tab = NewString(""); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGTCL\n"); + Printf(f_runtime, "\n"); + + /* Set the module name, namespace, and prefix */ + + module = NewStringf("%(lower)s", Getattr(n, "name")); + init_name = NewStringf("%(title)s_Init", module); + + ns_name = prefix ? Copy(prefix) : Copy(module); + if (prefix) + Append(prefix, "_"); + + + /* If shadow classing is enabled, we're going to change the module name to "_module" */ + if (itcl) { + String *filen; + filen = NewStringf("%s%s.itcl", Swig_file_dirname(outfile), module); + + Insert(module, 0, "_"); + + if ((f_shadow = NewFile(filen, "w", SWIG_output_files())) == 0) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + f_shadow_stubs = NewString(""); + + Swig_register_filebyname("shadow", f_shadow); + Swig_register_filebyname("itcl", f_shadow); + + Swig_banner_target_lang(f_shadow, "#"); + + Printv(f_shadow, "\npackage require Itcl\n\n", NIL); + Delete(filen); + } + + /* Generate some macros used throughout code generation */ + + Printf(f_header, "#define SWIG_init %s\n", init_name); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + if (nspace) { + Printf(f_header, "#define SWIG_prefix \"%s::\"\n", ns_name); + Printf(f_header, "#define SWIG_namespace \"%s\"\n\n", ns_name); + } else { + Printf(f_header, "#define SWIG_prefix \"%s\"\n", prefix); + } + Printf(f_header, "#define SWIG_version \"%s\"\n", version); + + Printf(cmd_tab, "\nstatic swig_command_info swig_commands[] = {\n"); + Printf(var_tab, "\nstatic swig_var_info swig_variables[] = {\n"); + Printf(const_tab, "\nstatic swig_const_info swig_constants[] = {\n"); + + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* Start emitting code */ + Language::top(n); + + /* Done. Close up the module */ + Printv(cmd_tab, tab4, "{0, 0, 0}\n", "};\n", NIL); + Printv(var_tab, tab4, "{0,0,0,0}\n", "};\n", NIL); + Printv(const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); + + Printv(f_wrappers, cmd_tab, var_tab, const_tab, NIL); + + /* Dump the pointer equivalency table */ + SwigType_emit_type_table(f_runtime, f_wrappers); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + /* Close the init function and quit */ + Printf(f_init, "return TCL_OK;\n}\n"); + + if (!nosafe) { + Printf(f_init, "SWIGEXPORT int %(title)s_SafeInit(Tcl_Interp *interp) {\n", module); + Printf(f_init, " return SWIG_init(interp);\n"); + Printf(f_init, "}\n"); + } + + if (itcl) { + Printv(f_shadow, f_shadow_stubs, "\n", NIL); + Close(f_shadow); + Delete(f_shadow); + } + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Printv(f_begin, f_header, f_wrappers, NIL); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * functionWrapper() + * ------------------------------------------------------------ */ + + virtual int functionWrapper(Node *n) { + String *name = Getattr(n, "name"); /* Like to get rid of this */ + String *iname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + ParmList *parms = Getattr(n, "parms"); + String *overname = 0; + + Parm *p; + int i; + String *tm; + Wrapper *f; + String *incode, *cleanup, *outarg, *argstr, *args; + int num_arguments = 0; + int num_required = 0; + int varargs = 0; + + char source[64]; + + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) + return SWIG_ERROR; + } + + incode = NewString(""); + cleanup = NewString(""); + outarg = NewString(""); + argstr = NewString("\""); + args = NewString(""); + + f = NewWrapper(); + +#ifdef SWIG_USE_RESULTOBJ + Wrapper_add_local(f, "resultobj", "Tcl_Obj *resultobj = NULL"); +#endif + + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + Setattr(n, "wrap:name", wname); + + Printv(f->def, "SWIGINTERN int\n ", wname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(parms, f); + + /* Attach standard typemaps */ + emit_attach_parmmaps(parms, f); + Setattr(n, "wrap:parms", parms); + + /* Get number of require and total arguments */ + num_arguments = emit_num_arguments(parms); + num_required = emit_num_required(parms); + varargs = emit_isvarargs(parms); + + /* Unmarshal parameters */ + + for (i = 0, p = parms; i < num_arguments; i++) { + /* Skip ignored arguments */ + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + /* Produce string representations of the source and target arguments */ + sprintf(source, "objv[%d]", i + 1); + + if (i == num_required) + Putc('|', argstr); + if ((tm = Getattr(p, "tmap:in"))) { + String *parse = Getattr(p, "tmap:in:parse"); + if (!parse) { + Replaceall(tm, "$target", ln); + Replaceall(tm, "$source", source); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + + Putc('o', argstr); + Printf(args, ",(void *)0"); + if (i >= num_required) { + Printf(incode, "if (objc > %d) {\n", i + 1); + } + Printf(incode, "%s\n", tm); + if (i >= num_required) { + Printf(incode, "}\n"); + } + } else { + Printf(argstr, "%s", parse); + Printf(args, ",&%s", ln); + if (Strcmp(parse, "p") == 0) { + SwigType *lt = SwigType_ltype(pt); + SwigType_remember(pt); + if (Cmp(lt, "p.void") == 0) { + Printf(args, ",(void *)0"); + } else { + Printf(args, ",SWIGTYPE%s", SwigType_manglestr(pt)); + } + Delete(lt); + } + } + p = Getattr(p, "tmap:in:next"); + continue; + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + } + p = nextSibling(p); + } + + if (!varargs) { + Putc(':', argstr); + } else { + Putc(';', argstr); + /* If variable length arguments we need to emit the in typemap here */ + if (p && (tm = Getattr(p, "tmap:in"))) { + sprintf(source, "objv[%d]", i + 1); + Printf(incode, "if (objc > %d) {\n", i); + Replaceall(tm, "$input", source); + Printv(incode, tm, "\n", NIL); + Printf(incode, "}\n"); + } + } + + Printf(argstr, "%s\"", usage_string(Char(iname), type, parms)); + + Printv(f->code, "if (SWIG_GetArgs(interp, objc, objv,", argstr, args, ") == TCL_ERROR) SWIG_fail;\n", NIL); + + Printv(f->code, incode, NIL); + + /* Insert constraint checking code */ + for (p = parms; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (i = 0, p = parms; p; i++) { + if (!checkAttribute(p, "tmap:in:numinputs", "0") + && !Getattr(p, "tmap:in:parse") && (tm = Getattr(p, "tmap:freearg"))) { + if (Len(tm) != 0) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + } + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (i = 0, p = parms; p; i++) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); +#ifdef SWIG_USE_RESULTOBJ + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); +#else + Replaceall(tm, "$target", "(Tcl_GetObjResult(interp))"); + Replaceall(tm, "$result", "(Tcl_GetObjResult(interp))"); +#endif + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + /* Now write code to make the function call */ + String *actioncode = emit_action(n); + + /* Need to redo all of this code (eventually) */ + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + Replaceall(tm, "$source", "result"); +#ifdef SWIG_USE_RESULTOBJ + Replaceall(tm, "$target", "resultobj"); + Replaceall(tm, "$result", "resultobj"); +#else + Replaceall(tm, "$target", "(Tcl_GetObjResult(interp))"); + Replaceall(tm, "$result", "(Tcl_GetObjResult(interp))"); +#endif + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "SWIG_POINTER_OWN"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), name); + } + emit_return_variable(n, type, f); + + /* Dump output argument code */ + Printv(f->code, outarg, NIL); + + /* Dump the argument cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look for any remaining cleanup */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } +#ifdef SWIG_USE_RESULTOBJ + Printv(f->code, "if (resultobj) Tcl_SetObjResult(interp, resultobj);\n", NIL); +#endif + Printv(f->code, "return TCL_OK;\n", NIL); + Printv(f->code, "fail:\n", cleanup, "return TCL_ERROR;\n", NIL); + Printv(f->code, "}\n", NIL); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + Replaceall(f->code, "$symname", iname); + + /* Dump out the function */ + Wrapper_print(f, f_wrappers); + + if (!Getattr(n, "sym:overloaded")) { + /* Register the function with Tcl */ + Printv(cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), ", NULL},\n", NIL); + } else { + if (!Getattr(n, "sym:nextSibling")) { + /* Emit overloading dispatch function */ + + int maxargs; + String *dispatch = Swig_overload_dispatch(n, "return %s(clientData, interp, objc, argv - 1);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *df = NewWrapper(); + String *dname = Swig_name_wrapper(iname); + + Printv(df->def, "SWIGINTERN int\n", dname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {", NIL); + Printf(df->code, "Tcl_Obj *CONST *argv = objv+1;\n"); + Printf(df->code, "int argc = objc-1;\n"); + Printv(df->code, dispatch, "\n", NIL); + Printf(df->code, "Tcl_SetResult(interp,(char *) \"No matching function for overloaded '%s'\", TCL_STATIC);\n", iname); + Printf(df->code, "return TCL_ERROR;\n"); + Printv(df->code, "}\n", NIL); + Wrapper_print(df, f_wrappers); + Printv(cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", dname, ", NULL},\n", NIL); + DelWrapper(df); + Delete(dispatch); + Delete(dname); + } + } + + Delete(incode); + Delete(cleanup); + Delete(outarg); + Delete(argstr); + Delete(args); + DelWrapper(f); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + + String *setname = 0; + String *setfname = 0; + Wrapper *setf = 0, *getf = 0; + int readonly = 0; + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + + /* Create a function for getting a variable */ + int addfail = 0; + getf = NewWrapper(); + String *getname = Swig_name_get(iname); + String *getfname = Swig_name_wrapper(getname); + Setattr(n, "wrap:name", getfname); + Printv(getf->def, "SWIGINTERN const char *", getfname, "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, char *name1, char *name2, int flags) {", NIL); + Wrapper_add_local(getf, "value", "Tcl_Obj *value = 0"); + if ((tm = Swig_typemap_lookup("varout", n, name, 0))) { + Replaceall(tm, "$source", name); + Replaceall(tm, "$target", "value"); + Replaceall(tm, "$result", "value"); + /* Printf(getf->code, "%s\n",tm); */ + addfail = emit_action_code(n, getf->code, tm); + Printf(getf->code, "if (value) {\n"); + Printf(getf->code, "Tcl_SetVar2(interp,name1,name2,Tcl_GetStringFromObj(value,NULL), flags);\n"); + Printf(getf->code, "Tcl_DecrRefCount(value);\n"); + Printf(getf->code, "}\n"); + Printf(getf->code, "return NULL;\n"); + if (addfail) { + Append(getf->code, "fail:\n"); + Printf(getf->code, "return \"%s\";\n", iname); + } + Printf(getf->code, "}\n"); + Wrapper_print(getf, f_wrappers); + } else { + Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); + DelWrapper(getf); + return SWIG_NOWRAP; + } + DelWrapper(getf); + + /* Try to create a function setting a variable */ + if (is_assignable(n)) { + setf = NewWrapper(); + setname = Swig_name_set(iname); + setfname = Swig_name_wrapper(setname); + Setattr(n, "wrap:name", setfname); + if (setf) { + Printv(setf->def, "SWIGINTERN const char *", setfname, + "(ClientData clientData SWIGUNUSED, Tcl_Interp *interp, char *name1, char *name2 SWIGUNUSED, int flags) {", NIL); + Wrapper_add_local(setf, "value", "Tcl_Obj *value = 0"); + Wrapper_add_local(setf, "name1o", "Tcl_Obj *name1o = 0"); + + if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { + Replaceall(tm, "$source", "value"); + Replaceall(tm, "$target", name); + Replaceall(tm, "$input", "value"); + Printf(setf->code, "name1o = Tcl_NewStringObj(name1,-1);\n"); + Printf(setf->code, "value = Tcl_ObjGetVar2(interp, name1o, 0, flags);\n"); + Printf(setf->code, "Tcl_DecrRefCount(name1o);\n"); + Printf(setf->code, "if (!value) SWIG_fail;\n"); + /* Printf(setf->code,"%s\n", tm); */ + emit_action_code(n, setf->code, tm); + Printf(setf->code, "return NULL;\n"); + Printf(setf->code, "fail:\n"); + Printf(setf->code, "return \"%s\";\n", iname); + Printf(setf->code, "}\n"); + Wrapper_print(setf, f_wrappers); + } else { + Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); + readonly = 1; + } + } + DelWrapper(setf); + } else { + readonly = 1; + } + + + Printv(var_tab, tab4, "{ SWIG_prefix \"", iname, "\", 0, (swig_variable_func) ", getfname, ",", NIL); + if (readonly) { + static int readonlywrap = 0; + if (!readonlywrap) { + Wrapper *ro = NewWrapper(); + Printf(ro->def, + "SWIGINTERN const char *swig_readonly(ClientData clientData SWIGUNUSED, Tcl_Interp *interp SWIGUNUSED, char *name1 SWIGUNUSED, char *name2 SWIGUNUSED, int flags SWIGUNUSED) {"); + Printv(ro->code, "return \"Variable is read-only\";\n", "}\n", NIL); + Wrapper_print(ro, f_wrappers); + readonlywrap = 1; + DelWrapper(ro); + } + Printf(var_tab, "(swig_variable_func) swig_readonly},\n"); + } else { + Printv(var_tab, "(swig_variable_func) ", setfname, "},\n", NIL); + } + Delete(getfname); + Delete(setfname); + Delete(setname); + Delete(getname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *nsname = !nspace ? Copy(iname) : NewStringf("%s::%s", ns_name, iname); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + if (nspace) + Setattr(n, "sym:name", nsname); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(const_tab, "%s,\n", tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(f_init, "%s\n", tm); + } else { + Delete(nsname); + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + Delete(nsname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + String *funcname = Getattr(n, "wrap:name"); + if (!addSymbol(funcname, n)) + return SWIG_ERROR; + + Printf(f_init, "\t Tcl_CreateObjCommand(interp, SWIG_prefix \"%s\", (swig_wrapper_func) %s, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);\n", name, + funcname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + static Hash *emitted = NewHash(); + String *mangled_classname = 0; + String *real_classname = 0; + + have_constructor = 0; + have_destructor = 0; + destructor_action = 0; + + if (itcl) { + constructor = NewString(""); + destructor = NewString(""); + base_classes = NewString(""); + base_class_init = NewString(""); + methods = NewString(""); + imethods = NewString(""); + attributes = NewString(""); + attribute_traces = NewString(""); + iattribute_traces = NewString(""); + + have_base_classes = 0; + have_methods = 0; + have_attributes = 0; + } + + class_name = Getattr(n, "sym:name"); + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + real_classname = Getattr(n, "name"); + mangled_classname = Swig_name_mangle(real_classname); + + if (Getattr(emitted, mangled_classname)) + return SWIG_NOWRAP; + Setattr(emitted, mangled_classname, "1"); + + attr_tab = NewString(""); + Printf(attr_tab, "static swig_attribute swig_"); + Printv(attr_tab, mangled_classname, "_attributes[] = {\n", NIL); + + methods_tab = NewStringf(""); + Printf(methods_tab, "static swig_method swig_"); + Printv(methods_tab, mangled_classname, "_methods[] = {\n", NIL); + + /* Generate normal wrappers */ + Language::classHandler(n); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType_add_pointer(t); + + // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' + // SwigType_remember(t); + String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); + SwigType_remember_clientdata(t, wrap_class); + + // t = Copy(Getattr(n,"classtype")); + // SwigType_add_pointer(t); + + String *rt = Copy(Getattr(n, "classtype")); + SwigType_add_pointer(rt); + + // Register the class structure with the type checker + /* Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_classname); */ + if (have_destructor) { + Printv(f_wrappers, "SWIGINTERN void swig_delete_", class_name, "(void *obj) {\n", NIL); + if (destructor_action) { + Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); + Printv(f_wrappers, destructor_action, "\n", NIL); + } else { + if (CPlusPlus) { + Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); + } else { + Printv(f_wrappers, " free((char *) obj);\n", NIL); + } + } + Printf(f_wrappers, "}\n"); + } + + Printf(methods_tab, " {0,0}\n};\n"); + Printv(f_wrappers, methods_tab, NIL); + + Printf(attr_tab, " {0,0,0}\n};\n"); + Printv(f_wrappers, attr_tab, NIL); + + /* Handle inheritance */ + + String *base_class = NewString(""); + String *base_class_names = NewString(""); + + if (itcl) { + base_classes = NewString(""); + } + + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + if (itcl) { + have_base_classes = 1; + Printv(base_classes, bname, " ", NIL); + Printv(base_class_init, " ", bname, "Ptr::constructor $ptr\n", NIL); + } + String *bmangle = Swig_name_mangle(bname); + // Printv(f_wrappers,"extern swig_class _wrap_class_", bmangle, ";\n", NIL); + // Printf(base_class,"&_wrap_class_%s",bmangle); + Printf(base_class, "0"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + /* Put code to register base classes in init function */ + + //Printf(f_init,"/* Register base : %s */\n", bmangle); + //Printf(f_init,"swig_%s_bases[%d] = (swig_class *) SWIG_TypeQuery(\"%s *\")->clientdata;\n", mangled_classname, index, SwigType_namestr(bname)); + b = Next(b); + index++; + Putc(',', base_class); + Delete(bmangle); + } + } + + if (itcl) { + String *ptrclass = NewString(""); + + // First, build the pointer base class + Printv(ptrclass, "itcl::class ", class_name, "Ptr {\n", NIL); + if (have_base_classes) + Printv(ptrclass, " inherit ", base_classes, "\n", NIL); + + // Define protected variables for SWIG object pointer + Printv(ptrclass, " protected variable swigobj\n", " protected variable thisown\n", NIL); + + // Define public variables + if (have_attributes) { + Printv(ptrclass, attributes, NIL); + + // base class swig_getset was being called for complex inheritance trees + if (nspace) { + + Printv(ptrclass, " protected method ", class_name, "_swig_getset {var name1 name2 op} {\n", NIL); + + Printv(ptrclass, + " switch -exact -- $op {\n", + " r {set $var [", ns_name, "::", class_name, "_[set var]_get $swigobj]}\n", + " w {", ns_name, "::", class_name, "_${var}_set $swigobj [set $var]}\n", " }\n", " }\n", NIL); + } else { + Printv(ptrclass, + " protected method ", class_name, "_swig_getset {var name1 name2 op} {\n", + " switch -exact -- $op {\n", + " r {set $var [", class_name, "_[set var]_get $swigobj]}\n", + " w {", class_name, "_${var}_set $swigobj [set $var]}\n", " }\n", " }\n", NIL); + } + } + // Add the constructor, which may include + // calls to base class class constructors + + Printv(ptrclass, " constructor { ptr } {\n", NIL); + if (have_base_classes) { + Printv(ptrclass, base_class_init, NIL); + Printv(ptrclass, " } {\n", NIL); + } + + Printv(ptrclass, " set swigobj $ptr\n", " set thisown 0\n", NIL); + + if (have_attributes) { + Printv(ptrclass, attribute_traces, NIL); + } + Printv(ptrclass, " }\n", NIL); + + + // Add destructor + Printv(ptrclass, " destructor {\n", + " set d_func delete_", class_name, "\n", + " if { $thisown && ([info command $d_func] != \"\") } {\n" " $d_func $swigobj\n", " }\n", " }\n", NIL); + + // Add methods + if (have_methods) { + Printv(ptrclass, imethods, NIL); + }; + + // Close out the pointer class + Printv(ptrclass, "}\n\n", NIL); + Printv(f_shadow, ptrclass, NIL); + // pointer class end + + + // Create the "real" class. + Printv(f_shadow, "itcl::class ", class_name, " {\n", NIL); + Printv(f_shadow, " inherit ", class_name, "Ptr\n", NIL); + + // If we have a constructor, then use it. + // If not, then we must have an abstract class without + // any constructor. So we create a class constructor + // which will fail for this class (but not for inherited + // classes). Note that the constructor must fail before + // calling the ptrclass constructor. + + if (have_constructor) { + Printv(f_shadow, constructor, NIL); + } else { + Printv(f_shadow, " constructor { } {\n", NIL); + Printv(f_shadow, " # This constructor will fail if called directly\n", NIL); + Printv(f_shadow, " if { [info class] == \"::", class_name, "\" } {\n", NIL); + Printv(f_shadow, " error \"No constructor for class ", class_name, (Getattr(n, "abstract") ? " - class is abstract" : ""), "\"\n", NIL); + Printv(f_shadow, " }\n", NIL); + Printv(f_shadow, " }\n", NIL); + } + + Printv(f_shadow, "}\n\n", NIL); + } + + Printv(f_wrappers, "static swig_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); + Printv(f_wrappers, "static const char * swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); + Delete(base_class); + Delete(base_class_names); + + Printv(f_wrappers, "static swig_class _wrap_class_", mangled_classname, " = { \"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + + if (have_constructor) { + Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(constructor_name))); + Delete(constructor_name); + constructor_name = 0; + } else { + Printf(f_wrappers, "0"); + } + if (have_destructor) { + Printv(f_wrappers, ", swig_delete_", class_name, NIL); + } else { + Printf(f_wrappers, ",0"); + } + Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases,", + "swig_", mangled_classname, "_base_names, &swig_module };\n", NIL); + + if (!itcl) { + Printv(cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, (ClientData)&_wrap_class_", mangled_classname, + "},\n", NIL); + }; + + Delete(t); + Delete(mangled_classname); + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + + String *realname, *rname; + + Language::memberfunctionHandler(n); + + realname = iname ? iname : name; + rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + if (!Getattr(n, "sym:nextSibling")) { + Printv(methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); + } + + if (itcl) { + ParmList *l = Getattr(n, "parms"); + Parm *p = 0; + String *pname = NewString(""); + + // Add this member to our class handler function + Printv(imethods, tab2, "method ", realname, " [list ", NIL); + + int pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + String *pn = Getattr(p, "name"); + String *dv = Getattr(p, "value"); + SwigType *pt = Getattr(p, "type"); + + Printv(pname, ",(", pt, ")", NIL); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + + if (Len(dv) > 0) { + String *defval = NewString(dv); + if (nspace) { + Insert(defval, 0, "::"); + Insert(defval, 0, ns_name); + } + if (Strncmp(dv, "(", 1) == 0) { + Insert(defval, 0, "$"); + Replaceall(defval, "(", ""); + Replaceall(defval, ")", ""); + } + Printv(imethods, "[list ", pname, " ", defval, "] ", NIL); + } else { + Printv(imethods, pname, " ", NIL); + } + } + ++pnum; + } + Printv(imethods, "] ", NIL); + + if (nspace) { + Printv(imethods, "{ ", ns_name, "::", class_name, "_", realname, " $swigobj", NIL); + } else { + Printv(imethods, "{ ", class_name, "_", realname, " $swigobj", NIL); + }; + + pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + String *pn = Getattr(p, "name"); + SwigType *pt = Getattr(p, "type"); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + Printv(imethods, " $", pname, NIL); + } + ++pnum; + } + Printv(imethods, " }\n", NIL); + have_methods = 1; + } + + Delete(rname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + String *symname = Getattr(n, "sym:name"); + String *rname; + + Language::membervariableHandler(n); + Printv(attr_tab, tab4, "{ \"-", symname, "\",", NIL); + rname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + Printv(attr_tab, rname, ", ", NIL); + Delete(rname); + if (!GetFlag(n, "feature:immutable")) { + rname = Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + Printv(attr_tab, rname, "},\n", NIL); + Delete(rname); + } else { + Printf(attr_tab, "0 },\n"); + } + + if (itcl) { + Printv(attributes, " public variable ", symname, "\n", NIL); + + Printv(attribute_traces, " trace variable ", symname, " rw [list ", class_name, "_swig_getset ", symname, "]\n", NIL); + Printv(attribute_traces, " set ", symname, "\n", NIL); + + have_attributes = 1; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + Language::constructorHandler(n); + + if (itcl) { + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + + String *realname; + + ParmList *l = Getattr(n, "parms"); + Parm *p = 0; + + String *pname = NewString(""); + + realname = iname ? iname : name; + + if (!have_constructor) { + // Add this member to our class handler function + Printf(constructor, " constructor { "); + + // Add parameter list + int pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + String *dv = Getattr(p, "value"); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + + if (Len(dv) > 0) { + Printv(constructor, "{", pname, " {", dv, "} } ", NIL); + } else { + Printv(constructor, pname, " ", NIL); + } + } + ++pnum; + } + Printf(constructor, "} { \n"); + + // [BRE] 08/17/00 Added test to see if we are instantiating this object + // type, or, if this constructor is being called as part of the itcl + // inheritance hierarchy. + // In the former case, we need to call the C++ constructor, in the + // latter we don't, or we end up with two C++ objects. + // Check to see if we are instantiating a 'realname' or something + // derived from it. + // + Printv(constructor, " if { [string equal -nocase \"", realname, "\" \"[namespace tail [info class]]\" ] } {\n", NIL); + + // Call to constructor wrapper and parent Ptr class + // [BRE] add -namespace/-prefix support + + if (nspace) { + Printv(constructor, " ", realname, "Ptr::constructor [", ns_name, "::new_", realname, NIL); + } else { + Printv(constructor, " ", realname, "Ptr::constructor [new_", realname, NIL); + } + + pnum = 0; + for (p = l; p; p = nextSibling(p)) { + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + Clear(pname); + + /* Only print an argument if not void */ + if (Cmp(pt, "void") != 0) { + if (Len(pn) > 0) { + Printv(pname, pn, NIL); + } else { + Printf(pname, "p%d", pnum); + } + Printv(constructor, " $", pname, NIL); + } + ++pnum; + } + + Printv(constructor, "]\n", " }\n", " } {\n", " set thisown 1\n", " }\n", NIL); + } + } + + constructor_name = NewString(Getattr(n, "sym:name")); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + have_destructor = 1; + destructor_action = Getattr(n, "wrap:action"); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * validIdentifier() + * ------------------------------------------------------------ */ + + virtual int validIdentifier(String *s) { + if (Strchr(s, ' ')) + return 0; + return 1; + } + + /* ------------------------------------------------------------ + * usage_string() + * ------------------------------------------------------------ */ + + char *usage_string(char *iname, SwigType *, ParmList *l) { + static String *temp = 0; + Parm *p; + int i, numopt, pcount; + + if (!temp) + temp = NewString(""); + Clear(temp); + if (nspace) { + Printf(temp, "%s::%s ", ns_name, iname); + } else { + Printf(temp, "%s ", iname); + } + /* Now go through and print parameters */ + i = 0; + pcount = emit_num_arguments(l); + numopt = pcount - emit_num_required(l); + for (p = l; p; p = nextSibling(p)) { + + SwigType *pt = Getattr(p, "type"); + String *pn = Getattr(p, "name"); + /* Only print an argument if not ignored */ + if (!checkAttribute(p, "tmap:in:numinputs", "0")) { + if (i >= (pcount - numopt)) + Putc('?', temp); + if (Len(pn) > 0) { + Printf(temp, "%s", pn); + } else { + Printf(temp, "%s", SwigType_str(pt, 0)); + } + if (i >= (pcount - numopt)) + Putc('?', temp); + Putc(' ', temp); + i++; + } + } + return Char(temp); + } + + String *runtimeCode() { + String *s = NewString(""); + String *serrors = Swig_include_sys("tclerrors.swg"); + if (!serrors) { + Printf(stderr, "*** Unable to open 'tclerrors.swg'\n"); + } else { + Append(s, serrors); + Delete(serrors); + } + String *sapi = Swig_include_sys("tclapi.swg"); + if (!sapi) { + Printf(stderr, "*** Unable to open 'tclapi.swg'\n"); + } else { + Append(s, sapi); + Delete(sapi); + } + String *srun = Swig_include_sys("tclrun.swg"); + if (!srun) { + Printf(stderr, "*** Unable to open 'tclrun.swg'\n"); + } else { + Append(s, srun); + Delete(srun); + } + + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigtclrun.h"); + } +}; + +/* ---------------------------------------------------------------------- + * swig_tcl() - Instantiate module + * ---------------------------------------------------------------------- */ + +static Language *new_swig_tcl() { + return new TCL8(); +} +extern "C" Language *swig_tcl(void) { + return new_swig_tcl(); +} diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx new file mode 100644 index 0000000..6cb7f0a --- /dev/null +++ b/Source/Modules/typepass.cxx @@ -0,0 +1,1164 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * typepass.cxx + * + * This module builds all of the internal type information by collecting + * typedef declarations as well as registering classes, structures, and unions. + * This information is needed to correctly handle shadow classes and other + * advanced features. This phase of compilation is also used to perform + * type-expansion. All types are fully qualified with namespace prefixes + * and other information needed for compilation. + * ----------------------------------------------------------------------------- */ + +char cvsroot_typepass_cxx[] = "$Id: typepass.cxx 11279 2009-06-16 19:29:08Z wsfulton $"; + +#include "swigmod.h" +#include "cparse.h" + +struct normal_node { + Symtab *symtab; + Hash *typescope; + List *normallist; + normal_node *next; +}; + +static normal_node *patch_list = 0; + +/* Singleton class - all non-static methods in this class are private */ +class TypePass:private Dispatcher { + Node *inclass; + Node *module; + int importmode; + String *nsname; + Hash *classhash; + List *normalize; + + TypePass() { + } + + /* Normalize a type. Replaces type with fully qualified version */ + void normalize_type(SwigType *ty) { + SwigType *qty; + if (CPlusPlus) { + Replaceall(ty, "struct ", ""); + Replaceall(ty, "union ", ""); + Replaceall(ty, "class ", ""); + } + + qty = SwigType_typedef_qualified(ty); + /* Printf(stdout,"%s --> %s\n", ty, qty); */ + Clear(ty); + Append(ty, qty); + Delete(qty); + } + + /* Normalize a parameter list */ + + void normalize_parms(ParmList *p) { + while (p) { + SwigType *ty = Getattr(p, "type"); + normalize_type(ty); + /* This is a check for a function type */ + { + SwigType *qty = SwigType_typedef_resolve_all(ty); + if (SwigType_isfunction(qty)) { + SwigType_add_pointer(ty); + } + Delete(qty); + } + + String *value = Getattr(p, "value"); + if (value) { + Node *n = Swig_symbol_clookup(value, 0); + if (n) { + String *q = Swig_symbol_qualified(n); + if (q && Len(q)) { + String *vb = Swig_scopename_last(value); + Clear(value); + Printf(value, "%s::%s", SwigType_namestr(q), vb); + Delete(q); + } + } + } + if (value && SwigType_istemplate(value)) { + String *nv = SwigType_namestr(value); + Setattr(p, "value", nv); + } + p = nextSibling(p); + } + } + + void normalize_later(ParmList *p) { + while (p) { + SwigType *ty = Getattr(p, "type"); + Append(normalize, ty); + p = nextSibling(p); + } + } + + /* Walk through entries in normalize list and patch them up */ + void normalize_list() { + Hash *currentsym = Swig_symbol_current(); + + normal_node *nn = patch_list; + normal_node *np; + while (nn) { + Swig_symbol_setscope(nn->symtab); + SwigType_set_scope(nn->typescope); + Iterator t; + for (t = First(nn->normallist); t.item; t = Next(t)) { + normalize_type(t.item); + } + Delete(nn->normallist); + np = nn->next; + delete(nn); + nn = np; + } + Swig_symbol_setscope(currentsym); + } + + /* generate C++ inheritance type-relationships */ + void cplus_inherit_types_impl(Node *first, Node *cls, String *clsname, const char *bases, const char *baselist, int ispublic, String *cast = 0) { + + if (first == cls) + return; /* The Marcelo check */ + if (!cls) + cls = first; + List *alist = 0; + List *ilist = Getattr(cls, bases); + if (!ilist) { + List *nlist = Getattr(cls, baselist); + if (nlist) { + int len = Len(nlist); + int i; + for (i = 0; i < len; i++) { + Node *bcls = 0; + int clsforward = 0; + String *bname = Getitem(nlist, i); + String *sname = bname; + String *tname = 0; + + /* Try to locate the base class. We look in the symbol table and we chase + typedef declarations to get to the base class if necessary */ + Symtab *st = Getattr(cls, "sym:symtab"); + + if (SwigType_istemplate(bname)) { + tname = SwigType_typedef_resolve_all(bname); + sname = tname; + } + while (1) { + String *qsname = SwigType_typedef_qualified(sname); + bcls = Swig_symbol_clookup(qsname, st); + Delete(qsname); + if (bcls) { + if (Strcmp(nodeType(bcls), "class") != 0) { + /* Not a class. The symbol could be a typedef. */ + if (checkAttribute(bcls, "storage", "typedef")) { + SwigType *decl = Getattr(bcls, "decl"); + if (!decl || !(Len(decl))) { + sname = Getattr(bcls, "type"); + st = Getattr(bcls, "sym:symtab"); + if (SwigType_istemplate(sname)) { + if (tname) + Delete(tname); + tname = SwigType_typedef_resolve_all(sname); + sname = tname; + } + continue; + } + } + if (Strcmp(nodeType(bcls), "classforward") != 0) { + Swig_error(Getfile(cls), Getline(cls), "'%s' does not have a valid base class.\n", Getattr(cls, "name")); + Swig_error(Getfile(bcls), Getline(bcls), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); + } else { + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(cls), Getline(cls), "Base class '%s' is incomplete.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_INCOMPLETE, Getfile(bcls), Getline(bcls), "Only forward declaration '%s' was found.\n", SwigType_namestr(bname)); + clsforward = 1; + } + bcls = 0; + } else { + if (Getattr(bcls, "typepass:visit")) { + if (!ilist) + ilist = alist = NewList(); + Append(ilist, bcls); + } else { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Base class '%s' undefined.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "'%s' must be defined before it is used as a base class.\n", SwigType_namestr(bname)); + } + } + } + break; + } + + if (tname) + Delete(tname); + if (!bcls) { + if (!clsforward) { + if (ispublic && !Getmeta(bname, "already_warned")) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Nothing known about base class '%s'. Ignored.\n", SwigType_namestr(bname)); + if (Strchr(bname, '<')) { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(cls), Getline(cls), "Maybe you forgot to instantiate '%s' using %%template.\n", + SwigType_namestr(bname)); + } + Setmeta(bname, "already_warned", "1"); + } + } + SwigType_inherit(clsname, bname, cast, 0); + } + } + } + if (ilist) { + Setattr(cls, bases, ilist); + } + } + if (alist) + Delete(alist); + + if (!ilist) + return; + int len = Len(ilist); + int i; + for (i = 0; i < len; i++) { + Node *n = Getitem(ilist, i); + String *bname = Getattr(n, "name"); + Node *bclass = n; /* Getattr(n,"class"); */ + Hash *scopes = Getattr(bclass, "typescope"); + SwigType_inherit(clsname, bname, cast, 0); + if (!importmode) { + String *btype = Copy(bname); + SwigType_add_pointer(btype); + SwigType_remember(btype); + Delete(btype); + } + if (scopes) { + SwigType_inherit_scope(scopes); + } + /* Set up inheritance in the symbol table */ + Symtab *st = Getattr(cls, "symtab"); + Symtab *bst = Getattr(bclass, "symtab"); + if (st == bst) { + Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(cls), Getline(cls), "Recursive scope inheritance of '%s'.\n", Getattr(cls, "name")); + continue; + } + Symtab *s = Swig_symbol_current(); + Swig_symbol_setscope(st); + Swig_symbol_inherit(bst); + Swig_symbol_setscope(s); + + /* Recursively hit base classes */ + String *namestr = SwigType_namestr(Getattr(bclass, "name")); + String *newcast = NewStringf("(%s *)%s", namestr, cast); + Delete(namestr); + cplus_inherit_types_impl(first, bclass, clsname, bases, baselist, ispublic, newcast); + Delete(newcast); + } + } + + void append_list(List *lb, List *la) { + if (la && lb) { + for (Iterator bi = First(la); bi.item; bi = Next(bi)) { + Append(lb, bi.item); + } + } + } + + void cplus_inherit_types(Node *first, Node *cls, String *clsname, String *cast = 0) { + cplus_inherit_types_impl(first, cls, clsname, "bases", "baselist", 1, cast); + cplus_inherit_types_impl(first, cls, clsname, "protectedbases", "protectedbaselist", 0, cast); + cplus_inherit_types_impl(first, cls, clsname, "privatebases", "privatebaselist", 0, cast); + + if (!cls) + cls = first; + + List *allbases = NewList(); + append_list(allbases, Getattr(cls, "bases")); + append_list(allbases, Getattr(cls, "protectedbases")); + append_list(allbases, Getattr(cls, "privatebases")); + if (Len(allbases)) { + Setattr(cls, "allbases", allbases); + } + Delete(allbases); + } + + /* ------------------------------------------------------------ + * top() + * ------------------------------------------------------------ */ + + virtual int top(Node *n) { + importmode = 0; + module = Getattr(n, "module"); + inclass = 0; + normalize = 0; + nsname = 0; + classhash = Getattr(n, "classes"); + emit_children(n); + normalize_list(); + SwigType_set_scope(0); + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * moduleDirective() + * ------------------------------------------------------------ */ + + virtual int moduleDirective(Node *n) { + if (!module) { + module = n; + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + String *oldmodule = module; + int oldimport = importmode; + importmode = 1; + module = 0; + emit_children(n); + importmode = oldimport; + module = oldmodule; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * includeDirective() + * externDirective() + * extendDirective() + * ------------------------------------------------------------ */ + + virtual int includeDirective(Node *n) { + return emit_children(n); + } + virtual int externDeclaration(Node *n) { + return emit_children(n); + } + virtual int extendDirective(Node *n) { + return emit_children(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *unnamed = Getattr(n, "unnamed"); + String *storage = Getattr(n, "storage"); + String *kind = Getattr(n, "kind"); + Node *oldinclass = inclass; + List *olist = normalize; + Symtab *symtab; + String *nname = 0; + String *fname = 0; + String *scopename = 0; + + normalize = NewList(); + + if (name) { + if (SwigType_istemplate(name)) { + // We need to fully resolve the name to make templates work correctly */ + Node *cn; + fname = SwigType_typedef_resolve_all(name); + if (Strcmp(fname, name) != 0 && (cn = Swig_symbol_clookup_local(fname, 0))) { + if ((n == cn) + || (Strcmp(nodeType(cn), "template") == 0) + || (Getattr(cn, "feature:onlychildren") != 0) + || (Getattr(n, "feature:onlychildren") != 0)) { + Swig_symbol_cadd(fname, n); + SwigType_typedef_class(fname); + scopename = Copy(fname); + } else { + Swig_warning(WARN_TYPE_REDEFINED, Getfile(n), Getline(n), "Template '%s' was already wrapped,\n", SwigType_namestr(name)); + Swig_warning(WARN_TYPE_REDEFINED, Getfile(cn), Getline(cn), "previous wrap of '%s'.\n", SwigType_namestr(Getattr(cn, "name"))); + scopename = 0; + } + } else { + Swig_symbol_cadd(fname, n); + SwigType_typedef_class(fname); + scopename = Copy(fname); + } + } else { + if ((CPlusPlus) || (unnamed)) { + SwigType_typedef_class(name); + } else { + SwigType_typedef_class(NewStringf("%s %s", kind, name)); + } + scopename = Copy(name); + } + } else { + scopename = 0; + } + + Setattr(n, "typepass:visit", "1"); + + /* Need to set up a typedef if unnamed */ + if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { + SwigType_typedef(unnamed, tdname); + } + + if (nsname) { + nname = NewStringf("%s::%s", nsname, name); + String *tdname = Getattr(n, "tdname"); + if (tdname) { + tdname = NewStringf("%s::%s", nsname, tdname); + Setattr(n, "tdname", tdname); + } + } + SwigType_new_scope(scopename); + SwigType_attach_symtab(Getattr(n, "symtab")); + + /* Inherit type definitions into the class */ + if (name) { + cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name)); + } + + inclass = n; + symtab = Swig_symbol_setscope(Getattr(n, "symtab")); + emit_children(n); + Swig_symbol_setscope(symtab); + + Hash *ts = SwigType_pop_scope(); + Setattr(n, "typescope", ts); + Delete(ts); + Setattr(n, "module", module); + + /* Normalize deferred types */ + { + normal_node *nn = new normal_node(); + nn->normallist = normalize; + nn->symtab = Getattr(n, "symtab"); + nn->next = patch_list; + nn->typescope = Getattr(n, "typescope"); + patch_list = nn; + } + + normalize = olist; + + inclass = oldinclass; + + /* If in a namespace, patch the class name */ + if (nname) { + Setattr(n, "name", nname); + Delete(nname); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * namespaceDeclaration() + * ------------------------------------------------------------ */ + + virtual int templateDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *ttype = Getattr(n, "templatetype"); + if (Strcmp(ttype, "class") == 0) { + String *rname = SwigType_typedef_resolve_all(name); + SwigType_typedef_class(rname); + Delete(rname); + } else if (Strcmp(ttype, "classforward") == 0) { + String *rname = SwigType_typedef_resolve_all(name); + SwigType_typedef_class(rname); + Delete(rname); + /* SwigType_typedef_class(name); */ + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classforwardDeclaration() + * ------------------------------------------------------------ */ + + virtual int classforwardDeclaration(Node *n) { + + /* Temporary hack. Can't do inside a class because it breaks + C nested structure wrapping */ + + if ((!inclass) || (CPlusPlus)) { + String *name = Getattr(n, "name"); + String *nname; + SwigType_typedef_class(name); + if (nsname) { + nname = NewStringf("%s::%s", nsname, name); + Setattr(n, "name", nname); + } + + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * namespaceDeclaration() + * ------------------------------------------------------------ */ + + virtual int namespaceDeclaration(Node *n) { + Symtab *symtab; + String *name = Getattr(n, "name"); + String *alias = Getattr(n, "alias"); + List *olist = normalize; + normalize = NewList(); + if (alias) { + Typetab *ts = Getattr(n, "typescope"); + if (!ts) { + Node *ns; + /* Create a empty scope for the alias */ + ns = Getattr(n, "namespace"); + if (ns) { + SwigType_scope_alias(name, Getattr(ns, "typescope")); + } + ts = Getattr(ns, "typescope"); + Setattr(n, "typescope", ts); + } + /* Namespace alias */ + return SWIG_OK; + } else { + if (name) { + Node *nn = Swig_symbol_clookup(name, n); + Hash *ts = 0; + if (nn) + ts = Getattr(nn, "typescope"); + if (!ts) { + SwigType_new_scope(name); + SwigType_attach_symtab(Getattr(n, "symtab")); + } else { + SwigType_set_scope(ts); + } + } + String *oldnsname = nsname; + nsname = Swig_symbol_qualified(Getattr(n, "symtab")); + symtab = Swig_symbol_setscope(Getattr(n, "symtab")); + emit_children(n); + Swig_symbol_setscope(symtab); + + if (name) { + Hash *ts = SwigType_pop_scope(); + Setattr(n, "typescope", ts); + Delete(ts); + } + + /* Normalize deferred types */ + { + normal_node *nn = new normal_node(); + nn->normallist = normalize; + nn->symtab = Getattr(n, "symtab"); + nn->next = patch_list; + nn->typescope = Getattr(n, "typescope"); + patch_list = nn; + } + normalize = olist; + + Delete(nsname); + nsname = oldnsname; + return SWIG_OK; + } + } + + /* ------------------------------------------------------------ + * cDeclaration() + * ------------------------------------------------------------ */ + + virtual int cDeclaration(Node *n) { + if (NoExcept) { + Delattr(n, "throws"); + } + + /* Normalize types. */ + SwigType *ty = Getattr(n, "type"); + normalize_type(ty); + SwigType *decl = Getattr(n, "decl"); + if (decl) { + normalize_type(decl); + } + normalize_parms(Getattr(n, "parms")); + normalize_parms(Getattr(n, "throws")); + if (GetFlag(n, "conversion_operator")) { + /* The call to the operator in the generated wrapper must be fully qualified in order to compile */ + SwigType *name = Getattr(n, "name"); + SwigType *qualifiedname = Swig_symbol_string_qualify(name,0); + Clear(name); + Append(name, qualifiedname); + Delete(qualifiedname); + } + + if (checkAttribute(n, "storage", "typedef")) { + String *name = Getattr(n, "name"); + ty = Getattr(n, "type"); + decl = Getattr(n, "decl"); + SwigType *t = Copy(ty); + { + /* If the typename is qualified, make sure the scopename is fully qualified when making a typedef */ + if (Swig_scopename_check(t) && strncmp(Char(t), "::", 2)) { + String *base, *prefix, *qprefix; + base = Swig_scopename_last(t); + prefix = Swig_scopename_prefix(t); + qprefix = SwigType_typedef_qualified(prefix); + Delete(t); + t = NewStringf("%s::%s", qprefix, base); + Delete(base); + Delete(prefix); + Delete(qprefix); + } + } + SwigType_push(t, decl); + if (CPlusPlus) { + Replaceall(t, "struct ", ""); + Replaceall(t, "union ", ""); + Replaceall(t, "class ", ""); + } + SwigType_typedef(t, name); + } + /* If namespaces are active. We need to patch the name with a namespace prefix */ + if (nsname && !inclass) { + String *name = Getattr(n, "name"); + if (name) { + String *nname = NewStringf("%s::%s", nsname, name); + Setattr(n, "name", nname); + Delete(nname); + } + } + clean_overloaded(n); + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * constructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int constructorDeclaration(Node *n) { + if (NoExcept) { + Delattr(n, "throws"); + } + + normalize_parms(Getattr(n, "parms")); + normalize_parms(Getattr(n, "throws")); + + /* If in a namespace, patch the class name */ + if (nsname) { + String *nname = NewStringf("%s::%s", nsname, Getattr(n, "name")); + Setattr(n, "name", nname); + } + clean_overloaded(n); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorDeclaration() + * ------------------------------------------------------------ */ + + virtual int destructorDeclaration(Node *n) { + /* If in a namespace, patch the class name */ + if (nsname) { + String *nname = NewStringf("%s::%s", nsname, Getattr(n, "name")); + Setattr(n, "name", nname); + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constantDirective() + * ------------------------------------------------------------ */ + + virtual int constantDirective(Node *n) { + SwigType *ty = Getattr(n, "type"); + if (ty) { + Setattr(n, "type", SwigType_typedef_qualified(ty)); + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + String *name = Getattr(n, "name"); + + if (name) { + String *scope = 0; + + // Add a typedef to the type table so that we can use 'enum Name' as well as just 'Name' + if (nsname || inclass) { + + // But first correct the name and tdname to contain the fully qualified scopename + if (nsname && inclass) { + scope = NewStringf("%s::%s", nsname, Getattr(inclass, "name")); + } else if (nsname) { + scope = NewStringf("%s", nsname); + } else if (inclass) { + scope = NewStringf("%s", Getattr(inclass, "name")); + } + + String *nname = NewStringf("%s::%s", scope, name); + Setattr(n, "name", nname); + + String *tdname = Getattr(n, "tdname"); + if (tdname) { + tdname = NewStringf("%s::%s", scope, tdname); + Setattr(n, "tdname", tdname); + } + + SwigType *t = NewStringf("enum %s", nname); + SwigType_typedef(t, name); + } else { + SwigType *t = NewStringf("enum %s", name); + SwigType_typedef(t, name); + } + Delete(scope); + } + + String *tdname = Getattr(n, "tdname"); + String *unnamed = Getattr(n, "unnamed"); + String *storage = Getattr(n, "storage"); + + // Construct enumtype - for declaring an enum of this type with SwigType_ltype() etc + String *enumtype = 0; + if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { + enumtype = Copy(Getattr(n, "tdname")); + } else if (name) { + enumtype = NewStringf("%s%s", CPlusPlus ? "" : "enum ", Getattr(n, "name")); + } else { + // anonymous enums + enumtype = Copy(Getattr(n, "type")); + } + Setattr(n, "enumtype", enumtype); + + // This block of code is for dealing with %ignore on an enum item where the target language + // attempts to use the C enum value in the target language itself and expects the previous enum value + // to be one more than the previous value... the previous enum item might not exist if it is ignored! + // - It sets the first non-ignored enum item with the "firstenumitem" attribute. + // - It adds an enumvalue attribute if the previous enum item is ignored + { + Node *c; + int count = 0; + String *previous = 0; + bool previous_ignored = false; + bool firstenumitem = false; + for (c = firstChild(n); c; c = nextSibling(c)) { + assert(strcmp(Char(nodeType(c)), "enumitem") == 0); + + bool reset; + String *enumvalue = Getattr(c, "enumvalue"); + if (GetFlag(c, "feature:ignore")) { + reset = enumvalue ? true : false; + previous_ignored = true; + } else { + if (!enumvalue && previous_ignored) { + if (previous) + Setattr(c, "enumvalue", NewStringf("(%s) + %d", previous, count+1)); + else + Setattr(c, "enumvalue", NewStringf("%d", count)); + SetFlag(c, "virtenumvalue"); // identify enumvalue as virtual, ie not from the parsed source + } + if (!firstenumitem) { + SetFlag(c, "firstenumitem"); + firstenumitem = true; + } + reset = true; + previous_ignored = false; + } + if (reset) { + previous = enumvalue ? enumvalue : Getattr(c, "name"); + count = 0; + } else { + count++; + } + } + } + + emit_children(n); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *value = Getattr(n, "value"); + if (!value) + value = name; + if (Strcmp(value, name) == 0) { + String *new_value; + if (((nsname) || (inclass)) && cparse_cplusplus) { + new_value = NewStringf("%s::%s", SwigType_namestr(Swig_symbol_qualified(n)), value); + } else { + new_value = NewString(value); + } + Setattr(n, "value", new_value); + Delete(new_value); + } + Node *next = nextSibling(n); + + // Make up an enumvalue if one was not specified in the parsed code (not designed to be used on enum items and %ignore - enumvalue will be set instead) + if (!GetFlag(n, "feature:ignore")) { + if (Getattr(n, "_last") && !Getattr(n, "enumvalue")) { // Only the first enum item has _last set (Note: first non-ignored enum item has firstenumitem set) + Setattr(n, "enumvalueex", "0"); + } + if (next && !Getattr(next, "enumvalue")) { + Setattr(next, "enumvalueex", NewStringf("%s + 1", Getattr(n, "sym:name"))); + } + } + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumforwardDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumforwardDeclaration(Node *n) { + + // Use enumDeclaration() to do all the hard work. + // Note that no children can be emitted in a forward declaration as there aren't any. + return enumDeclaration(n); + } + +#ifdef DEBUG_OVERLOADED + static void show_overloaded(Node *n) { + Node *c = Getattr(n, "sym:overloaded"); + Node *checkoverloaded = c; + Printf(stdout, "-------------------- overloaded start %s sym:overloaded():%p -------------------------------\n", Getattr(n, "name"), c); + while (c) { + if (Getattr(c, "error")) { + c = Getattr(c, "sym:nextSibling"); + continue; + } + if (Getattr(c, "sym:overloaded") != checkoverloaded) { + Printf(stdout, "sym:overloaded error c:%p checkoverloaded:%p\n", c, checkoverloaded); + Swig_print_node(c); + exit (1); + } + + String *decl = Strcmp(nodeType(c), "using") == 0 ? NewString("------") : Getattr(c, "decl"); + Printf(stdout, " show_overloaded %s::%s(%s) [%s] nodeType:%s\n", parentNode(c) ? Getattr(parentNode(c), "name") : "NOPARENT", Getattr(c, "name"), decl, Getattr(c, "sym:overname"), nodeType(c)); + if (!Getattr(c, "sym:overloaded")) { + Printf(stdout, "sym:overloaded error.....%p\n", c); + Swig_print_node(c); + exit (1); + } + c = Getattr(c, "sym:nextSibling"); + } + Printf(stdout, "-------------------- overloaded end %s -------------------------------\n", Getattr(n, "name")); + } +#endif + + /* ------------------------------------------------------------ + * usingDeclaration() + * ------------------------------------------------------------ */ + + virtual int usingDeclaration(Node *n) { + if (Getattr(n, "namespace")) { + /* using namespace id */ + + /* For a namespace import. We set up inheritance in the type system */ + Node *ns = Getattr(n, "node"); + if (ns) { + Typetab *ts = Getattr(ns, "typescope"); + if (ts) { + SwigType_using_scope(ts); + } + } + return SWIG_OK; + } else { + Node *ns; + /* using id */ + Symtab *stab = Getattr(n, "sym:symtab"); + if (stab) { + String *uname = Getattr(n, "uname"); + ns = Swig_symbol_clookup(uname, stab); + if (!ns && SwigType_istemplate(uname)) { + String *tmp = Swig_symbol_template_deftype(uname, 0); + if (!Equal(tmp, uname)) { + ns = Swig_symbol_clookup(tmp, stab); + } + Delete(tmp); + } + } else { + ns = 0; + } + if (!ns) { + if (is_public(n)) { + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(n), Getline(n), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(n, "uname"))); + } + } else { + /* Only a single symbol is being used. There are only a few symbols that + we actually care about. These are typedef, class declarations, and enum */ + String *ntype = nodeType(ns); + if (Strcmp(ntype, "cdecl") == 0) { + if (checkAttribute(ns, "storage", "typedef")) { + /* A typedef declaration */ + String *uname = Getattr(n, "uname"); + SwigType_typedef_using(uname); + } else { + /* A normal C declaration. */ + if ((inclass) && (!GetFlag(n, "feature:ignore")) && (Getattr(n, "sym:name"))) { + Node *c = ns; + Node *unodes = 0, *last_unodes = 0; + int ccount = 0; + String *symname = Getattr(n, "sym:name"); + while (c) { + if (Strcmp(nodeType(c), "cdecl") == 0) { + if (!(checkAttribute(c, "storage", "static") + || checkAttribute(c, "storage", "typedef") + || checkAttribute(c, "storage", "friend") + || (Getattr(c, "feature:extend") && !Getattr(c, "code")) + || GetFlag(c, "feature:ignore"))) { + + /* Don't generate a method if the method is overridden in this class, + * for example don't generate another m(bool) should there be a Base::m(bool) : + * struct Derived : Base { + * void m(bool); + * using Base::m; + * }; + */ + String *csymname = Getattr(c, "sym:name"); + if (!csymname || (Strcmp(csymname, symname) == 0)) { + { + String *decl = Getattr(c, "decl"); + Node *over = Getattr(n, "sym:overloaded"); + int match = 0; + while (over) { + String *odecl = Getattr(over, "decl"); + if (Cmp(decl, odecl) == 0) { + match = 1; + break; + } + over = Getattr(over, "sym:nextSibling"); + } + if (match) { + c = Getattr(c, "csym:nextSibling"); + continue; + } + } + Node *nn = copyNode(c); + Delattr(nn, "access"); // access might be different from the method in the base class + if (!Getattr(nn, "sym:name")) + Setattr(nn, "sym:name", symname); + + if (!GetFlag(nn, "feature:ignore")) { + ParmList *parms = CopyParmList(Getattr(c, "parms")); + int is_pointer = SwigType_ispointer_return(Getattr(nn, "decl")); + int is_void = checkAttribute(nn, "type", "void") && !is_pointer; + Setattr(nn, "parms", parms); + Delete(parms); + if (Getattr(n, "feature:extend")) { + String *ucode = is_void ? NewStringf("{ self->%s(", Getattr(n, "uname")) : NewStringf("{ return self->%s(", Getattr(n, "uname")); + + for (ParmList *p = parms; p;) { + Append(ucode, Getattr(p, "name")); + p = nextSibling(p); + if (p) + Append(ucode, ","); + } + Append(ucode, "); }"); + Setattr(nn, "code", ucode); + Delete(ucode); + } + ParmList *throw_parm_list = Getattr(c, "throws"); + if (throw_parm_list) + Setattr(nn, "throws", CopyParmList(throw_parm_list)); + ccount++; + if (!last_unodes) { + last_unodes = nn; + unodes = nn; + } else { + Setattr(nn, "previousSibling", last_unodes); + Setattr(last_unodes, "nextSibling", nn); + Setattr(nn, "sym:previousSibling", last_unodes); + Setattr(last_unodes, "sym:nextSibling", nn); + Setattr(nn, "sym:overloaded", unodes); + Setattr(unodes, "sym:overloaded", unodes); + last_unodes = nn; + } + } else { + Delete(nn); + } + } + } + } + c = Getattr(c, "csym:nextSibling"); + } + if (unodes) { + set_firstChild(n, unodes); + if (ccount > 1) { + if (!Getattr(n, "sym:overloaded")) { + Setattr(n, "sym:overloaded", n); + Setattr(n, "sym:overname", "_SWIG_0"); + } + } + } + + /* Hack the parse tree symbol table for overloaded methods. Replace the "using" node with the + * list of overloaded methods we have just added in as child nodes to the "using" node. + * The node will still exist, it is just the symbol table linked list of overloaded methods + * which is hacked. */ + if (Getattr(n, "sym:overloaded")) + { +#ifdef DEBUG_OVERLOADED +show_overloaded(n); +#endif + int cnt = 0; + Node *debugnode = n; + if (!firstChild(n)) { + // Remove from overloaded list ('using' node does not actually end up adding in any methods) + Node *ps = Getattr(n, "sym:previousSibling"); + Node *ns = Getattr(n, "sym:nextSibling"); + if (ps) { + Setattr(ps, "sym:nextSibling", ns); + } + if (ns) { + Setattr(ns, "sym:previousSibling", ps); + } + } else { + // The 'using' node results in methods being added in - slot in the these methods here + Node *ps = Getattr(n, "sym:previousSibling"); + Node *ns = Getattr(n, "sym:nextSibling"); + Node *fc = firstChild(n); + Node *pp = fc; + + Node *firstoverloaded = Getattr(n, "sym:overloaded"); + if (firstoverloaded == n) { + // This 'using' node we are cutting out was the first node in the overloaded list. + // Change the first node in the list to its first sibling + Delattr(firstoverloaded, "sym:overloaded"); + Node *nnn = Getattr(firstoverloaded, "sym:nextSibling"); + firstoverloaded = fc; + while (nnn) { + Setattr(nnn, "sym:overloaded", firstoverloaded); + nnn = Getattr(nnn, "sym:nextSibling"); + } + } + while (pp) { + Node *ppn = Getattr(pp, "sym:nextSibling"); + Setattr(pp, "sym:overloaded", firstoverloaded); + Setattr(pp, "sym:overname", NewStringf("%s_%d", Getattr(n, "sym:overname"), cnt++)); + if (ppn) + pp = ppn; + else + break; + } + if (ps) { + Setattr(ps, "sym:nextSibling", fc); + Setattr(fc, "sym:previousSibling", ps); + } + if (ns) { + Setattr(ns, "sym:previousSibling", pp); + Setattr(pp, "sym:nextSibling", ns); + } + debugnode = firstoverloaded; + } + Delattr(n, "sym:previousSibling"); + Delattr(n, "sym:nextSibling"); + Delattr(n, "sym:overloaded"); + Delattr(n, "sym:overname"); +#ifdef DEBUG_OVERLOADED +show_overloaded(debugnode); +#endif + clean_overloaded(n); // Needed? + } + } + } + } else if ((Strcmp(ntype, "class") == 0) || ((Strcmp(ntype, "classforward") == 0))) { + /* We install the using class name as kind of a typedef back to the original class */ + String *uname = Getattr(n, "uname"); + /* Import into current type scope */ + SwigType_typedef_using(uname); + } else if (Strcmp(ntype, "enum") == 0) { + SwigType_typedef_using(Getattr(n, "uname")); + } + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * typemapDirective() + * ------------------------------------------------------------ */ + + virtual int typemapDirective(Node *n) { + if (inclass || nsname) { + Node *items = firstChild(n); + while (items) { + Parm *pattern = Getattr(items, "pattern"); + Parm *parms = Getattr(items, "parms"); + normalize_later(pattern); + normalize_later(parms); + items = nextSibling(items); + } + } + return SWIG_OK; + } + + + /* ------------------------------------------------------------ + * typemapcopyDirective() + * ------------------------------------------------------------ */ + + virtual int typemapcopyDirective(Node *n) { + if (inclass || nsname) { + Node *items = firstChild(n); + ParmList *pattern = Getattr(n, "pattern"); + normalize_later(pattern); + while (items) { + ParmList *npattern = Getattr(items, "pattern"); + normalize_later(npattern); + items = nextSibling(items); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * applyDirective() + * ------------------------------------------------------------ */ + + virtual int applyDirective(Node *n) { + if (inclass || nsname) { + ParmList *pattern = Getattr(n, "pattern"); + normalize_later(pattern); + Node *items = firstChild(n); + while (items) { + Parm *apattern = Getattr(items, "pattern"); + normalize_later(apattern); + items = nextSibling(items); + } + } + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * clearDirective() + * ------------------------------------------------------------ */ + + virtual int clearDirective(Node *n) { + if (inclass || nsname) { + Node *p; + for (p = firstChild(n); p; p = nextSibling(p)) { + ParmList *pattern = Getattr(p, "pattern"); + normalize_later(pattern); + } + } + return SWIG_OK; + } + +public: + static void pass(Node *n) { + TypePass t; + t.top(n); + } +}; + +void Swig_process_types(Node *n) { + if (!n) + return; + TypePass::pass(n); +} diff --git a/Source/Modules/uffi.cxx b/Source/Modules/uffi.cxx new file mode 100644 index 0000000..780b9e8 --- /dev/null +++ b/Source/Modules/uffi.cxx @@ -0,0 +1,398 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * uffi.cxx + * + * Uffi language module for SWIG. + * ----------------------------------------------------------------------------- */ + +// TODO: remove remnants of lisptype + +char cvsroot_uffi_cxx[] = "$Id: uffi.cxx 11380 2009-07-08 12:17:45Z wsfulton $"; + +#include "swigmod.h" + +class UFFI:public Language { +public: + + virtual void main(int argc, char *argv[]); + virtual int top(Node *n); + virtual int functionWrapper(Node *n); + virtual int constantWrapper(Node *n); + virtual int classHandler(Node *n); + virtual int membervariableHandler(Node *n); + +}; + +static File *f_cl = 0; + +static struct { + int count; + String **entries; +} defined_foreign_types; + +static const char *identifier_converter = "identifier-convert-null"; + +static int any_varargs(ParmList *pl) { + Parm *p; + + for (p = pl; p; p = nextSibling(p)) { + if (SwigType_isvarargs(Getattr(p, "type"))) + return 1; + } + + return 0; +} + + +/* utilities */ +/* returns new string w/ parens stripped */ +static String *strip_parens(String *string) { + char *s = Char(string), *p; + int len = Len(string); + String *res; + + if (len == 0 || s[0] != '(' || s[len - 1] != ')') { + return NewString(string); + } + + p = (char *) malloc(len - 2 + 1); + if (!p) { + Printf(stderr, "Malloc failed\n"); + SWIG_exit(EXIT_FAILURE); + } + + strncpy(p, s + 1, len - 1); + p[len - 2] = 0; /* null terminate */ + + res = NewString(p); + free(p); + + return res; +} + + +static String *convert_literal(String *num_param, String *type) { + String *num = strip_parens(num_param), *res; + char *s = Char(num); + + /* Make sure doubles use 'd' instead of 'e' */ + if (!Strcmp(type, "double")) { + String *updated = Copy(num); + if (Replace(updated, "e", "d", DOH_REPLACE_ANY) > 1) { + Printf(stderr, "Weird!! number %s looks invalid.\n", num); + SWIG_exit(EXIT_FAILURE); + } + Delete(num); + return updated; + } + + if (SwigType_type(type) == T_CHAR) { + /* Use CL syntax for character literals */ + return NewStringf("#\\%s", num_param); + } else if (SwigType_type(type) == T_STRING) { + /* Use CL syntax for string literals */ + return NewStringf("\"%s\"", num_param); + } + + if (Len(num) < 2 || s[0] != '0') { + return num; + } + + /* octal or hex */ + + res = NewStringf("#%c%s", s[1] == 'x' ? 'x' : 'o', s + 2); + Delete(num); + + return res; +} + +static void add_defined_foreign_type(String *type) { + if (!defined_foreign_types.count) { + /* Make fresh */ + defined_foreign_types.count = 1; + defined_foreign_types.entries = (String **) malloc(sizeof(String *)); + } else { + /* make room */ + defined_foreign_types.count++; + defined_foreign_types.entries = (String **) + realloc(defined_foreign_types.entries, defined_foreign_types.count * sizeof(String *)); + } + + if (!defined_foreign_types.entries) { + Printf(stderr, "Out of memory\n"); + SWIG_exit(EXIT_FAILURE); + } + + /* Fill in the new data */ + defined_foreign_types.entries[defined_foreign_types.count - 1] = Copy(type); + +} + + +static String *get_ffi_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setattr(node, "name", name); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("ffitype", node, "", 0); + Delete(node); + + if (tm) { + return NewString(tm); + } else { + SwigType *tr = SwigType_typedef_resolve_all(ty); + char *type_reduced = Char(tr); + int i; + + //Printf(stdout,"convert_type %s\n", ty); + if (SwigType_isconst(tr)) { + SwigType_pop(tr); + type_reduced = Char(tr); + } + + if (SwigType_ispointer(type_reduced) || SwigType_isarray(ty) || !strncmp(type_reduced, "p.f", 3)) { + return NewString(":pointer-void"); + } + + for (i = 0; i < defined_foreign_types.count; i++) { + if (!Strcmp(ty, defined_foreign_types.entries[i])) { + return NewStringf("#.(%s \"%s\" :type :type)", identifier_converter, ty); + } + } + + if (!Strncmp(type_reduced, "enum ", 5)) { + return NewString(":int"); + } + + Printf(stderr, "Unsupported data type: %s (was: %s)\n", type_reduced, ty); + SWIG_exit(EXIT_FAILURE); + } + return 0; +} + +static String *get_lisp_type(Node *n, SwigType *ty, const_String_or_char_ptr name) { + Node *node = NewHash(); + Setattr(node, "type", ty); + Setattr(node, "name", name); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup("lisptype", node, "", 0); + Delete(node); + + return tm ? NewString(tm) : NewString(""); +} + +void UFFI::main(int argc, char *argv[]) { + int i; + + Preprocessor_define("SWIGUFFI 1", 0); + SWIG_library_directory("uffi"); + SWIG_config_file("uffi.swg"); + + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-identifier-converter")) { + char *conv = argv[i + 1]; + + if (!conv) + Swig_arg_error(); + + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + + /* check for built-ins */ + if (!strcmp(conv, "lispify")) { + identifier_converter = "identifier-convert-lispify"; + } else if (!strcmp(conv, "null")) { + identifier_converter = "identifier-convert-null"; + } else { + /* Must be user defined */ + char *idconv = new char[strlen(conv) + 1]; + strcpy(idconv, conv); + identifier_converter = idconv; + } + } + + if (!strcmp(argv[i], "-help")) { + fprintf(stdout, "UFFI Options (available with -uffi)\n"); + fprintf(stdout, + " -identifier-converter <type or funcname>\n" + "\tSpecifies the type of conversion to do on C identifiers to convert\n" + "\tthem to symbols. There are two built-in converters: 'null' and\n" + "\t 'lispify'. The default is 'null'. If you supply a name other\n" + "\tthan one of the built-ins, then a function by that name will be\n" + "\tcalled to convert identifiers to symbols.\n"); + } + } +} + +int UFFI::top(Node *n) { + String *module = Getattr(n, "name"); + String *output_filename = NewString(""); + File *f_null = NewString(""); + + Printf(output_filename, "%s%s.cl", SWIG_output_directory(), module); + + + f_cl = NewFile(output_filename, "w", SWIG_output_files()); + if (!f_cl) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + + Swig_register_filebyname("header", f_null); + Swig_register_filebyname("begin", f_null); + Swig_register_filebyname("runtime", f_null); + Swig_register_filebyname("wrapper", f_cl); + + Swig_banner_target_lang(f_cl, ";;"); + + Printf(f_cl, "\n" + ";; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; package: %s -*-\n\n(defpackage :%s\n (:use :common-lisp :uffi))\n\n(in-package :%s)\n", + module, module, module); + Printf(f_cl, "(eval-when (compile load eval)\n (defparameter *swig-identifier-converter* '%s))\n", identifier_converter); + + Language::top(n); + + Close(f_cl); + Delete(f_cl); // Delete the handle, not the file + Close(f_null); + Delete(f_null); + + return SWIG_OK; +} + +int UFFI::functionWrapper(Node *n) { + String *funcname = Getattr(n, "sym:name"); + ParmList *pl = Getattr(n, "parms"); + Parm *p; + int argnum = 0, first = 1, varargs = 0; + + //Language::functionWrapper(n); + + Printf(f_cl, "(swig-defun \"%s\"\n", funcname); + Printf(f_cl, " ("); + + /* Special cases */ + + if (ParmList_len(pl) == 0) { + Printf(f_cl, ":void"); + } else if (any_varargs(pl)) { + Printf(f_cl, "#| varargs |#"); + varargs = 1; + } else { + for (p = pl; p; p = nextSibling(p), argnum++) { + String *argname = Getattr(p, "name"); + SwigType *argtype = Getattr(p, "type"); + String *ffitype = get_ffi_type(n, argtype, argname); + String *lisptype = get_lisp_type(n, argtype, argname); + int tempargname = 0; + + if (!argname) { + argname = NewStringf("arg%d", argnum); + tempargname = 1; + } + + if (!first) { + Printf(f_cl, "\n "); + } + Printf(f_cl, "(%s %s %s)", argname, ffitype, lisptype); + first = 0; + + Delete(ffitype); + Delete(lisptype); + if (tempargname) + Delete(argname); + + } + } + Printf(f_cl, ")\n"); /* finish arg list */ + Printf(f_cl, " :returning %s\n" + //" :strings-convert t\n" + //" :call-direct %s\n" + //" :optimize-for-space t" + ")\n", get_ffi_type(n, Getattr(n, "type"), "result") + //,varargs ? "nil" : "t" + ); + + + return SWIG_OK; +} + +int UFFI::constantWrapper(Node *n) { + String *type = Getattr(n, "type"); + String *converted_value = convert_literal(Getattr(n, "value"), type); + String *name = Getattr(n, "sym:name"); + +#if 0 + Printf(stdout, "constant %s is of type %s. value: %s\n", name, type, converted_value); +#endif + + Printf(f_cl, "(swig-defconstant \"%s\" %s)\n", name, converted_value); + + Delete(converted_value); + + return SWIG_OK; +} + +// Includes structs +int UFFI::classHandler(Node *n) { + + String *name = Getattr(n, "sym:name"); + String *kind = Getattr(n, "kind"); + Node *c; + + if (Strcmp(kind, "struct")) { + Printf(stderr, "Don't know how to deal with %s kind of class yet.\n", kind); + Printf(stderr, " (name: %s)\n", name); + SWIG_exit(EXIT_FAILURE); + } + + Printf(f_cl, "(swig-def-struct \"%s\"\n \n", name); + + for (c = firstChild(n); c; c = nextSibling(c)) { + SwigType *type = Getattr(c, "type"); + SwigType *decl = Getattr(c, "decl"); + type = Copy(type); + SwigType_push(type, decl); + String *lisp_type; + + if (Strcmp(nodeType(c), "cdecl")) { + Printf(stderr, "Structure %s has a slot that we can't deal with.\n", name); + Printf(stderr, "nodeType: %s, name: %s, type: %s\n", nodeType(c), Getattr(c, "name"), Getattr(c, "type")); + SWIG_exit(EXIT_FAILURE); + } + + + /* Printf(stdout, "Converting %s in %s\n", type, name); */ + lisp_type = get_ffi_type(n, type, Getattr(c, "sym:name")); + + Printf(f_cl, " (#.(%s \"%s\" :type :slot) %s)\n", identifier_converter, Getattr(c, "sym:name"), lisp_type); + + Delete(lisp_type); + } + + // Language::classHandler(n); + + Printf(f_cl, " )\n"); + + /* Add this structure to the known lisp types */ + //Printf(stdout, "Adding %s foreign type\n", name); + add_defined_foreign_type(name); + + return SWIG_OK; +} + +int UFFI::membervariableHandler(Node *n) { + Language::membervariableHandler(n); + return SWIG_OK; +} + + +extern "C" Language *swig_uffi(void) { + return new UFFI(); +} diff --git a/Source/Modules/utils.cxx b/Source/Modules/utils.cxx new file mode 100644 index 0000000..496700a --- /dev/null +++ b/Source/Modules/utils.cxx @@ -0,0 +1,98 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * utils.cxx + * + * Various utility functions. + * ----------------------------------------------------------------------------- */ + +char cvsroot_utils_cxx[] = "$Id: utils.cxx 10423 2008-05-07 20:59:00Z wsfulton $"; + +#include <swigmod.h> + +int is_public(Node *n) { + String *access = Getattr(n, "access"); + return !access || !Cmp(access, "public"); +} + +int is_private(Node *n) { + String *access = Getattr(n, "access"); + return access && !Cmp(access, "private"); +} + +int is_protected(Node *n) { + String *access = Getattr(n, "access"); + return access && !Cmp(access, "protected"); +} + +static int is_member_director_helper(Node *parentnode, Node *member) { + int parent_nodirector = GetFlag(parentnode, "feature:nodirector"); + if (parent_nodirector) + return 0; + int parent_director = Swig_director_mode() && GetFlag(parentnode, "feature:director"); + int cdecl_director = parent_director || GetFlag(member, "feature:director"); + int cdecl_nodirector = GetFlag(member, "feature:nodirector"); + return cdecl_director && !cdecl_nodirector && !GetFlag(member, "feature:extend"); +} + +int is_member_director(Node *parentnode, Node *member) { + if (parentnode && checkAttribute(member, "storage", "virtual")) { + return is_member_director_helper(parentnode, member); + } else { + return 0; + } +} + +int is_member_director(Node *member) { + return is_member_director(Getattr(member, "parentNode"), member); +} + +// Identifies the additional protected members that are generated when the allprotected option is used. +// This does not include protected virtual methods as they are turned on with the dirprot option. +int is_non_virtual_protected_access(Node *n) { + int result = 0; + if (Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode() && is_protected(n) && !checkAttribute(n, "storage", "virtual")) { + if (is_member_director_helper(Getattr(n, "parentNode"), n)) + result = 1; + } + return result; +} + +/* Clean overloaded list. Removes templates, ignored, and errors */ + +void clean_overloaded(Node *n) { + Node *nn = Getattr(n, "sym:overloaded"); + Node *first = 0; + while (nn) { + String *ntype = nodeType(nn); + if ((GetFlag(nn, "feature:ignore")) || + (Getattr(nn, "error")) || + (Strcmp(ntype, "template") == 0) || + ((Strcmp(ntype, "cdecl") == 0) && is_protected(nn) && !is_member_director(nn) && !is_non_virtual_protected_access(n))) { + /* Remove from overloaded list */ + Node *ps = Getattr(nn, "sym:previousSibling"); + Node *ns = Getattr(nn, "sym:nextSibling"); + if (ps) { + Setattr(ps, "sym:nextSibling", ns); + } + if (ns) { + Setattr(ns, "sym:previousSibling", ps); + } + Delattr(nn, "sym:previousSibling"); + Delattr(nn, "sym:nextSibling"); + Delattr(nn, "sym:overloaded"); + nn = ns; + continue; + } else { + if (!first) + first = nn; + Setattr(nn, "sym:overloaded", first); + } + nn = Getattr(nn, "sym:nextSibling"); + } + if (!first || (first && !Getattr(first, "sym:nextSibling"))) { + if (Getattr(n, "sym:overloaded")) + Delattr(n, "sym:overloaded"); + } +} diff --git a/Source/Modules/xml.cxx b/Source/Modules/xml.cxx new file mode 100644 index 0000000..a3d393a --- /dev/null +++ b/Source/Modules/xml.cxx @@ -0,0 +1,320 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * xml.cxx + * + * An Xml parse tree generator. + * ----------------------------------------------------------------------------- */ + +char cvsroot_xml_cxx[] = "$Id: xml.cxx 10898 2008-11-03 12:51:45Z wsfulton $"; + +#include "swigmod.h" + +static const char *usage = "\ +XML Options (available with -xml)\n\ + -xmllang <lang> - Typedef language\n\ + -xmllite - More lightweight version of XML\n\ + ------\n\ + deprecated (use -o): -xml <output.xml> - Use <output.xml> as output file (extension .xml mandatory)\n"; + +static File *out = 0; +static int xmllite = 0; + + +class XML:public Language { +public: + + int indent_level; + long id; + + XML() :indent_level(0) , id(0) { + } + + virtual ~ XML() { + } + + virtual void main(int argc, char *argv[]) { + SWIG_typemap_lang("xml"); + for (int iX = 0; iX < argc; iX++) { + if (strcmp(argv[iX], "-xml") == 0) { + char *extension = 0; + if (iX + 1 >= argc) + continue; + extension = argv[iX + 1] + strlen(argv[iX + 1]) - 4; + if (strcmp(extension, ".xml")) + continue; + iX++; + Swig_mark_arg(iX); + String *outfile = NewString(argv[iX]); + out = NewFile(outfile, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + continue; + } + if (strcmp(argv[iX], "-xmllang") == 0) { + Swig_mark_arg(iX); + iX++; + SWIG_typemap_lang(argv[iX]); + Swig_mark_arg(iX); + continue; + } + if (strcmp(argv[iX], "-help") == 0) { + fputs(usage, stdout); + } + if (strcmp(argv[iX], "-xmllite") == 0) { + Swig_mark_arg(iX); + xmllite = 1; + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGXML 1", 0); + } + + /* Top of the parse tree */ + + virtual int top(Node *n) { + if (out == 0) { + String *outfile = Getattr(n, "outfile"); + Replaceall(outfile, ".cxx", ".xml"); + Replaceall(outfile, ".cpp", ".xml"); + Replaceall(outfile, ".c", ".xml"); + out = NewFile(outfile, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + } + Printf(out, "<?xml version=\"1.0\" ?> \n"); + Xml_print_tree(n); + return SWIG_OK; + } + + void print_indent(int l) { + int i; + for (i = 0; i < indent_level; i++) { + Printf(out, " "); + } + if (l) { + Printf(out, " "); + } + } + + void Xml_print_tree(DOH *obj) { + while (obj) { + Xml_print_node(obj); + obj = nextSibling(obj); + } + } + + void Xml_print_attributes(Node *obj) { + String *k; + indent_level += 4; + print_indent(0); + Printf(out, "<attributelist id=\"%ld\" addr=\"%x\" >\n", ++id, obj); + indent_level += 4; + Iterator ki; + ki = First(obj); + while (ki.key) { + k = ki.key; + if ((Cmp(k, "nodeType") == 0) + || (Cmp(k, "firstChild") == 0) + || (Cmp(k, "lastChild") == 0) + || (Cmp(k, "parentNode") == 0) + || (Cmp(k, "nextSibling") == 0) + || (Cmp(k, "previousSibling") == 0) + || (*(Char(k)) == '$')) { + /* Do nothing */ + } else if (Cmp(k, "module") == 0) { + Xml_print_module(Getattr(obj, k)); + } else if (Cmp(k, "baselist") == 0) { + Xml_print_baselist(Getattr(obj, k)); + } else if (!xmllite && Cmp(k, "typescope") == 0) { + Xml_print_typescope(Getattr(obj, k)); + } else if (!xmllite && Cmp(k, "typetab") == 0) { + Xml_print_typetab(Getattr(obj, k)); + } else if (Cmp(k, "kwargs") == 0) { + Xml_print_kwargs(Getattr(obj, k)); + } else if (Cmp(k, "parms") == 0 || Cmp(k, "pattern") == 0) { + Xml_print_parmlist(Getattr(obj, k)); + } else { + DOH *o; + print_indent(0); + if (DohIsString(Getattr(obj, k))) { + String *ck = NewString(k); + o = Str(Getattr(obj, k)); + Replaceall(ck, ":", "_"); + Replaceall(ck, "<", "<"); + /* Do first to avoid aliasing errors. */ + Replaceall(o, "&", "&"); + Replaceall(o, "<", "<"); + Replaceall(o, "\"", """); + Replaceall(o, "\\", "\\\\"); + Replaceall(o, "\n", " "); + Printf(out, "<attribute name=\"%s\" value=\"%s\" id=\"%ld\" addr=\"%x\" />\n", ck, o, ++id, o); + Delete(o); + Delete(ck); + } else { + o = Getattr(obj, k); + String *ck = NewString(k); + Replaceall(ck, ":", "_"); + Printf(out, "<attribute name=\"%s\" value=\"%x\" id=\"%ld\" addr=\"%x\" />\n", ck, o, ++id, o); + Delete(ck); + } + } + ki = Next(ki); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</attributelist >\n"); + indent_level -= 4; + } + + void Xml_print_node(Node *obj) { + Node *cobj; + + print_indent(0); + Printf(out, "<%s id=\"%ld\" addr=\"%x\" >\n", nodeType(obj), ++id, obj); + Xml_print_attributes(obj); + cobj = firstChild(obj); + if (cobj) { + indent_level += 4; + Printf(out, "\n"); + Xml_print_tree(cobj); + indent_level -= 4; + } else { + print_indent(1); + Printf(out, "\n"); + } + print_indent(0); + Printf(out, "</%s >\n", nodeType(obj)); + } + + + void Xml_print_parmlist(ParmList *p) { + + print_indent(0); + Printf(out, "<parmlist id=\"%ld\" addr=\"%x\" >\n", ++id, p); + indent_level += 4; + while (p) { + print_indent(0); + Printf(out, "<parm id=\"%ld\">\n", ++id); + Xml_print_attributes(p); + print_indent(0); + Printf(out, "</parm >\n"); + p = nextSibling(p); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</parmlist >\n"); + } + + void Xml_print_baselist(List *p) { + + print_indent(0); + Printf(out, "<baselist id=\"%ld\" addr=\"%x\" >\n", ++id, p); + indent_level += 4; + Iterator s; + for (s = First(p); s.item; s = Next(s)) { + print_indent(0); + String *item_name = Xml_escape_string(s.item); + Printf(out, "<base name=\"%s\" id=\"%ld\" addr=\"%x\" />\n", item_name, ++id, s.item); + Delete(item_name); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</baselist >\n"); + } + + String *Xml_escape_string(String *str) { + String *escaped_str = 0; + if (str) { + escaped_str = NewString(str); + Replaceall(escaped_str, "&", "&"); + Replaceall(escaped_str, "<", "<"); + Replaceall(escaped_str, "\"", """); + Replaceall(escaped_str, "\\", "\\\\"); + Replaceall(escaped_str, "\n", " "); + } + return escaped_str; + } + + void Xml_print_module(Node *p) { + + print_indent(0); + Printf(out, "<attribute name=\"module\" value=\"%s\" id=\"%ld\" addr=\"%x\" />\n", Getattr(p, "name"), ++id, p); + } + + void Xml_print_kwargs(Hash *p) { + Xml_print_hash(p, "kwargs"); + } + + void Xml_print_typescope(Hash *p) { + + Xml_print_hash(p, "typescope"); + } + + void Xml_print_typetab(Hash *p) { + + Xml_print_hash(p, "typetab"); + } + + + void Xml_print_hash(Hash *p, const char *markup) { + + print_indent(0); + Printf(out, "<%s id=\"%ld\" addr=\"%x\" >\n", markup, ++id, p); + Xml_print_attributes(p); + indent_level += 4; + Iterator n = First(p); + while (n.key) { + print_indent(0); + Printf(out, "<%ssitem id=\"%ld\" addr=\"%x\" >\n", markup, ++id, n.item); + Xml_print_attributes(n.item); + print_indent(0); + Printf(out, "</%ssitem >\n", markup); + n = Next(n); + } + indent_level -= 4; + print_indent(0); + Printf(out, "</%s >\n", markup); + } + +}; + +/* ----------------------------------------------------------------------------- + * Swig_print_xml + * + * Dump an XML version of the parse tree. This is different from using the -xml + * language module normally as it allows the real language module to process the + * tree first, possibly stuffing in new attributes, so the XML that is output ends + * up being a post-processing version of the tree. + * ----------------------------------------------------------------------------- */ + +void Swig_print_xml(DOH *obj, String *filename) { + XML xml; + xmllite = 1; + + if (!filename) { + out = stdout; + } else { + out = NewFile(filename, "w", SWIG_output_files()); + if (!out) { + FileErrorDisplay(filename); + SWIG_exit(EXIT_FAILURE); + } + } + + Printf(out, "<?xml version=\"1.0\" ?> \n"); + xml.Xml_print_tree(obj); +} + +static Language *new_swig_xml() { + return new XML(); +} +extern "C" Language *swig_xml(void) { + return new_swig_xml(); +} diff --git a/Source/Preprocessor/cpp.c b/Source/Preprocessor/cpp.c new file mode 100644 index 0000000..b456b5e --- /dev/null +++ b/Source/Preprocessor/cpp.c @@ -0,0 +1,1854 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * cpp.c + * + * An implementation of a C preprocessor plus some support for additional + * SWIG directives. + * + * - SWIG directives such as %include, %extern, and %import are handled + * - A new macro %define ... %enddef can be used for multiline macros + * - No preprocessing is performed in %{ ... %} blocks + * - Lines beginning with %# are stripped down to #... and passed through. + * ----------------------------------------------------------------------------- */ + +char cvsroot_cpp_c[] = "$Id: cpp.c 11098 2009-01-30 10:32:59Z bhy $"; + +#include "swig.h" +#include "preprocessor.h" +#include <ctype.h> + +static Hash *cpp = 0; /* C preprocessor data */ +static int include_all = 0; /* Follow all includes */ +static int ignore_missing = 0; +static int import_all = 0; /* Follow all includes, but as %import statements */ +static int imported_depth = 0; /* Depth of %imported files */ +static int single_include = 1; /* Only include each file once */ +static Hash *included_files = 0; +static List *dependencies = 0; +static Scanner *id_scan = 0; +static int error_as_warning = 0; /* Understand the cpp #error directive as a special #warning */ + +/* Test a character to see if it starts an identifier */ +#define isidentifier(c) ((isalpha(c)) || (c == '_') || (c == '$')) + +/* Test a character to see if it valid in an identifier (after the first letter) */ +#define isidchar(c) ((isalnum(c)) || (c == '_') || (c == '$')) + +DOH *Preprocessor_replace(DOH *); + +/* Skip whitespace */ +static void skip_whitespace(String *s, String *out) { + int c; + while ((c = Getc(s)) != EOF) { + if (!isspace(c)) { + Ungetc(c, s); + break; + } else if (out) + Putc(c, out); + } +} + +/* Skip to a specified character taking line breaks into account */ +static int skip_tochar(String *s, int ch, String *out) { + int c; + while ((c = Getc(s)) != EOF) { + if (out) + Putc(c, out); + if (c == ch) + break; + if (c == '\\') { + c = Getc(s); + if ((c != EOF) && (out)) + Putc(c, out); + } + } + if (c == EOF) + return -1; + return 0; +} + +static void copy_location(const DOH *s1, DOH *s2) { + Setfile(s2, Getfile((DOH *) s1)); + Setline(s2, Getline((DOH *) s1)); +} + +static String *cpp_include(const_String_or_char_ptr fn, int sysfile) { + String *s = sysfile ? Swig_include_sys(fn) : Swig_include(fn); + if (s && single_include) { + String *file = Getfile(s); + if (Getattr(included_files, file)) { + Delete(s); + return 0; + } + Setattr(included_files, file, file); + } + if (!s) { + /* XXX(bhy) may not need the seek */ + /* Seek(fn, 0, SEEK_SET); */ + if (ignore_missing) { + Swig_warning(WARN_PP_MISSING_FILE, Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn); + } else { + Swig_error(Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn); + } + } else { + String *lf; + Seek(s, 0, SEEK_SET); + if (!dependencies) { + dependencies = NewList(); + } + lf = Copy(Swig_last_file()); + Append(dependencies, lf); + Delete(lf); + } + return s; +} + +List *Preprocessor_depend(void) { + return dependencies; +} + +/* ----------------------------------------------------------------------------- + * void Preprocessor_cpp_init() - Initialize the preprocessor + * ----------------------------------------------------------------------------- */ +static String *kpp_args = 0; +static String *kpp_define = 0; +static String *kpp_defined = 0; +static String *kpp_elif = 0; +static String *kpp_else = 0; +static String *kpp_endif = 0; +static String *kpp_expanded = 0; +static String *kpp_if = 0; +static String *kpp_ifdef = 0; +static String *kpp_ifndef = 0; +static String *kpp_name = 0; +static String *kpp_swigmacro = 0; +static String *kpp_symbols = 0; +static String *kpp_undef = 0; +static String *kpp_value = 0; +static String *kpp_varargs = 0; +static String *kpp_error = 0; +static String *kpp_warning = 0; +static String *kpp_line = 0; +static String *kpp_include = 0; +static String *kpp_pragma = 0; +static String *kpp_level = 0; + +static String *kpp_dline = 0; +static String *kpp_ddefine = 0; +static String *kpp_dinclude = 0; +static String *kpp_dimport = 0; +static String *kpp_dextern = 0; + +static String *kpp_LINE = 0; +static String *kpp_FILE = 0; + +void Preprocessor_init(void) { + Hash *s; + + kpp_args = NewString("args"); + kpp_define = NewString("define"); + kpp_defined = NewString("defined"); + kpp_else = NewString("else"); + kpp_elif = NewString("elif"); + kpp_endif = NewString("endif"); + kpp_expanded = NewString("*expanded*"); + kpp_if = NewString("if"); + kpp_ifdef = NewString("ifdef"); + kpp_ifndef = NewString("ifndef"); + kpp_name = NewString("name"); + kpp_swigmacro = NewString("swigmacro"); + kpp_symbols = NewString("symbols"); + kpp_undef = NewString("undef"); + kpp_value = NewString("value"); + kpp_error = NewString("error"); + kpp_warning = NewString("warning"); + kpp_pragma = NewString("pragma"); + kpp_level = NewString("level"); + kpp_line = NewString("line"); + kpp_include = NewString("include"); + kpp_varargs = NewString("varargs"); + + kpp_dinclude = NewString("%include"); + kpp_dimport = NewString("%import"); + kpp_dextern = NewString("%extern"); + kpp_ddefine = NewString("%define"); + kpp_dline = NewString("%line"); + + + kpp_LINE = NewString("__LINE__"); + kpp_FILE = NewString("__FILE__"); + + cpp = NewHash(); + s = NewHash(); + Setattr(cpp, kpp_symbols, s); + Delete(s); + Preprocessor_expr_init(); /* Initialize the expression evaluator */ + included_files = NewHash(); + + id_scan = NewScanner();; + +} + +void Preprocessor_delete(void) { + Delete(kpp_args); + Delete(kpp_define); + Delete(kpp_defined); + Delete(kpp_else); + Delete(kpp_elif); + Delete(kpp_endif); + Delete(kpp_expanded); + Delete(kpp_if); + Delete(kpp_ifdef); + Delete(kpp_ifndef); + Delete(kpp_name); + Delete(kpp_swigmacro); + Delete(kpp_symbols); + Delete(kpp_undef); + Delete(kpp_value); + Delete(kpp_error); + Delete(kpp_warning); + Delete(kpp_pragma); + Delete(kpp_level); + Delete(kpp_line); + Delete(kpp_include); + Delete(kpp_varargs); + + Delete(kpp_dinclude); + Delete(kpp_dimport); + Delete(kpp_dextern); + Delete(kpp_ddefine); + Delete(kpp_dline); + + + Delete(kpp_LINE); + Delete(kpp_FILE); + Delete(cpp); + Delete(included_files); + Preprocessor_expr_delete(); + DelScanner(id_scan); + + Delete(dependencies); + + Delete(Swig_add_directory(0)); +} + +/* ----------------------------------------------------------------------------- + * void Preprocessor_include_all() - Instruct preprocessor to include all files + * ----------------------------------------------------------------------------- */ +void Preprocessor_include_all(int a) { + include_all = a; +} + +void Preprocessor_import_all(int a) { + import_all = a; +} + +void Preprocessor_ignore_missing(int a) { + ignore_missing = a; +} + +void Preprocessor_error_as_warning(int a) { + error_as_warning = a; +} + + +/* ----------------------------------------------------------------------------- + * Preprocessor_define() + * + * Defines a new C preprocessor symbol. swigmacro specifies whether or not the macro has + * SWIG macro semantics. + * ----------------------------------------------------------------------------- */ + + +String *Macro_vararg_name(const_String_or_char_ptr str, const_String_or_char_ptr line) { + String *argname; + String *varargname; + char *s, *dots; + + argname = Copy(str); + s = Char(argname); + dots = strchr(s, '.'); + if (!dots) { + Delete(argname); + return NULL; + } + + if (strcmp(dots, "...") != 0) { + Swig_error(Getfile(line), Getline(line), "Illegal macro argument name '%s'\n", str); + Delete(argname); + return NULL; + } + if (dots == s) { + varargname = NewString("__VA_ARGS__"); + } else { + *dots = '\0'; + varargname = NewString(s); + } + Delete(argname); + return varargname; +} + +Hash *Preprocessor_define(const_String_or_char_ptr _str, int swigmacro) { + String *macroname = 0, *argstr = 0, *macrovalue = 0, *file = 0, *s = 0; + Hash *macro = 0, *symbols = 0, *m1; + List *arglist = 0; + int c, line; + int varargs = 0; + String *str; + + assert(cpp); + assert(_str); + + /* First make sure that string is actually a string */ + if (DohCheck(_str)) { + s = Copy(_str); + copy_location(_str, s); + str = s; + } else { + str = NewString((char *) _str); + } + Seek(str, 0, SEEK_SET); + line = Getline(str); + file = Getfile(str); + + /* Skip over any leading whitespace */ + skip_whitespace(str, 0); + + /* Now look for a macro name */ + macroname = NewStringEmpty(); + while ((c = Getc(str)) != EOF) { + if (c == '(') { + argstr = NewStringEmpty(); + copy_location(str, argstr); + /* It is a macro. Go extract its argument string */ + while ((c = Getc(str)) != EOF) { + if (c == ')') + break; + else + Putc(c, argstr); + } + if (c != ')') { + Swig_error(Getfile(str), Getline(str), "Missing \')\' in macro parameters\n"); + goto macro_error; + } + break; + } else if (isidchar(c) || (c == '%')) { + Putc(c, macroname); + } else if (isspace(c)) { + break; + } else if (c == '\\') { + c = Getc(str); + if (c != '\n') { + Ungetc(c, str); + Ungetc('\\', str); + break; + } + } else { + /*Swig_error(Getfile(str),Getline(str),"Illegal character in macro name\n"); + goto macro_error; */ + Ungetc(c, str); + break; + } + } + if (!swigmacro) + skip_whitespace(str, 0); + macrovalue = NewStringEmpty(); + while ((c = Getc(str)) != EOF) { + Putc(c, macrovalue); + } + + /* If there are any macro arguments, convert into a list */ + if (argstr) { + String *argname, *varargname; + arglist = NewList(); + Seek(argstr, 0, SEEK_SET); + argname = NewStringEmpty(); + while ((c = Getc(argstr)) != EOF) { + if (c == ',') { + varargname = Macro_vararg_name(argname, str); + if (varargname) { + Delete(varargname); + Swig_error(Getfile(str), Getline(str), "Variable-length macro argument must be last parameter\n"); + } else { + Append(arglist, argname); + } + Delete(argname); + argname = NewStringEmpty(); + } else if (isidchar(c) || (c == '.')) { + Putc(c, argname); + } else if (!(isspace(c) || (c == '\\'))) { + Delete(argname); + Swig_error(Getfile(str), Getline(str), "Illegal character in macro argument name\n"); + goto macro_error; + } + } + if (Len(argname)) { + /* Check for varargs */ + varargname = Macro_vararg_name(argname, str); + if (varargname) { + Append(arglist, varargname); + Delete(varargname); + varargs = 1; + } else { + Append(arglist, argname); + } + } + Delete(argname); + } + + if (!swigmacro) { + Replace(macrovalue, "\\\n", " ", DOH_REPLACE_NOQUOTE); + } + + /* Look for special # substitutions. We only consider # that appears + outside of quotes and comments */ + + { + int state = 0; + char *cc = Char(macrovalue); + while (*cc) { + switch (state) { + case 0: + if (*cc == '#') + *cc = '\001'; + else if (*cc == '/') + state = 10; + else if (*cc == '\'') + state = 20; + else if (*cc == '\"') + state = 30; + break; + case 10: + if (*cc == '*') + state = 11; + else if (*cc == '/') + state = 15; + else { + state = 0; + cc--; + } + break; + case 11: + if (*cc == '*') + state = 12; + break; + case 12: + if (*cc == '/') + state = 0; + else if (*cc != '*') + state = 11; + break; + case 15: + if (*cc == '\n') + state = 0; + break; + case 20: + if (*cc == '\'') + state = 0; + if (*cc == '\\') + state = 21; + break; + case 21: + state = 20; + break; + case 30: + if (*cc == '\"') + state = 0; + if (*cc == '\\') + state = 31; + break; + case 31: + state = 30; + break; + default: + break; + } + cc++; + } + } + + /* Get rid of whitespace surrounding # */ + /* Replace(macrovalue,"#","\001",DOH_REPLACE_NOQUOTE); */ + while (strstr(Char(macrovalue), "\001 ")) { + Replace(macrovalue, "\001 ", "\001", DOH_REPLACE_ANY); + } + while (strstr(Char(macrovalue), " \001")) { + Replace(macrovalue, " \001", "\001", DOH_REPLACE_ANY); + } + /* Replace '##' with a special token */ + Replace(macrovalue, "\001\001", "\002", DOH_REPLACE_ANY); + /* Replace '#@' with a special token */ + Replace(macrovalue, "\001@", "\004", DOH_REPLACE_ANY); + /* Replace '##@' with a special token */ + Replace(macrovalue, "\002@", "\005", DOH_REPLACE_ANY); + + /* Go create the macro */ + macro = NewHash(); + Setattr(macro, kpp_name, macroname); + + if (arglist) { + Setattr(macro, kpp_args, arglist); + Delete(arglist); + if (varargs) { + Setattr(macro, kpp_varargs, "1"); + } + } + Setattr(macro, kpp_value, macrovalue); + Setline(macro, line); + Setfile(macro, file); + if (swigmacro) { + Setattr(macro, kpp_swigmacro, "1"); + } + symbols = Getattr(cpp, kpp_symbols); + if ((m1 = Getattr(symbols, macroname))) { + if (!Checkattr(m1, kpp_value, macrovalue)) { + Swig_error(Getfile(str), Getline(str), "Macro '%s' redefined,\n", macroname); + Swig_error(Getfile(m1), Getline(m1), "previous definition of '%s'.\n", macroname); + goto macro_error; + } + } else { + Setattr(symbols, macroname, macro); + Delete(macro); + } + + Delete(macroname); + Delete(macrovalue); + + Delete(str); + Delete(argstr); + return macro; + +macro_error: + Delete(str); + Delete(argstr); + Delete(arglist); + Delete(macroname); + Delete(macrovalue); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Preprocessor_undef() + * + * Undefines a macro. + * ----------------------------------------------------------------------------- */ +void Preprocessor_undef(const_String_or_char_ptr str) { + Hash *symbols; + assert(cpp); + symbols = Getattr(cpp, kpp_symbols); + Delattr(symbols, str); +} + +/* ----------------------------------------------------------------------------- + * find_args() + * + * Isolates macro arguments and returns them in a list. For each argument, + * leading and trailing whitespace is stripped (ala K&R, pg. 230). + * ----------------------------------------------------------------------------- */ +static List *find_args(String *s) { + List *args; + String *str; + int c, level; + long pos; + + /* Create a new list */ + args = NewList(); + copy_location(s, args); + + /* First look for a '(' */ + pos = Tell(s); + skip_whitespace(s, 0); + + /* Now see if the next character is a '(' */ + c = Getc(s); + if (c != '(') { + /* Not a macro, bail out now! */ + Seek(s, pos, SEEK_SET); + Delete(args); + return 0; + } + c = Getc(s); + /* Okay. This appears to be a macro so we will start isolating arguments */ + while (c != EOF) { + if (isspace(c)) { + skip_whitespace(s, 0); /* Skip leading whitespace */ + c = Getc(s); + } + str = NewStringEmpty(); + copy_location(s, str); + level = 0; + while (c != EOF) { + if (c == '\"') { + Putc(c, str); + skip_tochar(s, '\"', str); + c = Getc(s); + continue; + } else if (c == '\'') { + Putc(c, str); + skip_tochar(s, '\'', str); + c = Getc(s); + continue; + } + if ((c == ',') && (level == 0)) + break; + if ((c == ')') && (level == 0)) + break; + Putc(c, str); + if (c == '(') + level++; + if (c == ')') + level--; + c = Getc(s); + } + if (level > 0) { + goto unterm; + } + Chop(str); + if (Len(args) || Len(str)) + Append(args, str); + Delete(str); + + /* if (Len(str) && (c != ')')) + Append(args,str); */ + + if (c == ')') + return args; + c = Getc(s); + } +unterm: + Swig_error(Getfile(args), Getline(args), "Unterminated macro call.\n"); + return args; +} + +/* ----------------------------------------------------------------------------- + * DOH *get_filename(DOH *str) + * + * Read a filename from str. A filename can be enclose in quotes, angle brackets, + * or bare. + * ----------------------------------------------------------------------------- */ + +static String *get_filename(String *str, int *sysfile) { + String *fn; + int c; + + skip_whitespace(str, 0); + fn = NewStringEmpty(); + copy_location(str, fn); + c = Getc(str); + *sysfile = 0; + if (c == '\"') { + while (((c = Getc(str)) != EOF) && (c != '\"')) + Putc(c, fn); + } else if (c == '<') { + *sysfile = 1; + while (((c = Getc(str)) != EOF) && (c != '>')) + Putc(c, fn); + } else { + Putc(c, fn); + while (((c = Getc(str)) != EOF) && (!isspace(c))) + Putc(c, fn); + if (isspace(c)) + Ungetc(c, str); + } + Swig_filename_correct(fn); + Seek(fn, 0, SEEK_SET); + return fn; +} + +static String *get_options(String *str) { + + int c; + skip_whitespace(str, 0); + c = Getc(str); + if (c == '(') { + String *opt; + int level = 1; + opt = NewString("("); + while (((c = Getc(str)) != EOF)) { + Putc(c, opt); + if (c == ')') { + level--; + if (!level) + return opt; + } + if (c == '(') + level++; + } + Delete(opt); + return 0; + } else { + Ungetc(c, str); + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * expand_macro() + * + * Perform macro expansion and return a new string. Returns NULL if some sort + * of error occurred. + * ----------------------------------------------------------------------------- */ + +static String *expand_macro(String *name, List *args) { + String *ns; + DOH *symbols, *macro, *margs, *mvalue, *temp, *tempa, *e; + int i, l; + int isvarargs = 0; + + symbols = Getattr(cpp, kpp_symbols); + if (!symbols) + return 0; + + /* See if the name is actually defined */ + macro = Getattr(symbols, name); + if (!macro) + return 0; + if (Getattr(macro, kpp_expanded)) { + ns = NewStringEmpty(); + Append(ns, name); + if (args) { + int lenargs = Len(args); + if (lenargs) + Putc('(', ns); + for (i = 0; i < lenargs; i++) { + Append(ns, Getitem(args, i)); + if (i < (lenargs - 1)) + Putc(',', ns); + } + if (i) + Putc(')', ns); + } + return ns; + } + + /* Get macro arguments and value */ + mvalue = Getattr(macro, kpp_value); + assert(mvalue); + margs = Getattr(macro, kpp_args); + + if (args && Getattr(macro, kpp_varargs)) { + isvarargs = 1; + /* Variable length argument macro. We need to collect all of the extra arguments into a single argument */ + if (Len(args) >= (Len(margs) - 1)) { + int i; + int vi, na; + String *vararg = NewStringEmpty(); + vi = Len(margs) - 1; + na = Len(args); + for (i = vi; i < na; i++) { + Append(vararg, Getitem(args, i)); + if ((i + 1) < na) { + Append(vararg, ","); + } + } + /* Remove arguments */ + for (i = vi; i < na; i++) { + Delitem(args, vi); + } + Append(args, vararg); + Delete(vararg); + } + } + /* If there are arguments, see if they match what we were given */ + if (args && (margs) && (Len(margs) != Len(args))) { + if (Len(margs) > (1 + isvarargs)) + Swig_error(Getfile(args), Getline(args), "Macro '%s' expects %d arguments\n", name, Len(margs) - isvarargs); + else if (Len(margs) == (1 + isvarargs)) + Swig_error(Getfile(args), Getline(args), "Macro '%s' expects 1 argument\n", name); + else + Swig_error(Getfile(args), Getline(args), "Macro '%s' expects no arguments\n", name); + return 0; + } + + /* If the macro expects arguments, but none were supplied, we leave it in place */ + if (!args && (margs) && Len(margs) > 0) { + return NewString(name); + } + + /* Copy the macro value */ + ns = Copy(mvalue); + copy_location(mvalue, ns); + + /* Tag the macro as being expanded. This is to avoid recursion in + macro expansion */ + + temp = NewStringEmpty(); + tempa = NewStringEmpty(); + if (args && margs) { + l = Len(margs); + for (i = 0; i < l; i++) { + DOH *arg, *aname; + String *reparg; + arg = Getitem(args, i); /* Get an argument value */ + reparg = Preprocessor_replace(arg); + aname = Getitem(margs, i); /* Get macro argument name */ + if (strstr(Char(ns), "\001")) { + /* Try to replace a quoted version of the argument */ + Clear(temp); + Clear(tempa); + Printf(temp, "\001%s", aname); + Printf(tempa, "\"%s\"", arg); + Replace(ns, temp, tempa, DOH_REPLACE_ID_END); + } + if (strstr(Char(ns), "\002")) { + /* Look for concatenation tokens */ + Clear(temp); + Clear(tempa); + Printf(temp, "\002%s", aname); + Append(tempa, "\002\003"); + Replace(ns, temp, tempa, DOH_REPLACE_ID_END); + Clear(temp); + Clear(tempa); + Printf(temp, "%s\002", aname); + Append(tempa, "\003\002"); + Replace(ns, temp, tempa, DOH_REPLACE_ID_BEGIN); + } + + /* Non-standard macro expansion. The value `x` is replaced by a quoted + version of the argument except that if the argument is already quoted + nothing happens */ + + if (strchr(Char(ns), '`')) { + String *rep; + char *c; + Clear(temp); + Printf(temp, "`%s`", aname); + c = Char(arg); + if (*c == '\"') { + rep = arg; + } else { + Clear(tempa); + Printf(tempa, "\"%s\"", arg); + rep = tempa; + } + Replace(ns, temp, rep, DOH_REPLACE_ANY); + } + + /* Non-standard mangle expansions. + The #@Name is replaced by mangle_arg(Name). */ + if (strstr(Char(ns), "\004")) { + String *marg = Swig_string_mangle(arg); + Clear(temp); + Printf(temp, "\004%s", aname); + Replace(ns, temp, marg, DOH_REPLACE_ID_END); + Delete(marg); + } + if (strstr(Char(ns), "\005")) { + String *marg = Swig_string_mangle(arg); + Clear(temp); + Clear(tempa); + Printf(temp, "\005%s", aname); + Printf(tempa, "\"%s\"", marg); + Replace(ns, temp, tempa, DOH_REPLACE_ID_END); + Delete(marg); + } + + if (isvarargs && i == l - 1 && Len(arg) == 0) { + /* Zero length varargs macro argument. We search for commas that might appear before and nuke them */ + char *a, *s, *t, *name; + int namelen; + s = Char(ns); + name = Char(aname); + namelen = Len(aname); + a = strstr(s, name); + while (a) { + char ca = a[namelen + 1]; + if (!isidchar((int) ca)) { + /* Matched the entire vararg name, not just a prefix */ + t = a - 1; + if (*t == '\002') { + t--; + while (t >= s) { + if (isspace((int) *t)) + t--; + else if (*t == ',') { + *t = ' '; + } else + break; + } + } + } + a = strstr(a + namelen, name); + } + } + /* Replace(ns, aname, arg, DOH_REPLACE_ID); */ + Replace(ns, aname, reparg, DOH_REPLACE_ID); /* Replace expanded args */ + Replace(ns, "\003", arg, DOH_REPLACE_ANY); /* Replace unexpanded arg */ + Delete(reparg); + } + } + Replace(ns, "\002", "", DOH_REPLACE_ANY); /* Get rid of concatenation tokens */ + Replace(ns, "\001", "#", DOH_REPLACE_ANY); /* Put # back (non-standard C) */ + Replace(ns, "\004", "#@", DOH_REPLACE_ANY); /* Put # back (non-standard C) */ + + /* Expand this macro even further */ + Setattr(macro, kpp_expanded, "1"); + + e = Preprocessor_replace(ns); + + Delattr(macro, kpp_expanded); + Delete(ns); + + if (Getattr(macro, kpp_swigmacro)) { + String *g; + String *f = NewStringEmpty(); + Seek(e, 0, SEEK_SET); + copy_location(macro, e); + g = Preprocessor_parse(e); + +#if 0 + /* Drop the macro in place, but with a marker around it */ + Printf(f, "/*@%s,%d,%s@*/%s/*@@*/", Getfile(macro), Getline(macro), name, g); +#else + /* Use simplified around markers to properly count lines in cscanner.c */ + if (strchr(Char(g), '\n')) { + Printf(f, "/*@SWIG:%s,%d,%s@*/%s/*@SWIG@*/", Getfile(macro), Getline(macro), name, g); +#if 0 + Printf(f, "/*@SWIG:%s@*/%s/*@SWIG@*/", name, g); +#endif + } else { + Append(f, g); + } +#endif + + Delete(g); + Delete(e); + e = f; + } + Delete(temp); + Delete(tempa); + return e; +} + +/* ----------------------------------------------------------------------------- + * evaluate_args() + * + * Evaluate the arguments of a macro + * ----------------------------------------------------------------------------- */ + +List *evaluate_args(List *x) { + Iterator i; + List *nl = NewList(); + + for (i = First(x); i.item; i = Next(i)) { + Append(nl, Preprocessor_replace(i.item)); + } + return nl; +} + +/* ----------------------------------------------------------------------------- + * DOH *Preprocessor_replace(DOH *s) + * + * Performs a macro substitution on a string s. Returns a new string with + * substitutions applied. This function works by walking down s and looking + * for identifiers. When found, a check is made to see if they are macros + * which are then expanded. + * ----------------------------------------------------------------------------- */ + +/* #define SWIG_PUT_BUFF */ + +DOH *Preprocessor_replace(DOH *s) { + DOH *ns, *symbols, *m; + int c, i, state = 0; + + String *id = NewStringEmpty(); + + assert(cpp); + symbols = Getattr(cpp, kpp_symbols); + + ns = NewStringEmpty(); + copy_location(s, ns); + Seek(s, 0, SEEK_SET); + + /* Try to locate identifiers in s and replace them with macro replacements */ + while ((c = Getc(s)) != EOF) { + switch (state) { + case 0: + if (isidentifier(c) || (c == '%')) { + Clear(id); + Putc(c, id); + state = 1; + } else if (c == '\"') { + Putc(c, ns); + skip_tochar(s, '\"', ns); + } else if (c == '\'') { + Putc(c, ns); + skip_tochar(s, '\'', ns); + } else if (c == '/') { + Putc(c, ns); + state = 10; + } else { + Putc(c, ns); + } + break; + case 1: /* An identifier */ + if (isidchar(c)) { + Putc(c, id); + state = 1; + } else { + /* We found the end of a valid identifier */ + Ungetc(c, s); + /* See if this is the special "defined" macro */ + if (Equal(kpp_defined, id)) { + int lenargs = 0; + DOH *args = 0; + /* See whether or not a paranthesis has been used */ + skip_whitespace(s, 0); + c = Getc(s); + if (c == '(') { + Ungetc(c, s); + args = find_args(s); + } else if (isidchar(c)) { + DOH *arg = NewStringEmpty(); + args = NewList(); + Putc(c, arg); + while (((c = Getc(s)) != EOF)) { + if (!isidchar(c)) { + Ungetc(c, s); + break; + } + Putc(c, arg); + } + if (Len(arg)) + Append(args, arg); + Delete(arg); + } else { + Seek(s, -1, SEEK_CUR); + } + lenargs = Len(args); + if ((!args) || (!lenargs)) { + /* This is not a defined() macro. */ + Append(ns, id); + state = 0; + break; + } + for (i = 0; i < lenargs; i++) { + DOH *o = Getitem(args, i); + if (!Getattr(symbols, o)) { + break; + } + } + if (i < lenargs) + Putc('0', ns); + else + Putc('1', ns); + Delete(args); + state = 0; + break; + } + if (Equal(kpp_LINE, id)) { + Printf(ns, "%d", Getline(s)); + state = 0; + break; + } + if (Equal(kpp_FILE, id)) { + String *fn = Copy(Getfile(s)); + Replaceall(fn, "\\", "\\\\"); + Printf(ns, "\"%s\"", fn); + Delete(fn); + state = 0; + break; + } + /* See if the macro is defined in the preprocessor symbol table */ + if ((m = Getattr(symbols, id))) { + DOH *args = 0; + DOH *e; + /* See if the macro expects arguments */ + if (Getattr(m, kpp_args)) { + /* Yep. We need to go find the arguments and do a substitution */ + args = find_args(s); + if (!Len(args)) { + Delete(args); + args = 0; + } + } else { + args = 0; + } + e = expand_macro(id, args); + if (e) { + Append(ns, e); + } + Delete(e); + Delete(args); + } else { + Append(ns, id); + } + state = 0; + } + break; + case 10: + if (c == '/') + state = 11; + else if (c == '*') + state = 12; + else { + Ungetc(c, s); + state = 0; + break; + } + Putc(c, ns); + break; + case 11: + Putc(c, ns); + if (c == '\n') + state = 0; + break; + case 12: + Putc(c, ns); + if (c == '*') + state = 13; + break; + case 13: + Putc(c, ns); + if (c == '/') + state = 0; + else if (c != '*') + state = 12; + break; + default: + state = 0; + break; + } + } + + /* Identifier at the end */ + if (state == 1) { + /* See if this is the special "defined" macro */ + if (Equal(kpp_defined, id)) { + Swig_error(Getfile(s), Getline(s), "No arguments given to defined()\n"); + } else if ((m = Getattr(symbols, id))) { + DOH *e; + /* Yes. There is a macro here */ + /* See if the macro expects arguments */ + /* if (Getattr(m,"args")) { + Swig_error(Getfile(id),Getline(id),"Macro arguments expected.\n"); + } */ + e = expand_macro(id, 0); + Append(ns, e); + Delete(e); + } else { + Append(ns, id); + } + } + Delete(id); + return ns; +} + + +/* ----------------------------------------------------------------------------- + * int checkpp_id(DOH *s) + * + * Checks the string s to see if it contains any unresolved identifiers. This + * function contains the heuristic that determines whether or not a macro + * definition passes through the preprocessor as a constant declaration. + * ----------------------------------------------------------------------------- */ +static int checkpp_id(DOH *s) { + int c; + int hastok = 0; + Scanner *scan = id_scan; + + Seek(s, 0, SEEK_SET); + + Scanner_clear(scan); + s = Copy(s); + Seek(s, SEEK_SET, 0); + Scanner_push(scan, s); + while ((c = Scanner_token(scan))) { + hastok = 1; + if ((c == SWIG_TOKEN_ID) || (c == SWIG_TOKEN_LBRACE) || (c == SWIG_TOKEN_RBRACE)) + return 1; + } + if (!hastok) + return 1; + return 0; +} + +/* addline(). Utility function for adding lines to a chunk */ +static void addline(DOH *s1, DOH *s2, int allow) { + if (allow) { + Append(s1, s2); + } else { + char *c = Char(s2); + while (*c) { + if (*c == '\n') + Putc('\n', s1); + c++; + } + } +} + +static void add_chunk(DOH *ns, DOH *chunk, int allow) { + DOH *echunk; + Seek(chunk, 0, SEEK_SET); + if (allow) { + echunk = Preprocessor_replace(chunk); + addline(ns, echunk, allow); + Delete(echunk); + } else { + addline(ns, chunk, 0); + } + Clear(chunk); +} + +/* + push/pop_imported(): helper functions for defining and undefining + SWIGIMPORTED (when %importing a file). + */ +static void push_imported() { + if (imported_depth == 0) { + Preprocessor_define("SWIGIMPORTED 1", 0); + } + ++imported_depth; +} + +static void pop_imported() { + --imported_depth; + if (imported_depth == 0) { + Preprocessor_undef("SWIGIMPORTED"); + } +} + + +/* ----------------------------------------------------------------------------- + * Preprocessor_parse() + * + * Parses the string s. Returns a new string containing the preprocessed version. + * + * Parsing rules : + * 1. Lines starting with # are C preprocessor directives + * 2. Macro expansion inside strings is not allowed + * 3. All code inside false conditionals is changed to blank lines + * 4. Code in %{, %} is not parsed because it may need to be + * included inline (with all preprocessor directives included). + * ----------------------------------------------------------------------------- */ + +String *Preprocessor_parse(String *s) { + String *ns; /* New string containing the preprocessed text */ + String *chunk, *decl; + Hash *symbols; + String *id = 0, *value = 0, *comment = 0; + int i, state, e, c; + int start_line = 0; + int allow = 1; + int level = 0; + int dlevel = 0; + int mask = 0; + int start_level = 0; + int cpp_lines = 0; + int cond_lines[256]; + + /* Blow away all carriage returns */ + Replace(s, "\015", "", DOH_REPLACE_ANY); + + ns = NewStringEmpty(); /* Return result */ + + decl = NewStringEmpty(); + id = NewStringEmpty(); + value = NewStringEmpty(); + comment = NewStringEmpty(); + chunk = NewStringEmpty(); + copy_location(s, chunk); + copy_location(s, ns); + symbols = Getattr(cpp, kpp_symbols); + + state = 0; + while ((c = Getc(s)) != EOF) { + switch (state) { + case 0: /* Initial state - in first column */ + /* Look for C preprocessor directives. Otherwise, go directly to state 1 */ + if (c == '#') { + add_chunk(ns, chunk, allow); + copy_location(s, chunk); + cpp_lines = 1; + state = 40; + } else if (isspace(c)) { + Putc(c, chunk); + skip_whitespace(s, chunk); + } else { + state = 1; + Ungetc(c, s); + } + break; + case 1: /* Non-preprocessor directive */ + /* Look for SWIG directives */ + if (c == '%') { + state = 100; + break; + } + Putc(c, chunk); + if (c == '\n') + state = 0; + else if (c == '\"') { + start_line = Getline(s); + if (skip_tochar(s, '\"', chunk) < 0) { + Swig_error(Getfile(s), -1, "Unterminated string constant starting at line %d\n", start_line); + } + } else if (c == '\'') { + start_line = Getline(s); + if (skip_tochar(s, '\'', chunk) < 0) { + Swig_error(Getfile(s), -1, "Unterminated character constant starting at line %d\n", start_line); + } + } else if (c == '/') + state = 30; /* Comment */ + break; + + case 30: /* Possibly a comment string of some sort */ + start_line = Getline(s); + Putc(c, chunk); + if (c == '/') + state = 31; + else if (c == '*') + state = 32; + else + state = 1; + break; + case 31: + Putc(c, chunk); + if (c == '\n') + state = 0; + break; + case 32: + Putc(c, chunk); + if (c == '*') + state = 33; + break; + case 33: + Putc(c, chunk); + if (c == '/') + state = 1; + else if (c != '*') + state = 32; + break; + + case 40: /* Start of a C preprocessor directive */ + if (c == '\n') { + Putc('\n', chunk); + state = 0; + } else if (isspace(c)) { + state = 40; + } else { + /* Got the start of a preprocessor directive */ + Ungetc(c, s); + Clear(id); + copy_location(s, id); + state = 41; + } + break; + + case 41: /* Build up the name of the preprocessor directive */ + if ((isspace(c) || (!isalpha(c)))) { + Clear(value); + Clear(comment); + if (c == '\n') { + Ungetc(c, s); + state = 50; + } else { + state = 42; + if (!isspace(c)) { + Ungetc(c, s); + } + } + + copy_location(s, value); + break; + } + Putc(c, id); + break; + + case 42: /* Strip any leading space before preprocessor value */ + if (isspace(c)) { + if (c == '\n') { + Ungetc(c, s); + state = 50; + } + break; + } + state = 43; + /* no break intended here */ + + case 43: + /* Get preprocessor value */ + if (c == '\n') { + Ungetc(c, s); + state = 50; + } else if (c == '/') { + state = 45; + } else if (c == '\"') { + Putc(c, value); + skip_tochar(s, '\"', value); + } else if (c == '\'') { + Putc(c, value); + skip_tochar(s, '\'', value); + } else { + Putc(c, value); + if (c == '\\') + state = 44; + } + break; + + case 44: + if (c == '\n') { + Putc(c, value); + cpp_lines++; + } else { + Ungetc(c, s); + } + state = 43; + break; + + /* States 45-48 are used to remove, but retain comments from macro values. The comments + will be placed in the output in an alternative form */ + + case 45: + if (c == '/') + state = 46; + else if (c == '*') + state = 47; + else if (c == '\n') { + Putc('/', value); + Ungetc(c, s); + cpp_lines++; + state = 50; + } else { + Putc('/', value); + Putc(c, value); + state = 43; + } + break; + case 46: + if (c == '\n') { + Ungetc(c, s); + cpp_lines++; + state = 50; + } else + Putc(c, comment); + break; + case 47: + if (c == '*') + state = 48; + else + Putc(c, comment); + break; + case 48: + if (c == '/') + state = 43; + else if (c == '*') + Putc(c, comment); + else { + Putc('*', comment); + Putc(c, comment); + state = 47; + } + break; + case 50: + /* Check for various preprocessor directives */ + Chop(value); + if (Equal(id, kpp_define)) { + if (allow) { + DOH *m, *v, *v1; + Seek(value, 0, SEEK_SET); + m = Preprocessor_define(value, 0); + if ((m) && !(Getattr(m, kpp_args))) { + v = Copy(Getattr(m, kpp_value)); + if (Len(v)) { + Swig_error_silent(1); + v1 = Preprocessor_replace(v); + Swig_error_silent(0); + /* Printf(stdout,"checking '%s'\n", v1); */ + if (!checkpp_id(v1)) { + if (Len(comment) == 0) + Printf(ns, "%%constant %s = %s;\n", Getattr(m, kpp_name), v1); + else + Printf(ns, "%%constant %s = %s; /*%s*/\n", Getattr(m, kpp_name), v1, comment); + cpp_lines--; + } + Delete(v1); + } + Delete(v); + } + } + } else if (Equal(id, kpp_undef)) { + if (allow) + Preprocessor_undef(value); + } else if (Equal(id, kpp_ifdef)) { + cond_lines[level] = Getline(id); + level++; + if (allow) { + start_level = level; + /* See if the identifier is in the hash table */ + if (!Getattr(symbols, value)) + allow = 0; + mask = 1; + } + } else if (Equal(id, kpp_ifndef)) { + cond_lines[level] = Getline(id); + level++; + if (allow) { + start_level = level; + /* See if the identifier is in the hash table */ + if (Getattr(symbols, value)) + allow = 0; + mask = 1; + } + } else if (Equal(id, kpp_else)) { + if (level <= 0) { + Swig_error(Getfile(s), Getline(id), "Misplaced #else.\n"); + } else { + cond_lines[level - 1] = Getline(id); + if (allow) { + allow = 0; + mask = 0; + } else if (level == start_level) { + allow = 1 * mask; + } + } + } else if (Equal(id, kpp_endif)) { + level--; + if (level < 0) { + Swig_error(Getfile(id), Getline(id), "Extraneous #endif.\n"); + level = 0; + } else { + if (level < start_level) { + allow = 1; + start_level--; + } + } + } else if (Equal(id, kpp_if)) { + cond_lines[level] = Getline(id); + level++; + if (allow) { + int val; + String *sval = Preprocessor_replace(value); + start_level = level; + Seek(sval, 0, SEEK_SET); + /* Printf(stdout,"Evaluating '%s'\n", sval); */ + val = Preprocessor_expr(sval, &e); + if (e) { + char *msg = Preprocessor_expr_error(); + Seek(value, 0, SEEK_SET); + Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate '%s'\n", value); + if (msg) + Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg); + allow = 0; + } else { + if (val == 0) + allow = 0; + } + mask = 1; + } + } else if (Equal(id, kpp_elif)) { + if (level == 0) { + Swig_error(Getfile(s), Getline(id), "Misplaced #elif.\n"); + } else { + cond_lines[level - 1] = Getline(id); + if (allow) { + allow = 0; + mask = 0; + } else if (level == start_level) { + int val; + String *sval = Preprocessor_replace(value); + Seek(sval, 0, SEEK_SET); + val = Preprocessor_expr(sval, &e); + if (e) { + char *msg = Preprocessor_expr_error(); + Seek(value, 0, SEEK_SET); + Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate '%s'\n", value); + if (msg) + Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg); + allow = 0; + } else { + if (val) + allow = 1 * mask; + else + allow = 0; + } + } + } + } else if (Equal(id, kpp_warning)) { + if (allow) { + Swig_warning(WARN_PP_CPP_WARNING, Getfile(s), Getline(id), "CPP #warning, %s\n", value); + } + } else if (Equal(id, kpp_error)) { + if (allow) { + if (error_as_warning) { + Swig_warning(WARN_PP_CPP_ERROR, Getfile(s), Getline(id), "CPP #error \"%s\".\n", value); + } else { + Swig_error(Getfile(s), Getline(id), "CPP #error \"%s\". Use the -cpperraswarn option to continue swig processing.\n", value); + } + } + } else if (Equal(id, kpp_line)) { + } else if (Equal(id, kpp_include)) { + if (((include_all) || (import_all)) && (allow)) { + String *s1, *s2, *fn; + char *dirname; + int sysfile = 0; + if (include_all && import_all) { + Swig_warning(WARN_PP_INCLUDEALL_IMPORTALL, Getfile(s), Getline(id), "Both includeall and importall are defined: using includeall\n"); + import_all = 0; + } + Seek(value, 0, SEEK_SET); + fn = get_filename(value, &sysfile); + s1 = cpp_include(fn, sysfile); + if (s1) { + if (include_all) + Printf(ns, "%%includefile \"%s\" [\n", Swig_last_file()); + else if (import_all) { + Printf(ns, "%%importfile \"%s\" [\n", Swig_last_file()); + push_imported(); + } + + /* See if the filename has a directory component */ + dirname = Swig_file_dirname(Swig_last_file()); + if (sysfile || !strlen(dirname)) + dirname = 0; + if (dirname) { + dirname[strlen(dirname) - 1] = 0; /* Kill trailing directory delimiter */ + Swig_push_directory(dirname); + } + s2 = Preprocessor_parse(s1); + addline(ns, s2, allow); + Append(ns, "\n]"); + if (dirname) { + Swig_pop_directory(); + } + if (import_all) { + pop_imported(); + } + Delete(s2); + } + Delete(s1); + Delete(fn); + } + } else if (Equal(id, kpp_pragma)) { + if (Strncmp(value, "SWIG ", 5) == 0) { + char *c = Char(value) + 5; + while (*c && (isspace((int) *c))) + c++; + if (*c) { + if (strncmp(c, "nowarn=", 7) == 0) { + String *val = NewString(c + 7); + String *nowarn = Preprocessor_replace(val); + Swig_warnfilter(nowarn, 1); + Delete(nowarn); + Delete(val); + } else if (strncmp(c, "cpperraswarn=", 13) == 0) { + error_as_warning = atoi(c + 13); + } else { + Swig_error(Getfile(s), Getline(id), "Unknown SWIG pragma: %s\n", c); + } + } + } + } else if (Equal(id, kpp_level)) { + Swig_error(Getfile(s), Getline(id), "cpp debug: level = %d, startlevel = %d\n", level, start_level); + } + for (i = 0; i < cpp_lines; i++) + Putc('\n', ns); + state = 0; + break; + + /* Swig directives */ + case 100: + /* %{,%} block */ + if (c == '{') { + start_line = Getline(s); + add_chunk(ns, chunk, allow); + copy_location(s, chunk); + Putc('%', chunk); + Putc(c, chunk); + state = 105; + } + /* %#cpp - an embedded C preprocessor directive (we strip off the %) */ + else if (c == '#') { + add_chunk(ns, chunk, allow); + Putc(c, chunk); + state = 107; + } else if (isidentifier(c)) { + Clear(decl); + Putc('%', decl); + Putc(c, decl); + state = 110; + } else { + Putc('%', chunk); + Putc(c, chunk); + state = 1; + } + break; + + case 105: + Putc(c, chunk); + if (c == '%') + state = 106; + break; + + case 106: + Putc(c, chunk); + if (c == '}') { + state = 1; + addline(ns, chunk, allow); + Clear(chunk); + copy_location(s, chunk); + } else { + state = 105; + } + break; + + case 107: + Putc(c, chunk); + if (c == '\n') { + addline(ns, chunk, allow); + Clear(chunk); + state = 0; + } else if (c == '\\') { + state = 108; + } + break; + + case 108: + Putc(c, chunk); + state = 107; + break; + + case 110: + if (!isidchar(c)) { + Ungetc(c, s); + /* Look for common Swig directives */ + if (Equal(decl, kpp_dinclude) || Equal(decl, kpp_dimport) || Equal(decl, kpp_dextern)) { + /* Got some kind of file inclusion directive */ + if (allow) { + DOH *s1, *s2, *fn, *opt; + int sysfile = 0; + + if (Equal(decl, kpp_dextern)) { + Swig_warning(WARN_DEPRECATED_EXTERN, Getfile(s), Getline(s), "%%extern is deprecated. Use %%import instead.\n"); + Clear(decl); + Append(decl, "%%import"); + } + opt = get_options(s); + fn = get_filename(s, &sysfile); + s1 = cpp_include(fn, sysfile); + if (s1) { + char *dirname; + add_chunk(ns, chunk, allow); + copy_location(s, chunk); + Printf(ns, "%sfile%s \"%s\" [\n", decl, opt, Swig_last_file()); + if (Equal(decl, kpp_dimport)) { + push_imported(); + } + dirname = Swig_file_dirname(Swig_last_file()); + if (sysfile || !strlen(dirname)) + dirname = 0; + if (dirname) { + dirname[strlen(dirname) - 1] = 0; /* Kill trailing directory delimiter */ + Swig_push_directory(dirname); + } + s2 = Preprocessor_parse(s1); + if (dirname) { + Swig_pop_directory(); + } + if (Equal(decl, kpp_dimport)) { + pop_imported(); + } + addline(ns, s2, allow); + Append(ns, "\n]"); + Delete(s2); + Delete(s1); + } + Delete(fn); + } + state = 1; + } else if (Equal(decl, kpp_dline)) { + /* Got a line directive */ + state = 1; + } else if (Equal(decl, kpp_ddefine)) { + /* Got a define directive */ + dlevel++; + add_chunk(ns, chunk, allow); + copy_location(s, chunk); + Clear(value); + copy_location(s, value); + state = 150; + } else { + Append(chunk, decl); + state = 1; + } + } else { + Putc(c, decl); + } + break; + + /* Searching for the end of a %define statement */ + case 150: + Putc(c, value); + if (c == '%') { + const char *ed = "enddef"; + const char *df = "define"; + char statement[7]; + int i = 0; + for (i = 0; i < 6;) { + c = Getc(s); + Putc(c, value); + statement[i++] = (char)c; + if (strncmp(statement, ed, i) && strncmp(statement, df, i)) + break; + } + c = Getc(s); + Ungetc(c, s); + if ((i == 6) && (isspace(c))) { + if (strncmp(statement, df, i) == 0) { + ++dlevel; + } else { + if (strncmp(statement, ed, i) == 0) { + --dlevel; + if (!dlevel) { + /* Got the macro */ + for (i = 0; i < 7; i++) { + Delitem(value, DOH_END); + } + if (allow) { + Seek(value, 0, SEEK_SET); + Preprocessor_define(value, 1); + } + /* Putc('\n',ns); */ + addline(ns, value, 0); + state = 0; + } + } + } + } + } + break; + default: + Printf(stderr, "cpp: Invalid parser state %d\n", state); + abort(); + break; + } + } + while (level > 0) { + Swig_error(Getfile(s), -1, "Missing #endif for conditional starting on line %d\n", cond_lines[level - 1]); + level--; + } + if (state == 150) { + Seek(value, 0, SEEK_SET); + Swig_error(Getfile(s), -1, "Missing %%enddef for macro starting on line %d\n", Getline(value)); + } + if ((state >= 105) && (state < 107)) { + Swig_error(Getfile(s), -1, "Unterminated %%{ ... %%} block starting on line %d\n", start_line); + } + if ((state >= 30) && (state < 40)) { + Swig_error(Getfile(s), -1, "Unterminated comment starting on line %d\n", start_line); + } + add_chunk(ns, chunk, allow); + copy_location(s, chunk); + + /* DelScope(scp); */ + Delete(decl); + Delete(id); + Delete(value); + Delete(comment); + Delete(chunk); + + /* fprintf(stderr,"cpp: %d\n", Len(Getattr(cpp,"symbols"))); */ + return ns; +} diff --git a/Source/Preprocessor/expr.c b/Source/Preprocessor/expr.c new file mode 100644 index 0000000..e6e9459 --- /dev/null +++ b/Source/Preprocessor/expr.c @@ -0,0 +1,436 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * expr.c + * + * Integer arithmetic expression evaluator used to handle expressions + * encountered during preprocessing. + * ----------------------------------------------------------------------------- */ + +char cvsroot_expr_c[] = "$Id: expr.c 10310 2008-03-17 00:36:35Z olly $"; + +#include "swig.h" +#include "preprocessor.h" + +static Scanner *scan = 0; + +typedef struct { + int op; + long value; + String *svalue; +} exprval; + +#define EXPR_TOP 1 +#define EXPR_VALUE 2 +#define EXPR_OP 3 +#define EXPR_GROUP 4 +#define EXPR_UMINUS 100 + +static exprval stack[256]; /* Parsing stack */ +static int sp = 0; /* Stack pointer */ +static int prec[256]; /* Precedence rules */ +static int expr_init = 0; /* Initialization flag */ +static char *errmsg = 0; /* Parsing error */ + +/* Initialize the precedence table for various operators. Low values have higher precedence */ +static void init_precedence() { + prec[SWIG_TOKEN_NOT] = 10; + prec[EXPR_UMINUS] = 10; + prec[SWIG_TOKEN_STAR] = 20; + prec[SWIG_TOKEN_SLASH] = 20; + prec[SWIG_TOKEN_PERCENT] = 20; + prec[SWIG_TOKEN_PLUS] = 30; + prec[SWIG_TOKEN_MINUS] = 30; + prec[SWIG_TOKEN_LSHIFT] = 40; + prec[SWIG_TOKEN_RSHIFT] = 40; + prec[SWIG_TOKEN_AND] = 50; + prec[SWIG_TOKEN_XOR] = 60; + prec[SWIG_TOKEN_OR] = 70; + prec[SWIG_TOKEN_EQUALTO] = 80; + prec[SWIG_TOKEN_NOTEQUAL] = 80; + prec[SWIG_TOKEN_LESSTHAN] = 80; + prec[SWIG_TOKEN_GREATERTHAN] = 80; + prec[SWIG_TOKEN_LTEQUAL] = 80; + prec[SWIG_TOKEN_GTEQUAL] = 80; + prec[SWIG_TOKEN_LNOT] = 90; + prec[SWIG_TOKEN_LAND] = 100; + prec[SWIG_TOKEN_LOR] = 110; + expr_init = 1; +} + +#define UNARY_OP(token) (((token) == SWIG_TOKEN_NOT) || \ + ((token) == SWIG_TOKEN_LNOT) || \ + ((token) == EXPR_UMINUS)) + +/* Reduce a single operator on the stack */ +/* return 0 on failure, 1 on success */ +static int reduce_op() { + long op_token = stack[sp - 1].value; + assert(sp > 0); + assert(stack[sp - 1].op == EXPR_OP); + /* do some basic checking first: */ + if (stack[sp].op != EXPR_VALUE) { + errmsg = "Right-hand side is not value"; + return 0; + } + if (UNARY_OP(op_token)) { + if (stack[sp].svalue) { + errmsg = "Syntax error: attempt to apply unary operator to string"; + return 0; + } + } else { + /* binary operator: */ + if (sp == 1) { + /* top of stack: don't attempt to use sp-2! */ + errmsg = "Missing left-hand side for binary operator"; + return 0; + } + if (stack[sp].op != EXPR_VALUE) { + errmsg = "Left-hand side of binary operator is not a value"; + return 0; + } + if ((!stack[sp - 2].svalue) != (!stack[sp].svalue)) { + errmsg = "Can't mix strings and integers in expression"; + return 0; + } + } + if (stack[sp].svalue) { + /* A binary string expression */ + switch (stack[sp - 1].value) { + case SWIG_TOKEN_EQUALTO: + stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) == 0); + Delete(stack[sp - 2].svalue); + Delete(stack[sp].svalue); + sp -= 2; + break; + case SWIG_TOKEN_NOTEQUAL: + stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) != 0); + Delete(stack[sp - 2].svalue); + Delete(stack[sp].svalue); + sp -= 2; + break; + default: + errmsg = "Syntax error: bad binary operator for strings"; + return 0; + break; + } + } else { + switch (op_token) { + case SWIG_TOKEN_STAR: + stack[sp - 2].value = stack[sp - 2].value * stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_EQUALTO: + stack[sp - 2].value = stack[sp - 2].value == stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_NOTEQUAL: + stack[sp - 2].value = stack[sp - 2].value != stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_PLUS: + stack[sp - 2].value = stack[sp - 2].value + stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_MINUS: + stack[sp - 2].value = stack[sp - 2].value - stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_AND: + stack[sp - 2].value = stack[sp - 2].value & stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_LAND: + stack[sp - 2].value = stack[sp - 2].value && stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_OR: + stack[sp - 2].value = stack[sp - 2].value | stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_LOR: + stack[sp - 2].value = stack[sp - 2].value || stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_XOR: + stack[sp - 2].value = stack[sp - 2].value ^ stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_LESSTHAN: + stack[sp - 2].value = stack[sp - 2].value < stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_GREATERTHAN: + stack[sp - 2].value = stack[sp - 2].value > stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_LTEQUAL: + stack[sp - 2].value = stack[sp - 2].value <= stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_GTEQUAL: + stack[sp - 2].value = stack[sp - 2].value >= stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_NOT: + stack[sp - 1].value = ~stack[sp].value; + sp--; + break; + case SWIG_TOKEN_LNOT: + stack[sp - 1].value = !stack[sp].value; + sp--; + break; + case EXPR_UMINUS: + stack[sp - 1].value = -stack[sp].value; + sp--; + break; + case SWIG_TOKEN_SLASH: + stack[sp - 2].value = stack[sp - 2].value / stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_PERCENT: + stack[sp - 2].value = stack[sp - 2].value % stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_LSHIFT: + stack[sp - 2].value = stack[sp - 2].value << stack[sp].value; + sp -= 2; + break; + case SWIG_TOKEN_RSHIFT: + stack[sp - 2].value = stack[sp - 2].value >> stack[sp].value; + sp -= 2; + break; + default: + errmsg = "Syntax error: bad operator"; + return 0; + break; + } + } + stack[sp].op = EXPR_VALUE; + stack[sp].svalue = 0; /* ensure it's not a string! */ + return 1; +} + +/* ----------------------------------------------------------------------------- + * Preprocessor_expr_init() + * + * Initialize the expression evaluator + * ----------------------------------------------------------------------------- */ + +void Preprocessor_expr_init(void) { + if (!expr_init) + init_precedence(); + if (!scan) + scan = NewScanner(); +} + +void Preprocessor_expr_delete(void) { + DelScanner(scan); +} + + +/* ----------------------------------------------------------------------------- + * Tokenizer + * ----------------------------------------------------------------------------- */ + +static int expr_token(Scanner * s) { + int t; + while (1) { + t = Scanner_token(s); + if (!((t == SWIG_TOKEN_BACKSLASH) || (t == SWIG_TOKEN_ENDLINE) || (t == SWIG_TOKEN_COMMENT))) + break; + } + return t; +} + +/* ----------------------------------------------------------------------------- + * Preprocessor_expr() + * + * Evaluates an arithmetic expression. Returns the result and sets an error code. + * ----------------------------------------------------------------------------- */ + +int Preprocessor_expr(DOH *s, int *error) { + int token = 0; + int op = 0; + + sp = 0; + assert(s); + assert(scan); + + Seek(s, 0, SEEK_SET); + /* Printf(stdout,"evaluating : '%s'\n", s); */ + *error = 0; + Scanner_clear(scan); + Scanner_push(scan, s); + + /* Put initial state onto the stack */ + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + + while (1) { + /* Look at the top of the stack */ + switch (stack[sp].op) { + case EXPR_TOP: + /* An expression. Can be a number or another expression enclosed in parens */ + token = expr_token(scan); + if (!token) { + errmsg = "Expected an expression"; + *error = 1; + return 0; + } + if ((token == SWIG_TOKEN_INT) || (token == SWIG_TOKEN_UINT) || (token == SWIG_TOKEN_LONG) || (token == SWIG_TOKEN_ULONG)) { + /* A number. Reduce EXPR_TOP to an EXPR_VALUE */ + char *c = Char(Scanner_text(scan)); + stack[sp].value = (long) strtol(c, 0, 0); + stack[sp].svalue = 0; + /* stack[sp].value = (long) atol(Char(Scanner_text(scan))); */ + stack[sp].op = EXPR_VALUE; + } else if (token == SWIG_TOKEN_PLUS) { + } else if ((token == SWIG_TOKEN_MINUS) || (token == SWIG_TOKEN_LNOT) || (token == SWIG_TOKEN_NOT)) { + if (token == SWIG_TOKEN_MINUS) + token = EXPR_UMINUS; + stack[sp].value = token; + stack[sp++].op = EXPR_OP; + stack[sp].op = EXPR_TOP; + stack[sp].svalue = 0; + } else if ((token == SWIG_TOKEN_LPAREN)) { + stack[sp++].op = EXPR_GROUP; + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + stack[sp].svalue = 0; + } else if (token == SWIG_TOKEN_ENDLINE) { + } else if ((token == SWIG_TOKEN_STRING)) { + stack[sp].svalue = NewString(Scanner_text(scan)); + stack[sp].op = EXPR_VALUE; + } else if ((token == SWIG_TOKEN_ID)) { + stack[sp].value = 0; + stack[sp].svalue = 0; + stack[sp].op = EXPR_VALUE; + } else + goto syntax_error; + break; + case EXPR_VALUE: + /* A value is on the stack. We may reduce or evaluate depending on what the next token is */ + token = expr_token(scan); + if (!token) { + /* End of input. Might have to reduce if an operator is on stack */ + while (sp > 0) { + if (stack[sp - 1].op == EXPR_OP) { + if (!reduce_op()) + goto reduce_error; + } else if (stack[sp - 1].op == EXPR_GROUP) { + errmsg = "Missing \')\'"; + *error = 1; + return 0; + } else + goto syntax_error; + } + return stack[sp].value; + } + /* Token must be an operator */ + switch (token) { + case SWIG_TOKEN_STAR: + case SWIG_TOKEN_EQUALTO: + case SWIG_TOKEN_NOTEQUAL: + case SWIG_TOKEN_PLUS: + case SWIG_TOKEN_MINUS: + case SWIG_TOKEN_AND: + case SWIG_TOKEN_LAND: + case SWIG_TOKEN_OR: + case SWIG_TOKEN_LOR: + case SWIG_TOKEN_XOR: + case SWIG_TOKEN_LESSTHAN: + case SWIG_TOKEN_GREATERTHAN: + case SWIG_TOKEN_LTEQUAL: + case SWIG_TOKEN_GTEQUAL: + case SWIG_TOKEN_SLASH: + case SWIG_TOKEN_PERCENT: + case SWIG_TOKEN_LSHIFT: + case SWIG_TOKEN_RSHIFT: + if ((sp == 0) || (stack[sp - 1].op == EXPR_GROUP)) { + /* No possibility of reduce. Push operator and expression */ + sp++; + stack[sp].op = EXPR_OP; + stack[sp].value = token; + sp++; + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + } else { + if (stack[sp - 1].op != EXPR_OP) + goto syntax_error_expected_operator; + op = stack[sp - 1].value; /* Previous operator */ + + /* Now, depending on the precedence relationship between the last operator and the current + we will reduce or push */ + + if (prec[op] <= prec[token]) { + /* Reduce the previous operator */ + if (!reduce_op()) + goto reduce_error; + } + sp++; + stack[sp].op = EXPR_OP; + stack[sp].value = token; + sp++; + stack[sp].op = EXPR_TOP; + stack[sp].value = 0; + } + break; + case SWIG_TOKEN_RPAREN: + if (sp == 0) + goto extra_rparen; + + /* Might have to reduce operators first */ + while ((sp > 0) && (stack[sp - 1].op == EXPR_OP)) { + if (!reduce_op()) + goto reduce_error; + } + if ((sp == 0) || (stack[sp - 1].op != EXPR_GROUP)) + goto extra_rparen; + stack[sp - 1].op = EXPR_VALUE; + stack[sp - 1].value = stack[sp].value; + sp--; + break; + default: + goto syntax_error_expected_operator; + break; + } + break; + + default: + fprintf(stderr, "Internal error in expression evaluator.\n"); + abort(); + } + } + +syntax_error: + errmsg = "Syntax error"; + *error = 1; + return 0; + +syntax_error_expected_operator: + errmsg = "Syntax error: expected operator"; + *error = 1; + return 0; + +reduce_error: + /* errmsg has been set by reduce_op */ + *error = 1; + return 0; + +extra_rparen: + errmsg = "Extra \')\'"; + *error = 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * Preprocessor_expr_error() + * + * Return error message set by the evaluator (if any) + * ----------------------------------------------------------------------------- */ + +char *Preprocessor_expr_error() { + return errmsg; +} diff --git a/Source/Preprocessor/preprocessor.h b/Source/Preprocessor/preprocessor.h new file mode 100644 index 0000000..2b90808 --- /dev/null +++ b/Source/Preprocessor/preprocessor.h @@ -0,0 +1,38 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * preprocessor.h + * + * SWIG preprocessor module. + * ----------------------------------------------------------------------------- */ + +/* $Id: preprocessor.h 11080 2009-01-24 13:15:51Z bhy $ */ + +#ifndef SWIG_PREPROCESSOR_H_ +#define SWIG_PREPROCESSOR_H_ + +#include "swigwarn.h" + +#ifdef __cplusplus +extern "C" { +#endif + extern int Preprocessor_expr(String *s, int *error); + extern char *Preprocessor_expr_error(void); + extern Hash *Preprocessor_define(const_String_or_char_ptr str, int swigmacro); + extern void Preprocessor_undef(const_String_or_char_ptr name); + extern void Preprocessor_init(void); + extern void Preprocessor_delete(void); + extern String *Preprocessor_parse(String *s); + extern void Preprocessor_include_all(int); + extern void Preprocessor_import_all(int); + extern void Preprocessor_ignore_missing(int); + extern void Preprocessor_error_as_warning(int); + extern List *Preprocessor_depend(void); + extern void Preprocessor_expr_init(void); + extern void Preprocessor_expr_delete(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Source/README b/Source/README new file mode 100644 index 0000000..814ec45 --- /dev/null +++ b/Source/README @@ -0,0 +1,25 @@ +SWIG Source directory + + Source/DOH - A core set of basic datatypes including + strings, lists, hashes, and files. Used + extensively by the rest of SWIG. + + Source/Swig - Swig core. Type-system, utility functions. + + Source/Preprocessor - SWIG C Preprocessor + + Source/CParse - SWIG C Parser (still messy) + + Source/Modules - Language modules. + + Source/Include - Include files. + +Historic directories which may be in CVS, but have been removed: + + Source/Modules1.1 - Old SWIG-1.1 modules. Empty. + + Source/LParse - Experimental parser. Officially dead + as CParse is more capable. + + Source/SWIG1.1 - Old SWIG1.1 core. Completely empty now. + diff --git a/Source/Swig/cwrap.c b/Source/Swig/cwrap.c new file mode 100644 index 0000000..72c06f3 --- /dev/null +++ b/Source/Swig/cwrap.c @@ -0,0 +1,1462 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * cwrap.c + * + * This file defines a variety of wrapping rules for C/C++ handling including + * the naming of local variables, calling conventions, and so forth. + * ----------------------------------------------------------------------------- */ + +char cvsroot_cwrap_c[] = "$Id: cwrap.c 11312 2009-06-24 17:20:17Z wsfulton $"; + +#include "swig.h" + +extern int cparse_cplusplus; + +static Parm *nonvoid_parms(Parm *p) { + if (p) { + SwigType *t = Getattr(p, "type"); + if (SwigType_type(t) == T_VOID) + return 0; + } + return p; +} + +/* ----------------------------------------------------------------------------- + * Swig_parm_name() + * + * Generates a name for the ith argument in an argument list + * ----------------------------------------------------------------------------- */ + +String *Swig_cparm_name(Parm *p, int i) { + String *name = NewStringf("arg%d", i + 1); + if (p) { + Setattr(p, "lname", name); + } + + return name; +} + +/* ----------------------------------------------------------------------------- + * Swig_clocal() + * + * Creates a string that declares a C local variable type. Converts references + * and user defined types to pointers. + * ----------------------------------------------------------------------------- */ + +static String *Swig_clocal(SwigType *t, const_String_or_char_ptr name, const_String_or_char_ptr value) { + String *decl; + + decl = NewStringEmpty(); + + switch (SwigType_type(t)) { + case T_REFERENCE: + if (value) { + String *lstrname = SwigType_lstr(t, name); + String *lstr = SwigType_lstr(t, 0); + Printf(decl, "%s = (%s) &%s_defvalue", lstrname, lstr, name); + Delete(lstrname); + Delete(lstr); + } else { + String *lstrname = SwigType_lstr(t, name); + Printf(decl, "%s = 0", lstrname); + Delete(lstrname); + } + break; + case T_VOID: + break; + case T_VARARGS: + Printf(decl, "void *%s = 0", name); + break; + + default: + if (value) { + String *lcaststr = SwigType_lcaststr(t, value); + String *lstr = SwigType_lstr(t, 0); + String *lstrn = SwigType_lstr(t, name); + Printf(decl, "%s = (%s) %s", lstrn, lstr, lcaststr); + Delete(lcaststr); + Delete(lstr); + Delete(lstrn); + } else { + String *lstrname = SwigType_lstr(t, name); + Append(decl, lstrname); + Delete(lstrname); + } + } + return decl; +} + +/* ----------------------------------------------------------------------------- + * Swig_wrapped_var_convert() + * + * Converts a member variable for use in the get and set wrapper methods. + * This function only converts user defined types to pointers. + * ----------------------------------------------------------------------------- */ + +String *Swig_wrapped_var_type(SwigType *t, int varcref) { + SwigType *ty; + + if (!Strstr(t, "enum $unnamed")) { + ty = Copy(t); + } else { + /* Change the type for unnamed enum instance variables */ + ty = NewString("int"); + } + + if (SwigType_isclass(t)) { + if (varcref) { + if (cparse_cplusplus) { + if (!SwigType_isconst(ty)) + SwigType_add_qualifier(ty, "const"); + SwigType_add_reference(ty); + } else { + return Copy(ty); + } + } else { + SwigType_add_pointer(ty); + } + } + return ty; +} + +String *Swig_wrapped_member_var_type(SwigType *t, int varcref) { + SwigType *ty; + + if (!Strstr(t, "enum $unnamed")) { + ty = Copy(t); + } else { + /* Change the type for unnamed enum instance variables */ + ty = NewString("int"); + } + if (SwigType_isclass(t)) { + if (varcref) { + if (cparse_cplusplus) { + if (!SwigType_isconst(ty)) + SwigType_add_qualifier(ty, "const"); + SwigType_add_reference(ty); + } else { + return Copy(ty); + } + } else { + SwigType_add_pointer(ty); + } + } + return ty; +} + + +static String *Swig_wrapped_var_deref(SwigType *t, const_String_or_char_ptr name, int varcref) { + if (SwigType_isclass(t)) { + if (varcref) { + if (cparse_cplusplus) { + return NewStringf("*%s", name); + } else { + return NewStringf("%s", name); + } + } else { + return NewStringf("*%s", name); + } + } else { + return SwigType_rcaststr(t, name); + } +} + +static String *Swig_wrapped_var_assign(SwigType *t, const_String_or_char_ptr name, int varcref) { + if (SwigType_isclass(t)) { + if (varcref) { + return NewStringf("%s", name); + } else { + return NewStringf("&%s", name); + } + } else { + return SwigType_lcaststr(t, name); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_cargs() + * + * Emit all of the local variables for a list of parameters. Returns the + * number of parameters. + * Default values for the local variables are only emitted if the compact default + * argument behaviour is required. + * ----------------------------------------------------------------------------- */ +int Swig_cargs(Wrapper *w, ParmList *p) { + int i = 0; + int compactdefargs = ParmList_is_compactdefargs(p); + + while (p != 0) { + String *lname = Swig_cparm_name(p, i); + SwigType *pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *local = 0; + String *type = Getattr(p, "type"); + /* default values only emitted if in compact default args mode */ + String *pvalue = (compactdefargs) ? Getattr(p, "value") : 0; + + /* When using compactdefaultargs, the code generated initialises a variable via a constructor call that accepts the + * default value as a parameter. The default constructor is not called and therefore SwigValueWrapper is not needed. */ + SwigType *altty = pvalue ? 0 : SwigType_alttype(type, 0); + + int tycode = SwigType_type(type); + if (tycode == T_REFERENCE) { + if (pvalue) { + SwigType *tvalue; + String *defname, *defvalue, *rvalue, *qvalue; + rvalue = SwigType_typedef_resolve_all(pvalue); + qvalue = SwigType_typedef_qualified(rvalue); + defname = NewStringf("%s_defvalue", lname); + tvalue = Copy(type); + SwigType_del_reference(tvalue); + tycode = SwigType_type(tvalue); + if (tycode != T_USER) { + /* plain primitive type, we copy the the def value */ + String *lstr = SwigType_lstr(tvalue, defname); + defvalue = NewStringf("%s = %s", lstr, qvalue); + Delete(lstr); + } else { + /* user type, we copy the reference value */ + String *str = SwigType_str(type, defname); + defvalue = NewStringf("%s = %s", str, qvalue); + Delete(str); + } + Wrapper_add_localv(w, defname, defvalue, NIL); + Delete(tvalue); + Delete(rvalue); + Delete(qvalue); + Delete(defname); + Delete(defvalue); + } + } else if (!pvalue && ((tycode == T_POINTER) || (tycode == T_STRING))) { + pvalue = (String *) "0"; + } + if (!altty) { + local = Swig_clocal(pt, lname, pvalue); + } else { + local = Swig_clocal(altty, lname, pvalue); + Delete(altty); + } + Wrapper_add_localv(w, lname, local, NIL); + Delete(local); + i++; + } + Delete(lname); + p = nextSibling(p); + } + return (i); +} + +/* ----------------------------------------------------------------------------- + * Swig_cresult() + * + * This function generates the C code needed to set the result of a C + * function call. + * ----------------------------------------------------------------------------- */ + +String *Swig_cresult(SwigType *t, const_String_or_char_ptr name, const_String_or_char_ptr decl) { + String *fcall; + + fcall = NewStringEmpty(); + switch (SwigType_type(t)) { + case T_VOID: + break; + case T_REFERENCE: + { + String *lstr = SwigType_lstr(t, 0); + Printf(fcall, "%s = (%s) &", name, lstr); + Delete(lstr); + } + break; + case T_USER: + Printf(fcall, "%s = ", name); + break; + + default: + /* Normal return value */ + { + String *lstr = SwigType_lstr(t, 0); + Printf(fcall, "%s = (%s)", name, lstr); + Delete(lstr); + } + break; + } + + /* Now print out function call */ + Append(fcall, decl); + + /* A sick hack */ + { + char *c = Char(decl) + Len(decl) - 1; + if (!((*c == ';') || (*c == '}'))) + Append(fcall, ";"); + } + + return fcall; +} + +/* ----------------------------------------------------------------------------- + * Swig_cfunction_call() + * + * Creates a string that calls a C function using the local variable rules + * defined above. + * + * name(arg0, arg1, arg2, ... argn) + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cfunction_call(const_String_or_char_ptr name, ParmList *parms) { + String *func; + int i = 0; + int comma = 0; + Parm *p = parms; + String *nname; + + func = NewStringEmpty(); + nname = SwigType_namestr(name); + + /* + SWIGTEMPLATEDISAMBIGUATOR is compiler dependent (swiglabels.swg), + - SUN Studio 9 requires 'template', + - gcc-3.4 forbids the use of 'template'. + the rest seems not caring very much, + */ + if (SwigType_istemplate(name)) { + String *prefix = Swig_scopename_prefix(nname); + if (!prefix || Len(prefix) == 0) { + Printf(func, "%s(", nname); + } else { + String *last = Swig_scopename_last(nname); + Printf(func, "%s::SWIGTEMPLATEDISAMBIGUATOR %s(", prefix, last); + Delete(last); + } + Delete(prefix); + } else { + Printf(func, "%s(", nname); + } + Delete(nname); + + while (p) { + SwigType *pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + SwigType *rpt = SwigType_typedef_resolve_all(pt); + String *pname = Swig_cparm_name(p, i); + String *rcaststr = SwigType_rcaststr(rpt, pname); + + if (comma) { + Printv(func, ",", rcaststr, NIL); + } else { + Append(func, rcaststr); + } + Delete(rpt); + Delete(pname); + Delete(rcaststr); + comma = 1; + i++; + } + p = nextSibling(p); + } + Append(func, ")"); + return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_cmethod_call() + * + * Generates a string that calls a C++ method from a list of parameters. + * + * arg0->name(arg1, arg2, arg3, ..., argn) + * + * self is an argument that defines how to handle the first argument. Normally, + * it should be set to "this->". With C++ proxy classes enabled, it could be + * set to "(*this)->" or some similar sequence. + * ----------------------------------------------------------------------------- */ + +static String *Swig_cmethod_call(const_String_or_char_ptr name, ParmList *parms, const_String_or_char_ptr self, String *explicit_qualifier, SwigType *director_type) { + String *func, *nname; + int i = 0; + Parm *p = parms; + SwigType *pt; + int comma = 0; + + func = NewStringEmpty(); + if (!p) + return func; + + if (!self) + self = (char *) "(this)->"; + Append(func, self); + + if (SwigType_istemplate(name) && (strncmp(Char(name), "operator ", 9) == 0)) { + /* fix for template + operators and compilers like gcc 3.3.5 */ + String *tprefix = SwigType_templateprefix(name); + nname = tprefix; + } else { + nname = SwigType_namestr(name); + } + + if (director_type) { + const char *pname = "darg"; + String *rcaststr = SwigType_rcaststr(director_type, pname); + Replaceall(func, "this", rcaststr); + Delete(rcaststr); + } else { + pt = Getattr(p, "type"); + + /* If the method is invoked through a dereferenced pointer, we don't add any casts + (needed for smart pointers). Otherwise, we cast to the appropriate type */ + + if (Strstr(func, "*this")) { + String *pname = Swig_cparm_name(p, 0); + Replaceall(func, "this", pname); + Delete(pname); + } else { + String *pname = Swig_cparm_name(p, 0); + String *rcaststr = SwigType_rcaststr(pt, pname); + Replaceall(func, "this", rcaststr); + Delete(rcaststr); + Delete(pname); + } + + /* + SWIGTEMPLATEDESIMBUAGATOR is compiler dependent (swiglabels.swg), + - SUN Studio 9 requires 'template', + - gcc-3.4 forbids the use of 'template' (correctly implementing the ISO C++ standard) + the others don't seem to care, + */ + if (SwigType_istemplate(name)) + Printf(func, "SWIGTEMPLATEDISAMBIGUATOR "); + + if (explicit_qualifier) { + Printv(func, explicit_qualifier, "::", NIL); + } + } + + Printf(func, "%s(", nname); + + i++; + p = nextSibling(p); + while (p) { + pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *pname = Swig_cparm_name(p, i); + String *rcaststr = SwigType_rcaststr(pt, pname); + if (comma) + Append(func, ","); + Append(func, rcaststr); + Delete(rcaststr); + Delete(pname); + comma = 1; + i++; + } + p = nextSibling(p); + } + Append(func, ")"); + Delete(nname); + return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_cconstructor_call() + * + * Creates a string that calls a C constructor function. + * + * calloc(1,sizeof(name)); + * ----------------------------------------------------------------------------- */ + +String *Swig_cconstructor_call(const_String_or_char_ptr name) { + DOH *func; + + func = NewStringEmpty(); + Printf(func, "calloc(1, sizeof(%s))", name); + return func; +} + + +/* ----------------------------------------------------------------------------- + * Swig_cppconstructor_call() + * + * Creates a string that calls a C function using the local variable rules + * defined above. + * + * name(arg0, arg1, arg2, ... argn) + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cppconstructor_base_call(const_String_or_char_ptr name, ParmList *parms, int skip_self) { + String *func; + String *nname; + int i = 0; + int comma = 0; + Parm *p = parms; + SwigType *pt; + if (skip_self) { + if (p) + p = nextSibling(p); + i++; + } + nname = SwigType_namestr(name); + func = NewStringEmpty(); + Printf(func, "new %s(", nname); + while (p) { + pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *rcaststr = 0; + String *pname = 0; + if (comma) + Append(func, ","); + if (!Getattr(p, "arg:byname")) { + pname = Swig_cparm_name(p, i); + i++; + } else { + pname = Getattr(p, "value"); + if (pname) + pname = Copy(pname); + else + pname = Copy(Getattr(p, "name")); + } + rcaststr = SwigType_rcaststr(pt, pname); + Append(func, rcaststr); + Delete(rcaststr); + comma = 1; + Delete(pname); + } + p = nextSibling(p); + } + Append(func, ")"); + Delete(nname); + return func; +} + +String *Swig_cppconstructor_call(const_String_or_char_ptr name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 0); +} + +String *Swig_cppconstructor_nodirector_call(const_String_or_char_ptr name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 1); +} + +String *Swig_cppconstructor_director_call(const_String_or_char_ptr name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 0); +} + +/* ----------------------------------------------------------------------------- + * Swig_rflag_search() + * + * This function searches for the class attribute 'attr' in the class + * 'n' or recursively in its bases. + * + * If you define SWIG_FAST_REC_SEARCH, the method will set the found + * 'attr' in the target class 'n'. If not, the method will set the + * 'noattr' one. This prevents of having to navigate the entire + * hierarchy tree everytime, so, it is an O(1) method... or something + * like that. However, it populates all the parsed classes with the + * 'attr' and/or 'noattr' attributes. + * + * If you undefine the SWIG_FAST_REC_SEARCH no attribute will be set + * while searching. This could be slower for large projects with very + * large hierarchy trees... or maybe not. But it will be cleaner. + * + * Maybe later a swig option can be added to switch at runtime. + * + * ----------------------------------------------------------------------------- */ + +/* #define SWIG_FAST_REC_SEARCH 1 */ +String *Swig_rflag_search(Node *n, const String *attr, const String *noattr) { + String *f = 0; + n = Swig_methodclass(n); + if (GetFlag(n, noattr)) { + return 0; + } + f = GetFlagAttr(n, attr); + if (f) { + return f; + } else { + List *bl = Getattr(n, "bases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + f = Swig_rflag_search(bi.item, attr, noattr); + if (f) { +#ifdef SWIG_FAST_REC_SEARCH + SetFlagAttr(n, attr, f); +#endif + return f; + } + } + } + } +#ifdef SWIG_FAST_REC_SEARCH + SetFlag(n, noattr); +#endif + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_unref_call() + * + * find the unref call, if any. + * ----------------------------------------------------------------------------- */ + +String *Swig_unref_call(Node *n) { + Node *cn = Swig_methodclass(n); + String *unref = Swig_rflag_search(cn, "feature:unref", "feature:nounref"); + if (unref) { + String *pname = Swig_cparm_name(0, 0); + unref = NewString(unref); + Replaceall(unref, "$this", pname); + Replaceall(unref, "$self", pname); + Delete(pname); + } + return unref; +} + +/* ----------------------------------------------------------------------------- + * Swig_ref_call() + * + * find the ref call, if any. + * ----------------------------------------------------------------------------- */ + +String *Swig_ref_call(Node *n, const String *lname) { + Node *cn = Swig_methodclass(n); + String *ref = Swig_rflag_search(cn, "feature:ref", "feature:noref"); + if (ref) { + ref = NewString(ref); + Replaceall(ref, "$this", lname); + Replaceall(ref, "$self", lname); + } + return ref; +} + +/* ----------------------------------------------------------------------------- + * Swig_cdestructor_call() + * + * Creates a string that calls a C destructor function. + * + * free((char *) arg0); + * ----------------------------------------------------------------------------- */ + +String *Swig_cdestructor_call(Node *n) { + String *unref = Swig_unref_call(n); + + if (unref) { + return unref; + } else { + String *pname = Swig_cparm_name(0, 0); + String *call = NewStringf("free((char *) %s);", pname); + Delete(pname); + return call; + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_cppdestructor_call() + * + * Creates a string that calls a C destructor function. + * + * delete arg1; + * ----------------------------------------------------------------------------- */ + +String *Swig_cppdestructor_call(Node *n) { + String *unref = Swig_unref_call(n); + if (unref) { + return unref; + } else { + String *pname = Swig_cparm_name(0, 0); + String *call = NewStringf("delete %s;", pname); + Delete(pname); + return call; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_cmemberset_call() + * + * Generates a string that sets the name of a member in a C++ class or C struct. + * + * arg0->name = arg1 + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cmemberset_call(const_String_or_char_ptr name, SwigType *type, String *self, int varcref) { + String *func; + String *pname0 = Swig_cparm_name(0, 0); + String *pname1 = Swig_cparm_name(0, 1); + func = NewStringEmpty(); + if (!self) + self = NewString("(this)->"); + else + self = NewString(self); + Replaceall(self, "this", pname0); + if (SwigType_type(type) != T_ARRAY) { + if (!Strstr(type, "enum $unnamed")) { + String *dref = Swig_wrapped_var_deref(type, pname1, varcref); + Printf(func, "if (%s) %s%s = %s", pname0, self, name, dref); + Delete(dref); + } else { + Printf(func, "if (%s && sizeof(int) == sizeof(%s%s)) *(int*)(void*)&(%s%s) = %s", pname0, self, name, self, name, pname1); + } + } + Delete(self); + Delete(pname0); + Delete(pname1); + return (func); +} + + +/* ----------------------------------------------------------------------------- + * Swig_cmemberget_call() + * + * Generates a string that sets the name of a member in a C++ class or C struct. + * + * arg0->name + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cmemberget_call(const_String_or_char_ptr name, SwigType *t, String *self, int varcref) { + String *func; + String *call; + String *pname0 = Swig_cparm_name(0, 0); + if (!self) + self = NewString("(this)->"); + else + self = NewString(self); + Replaceall(self, "this", pname0); + func = NewStringEmpty(); + call = Swig_wrapped_var_assign(t, "", varcref); + Printf(func, "%s (%s%s)", call, self, name); + Delete(self); + Delete(call); + Delete(pname0); + return func; +} + +/* ----------------------------------------------------------------------------- + * extension_code() + * + * Generates an extension function (a function defined in %extend) + * + * return_type function_name(parms) code + * + * ----------------------------------------------------------------------------- */ +static String *extension_code(const String *function_name, ParmList *parms, SwigType *return_type, const String *code, int cplusplus, const String *self) { + String *parms_str = cplusplus ? ParmList_str_defaultargs(parms) : ParmList_str(parms); + String *sig = NewStringf("%s(%s)", function_name, parms_str); + String *rt_sig = SwigType_str(return_type, sig); + String *body = NewStringf("SWIGINTERN %s", rt_sig); + Printv(body, code, "\n", NIL); + if (self) + Replaceall(body, "$self", self); + Delete(parms_str); + Delete(sig); + Delete(rt_sig); + return body; +} + +/* ----------------------------------------------------------------------------- + * Swig_add_extension_code() + * + * Generates an extension function (a function defined in %extend) and + * adds it to the "wrap:code" attribute of a node + * + * See also extension_code() + * + * ----------------------------------------------------------------------------- */ +int Swig_add_extension_code(Node *n, const String *function_name, ParmList *parms, SwigType *return_type, const String *code, int cplusplus, const String *self) { + String *body = extension_code(function_name, parms, return_type, code, cplusplus, self); + Setattr(n, "wrap:code", body); + Delete(body); + return SWIG_OK; +} + + +/* ----------------------------------------------------------------------------- + * Swig_MethodToFunction(Node *n) + * + * Converts a C++ method node to a function accessor function. + * ----------------------------------------------------------------------------- */ + +int Swig_MethodToFunction(Node *n, String *classname, int flags, SwigType *director_type, int is_director) { + String *name, *qualifier; + ParmList *parms; + SwigType *type; + Parm *p; + String *self = 0; + + /* If smart pointer, change self dereferencing */ + if (flags & CWRAP_SMART_POINTER) { + self = NewString("(*this)->"); + } + + /* If node is a member template expansion, we don't allow added code */ + if (Getattr(n, "templatetype")) + flags &= ~(CWRAP_EXTEND); + + name = Getattr(n, "name"); + qualifier = Getattr(n, "qualifier"); + parms = CopyParmList(nonvoid_parms(Getattr(n, "parms"))); + + type = NewString(classname); + if (qualifier) { + SwigType_push(type, qualifier); + } + SwigType_add_pointer(type); + p = NewParm(type, "self"); + Setattr(p, "self", "1"); + Setattr(p, "hidden","1"); + /* + Disable the 'this' ownership in 'self' to manage inplace + operations like: + + A& A::operator+=(int i) { ...; return *this;} + + Here the 'self' parameter ownership needs to be disabled since + there could be two objects sharing the same 'this' pointer: the + input and the result one. And worse, the pointer could be deleted + in one of the objects (input), leaving the other (output) with + just a seg. fault to happen. + + To avoid the previous problem, use + + %feature("self:disown") *::operator+=; + %feature("new") *::operator+=; + + These two lines just transfer the ownership of the 'this' pointer + from the input to the output wrapping object. + + This happens in python, but may also happens in other target + languages. + */ + if (GetFlag(n, "feature:self:disown")) { + Setattr(p, "wrap:disown", "1"); + } + set_nextSibling(p, parms); + Delete(type); + + /* Generate action code for the access */ + if (!(flags & CWRAP_EXTEND)) { + String *explicit_qualifier = 0; + String *call = 0; + String *cres = 0; + String *explicitcall_name = 0; + int pure_virtual = !(Cmp(Getattr(n, "storage"), "virtual")) && !(Cmp(Getattr(n, "value"), "0")); + + /* Call the explicit method rather than allow for a polymorphic call */ + if ((flags & CWRAP_DIRECTOR_TWO_CALLS) || (flags & CWRAP_DIRECTOR_ONE_CALL)) { + String *access = Getattr(n, "access"); + if (access && (Cmp(access, "protected") == 0)) { + /* If protected access (can only be if a director method) then call the extra public accessor method (language module must provide this) */ + String *explicit_qualifier_tmp = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), "qname")); + explicitcall_name = NewStringf("%sSwigPublic", name); + explicit_qualifier = NewStringf("SwigDirector_%s", explicit_qualifier_tmp); + Delete(explicit_qualifier_tmp); + } else { + explicit_qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), "qname")); + } + } + + call = Swig_cmethod_call(explicitcall_name ? explicitcall_name : name, p, self, explicit_qualifier, director_type); + cres = Swig_cresult(Getattr(n, "type"), "result", call); + + if (pure_virtual && is_director && (flags & CWRAP_DIRECTOR_TWO_CALLS)) { + String *qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), "qname")); + Delete(cres); + cres = NewStringf("Swig::DirectorPureVirtualException::raise(\"%s::%s\");", qualifier, name); + Delete(qualifier); + } + + if (flags & CWRAP_DIRECTOR_TWO_CALLS) { + /* Create two method calls, one to call the explicit method, the other a normal polymorphic function call */ + String *cres_both_calls = NewStringf(""); + String *call_extra = Swig_cmethod_call(name, p, self, 0, director_type); + String *cres_extra = Swig_cresult(Getattr(n, "type"), "result", call_extra); + Printv(cres_both_calls, "if (upcall) {\n", cres, "\n", "} else {", cres_extra, "\n}", NIL); + Setattr(n, "wrap:action", cres_both_calls); + Delete(cres_extra); + Delete(call_extra); + Delete(cres_both_calls); + } else { + Setattr(n, "wrap:action", cres); + } + + Delete(explicitcall_name); + Delete(call); + Delete(cres); + Delete(explicit_qualifier); + } else { + /* Methods with default arguments are wrapped with additional methods for each default argument, + * however, only one extra %extend method is generated. */ + + String *defaultargs = Getattr(n, "defaultargs"); + String *code = Getattr(n, "code"); + String *cname = Getattr(n, "classname") ? Getattr(n, "classname") : classname; + String *membername = Swig_name_member(cname, name); + String *mangled = Swig_name_mangle(membername); + int is_smart_pointer = flags & CWRAP_SMART_POINTER; + + type = Getattr(n, "type"); + + /* Check if the method is overloaded. If so, and it has code attached, we append an extra suffix + to avoid a name-clash in the generated wrappers. This allows overloaded methods to be defined + in C. */ + if (Getattr(n, "sym:overloaded") && code) { + Append(mangled, Getattr(defaultargs ? defaultargs : n, "sym:overname")); + } + + /* See if there is any code that we need to emit */ + if (!defaultargs && code && !is_smart_pointer) { + Swig_add_extension_code(n, mangled, p, type, code, cparse_cplusplus, "self"); + } + if (is_smart_pointer) { + int i = 0; + Parm *pp = p; + String *func = NewStringf("%s(", mangled); + String *cres; + + if (Cmp(Getattr(n, "storage"), "static") != 0) { + String *pname = Swig_cparm_name(pp, i); + String *ctname = SwigType_namestr(cname); + String *fadd = NewStringf("(%s*)(%s)->operator ->()", ctname, pname); + Append(func, fadd); + Delete(ctname); + Delete(fadd); + Delete(pname); + pp = nextSibling(pp); + if (pp) + Append(func, ","); + } else { + pp = nextSibling(pp); + } + ++i; + while (pp) { + SwigType *pt = Getattr(pp, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *pname = Swig_cparm_name(pp, i++); + String *rcaststr = SwigType_rcaststr(pt, pname); + Append(func, rcaststr); + Delete(rcaststr); + Delete(pname); + pp = nextSibling(pp); + if (pp) + Append(func, ","); + } + } + Append(func, ")"); + cres = Swig_cresult(Getattr(n, "type"), "result", func); + Setattr(n, "wrap:action", cres); + Delete(cres); + } else { + String *call = Swig_cfunction_call(mangled, p); + String *cres = Swig_cresult(Getattr(n, "type"), "result", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + + Delete(membername); + Delete(mangled); + } + Setattr(n, "parms", p); + Delete(p); + Delete(self); + Delete(parms); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_methodclass() + * + * This function returns the class node for a given method or class. + * ----------------------------------------------------------------------------- */ + +Node *Swig_methodclass(Node *n) { + Node *nodetype = nodeType(n); + if (Cmp(nodetype, "class") == 0) + return n; + return GetFlag(n, "feature:extend") ? parentNode(parentNode(n)) : parentNode(n); +} + +int Swig_directorclass(Node *n) { + Node *classNode = Swig_methodclass(n); + assert(classNode != 0); + return (Getattr(classNode, "vtable") != 0); +} + +Node *Swig_directormap(Node *module, String *type) { + int is_void = !Cmp(type, "void"); + if (!is_void && module) { + /* ?? follow the inheritance hierarchy? */ + + String *base = SwigType_base(type); + + Node *directormap = Getattr(module, "wrap:directormap"); + if (directormap) + return Getattr(directormap, base); + } + return 0; +} + + +/* ----------------------------------------------------------------------------- + * Swig_ConstructorToFunction() + * + * This function creates a C wrapper for a C constructor function. + * ----------------------------------------------------------------------------- */ + +int Swig_ConstructorToFunction(Node *n, String *classname, String *none_comparison, String *director_ctor, int cplus, int flags) { + ParmList *parms; + Parm *prefix_args; + Parm *p; + ParmList *directorparms; + SwigType *type; + Node *classNode; + int use_director; + + classNode = Swig_methodclass(n); + use_director = Swig_directorclass(n); + + parms = CopyParmList(nonvoid_parms(Getattr(n, "parms"))); + + /* Prepend the list of prefix_args (if any) */ + prefix_args = Getattr(n, "director:prefix_args"); + if (prefix_args != NIL) { + Parm *p2, *p3; + + directorparms = CopyParmList(prefix_args); + for (p = directorparms; nextSibling(p); p = nextSibling(p)); + for (p2 = parms; p2; p2 = nextSibling(p2)) { + p3 = CopyParm(p2); + set_nextSibling(p, p3); + Delete(p3); + p = p3; + } + } else + directorparms = parms; + + type = NewString(classname); + SwigType_add_pointer(type); + + if (flags & CWRAP_EXTEND) { + /* Constructors with default arguments are wrapped with additional constructor methods for each default argument, + * however, only one extra %extend method is generated. */ + String *call; + String *cres; + String *defaultargs = Getattr(n, "defaultargs"); + String *code = Getattr(n, "code"); + String *membername = Swig_name_construct(classname); + String *mangled = Swig_name_mangle(membername); + + /* Check if the constructor is overloaded. If so, and it has code attached, we append an extra suffix + to avoid a name-clash in the generated wrappers. This allows overloaded constructors to be defined + in C. */ + if (Getattr(n, "sym:overloaded") && code) { + Append(mangled, Getattr(defaultargs ? defaultargs : n, "sym:overname")); + } + + /* See if there is any code that we need to emit */ + if (!defaultargs && code) { + Swig_add_extension_code(n, mangled, parms, type, code, cparse_cplusplus, "self"); + } + + call = Swig_cfunction_call(mangled, parms); + cres = Swig_cresult(type, "result", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + Delete(membername); + Delete(mangled); + } else { + if (cplus) { + /* if a C++ director class exists, create it rather than the original class */ + if (use_director) { + Node *parent = Swig_methodclass(n); + int abstract = Getattr(parent, "abstract") != 0; + String *name = Getattr(parent, "sym:name"); + String *directorname = NewStringf("SwigDirector_%s", name); + String *action = NewStringEmpty(); + String *tmp_none_comparison = Copy(none_comparison); + String *director_call; + String *nodirector_call; + + Replaceall(tmp_none_comparison, "$arg", "arg1"); + + director_call = Swig_cppconstructor_director_call(directorname, directorparms); + nodirector_call = Swig_cppconstructor_nodirector_call(classname, parms); + + if (abstract) { + /* whether or not the abstract class has been subclassed in python, + * create a director instance (there's no way to create a normal + * instance). if any of the pure virtual methods haven't been + * implemented in the target language, calls to those methods will + * generate Swig::DirectorPureVirtualException exceptions. + */ + String *cres = Swig_cresult(type, "result", director_call); + Append(action, cres); + Delete(cres); + } else { + /* (scottm): The code for creating a new director is now a string + template that gets passed in via the director_ctor argument. + + $comparison : an 'if' comparison from none_comparison + $director_new: Call new for director class + $nondirector_new: Call new for non-director class + */ + String *cres; + Append(action, director_ctor); + Replaceall(action, "$comparison", tmp_none_comparison); + + cres = Swig_cresult(type, "result", director_call); + Replaceall(action, "$director_new", cres); + Delete(cres); + + cres = Swig_cresult(type, "result", nodirector_call); + Replaceall(action, "$nondirector_new", cres); + Delete(cres); + } + Setattr(n, "wrap:action", action); + Delete(tmp_none_comparison); + Delete(action); + Delete(directorname); + } else { + String *call = Swig_cppconstructor_call(classname, parms); + String *cres = Swig_cresult(type, "result", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + } + } else { + String *call = Swig_cconstructor_call(classname); + String *cres = Swig_cresult(type, "result", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + } + } + Setattr(n, "type", type); + Setattr(n, "parms", parms); + Delete(type); + if (directorparms != parms) + Delete(directorparms); + Delete(parms); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_DestructorToFunction() + * + * This function creates a C wrapper for a destructor function. + * ----------------------------------------------------------------------------- */ + +int Swig_DestructorToFunction(Node *n, String *classname, int cplus, int flags) { + SwigType *type; + Parm *p; + + type = NewString(classname); + SwigType_add_pointer(type); + p = NewParm(type, "self"); + Setattr(p, "self", "1"); + Setattr(p, "hidden", "1"); + Setattr(p, "wrap:disown", "1"); + Delete(type); + type = NewString("void"); + + if (flags & CWRAP_EXTEND) { + String *cres; + String *call; + String *membername, *mangled, *code; + membername = Swig_name_destroy(classname); + mangled = Swig_name_mangle(membername); + code = Getattr(n, "code"); + if (code) { + Swig_add_extension_code(n, mangled, p, type, code, cparse_cplusplus, "self"); + } + call = Swig_cfunction_call(mangled, p); + cres = NewStringf("%s;", call); + Setattr(n, "wrap:action", cres); + Delete(membername); + Delete(mangled); + Delete(call); + Delete(cres); + } else { + if (cplus) { + String *call = Swig_cppdestructor_call(n); + String *cres = NewStringf("%s", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } else { + String *call = Swig_cdestructor_call(n); + String *cres = NewStringf("%s", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + } + Setattr(n, "type", type); + Setattr(n, "parms", p); + Delete(type); + Delete(p); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_MembersetToFunction() + * + * This function creates a C wrapper for setting a structure member. + * ----------------------------------------------------------------------------- */ + +int Swig_MembersetToFunction(Node *n, String *classname, int flags, String **call) { + String *name; + ParmList *parms; + Parm *p; + SwigType *t; + SwigType *ty; + SwigType *type; + SwigType *void_type = NewString("void"); + String *membername; + String *mangled; + String *self = 0; + String *sname; + + int varcref = flags & CWRAP_NATURAL_VAR; + + if (flags & CWRAP_SMART_POINTER) { + self = NewString("(*this)->"); + } + if (flags & CWRAP_ALL_PROTECTED_ACCESS) { + self = NewStringf("darg->"); + } + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + + sname = Swig_name_set(name); + membername = Swig_name_member(classname, sname); + mangled = Swig_name_mangle(membername); + + t = NewString(classname); + SwigType_add_pointer(t); + parms = NewParm(t, "self"); + Setattr(parms, "self", "1"); + Setattr(parms, "hidden","1"); + Delete(t); + + ty = Swig_wrapped_member_var_type(type, varcref); + p = NewParm(ty, name); + Setattr(parms, "hidden", "1"); + set_nextSibling(parms, p); + + /* If the type is a pointer or reference. We mark it with a special wrap:disown attribute */ + if (SwigType_check_decl(type, "p.")) { + Setattr(p, "wrap:disown", "1"); + } + Delete(p); + + if (flags & CWRAP_EXTEND) { + String *cres; + String *code = Getattr(n, "code"); + if (code) { + /* I don't think this ever gets run - WSF */ + Swig_add_extension_code(n, mangled, parms, void_type, code, cparse_cplusplus, "self"); + } + *call = Swig_cfunction_call(mangled, parms); + cres = NewStringf("%s;", *call); + Setattr(n, "wrap:action", cres); + Delete(cres); + } else { + String *cres; + *call = Swig_cmemberset_call(name, type, self, varcref); + cres = NewStringf("%s;", *call); + Setattr(n, "wrap:action", cres); + Delete(cres); + } + Setattr(n, "type", void_type); + Setattr(n, "parms", parms); + Delete(parms); + Delete(ty); + Delete(void_type); + Delete(membername); + Delete(sname); + Delete(mangled); + Delete(self); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_MembergetToFunction() + * + * This function creates a C wrapper for getting a structure member. + * ----------------------------------------------------------------------------- */ + +int Swig_MembergetToFunction(Node *n, String *classname, int flags) { + String *name; + ParmList *parms; + SwigType *t; + SwigType *ty; + SwigType *type; + String *membername; + String *mangled; + String *self = 0; + String *gname; + + int varcref = flags & CWRAP_NATURAL_VAR; + + if (flags & CWRAP_SMART_POINTER) { + if (checkAttribute(n, "storage", "static")) { + Node *sn = Getattr(n, "cplus:staticbase"); + String *base = Getattr(sn, "name"); + self = NewStringf("%s::", base); + } else { + self = NewString("(*this)->"); + } + } + if (flags & CWRAP_ALL_PROTECTED_ACCESS) { + self = NewStringf("darg->"); + } + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + + gname = Swig_name_get(name); + membername = Swig_name_member(classname, gname); + mangled = Swig_name_mangle(membername); + + t = NewString(classname); + SwigType_add_pointer(t); + parms = NewParm(t, "self"); + Setattr(parms, "self", "1"); + Setattr(parms, "hidden","1"); + Delete(t); + + ty = Swig_wrapped_member_var_type(type, varcref); + if (flags & CWRAP_EXTEND) { + String *call; + String *cres; + + String *code = Getattr(n, "code"); + if (code) { + /* I don't think this ever gets run - WSF */ + Swig_add_extension_code(n, mangled, parms, ty, code, cparse_cplusplus, "self"); + } + call = Swig_cfunction_call(mangled, parms); + cres = Swig_cresult(ty, "result", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + } else { + String *call = Swig_cmemberget_call(name, type, self, varcref); + String *cres = Swig_cresult(ty, "result", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + Setattr(n, "type", ty); + Setattr(n, "parms", parms); + Delete(parms); + Delete(ty); + Delete(membername); + Delete(gname); + Delete(mangled); + + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_VarsetToFunction() + * + * This function creates a C wrapper for setting a global variable or static member + * variable. + * ----------------------------------------------------------------------------- */ + +int Swig_VarsetToFunction(Node *n, int flags) { + String *name, *nname; + ParmList *parms; + SwigType *type, *ty; + + int varcref = flags & CWRAP_NATURAL_VAR; + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + nname = SwigType_namestr(name); + ty = Swig_wrapped_var_type(type, varcref); + parms = NewParm(ty, name); + + if (flags & CWRAP_EXTEND) { + String *sname = Swig_name_set(name); + String *mangled = Swig_name_mangle(sname); + String *call = Swig_cfunction_call(mangled, parms); + String *cres = NewStringf("%s;", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + Delete(mangled); + Delete(sname); + } else { + if (!Strstr(type, "enum $unnamed")) { + String *pname = Swig_cparm_name(0, 0); + String *dref = Swig_wrapped_var_deref(type, pname, varcref); + String *call = NewStringf("%s = %s;", nname, dref); + Setattr(n, "wrap:action", call); + Delete(call); + Delete(dref); + Delete(pname); + } else { + String *pname = Swig_cparm_name(0, 0); + String *call = NewStringf("if (sizeof(int) == sizeof(%s)) *(int*)(void*)&(%s) = %s;", nname, nname, pname); + Setattr(n, "wrap:action", call); + Delete(pname); + Delete(call); + } + } + Setattr(n, "type", "void"); + Setattr(n, "parms", parms); + Delete(parms); + Delete(ty); + Delete(nname); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_VargetToFunction() + * + * This function creates a C wrapper for getting a global variable or static member + * variable. + * ----------------------------------------------------------------------------- */ + +int Swig_VargetToFunction(Node *n, int flags) { + String *cres, *call; + String *name; + SwigType *type; + SwigType *ty = 0; + + int varcref = flags & CWRAP_NATURAL_VAR; + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + ty = Swig_wrapped_var_type(type, varcref); + + if (flags & CWRAP_EXTEND) { + String *sname = Swig_name_get(name); + String *mangled = Swig_name_mangle(sname); + call = Swig_cfunction_call(mangled, 0); + cres = Swig_cresult(ty, "result", call); + Setattr(n, "wrap:action", cres); + Delete(mangled); + Delete(sname); + } else { + String *nname = SwigType_namestr(name); + call = Swig_wrapped_var_assign(type, nname, varcref); + cres = Swig_cresult(ty, "result", call); + Setattr(n, "wrap:action", cres); + Delete(nname); + } + + Setattr(n, "type", ty); + Delattr(n, "parms"); + Delete(cres); + Delete(call); + Delete(ty); + return SWIG_OK; +} diff --git a/Source/Swig/deprecate.c b/Source/Swig/deprecate.c new file mode 100644 index 0000000..475d2c6 --- /dev/null +++ b/Source/Swig/deprecate.c @@ -0,0 +1,105 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * deprecate.c + * + * The functions in this file are SWIG core functions that are deprecated + * or which do not fit in nicely with everything else. Generally this means + * that the function and/or API needs to be changed in some future release. + * ----------------------------------------------------------------------------- */ + +char cvsroot_deprecate_c[] = "$Id: parms.c 9630 2007-01-02 21:17:19Z beazley $"; + +#include "swig.h" + +/* --------------------------------------------------------------------- + * ParmList_is_compactdefargs() + * + * Returns 1 if the parameter list passed in is marked for compact argument + * handling (by the "compactdefargs" attribute). Otherwise returns 0. + * ---------------------------------------------------------------------- */ + +/* Discussion: + + "compactdefargs" is a property set by the Parser to indicate special + handling of default arguments. This property seems to be something that + is associated with functions and methods rather than low-level ParmList + objects. Therefore, I don't like the fact that this special purpose + feature is bolted onto the side of ParmList objects. + + Proposed solution: + + 1. "compactdefargs" should be a feature set on function/method nodes + instead of ParmList objects. For example, if you have a function, + you would check the function node to see if the parameters are + to be handled in this way. + + + Difficulties: + + 1. This is used by functions in cwrap.c and emit.cxx, none of which + are passed information about the function/method node. We might + have to change the API of those functions to make this work correctly. + For example: + + int emit_num_required(ParmList *parms) + + might become + + int emit_num_required(ParmList *parms, int compactargs) + +*/ + +int ParmList_is_compactdefargs(ParmList *p) { + int compactdefargs = 0; + + if (p) { + compactdefargs = Getattr(p, "compactdefargs") ? 1 : 0; + + /* The "compactdefargs" attribute should only be set on the first parameter in the list. + * However, sometimes an extra parameter is inserted at the beginning of the parameter list, + * so we check the 2nd parameter too. */ + if (!compactdefargs) { + Parm *nextparm = nextSibling(p); + compactdefargs = (nextparm && Getattr(nextparm, "compactdefargs")) ? 1 : 0; + } + } + + return compactdefargs; +} + +/* --------------------------------------------------------------------- + * ParmList_errorstr() + * + * Generate a prototype string suitable for use in error/warning messages. + * This function is aware of hidden parameters. + * ---------------------------------------------------------------------- */ + +/* Discussion. This function is used to generate error messages, but take + into account that there might be a hidden parameter. Although this involves + parameter lists, it really isn't a core feature of swigparm.h or parms.c. + This is because the "hidden" attribute of parameters is added elsewhere (cwrap.c). + + For now, this function is placed here because it doesn't really seem to fit in + with the parms.c interface. + +*/ + +String *ParmList_errorstr(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + if (Getattr(p,"hidden")) { + p = nextSibling(p); + } else { + String *pstr = SwigType_str(Getattr(p, "type"), 0); + Append(out, pstr); + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + } + return out; +} diff --git a/Source/Swig/error.c b/Source/Swig/error.c new file mode 100644 index 0000000..84520d9 --- /dev/null +++ b/Source/Swig/error.c @@ -0,0 +1,277 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * error.c + * + * Error handling functions. These are used to issue warnings and + * error messages. + * ----------------------------------------------------------------------------- */ + +char cvsroot_error_c[] = "$Id: error.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" +#include <stdarg.h> +#include <ctype.h> + +/* ----------------------------------------------------------------------------- + * Commentary on the warning filter. + * + * The warning filter is a string of numbers prefaced by (-) or (+) to + * indicate whether or not a warning message is displayed. For example: + * + * "-304-201-140+210+201" + * + * The filter string is scanned left to right and the first occurrence + * of a warning number is used to determine printing behavior. + * + * The same number may appear more than once in the string. For example, in the + * above string, "201" appears twice. This simply means that warning 201 + * was disabled after it was previously enabled. This may only be temporary + * setting--the first number may be removed later in which case the warning + * is reenabled. + * ----------------------------------------------------------------------------- */ + +#if defined(_WIN32) +# define DEFAULT_ERROR_MSG_FORMAT EMF_MICROSOFT +#else +# define DEFAULT_ERROR_MSG_FORMAT EMF_STANDARD +#endif +static ErrorMessageFormat msg_format = DEFAULT_ERROR_MSG_FORMAT; +static int silence = 0; /* Silent operation */ +static String *filter = 0; /* Warning filter */ +static int warnall = 0; +static int nwarning = 0; +static int nerrors = 0; + +static int init_fmt = 0; +static char wrn_wnum_fmt[64]; +static char wrn_nnum_fmt[64]; +static char err_line_fmt[64]; +static char err_eof_fmt[64]; + +static String *format_filename(const_String_or_char_ptr filename); + +/* ----------------------------------------------------------------------------- + * Swig_warning() + * + * Issue a warning message + * ----------------------------------------------------------------------------- */ + +void Swig_warning(int wnum, const_String_or_char_ptr filename, int line, const char *fmt, ...) { + String *out; + char *msg; + int wrn = 1; + va_list ap; + if (silence) + return; + if (!init_fmt) + Swig_error_msg_format(DEFAULT_ERROR_MSG_FORMAT); + + va_start(ap, fmt); + + out = NewStringEmpty(); + vPrintf(out, fmt, ap); + + msg = Char(out); + if (isdigit((unsigned char) *msg)) { + unsigned long result = strtoul(msg, &msg, 10); + if (msg != Char(out)) { + msg++; + wnum = result; + } + } + + /* Check in the warning filter */ + if (filter) { + char temp[32]; + char *c; + char *f = Char(filter); + sprintf(temp, "%d", wnum); + while (*f != '\0' && (c = strstr(f, temp))) { + if (*(c - 1) == '-') { + wrn = 0; /* Warning disabled */ + break; + } + if (*(c - 1) == '+') { + wrn = 1; /* Warning enabled */ + break; + } + f += strlen(temp); + } + } + if (warnall || wrn) { + String *formatted_filename = format_filename(filename); + if (wnum) { + Printf(stderr, wrn_wnum_fmt, formatted_filename, line, wnum); + } else { + Printf(stderr, wrn_nnum_fmt, formatted_filename, line); + } + Printf(stderr, "%s", msg); + nwarning++; + Delete(formatted_filename); + } + Delete(out); + va_end(ap); +} + +/* ----------------------------------------------------------------------------- + * Swig_error() + * + * Issue an error message + * ----------------------------------------------------------------------------- */ + +void Swig_error(const_String_or_char_ptr filename, int line, const char *fmt, ...) { + va_list ap; + String *formatted_filename = NULL; + + if (silence) + return; + if (!init_fmt) + Swig_error_msg_format(DEFAULT_ERROR_MSG_FORMAT); + + va_start(ap, fmt); + formatted_filename = format_filename(filename); + if (line > 0) { + Printf(stderr, err_line_fmt, formatted_filename, line); + } else { + Printf(stderr, err_eof_fmt, formatted_filename); + } + vPrintf(stderr, fmt, ap); + va_end(ap); + nerrors++; + Delete(formatted_filename); +} + +/* ----------------------------------------------------------------------------- + * Swig_error_count() + * + * Returns number of errors received. + * ----------------------------------------------------------------------------- */ + +int Swig_error_count(void) { + return nerrors; +} + +/* ----------------------------------------------------------------------------- + * Swig_error_silent() + * + * Set silent flag + * ----------------------------------------------------------------------------- */ + +void Swig_error_silent(int s) { + silence = s; +} + + +/* ----------------------------------------------------------------------------- + * Swig_warnfilter() + * + * Takes a comma separate list of warning numbers and puts in the filter. + * ----------------------------------------------------------------------------- */ + +void Swig_warnfilter(const_String_or_char_ptr wlist, int add) { + char *c; + char *cw; + String *s; + if (!filter) + filter = NewStringEmpty(); + + s = NewString(""); + Clear(s); + cw = Char(wlist); + while (*cw != '\0') { + if (*cw != ' ') { + Putc(*cw, s); + } + ++cw; + } + c = Char(s); + c = strtok(c, ", "); + while (c) { + if (isdigit((int) *c) || (*c == '+') || (*c == '-')) { + /* Even if c is a digit, the rest of the string might not be, eg in the case of typemap + * warnings (a bit odd really), eg: %warnfilter(SWIGWARN_TYPEMAP_CHARLEAK_MSG) */ + if (add) { + Insert(filter, 0, c); + if (isdigit((int) *c)) { + Insert(filter, 0, "-"); + } + } else { + char *temp = (char *)malloc(sizeof(char)*strlen(c) + 2); + if (isdigit((int) *c)) { + sprintf(temp, "-%s", c); + } else { + strcpy(temp, c); + } + Replace(filter, temp, "", DOH_REPLACE_FIRST); + free(temp); + } + } + c = strtok(NULL, ", "); + } + Delete(s); +} + +void Swig_warnall(void) { + warnall = 1; +} + + +/* ----------------------------------------------------------------------------- + * Swig_warn_count() + * + * Return the number of warnings + * ----------------------------------------------------------------------------- */ + +int Swig_warn_count(void) { + return nwarning; +} + +/* ----------------------------------------------------------------------------- + * Swig_error_msg_format() + * + * Set the type of error/warning message display + * ----------------------------------------------------------------------------- */ + +void Swig_error_msg_format(ErrorMessageFormat format) { + const char *error = "Error"; + const char *warning = "Warning"; + + const char *fmt_eof = 0; + const char *fmt_line = 0; + + /* here 'format' could be directly a string instead of an enum, but + by now a switch is used to translated into one. */ + switch (format) { + case EMF_MICROSOFT: + fmt_line = "%s(%d)"; + fmt_eof = "%s(999999)"; /* Is there a special character for EOF? Just use a large number. */ + break; + case EMF_STANDARD: + default: + fmt_line = "%s:%d"; + fmt_eof = "%s:EOF"; + } + + sprintf(wrn_wnum_fmt, "%s: %s(%%d): ", fmt_line, warning); + sprintf(wrn_nnum_fmt, "%s: %s: ", fmt_line, warning); + sprintf(err_line_fmt, "%s: %s: ", fmt_line, error); + sprintf(err_eof_fmt, "%s: %s: ", fmt_eof, error); + + msg_format = format; + init_fmt = 1; +} + +/* ----------------------------------------------------------------------------- + * format_filename() + * + * Remove double backslashes in Windows filename paths for display + * ----------------------------------------------------------------------------- */ +static String *format_filename(const_String_or_char_ptr filename) { + String *formatted_filename = NewString(filename); +#if defined(_WIN32) + Replaceall(formatted_filename, "\\\\", "\\"); +#endif + return formatted_filename; +} diff --git a/Source/Swig/fragment.c b/Source/Swig/fragment.c new file mode 100644 index 0000000..3730c71 --- /dev/null +++ b/Source/Swig/fragment.c @@ -0,0 +1,181 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * fragment.c + * + * This file manages named code fragments. Code fragments are typically + * used to hold helper-code that may or may not be included in the wrapper + * file (depending on what features are actually used in the interface). + * + * By using fragments, it's possible to greatly reduce the amount of + * wrapper code and to generate cleaner wrapper files. + * ----------------------------------------------------------------------------- */ + +char cvsroot_fragment_c[] = "$Id: fragment.c 9632 2007-01-03 20:58:19Z beazley $"; + +#include "swig.h" +#include "swigwarn.h" + +static Hash *fragments = 0; +static Hash *looking_fragments = 0; +static int debug = 0; + + +/* ----------------------------------------------------------------------------- + * Swig_fragment_register() + * + * Add a fragment. Use the original Node*, so, if something needs to be + * changed, lang.cxx doesn't nedd to be touched again. + * ----------------------------------------------------------------------------- */ + +void Swig_fragment_register(Node *fragment) { + if (Getattr(fragment, "emitonly")) { + Swig_fragment_emit(fragment); + return; + } else { + String *name = Copy(Getattr(fragment, "value")); + String *type = Getattr(fragment, "type"); + if (type) { + SwigType *rtype = SwigType_typedef_resolve_all(type); + String *mangle = Swig_string_mangle(type); + Append(name, mangle); + Delete(mangle); + Delete(rtype); + if (debug) + Printf(stdout, "register fragment %s %s\n", name, type); + } + if (!fragments) { + fragments = NewHash(); + } + if (!Getattr(fragments, name)) { + String *section = Copy(Getattr(fragment, "section")); + String *ccode = Copy(Getattr(fragment, "code")); + Hash *kwargs = Getattr(fragment, "kwargs"); + Setmeta(ccode, "section", section); + if (kwargs) { + Setmeta(ccode, "kwargs", kwargs); + } + Setattr(fragments, name, ccode); + if (debug) + Printf(stdout, "registering fragment %s %s\n", name, section); + Delete(section); + Delete(ccode); + } + Delete(name); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_fragment_emit() + * + * Emit a fragment + * ----------------------------------------------------------------------------- */ + +static +char *char_index(char *str, char c) { + while (*str && (c != *str)) + ++str; + return (c == *str) ? str : 0; +} + +void Swig_fragment_emit(Node *n) { + String *code; + char *pc, *tok; + String *t; + String *mangle = 0; + String *name = 0; + String *type = 0; + + if (!fragments) { + Swig_warning(WARN_FRAGMENT_NOT_FOUND, Getfile(n), Getline(n), "Fragment '%s' not found.\n", name); + return; + } + + + name = Getattr(n, "value"); + if (!name) { + name = n; + } + type = Getattr(n, "type"); + if (type) { + mangle = Swig_string_mangle(type); + } + + if (debug) + Printf(stdout, "looking fragment %s %s\n", name, type); + t = Copy(name); + tok = Char(t); + pc = char_index(tok, ','); + if (pc) + *pc = 0; + while (tok) { + String *name = NewString(tok); + if (mangle) + Append(name, mangle); + if (looking_fragments && Getattr(looking_fragments, name)) { + return; + } + code = Getattr(fragments, name); + if (debug) + Printf(stdout, "looking subfragment %s\n", name); + if (code && (Strcmp(code, "ignore") != 0)) { + String *section = Getmeta(code, "section"); + Hash *nn = Getmeta(code, "kwargs"); + if (!looking_fragments) + looking_fragments = NewHash(); + Setattr(looking_fragments, name, "1"); + while (nn) { + if (Equal(Getattr(nn, "name"), "fragment")) { + if (debug) + Printf(stdout, "emitting fragment %s %s\n", nn, type); + Setfile(nn, Getfile(n)); + Setline(nn, Getline(n)); + Swig_fragment_emit(nn); + } + nn = nextSibling(nn); + } + if (section) { + File *f = Swig_filebyname(section); + if (!f) { + Swig_error(Getfile(code), Getline(code), "Bad section '%s' for code fragment '%s'\n", section, name); + } else { + if (debug) + Printf(stdout, "emitting subfragment %s %s\n", name, section); + if (debug) + Printf(f, "/* begin fragment %s */\n", name); + Printf(f, "%s\n", code); + if (debug) + Printf(f, "/* end fragment %s */\n\n", name); + Setattr(fragments, name, "ignore"); + Delattr(looking_fragments, name); + } + } + } else if (!code && type) { + SwigType *rtype = SwigType_typedef_resolve_all(type); + if (!Equal(type, rtype)) { + String *name = Copy(Getattr(n, "value")); + String *mangle = Swig_string_mangle(type); + Append(name, mangle); + Setfile(name, Getfile(n)); + Setline(name, Getline(n)); + Swig_fragment_emit(name); + Delete(mangle); + Delete(name); + } + Delete(rtype); + } + + if (!code) { + Swig_warning(WARN_FRAGMENT_NOT_FOUND, Getfile(n), Getline(n), "Fragment '%s' not found.\n", name); + } + tok = pc ? pc + 1 : 0; + if (tok) { + pc = char_index(tok, ','); + if (pc) + *pc = 0; + } + Delete(name); + } + Delete(t); +} diff --git a/Source/Swig/getopt.c b/Source/Swig/getopt.c new file mode 100644 index 0000000..6039905 --- /dev/null +++ b/Source/Swig/getopt.c @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * getopt.c + * + * Handles the parsing of command line options. This is particularly nasty + * compared to other utilities given that command line options can potentially + * be read by many different modules within SWIG. Thus, in order to make sure + * there are no unrecognized options, each module is required to "mark" + * the options that it uses. Afterwards, we can make a quick scan to make + * sure there are no unmarked options. + * + * TODO: + * - This module needs to be modified so that it doesn't call exit(). + * Should have cleaner error handling in general. + * ----------------------------------------------------------------------------- */ + +char cvsroot_getopt_c[] = "$Id: getopt.c 10926 2008-11-11 22:17:40Z wsfulton $"; + +#include "swig.h" + +static char **args; +static int numargs; +static int *marked; + +/* ----------------------------------------------------------------------------- + * Swig_init_args() + * + * Initialize the argument list handler. + * ----------------------------------------------------------------------------- */ + +void Swig_init_args(int argc, char **argv) { + int i; + assert(argc > 0); + assert(argv); + + numargs = argc; + args = argv; + marked = (int *) malloc(numargs * sizeof(int)); + for (i = 0; i < argc; i++) { + marked[i] = 0; + } + marked[0] = 1; +} + +/* ----------------------------------------------------------------------------- + * Swig_mark_arg() + * + * Marks an argument as being parsed. + * ----------------------------------------------------------------------------- */ + +void Swig_mark_arg(int n) { + assert(marked); + assert((n >= 0) && (n < numargs)); + marked[n] = 1; +} + +/* ----------------------------------------------------------------------------- + * Swig_check_marked() + * + * Checks to see if argument has been picked up. + * ----------------------------------------------------------------------------- */ + +int Swig_check_marked(int n) { + assert((n >= 0) && (n < numargs)); + return marked[n]; +} + +/* ----------------------------------------------------------------------------- + * Swig_check_options() + * + * Checkers for unprocessed command line options and errors. + * ----------------------------------------------------------------------------- */ + +void Swig_check_options(int check_input) { + int error = 0; + int i; + int max = check_input ? numargs - 1 : numargs; + assert(marked); + for (i = 1; i < max; i++) { + if (!marked[i]) { + Printf(stderr, "swig error : Unrecognized option %s\n", args[i]); + error = 1; + } + } + if (error) { + Printf(stderr, "Use 'swig -help' for available options.\n"); + exit(1); + } + if (check_input && marked[numargs - 1]) { + Printf(stderr, "Must specify an input file. Use -help for available options.\n"); + exit(1); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_arg_error() + * + * Generates a generic error message and exits. + * ----------------------------------------------------------------------------- */ + +void Swig_arg_error(void) { + Printf(stderr, "SWIG : Unable to parse command line options.\n"); + Printf(stderr, "Use 'swig -help' for available options.\n"); + exit(1); +} diff --git a/Source/Swig/include.c b/Source/Swig/include.c new file mode 100644 index 0000000..724b191 --- /dev/null +++ b/Source/Swig/include.c @@ -0,0 +1,383 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * include.c + * + * The functions in this file are used to manage files in the SWIG library. + * General purpose functions for opening, including, and retrieving pathnames + * are provided. + * ----------------------------------------------------------------------------- */ + +char cvsroot_include_c[] = "$Id: include.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" + +static List *directories = 0; /* List of include directories */ +static String *lastpath = 0; /* Last file that was included */ +static List *pdirectories = 0; /* List of pushed directories */ +static int dopush = 1; /* Whether to push directories */ + +/* This functions determine whether to push/pop dirs in the preprocessor */ +void Swig_set_push_dir(int push) { + dopush = push; +} + +int Swig_get_push_dir(void) { + return dopush; +} + +/* ----------------------------------------------------------------------------- + * Swig_add_directory() + * + * Adds a directory to the SWIG search path. + * ----------------------------------------------------------------------------- */ + +List *Swig_add_directory(const_String_or_char_ptr dirname) { + String *adirname; + if (!directories) + directories = NewList(); + assert(directories); + if (dirname) { + adirname = NewString(dirname); + Append(directories,adirname); + Delete(adirname); + } + return directories; +} + +/* ----------------------------------------------------------------------------- + * Swig_push_directory() + * + * Inserts a directory at the front of the SWIG search path. This is used by + * the preprocessor to grab files in the same directory as other included files. + * ----------------------------------------------------------------------------- */ + +void Swig_push_directory(const_String_or_char_ptr dirname) { + String *pdirname; + if (!Swig_get_push_dir()) + return; + if (!pdirectories) + pdirectories = NewList(); + assert(pdirectories); + pdirname = NewString(dirname); + assert(pdirname); + Insert(pdirectories,0,pdirname); + Delete(pdirname); +} + +/* ----------------------------------------------------------------------------- + * Swig_pop_directory() + * + * Pops a directory off the front of the SWIG search path. This is used by + * the preprocessor. + * ----------------------------------------------------------------------------- */ + +void Swig_pop_directory(void) { + if (!Swig_get_push_dir()) + return; + if (!pdirectories) + return; + Delitem(pdirectories, 0); +} + +/* ----------------------------------------------------------------------------- + * Swig_last_file() + * + * Returns the full pathname of the last file opened. + * ----------------------------------------------------------------------------- */ + +String *Swig_last_file(void) { + assert(lastpath); + return lastpath; +} + +/* ----------------------------------------------------------------------------- + * Swig_search_path_any() + * + * Returns a list of the current search paths. + * ----------------------------------------------------------------------------- */ + +static List *Swig_search_path_any(int syspath) { + String *filename; + List *slist; + int i, ilen; + + slist = NewList(); + assert(slist); + filename = NewStringEmpty(); + assert(filename); +#ifdef MACSWIG + Printf(filename, "%s", SWIG_FILE_DELIMITER); +#else + Printf(filename, ".%s", SWIG_FILE_DELIMITER); +#endif + Append(slist, filename); + Delete(filename); + + /* If there are any pushed directories. Add them first */ + if (pdirectories) { + ilen = Len(pdirectories); + for (i = 0; i < ilen; i++) { + filename = NewString(Getitem(pdirectories,i)); + Append(filename,SWIG_FILE_DELIMITER); + Append(slist,filename); + Delete(filename); + } + } + /* Add system directories next */ + ilen = Len(directories); + for (i = 0; i < ilen; i++) { + filename = NewString(Getitem(directories,i)); + Append(filename,SWIG_FILE_DELIMITER); + if (syspath) { + /* If doing a system include, put the system directories first */ + Insert(slist,i,filename); + } else { + /* Otherwise, just put the system directories after the pushed directories (if any) */ + Append(slist,filename); + } + Delete(filename); + } + return slist; +} + +List *Swig_search_path() { + return Swig_search_path_any(0); +} + + + +/* ----------------------------------------------------------------------------- + * Swig_open() + * + * open a file, optionally looking for it in the include path. Returns an open + * FILE * on success. + * ----------------------------------------------------------------------------- */ + +static FILE *Swig_open_file(const_String_or_char_ptr name, int sysfile, int use_include_path) { + FILE *f; + String *filename; + List *spath = 0; + char *cname; + int i, ilen; + + if (!directories) + directories = NewList(); + assert(directories); + + cname = Char(name); + filename = NewString(cname); + assert(filename); + f = fopen(Char(filename), "r"); + if (!f && use_include_path) { + spath = Swig_search_path_any(sysfile); + ilen = Len(spath); + for (i = 0; i < ilen; i++) { + Clear(filename); + Printf(filename, "%s%s", Getitem(spath, i), cname); + f = fopen(Char(filename), "r"); + if (f) + break; + } + Delete(spath); + } + if (f) { + Delete(lastpath); + lastpath = Swig_filename_escape(filename); + } + Delete(filename); + return f; +} + +/* Open a file - searching the include paths to find it */ +FILE *Swig_include_open(const_String_or_char_ptr name) { + return Swig_open_file(name, 0, 1); +} + +/* Open a file - does not use include paths to find it */ +FILE *Swig_open(const_String_or_char_ptr name) { + return Swig_open_file(name, 0, 0); +} + + + +/* ----------------------------------------------------------------------------- + * Swig_read_file() + * + * Reads data from an open FILE * and returns it as a string. + * ----------------------------------------------------------------------------- */ + +String *Swig_read_file(FILE *f) { + int len; + char buffer[4096]; + String *str = NewStringEmpty(); + + assert(str); + while (fgets(buffer, 4095, f)) { + Append(str, buffer); + } + len = Len(str); + if (len) { + char *cstr = Char(str); + if (cstr[len - 1] != '\n') { + Append(str, "\n"); + } + } + return str; +} + +/* ----------------------------------------------------------------------------- + * Swig_include() + * + * Opens a file and returns it as a string. + * ----------------------------------------------------------------------------- */ + +static String *Swig_include_any(const_String_or_char_ptr name, int sysfile) { + FILE *f; + String *str; + String *file; + + f = Swig_open_file(name, sysfile, 1); + if (!f) + return 0; + str = Swig_read_file(f); + fclose(f); + Seek(str, 0, SEEK_SET); + file = Copy(lastpath); + Setfile(str, file); + Delete(file); + Setline(str, 1); + return str; +} + +String *Swig_include(const_String_or_char_ptr name) { + return Swig_include_any(name, 0); +} + +String *Swig_include_sys(const_String_or_char_ptr name) { + return Swig_include_any(name, 1); +} + +/* ----------------------------------------------------------------------------- + * Swig_insert_file() + * + * Copies the contents of a file into another file + * ----------------------------------------------------------------------------- */ + +int Swig_insert_file(const_String_or_char_ptr filename, File *outfile) { + char buffer[4096]; + int nbytes; + FILE *f = Swig_include_open(filename); + + if (!f) + return -1; + while ((nbytes = Read(f, buffer, 4096)) > 0) { + Write(outfile, buffer, nbytes); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_register_filebyname() + * + * Register a "named" file with the core. Named files can become targets + * for %insert directives and other SWIG operations. This function takes + * the place of the f_header, f_wrapper, f_init, and other global variables + * in SWIG1.1 + * ----------------------------------------------------------------------------- */ + +static Hash *named_files = 0; + +void Swig_register_filebyname(const_String_or_char_ptr filename, File *outfile) { + if (!named_files) + named_files = NewHash(); + Setattr(named_files, filename, outfile); +} + +/* ----------------------------------------------------------------------------- + * Swig_filebyname() + * + * Get a named file + * ----------------------------------------------------------------------------- */ + +File *Swig_filebyname(const_String_or_char_ptr filename) { + if (!named_files) + return 0; + return Getattr(named_files, filename); +} + +/* ----------------------------------------------------------------------------- + * Swig_file_suffix() + * + * Returns the suffix of a file + * ----------------------------------------------------------------------------- */ + +char *Swig_file_suffix(const_String_or_char_ptr filename) { + char *d; + char *c = Char(filename); + int len = Len(filename); + if (strlen(c)) { + d = c + len - 1; + while (d != c) { + if (*d == '.') + return d; + d--; + } + return c + len; + } + return c; +} + +/* ----------------------------------------------------------------------------- + * Swig_file_basename() + * + * Returns the filename with no suffix attached. + * ----------------------------------------------------------------------------- */ + +char *Swig_file_basename(const_String_or_char_ptr filename) { + static char tmp[1024]; + char *c; + strcpy(tmp, Char(filename)); + c = Swig_file_suffix(tmp); + *c = 0; + return tmp; +} + +/* ----------------------------------------------------------------------------- + * Swig_file_filename() + * + * Return the file with any leading path stripped off + * ----------------------------------------------------------------------------- */ +char *Swig_file_filename(const_String_or_char_ptr filename) { + static char tmp[1024]; + const char *delim = SWIG_FILE_DELIMITER; + char *c; + + strcpy(tmp, Char(filename)); + c = strrchr(tmp, *delim); + if (c) + return c + 1; + else + return tmp; +} + +/* ----------------------------------------------------------------------------- + * Swig_file_dirname() + * + * Return the name of the directory associated with a file + * ----------------------------------------------------------------------------- */ +char *Swig_file_dirname(const_String_or_char_ptr filename) { + static char tmp[1024]; + const char *delim = SWIG_FILE_DELIMITER; + char *c; + strcpy(tmp, Char(filename)); + if (!strstr(tmp, delim)) { + return ""; + } + c = tmp + strlen(tmp) - 1; + while (*c != *delim) + c--; + *(++c) = 0; + return tmp; +} diff --git a/Source/Swig/misc.c b/Source/Swig/misc.c new file mode 100644 index 0000000..ce4e50c --- /dev/null +++ b/Source/Swig/misc.c @@ -0,0 +1,1156 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * misc.c + * + * Miscellaneous functions that don't really fit anywhere else. + * ----------------------------------------------------------------------------- */ + +char cvsroot_misc_c[] = "$Id: misc.c 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swig.h" +#include <errno.h> +#include <ctype.h> +#include <limits.h> + +static char *fake_version = 0; + +/* ----------------------------------------------------------------------------- + * Swig_copy_string() + * + * Duplicate a NULL-terminate string given as a char *. + * ----------------------------------------------------------------------------- */ + +char *Swig_copy_string(const char *s) { + char *c = 0; + if (s) { + c = (char *) malloc(strlen(s) + 1); + strcpy(c, s); + } + return c; +} + +/* ----------------------------------------------------------------------------- + * Swig_set_fakeversion() + * + * Version string override + * ----------------------------------------------------------------------------- */ + +void Swig_set_fakeversion(const char *version) { + fake_version = Swig_copy_string(version); +} + +/* ----------------------------------------------------------------------------- + * Swig_package_version() + * + * Return the package string containing the version number + * ----------------------------------------------------------------------------- */ + +const char *Swig_package_version(void) { + return fake_version ? fake_version : PACKAGE_VERSION; +} + +/* ----------------------------------------------------------------------------- + * Swig_banner() + * + * Emits the SWIG identifying banner for the C/C++ wrapper file. + * ----------------------------------------------------------------------------- */ + +void Swig_banner(File *f) { + Printf(f, "/* ----------------------------------------------------------------------------\n\ + * This file was automatically generated by SWIG (http://www.swig.org).\n\ + * Version %s\n\ + * \n\ + * This file is not intended to be easily readable and contains a number of \n\ + * coding conventions designed to improve portability and efficiency. Do not make\n\ + * changes to this file unless you know what you are doing--modify the SWIG \n\ + * interface file instead. \n", Swig_package_version()); + /* String too long for ISO compliance */ + Printf(f, " * ----------------------------------------------------------------------------- */\n"); + +} + +/* ----------------------------------------------------------------------------- + * Swig_banner_target_lang() + * + * Emits a SWIG identifying banner in the target language + * ----------------------------------------------------------------------------- */ + +void Swig_banner_target_lang(File *f, const_String_or_char_ptr commentchar) { + Printf(f, "%s This file was automatically generated by SWIG (http://www.swig.org).\n", commentchar); + Printf(f, "%s Version %s\n", commentchar, Swig_package_version()); + Printf(f, "%s\n", commentchar); + Printf(f, "%s Do not make changes to this file unless you know what you are doing--modify\n", commentchar); + Printf(f, "%s the SWIG interface file instead.\n", commentchar); +} + +/* ----------------------------------------------------------------------------- + * Swig_strip_c_comments() + * + * Return a new string with C comments stripped from the input string. Null is + * returned if there aren't any. + * ----------------------------------------------------------------------------- */ + +String *Swig_strip_c_comments(const String *s) { + const char *c = Char(s); + const char *comment_begin = 0; + const char *comment_end = 0; + String *stripped = 0; + + while (*c) { + if (!comment_begin && *c == '/') { + ++c; + if (!*c) + break; + if (*c == '*') + comment_begin = c-1; + } else if (comment_begin && !comment_end && *c == '*') { + ++c; + if (*c == '/') + comment_end = c; + break; + } + ++c; + } + + if (comment_begin && comment_end) { + int size = comment_begin - Char(s); + String *stripmore = 0; + stripped = NewStringWithSize(s, size); + Printv(stripped, comment_end + 1, NIL); + do { + stripmore = Swig_strip_c_comments(stripped); + if (stripmore) { + Delete(stripped); + stripped = stripmore; + } + } while (stripmore); + } + return stripped; +} + + +/* ----------------------------------------------------------------------------- + * Swig_filename_correct() + * + * Corrects filenames on non-unix systems + * ----------------------------------------------------------------------------- */ + +void Swig_filename_correct(String *filename) { + (void)filename; +#if defined(_WIN32) || defined(MACSWIG) + /* accept Unix path separator on non-Unix systems */ + Replaceall(filename, "/", SWIG_FILE_DELIMITER); +#endif +#if defined(__CYGWIN__) + /* accept Windows path separator in addition to Unix path separator */ + Replaceall(filename, "\\", SWIG_FILE_DELIMITER); +#endif +} + +/* ----------------------------------------------------------------------------- + * Swig_filename_escape() + * + * Escapes backslashes in filename - for Windows + * ----------------------------------------------------------------------------- */ + +String *Swig_filename_escape(String *filename) { + String *adjusted_filename = Copy(filename); +#if defined(_WIN32) /* Note not on Cygwin else filename is displayed with double '/' */ + Replaceall(adjusted_filename, "\\\\", "\\"); /* remove double '\' in case any already present */ + Replaceall(adjusted_filename, "\\", "\\\\"); +#endif + return adjusted_filename; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_escape() + * + * Takes a string object and produces a string with escape codes added to it. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_escape(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + while ((c = Getc(s)) != EOF) { + if (c == '\n') { + Printf(ns, "\\n"); + } else if (c == '\r') { + Printf(ns, "\\r"); + } else if (c == '\t') { + Printf(ns, "\\t"); + } else if (c == '\\') { + Printf(ns, "\\\\"); + } else if (c == '\'') { + Printf(ns, "\\'"); + } else if (c == '\"') { + Printf(ns, "\\\""); + } else if (c == ' ') { + Putc(c, ns); + } else if (!isgraph(c)) { + if (c < 0) + c += UCHAR_MAX + 1; + Printf(ns, "\\%o", c); + } else { + Putc(c, ns); + } + } + return ns; +} + + +/* ----------------------------------------------------------------------------- + * Swig_string_upper() + * + * Takes a string object and returns a copy that is uppercase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_upper(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + Putc(toupper(c), ns); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_lower() + * + * Takes a string object and returns a copy that is lowercase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_lower(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + Putc(tolower(c), ns); + } + return ns; +} + + +/* ----------------------------------------------------------------------------- + * Swig_string_title() + * + * Takes a string object and returns a copy that is lowercase with first letter + * capitalized + * ----------------------------------------------------------------------------- */ + +String *Swig_string_title(String *s) { + String *ns; + int first = 1; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + Putc(first ? toupper(c) : tolower(c), ns); + first = 0; + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_ccase() + * + * Takes a string object and returns a copy that is lowercase with the first + * letter capitalized and the one following '_', which are removed. + * + * camel_case -> CamelCase + * camelCase -> CamelCase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_ccase(String *s) { + String *ns; + int first = 1; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + if (c == '_') { + first = 1; + continue; + } + Putc(first ? toupper(c) : c, ns); + first = 0; + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_lccase() + * + * Takes a string object and returns a copy with the character after + * each '_' capitalised, and the '_' removed. The first character is + * also forced to lowercase. + * + * camel_case -> camelCase + * CamelCase -> camelCase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_lccase(String *s) { + String *ns; + int first = 1; + int after_underscore = 0; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + if (c == '_') { + after_underscore = 1; + continue; + } + if (first) { + Putc(tolower(c), ns); + first = 0; + } else { + Putc(after_underscore ? toupper(c) : c, ns); + } + after_underscore = 0; + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_ucase() + * + * This is the reverse case of ccase, ie + * + * CamelCase -> camel_case + * get2D -> get_2d + * asFloat2 -> as_float2 + * ----------------------------------------------------------------------------- */ + +String *Swig_string_ucase(String *s) { + String *ns; + int c; + int lastC = 0; + int nextC = 0; + int underscore = 0; + ns = NewStringEmpty(); + + /* We insert a underscore when: + 1. Lower case char followed by upper case char + getFoo > get_foo; getFOo > get_foo; GETFOO > getfoo + 2. Number proceded by char and not end of string + get2D > get_2d; get22D > get_22d; GET2D > get_2d + but: + asFloat2 > as_float2 + */ + + Seek(s, 0, SEEK_SET); + + while ((c = Getc(s)) != EOF) { + nextC = Getc(s); Ungetc(nextC, s); + if (isdigit(c) && isalpha(lastC) && nextC != EOF) + underscore = 1; + else if (isupper(c) && isalpha(lastC) && !isupper(lastC)) + underscore = 1; + + lastC = c; + + if (underscore) { + Putc('_', ns); + underscore = 0; + } + + Putc(tolower(c), ns); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_first_upper() + * + * Make the first character in the string uppercase, leave all the + * rest the same. This is used by the Ruby module to provide backwards + * compatibility with the old way of naming classes and constants. For + * more info see the Ruby documentation. + * + * firstUpper -> FirstUpper + * ----------------------------------------------------------------------------- */ + +String *Swig_string_first_upper(String *s) { + String *ns = NewStringEmpty(); + char *cs = Char(s); + if (cs && cs[0] != 0) { + Putc(toupper((int)cs[0]), ns); + Append(ns, cs + 1); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_first_lower() + * + * Make the first character in the string lowercase, leave all the + * rest the same. This is used by the Ruby module to provide backwards + * compatibility with the old way of naming classes and constants. For + * more info see the Ruby documentation. + * + * firstLower -> FirstLower + * ----------------------------------------------------------------------------- */ + +String *Swig_string_first_lower(String *s) { + String *ns = NewStringEmpty(); + char *cs = Char(s); + if (cs && cs[0] != 0) { + Putc(tolower((int)cs[0]), ns); + Append(ns, cs + 1); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_schemify() + * + * Replace underscores with dashes, to make identifiers look nice to Schemers. + * + * under_scores -> under-scores + * ----------------------------------------------------------------------------- */ + +String *Swig_string_schemify(String *s) { + String *ns = NewString(s); + Replaceall(ns, "_", "-"); + return ns; +} + + +/* ----------------------------------------------------------------------------- + * Swig_string_typecode() + * + * Takes a string with possible type-escapes in it and replaces them with + * real C datatypes. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_typecode(String *s) { + String *ns; + int c; + String *tc; + ns = NewStringEmpty(); + while ((c = Getc(s)) != EOF) { + if (c == '`') { + String *str = 0; + tc = NewStringEmpty(); + while ((c = Getc(s)) != EOF) { + if (c == '`') + break; + Putc(c, tc); + } + str = SwigType_str(tc, 0); + Append(ns, str); + Delete(str); + } else { + Putc(c, ns); + if (c == '\'') { + while ((c = Getc(s)) != EOF) { + Putc(c, ns); + if (c == '\'') + break; + if (c == '\\') { + c = Getc(s); + Putc(c, ns); + } + } + } else if (c == '\"') { + while ((c = Getc(s)) != EOF) { + Putc(c, ns); + if (c == '\"') + break; + if (c == '\\') { + c = Getc(s); + Putc(c, ns); + } + } + } + } + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_mangle() + * + * Take a string and mangle it by stripping all non-valid C identifier + * characters. + * + * This routine skips unnecessary blank spaces, therefore mangling + * 'char *' and 'char*', 'std::pair<int, int >' and + * 'std::pair<int,int>', produce the same result. + * + * However, note that 'long long' and 'long_long' produce different + * mangled strings. + * + * The mangling method still is not 'perfect', for example std::pair and + * std_pair return the same mangling. This is just a little better + * than before, but it seems to be enough for most of the purposes. + * + * Having a perfect mangling will break some examples and code which + * assume, for example, that A::get_value will be mangled as + * A_get_value. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_mangle(const String *s) { +#if 0 + /* old mangling, not suitable for using in macros */ + String *t = Copy(s); + char *c = Char(t); + while (*c) { + if (!isalnum(*c)) + *c = '_'; + c++; + } + return t; +#else + String *result = NewStringEmpty(); + int space = 0; + int state = 0; + char *pc, *cb; + String *b = Copy(s); + if (SwigType_istemplate(b)) { + String *st = Swig_symbol_template_deftype(b, 0); + String *sq = Swig_symbol_type_qualify(st, 0); + String *t = SwigType_namestr(sq); + Delete(st); + Delete(sq); + Delete(b); + b = t; + } + pc = cb = Char(b); + while (*pc) { + char c = *pc; + if (isalnum((int) c) || (c == '_')) { + state = 1; + if (space && (space == state)) { + Append(result, "_SS_"); + } + space = 0; + Printf(result, "%c", (int) c); + + } else { + if (isspace((int) c)) { + space = state; + ++pc; + continue; + } else { + state = 3; + space = 0; + } + switch (c) { + case '.': + if ((cb != pc) && (*(pc - 1) == 'p')) { + Append(result, "_"); + ++pc; + continue; + } else { + c = 'f'; + } + break; + case ':': + if (*(pc + 1) == ':') { + Append(result, "_"); + ++pc; + ++pc; + continue; + } + break; + case '*': + c = 'm'; + break; + case '&': + c = 'A'; + break; + case '<': + c = 'l'; + break; + case '>': + c = 'g'; + break; + case '=': + c = 'e'; + break; + case ',': + c = 'c'; + break; + case '(': + c = 'p'; + break; + case ')': + c = 'P'; + break; + case '[': + c = 'b'; + break; + case ']': + c = 'B'; + break; + case '^': + c = 'x'; + break; + case '|': + c = 'o'; + break; + case '~': + c = 'n'; + break; + case '!': + c = 'N'; + break; + case '%': + c = 'M'; + break; + case '?': + c = 'q'; + break; + case '+': + c = 'a'; + break; + case '-': + c = 's'; + break; + case '/': + c = 'd'; + break; + default: + break; + } + if (isalpha((int) c)) { + Printf(result, "_S%c_", (int) c); + } else { + Printf(result, "_S%02X_", (int) c); + } + } + ++pc; + } + Delete(b); + return result; +#endif +} + +String *Swig_string_emangle(String *s) { + return Swig_string_mangle(s); +} + + +/* ----------------------------------------------------------------------------- + * Swig_scopename_prefix() + * + * Take a qualified name like "A::B::C" and return the scope name. + * In this case, "A::B". Returns NULL if there is no base. + * ----------------------------------------------------------------------------- */ + +void Swig_scopename_split(const String *s, String **rprefix, String **rlast) { + char *tmp = Char(s); + char *c = tmp; + char *cc = c; + char *co = 0; + if (!strstr(c, "::")) { + *rprefix = 0; + *rlast = Copy(s); + } + + co = strstr(cc, "operator "); + if (co) { + if (co == cc) { + *rprefix = 0; + *rlast = Copy(s); + return; + } else { + *rprefix = NewStringWithSize(cc, co - cc - 2); + *rlast = NewString(co); + return; + } + } + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + cc = c; + c += 2; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + + if (cc != tmp) { + *rprefix = NewStringWithSize(tmp, cc - tmp); + *rlast = NewString(cc + 2); + return; + } else { + *rprefix = 0; + *rlast = Copy(s); + } +} + + +String *Swig_scopename_prefix(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *cc = c; + char *co = 0; + if (!strstr(c, "::")) + return 0; + co = strstr(cc, "operator "); + + if (co) { + if (co == cc) { + return 0; + } else { + String *prefix = NewStringWithSize(cc, co - cc - 2); + return prefix; + } + } + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + cc = c; + c += 2; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + + if (cc != tmp) { + return NewStringWithSize(tmp, cc - tmp); + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_last() + * + * Take a qualified name like "A::B::C" and returns the last. In this + * case, "C". + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_last(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *cc = c; + char *co = 0; + if (!strstr(c, "::")) + return NewString(s); + + co = strstr(cc, "operator "); + if (co) { + return NewString(co); + } + + + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + cc = c; + c += 2; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + return NewString(cc + 2); +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_first() + * + * Take a qualified name like "A::B::C" and returns the first scope name. + * In this case, "A". Returns NULL if there is no base. + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_first(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *co = 0; + if (!strstr(c, "::")) + return 0; + + co = strstr(c, "operator "); + if (co) { + if (co == c) { + return 0; + } + } else { + co = c + Len(s); + } + + while (*c && (c != co)) { + if ((*c == ':') && (*(c + 1) == ':')) { + break; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + if (*c && (c != tmp)) { + return NewStringWithSize(tmp, c - tmp); + } else { + return 0; + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_scopename_suffix() + * + * Take a qualified name like "A::B::C" and returns the suffix. + * In this case, "B::C". Returns NULL if there is no suffix. + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_suffix(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *co = 0; + if (!strstr(c, "::")) + return 0; + + co = strstr(c, "operator "); + if (co) { + if (co == c) + return 0; + } + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + break; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + if (*c && (c != tmp)) { + return NewString(c + 2); + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_check() + * + * Checks to see if a name is qualified with a scope name + * ----------------------------------------------------------------------------- */ + +int Swig_scopename_check(const String *s) { + char *c = Char(s); + char *co = strstr(c, "operator "); + + if (co) { + if (co == c) + return 0; + } + if (!strstr(c, "::")) + return 0; + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + return 1; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_command() + * + * Executes a external command via popen with the string as a command + * line parameter. For example: + * + * Printf(stderr,"%(command:sed 's/[a-z]/\U\\1/' <<<)s","hello") -> Hello + * ----------------------------------------------------------------------------- */ +#if defined(HAVE_POPEN) +# if defined(_MSC_VER) +# define popen _popen +# define pclose _pclose +# else +extern FILE *popen(const char *command, const char *type); +extern int pclose(FILE *stream); +# endif +#else +# if defined(_MSC_VER) +# define HAVE_POPEN 1 +# define popen _popen +# define pclose _pclose +# endif +#endif + +String *Swig_string_command(String *s) { + String *res = NewStringEmpty(); +#if defined(HAVE_POPEN) + if (Len(s)) { + char *command = Char(s); + FILE *fp = popen(command, "r"); + if (fp) { + char buffer[1025]; + while (fscanf(fp, "%1024s", buffer) != EOF) { + Append(res, buffer); + } + pclose(fp); + } else { + Swig_error("SWIG", Getline(s), "Command encoder fails attempting '%s'.\n", s); + exit(1); + } + } +#endif + return res; +} + + +/* ----------------------------------------------------------------------------- + * Swig_string_strip() + * + * Strip given prefix from identifiers + * + * Printf(stderr,"%(strip:[wx])s","wxHello") -> Hello + * ----------------------------------------------------------------------------- */ + +String *Swig_string_strip(String *s) { + String *ns; + if (!Len(s)) { + ns = NewString(s); + } else { + const char *cs = Char(s); + const char *ce = Strchr(cs, ']'); + if (*cs != '[' || ce == NULL) { + ns = NewString(s); + } else { + String *fmt = NewStringf("%%.%ds", ce-cs-1); + String *prefix = NewStringf(fmt, cs+1); + if (0 == Strncmp(ce+1, prefix, Len(prefix))) { + ns = NewString(ce+1+Len(prefix)); + } else { + ns = NewString(ce+1); + } + } + } + return ns; +} + + +/* ----------------------------------------------------------------------------- + * Swig_string_rxspencer() + * + * Executes a regexp substitution via the RxSpencer library. For example: + * + * Printf(stderr,"gsl%(rxspencer:[GSL_.*_][@1])s","GSL_Hello_") -> gslHello + * ----------------------------------------------------------------------------- */ +#if defined(HAVE_RXSPENCER) +#include <sys/types.h> +#include <rxspencer/regex.h> +#define USE_RXSPENCER +#endif + +const char *skip_delim(char pb, char pe, const char *ce) { + int end = 0; + int lb = 0; + while (!end && *ce != '\0') { + if (*ce == pb) { + ++lb; + } + if (*ce == pe) { + if (!lb) { + end = 1; + --ce; + } else { + --lb; + } + } + ++ce; + } + return end ? ce : 0; +} + + +#if defined(USE_RXSPENCER) +String *Swig_string_rxspencer(String *s) { + String *res = 0; + if (Len(s)) { + const char *cs = Char(s); + const char *cb; + const char *ce; + if (*cs == '[') { + int retval; + regex_t compiled; + cb = ++cs; + ce = skip_delim('[', ']', cb); + if (ce) { + char bregexp[512]; + strncpy(bregexp, cb, ce - cb); + bregexp[ce - cb] = '\0'; + ++ce; + retval = regcomp(&compiled, bregexp, REG_EXTENDED); + if (retval == 0) { + cs = ce; + if (*cs == '[') { + cb = ++cs; + ce = skip_delim('[', ']', cb); + if (ce) { + const char *cvalue = ce + 1; + int nsub = (int) compiled.re_nsub + 1; + regmatch_t *pmatch = (regmatch_t *) malloc(sizeof(regmatch_t) * (nsub)); + retval = regexec(&compiled, cvalue, nsub, pmatch, 0); + if (retval != REG_NOMATCH) { + char *spos = 0; + res = NewStringWithSize(cb, ce - cb); + spos = Strchr(res, '@'); + while (spos) { + char cd = *(++spos); + if (isdigit(cd)) { + char arg[8]; + size_t len; + int i = cd - '0'; + sprintf(arg, "@%d", i); + if (i < nsub && (len = pmatch[i].rm_eo - pmatch[i].rm_so)) { + char value[256]; + strncpy(value, cvalue + pmatch[i].rm_so, len); + value[len] = 0; + Replaceall(res, arg, value); + } else { + Replaceall(res, arg, ""); + } + spos = Strchr(res, '@'); + } else if (cd == '@') { + spos = strchr(spos + 1, '@'); + } + } + } + free(pmatch); + } + } + } + regfree(&compiled); + } + } + } + if (!res) + res = NewStringEmpty(); + return res; +} +#else +String *Swig_string_rxspencer(String *s) { + (void) s; + return NewStringEmpty(); +} +#endif + + +/* ----------------------------------------------------------------------------- + * Swig_init() + * + * Initialize the SWIG core + * ----------------------------------------------------------------------------- */ + +void Swig_init() { + /* Set some useful string encoding methods */ + DohEncoding("escape", Swig_string_escape); + DohEncoding("upper", Swig_string_upper); + DohEncoding("lower", Swig_string_lower); + DohEncoding("title", Swig_string_title); + DohEncoding("ctitle", Swig_string_ccase); + DohEncoding("lctitle", Swig_string_lccase); + DohEncoding("utitle", Swig_string_ucase); + DohEncoding("typecode", Swig_string_typecode); + DohEncoding("mangle", Swig_string_emangle); + DohEncoding("command", Swig_string_command); + DohEncoding("rxspencer", Swig_string_rxspencer); + DohEncoding("schemify", Swig_string_schemify); + DohEncoding("strip", Swig_string_strip); + + /* aliases for the case encoders */ + DohEncoding("uppercase", Swig_string_upper); + DohEncoding("lowercase", Swig_string_lower); + DohEncoding("camelcase", Swig_string_ccase); + DohEncoding("lowercamelcase", Swig_string_lccase); + DohEncoding("undercase", Swig_string_ucase); + DohEncoding("firstuppercase", Swig_string_first_upper); + DohEncoding("firstlowercase", Swig_string_first_lower); + + /* Initialize typemaps */ + Swig_typemap_init(); + + /* Initialize symbol table */ + Swig_symbol_init(); + + /* Initialize type system */ + SwigType_typesystem_init(); + + /* Initialize template system */ + SwigType_template_init(); +} diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c new file mode 100644 index 0000000..1398de8 --- /dev/null +++ b/Source/Swig/naming.c @@ -0,0 +1,1652 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * naming.c + * + * Functions for generating various kinds of names during code generation. + * ----------------------------------------------------------------------------- */ + +char cvsroot_naming_c[] = "$Id: naming.c 11454 2009-07-26 21:21:26Z wsfulton $"; + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +/* Hash table containing naming data */ + +static Hash *naming_hash = 0; + +#if 0 +#define SWIG_DEBUG +#endif + +/* ----------------------------------------------------------------------------- + * Swig_name_register() + * + * Register a new naming format. + * ----------------------------------------------------------------------------- */ + +void Swig_name_register(const_String_or_char_ptr method, const_String_or_char_ptr format) { + if (!naming_hash) + naming_hash = NewHash(); + Setattr(naming_hash, method, format); +} + +void Swig_name_unregister(const_String_or_char_ptr method) { + if (naming_hash) { + Delattr(naming_hash, method); + } +} + +static int name_mangle(String *r) { + char *c; + int special; + special = 0; + Replaceall(r, "::", "_"); + c = Char(r); + while (*c) { + if (!isalnum((int) *c) && (*c != '_')) { + special = 1; + switch (*c) { + case '+': + *c = 'a'; + break; + case '-': + *c = 's'; + break; + case '*': + *c = 'm'; + break; + case '/': + *c = 'd'; + break; + case '<': + *c = 'l'; + break; + case '>': + *c = 'g'; + break; + case '=': + *c = 'e'; + break; + case ',': + *c = 'c'; + break; + case '(': + *c = 'p'; + break; + case ')': + *c = 'P'; + break; + case '[': + *c = 'b'; + break; + case ']': + *c = 'B'; + break; + case '^': + *c = 'x'; + break; + case '&': + *c = 'A'; + break; + case '|': + *c = 'o'; + break; + case '~': + *c = 'n'; + break; + case '!': + *c = 'N'; + break; + case '%': + *c = 'M'; + break; + case '.': + *c = 'f'; + break; + case '?': + *c = 'q'; + break; + default: + *c = '_'; + break; + } + } + c++; + } + if (special) + Append(r, "___"); + return special; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_mangle() + * + * Converts all of the non-identifier characters of a string to underscores. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_mangle(const_String_or_char_ptr s) { +#if 0 + String *r = NewString(s); + name_mangle(r); + return r; +#else + return Swig_string_mangle(s); +#endif +} + +/* ----------------------------------------------------------------------------- + * Swig_name_wrapper() + * + * Returns the name of a wrapper function. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_wrapper(const_String_or_char_ptr fname) { + String *r; + String *f; + + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "wrapper"); + if (!f) { + Append(r, "_wrap_%f"); + } else { + Append(r, f); + } + Replace(r, "%f", fname, DOH_REPLACE_ANY); + name_mangle(r); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_member() + * + * Returns the name of a class method. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_member(const_String_or_char_ptr classname, const_String_or_char_ptr mname) { + String *r; + String *f; + String *rclassname; + char *cname; + + rclassname = SwigType_namestr(classname); + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "member"); + if (!f) { + Append(r, "%c_%m"); + } else { + Append(r, f); + } + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Replace(r, "%m", mname, DOH_REPLACE_ANY); + /* name_mangle(r); */ + Delete(rclassname); + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_get() + * + * Returns the name of the accessor function used to get a variable. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_get(const_String_or_char_ptr vname) { + String *r; + String *f; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_get: '%s'\n", vname); +#endif + + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "get"); + if (!f) { + Append(r, "%v_get"); + } else { + Append(r, f); + } + Replace(r, "%v", vname, DOH_REPLACE_ANY); + /* name_mangle(r); */ + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_set() + * + * Returns the name of the accessor function used to set a variable. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_set(const_String_or_char_ptr vname) { + String *r; + String *f; + + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "set"); + if (!f) { + Append(r, "%v_set"); + } else { + Append(r, f); + } + Replace(r, "%v", vname, DOH_REPLACE_ANY); + /* name_mangle(r); */ + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_construct() + * + * Returns the name of the accessor function used to create an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_construct(const_String_or_char_ptr classname) { + String *r; + String *f; + String *rclassname; + char *cname; + + rclassname = SwigType_namestr(classname); + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "construct"); + if (!f) { + Append(r, "new_%c"); + } else { + Append(r, f); + } + + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Delete(rclassname); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_copyconstructor() + * + * Returns the name of the accessor function used to copy an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_copyconstructor(const_String_or_char_ptr classname) { + String *r; + String *f; + String *rclassname; + char *cname; + + rclassname = SwigType_namestr(classname); + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "copy"); + if (!f) { + Append(r, "copy_%c"); + } else { + Append(r, f); + } + + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Delete(rclassname); + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_destroy() + * + * Returns the name of the accessor function used to destroy an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_destroy(const_String_or_char_ptr classname) { + String *r; + String *f; + String *rclassname; + char *cname; + rclassname = SwigType_namestr(classname); + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "destroy"); + if (!f) { + Append(r, "delete_%c"); + } else { + Append(r, f); + } + + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Delete(rclassname); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_disown() + * + * Returns the name of the accessor function used to disown an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_disown(const_String_or_char_ptr classname) { + String *r; + String *f; + String *rclassname; + char *cname; + rclassname = SwigType_namestr(classname); + r = NewStringEmpty(); + if (!naming_hash) + naming_hash = NewHash(); + f = Getattr(naming_hash, "disown"); + if (!f) { + Append(r, "disown_%c"); + } else { + Append(r, f); + } + + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Delete(rclassname); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_object_set() + * + * Sets an object associated with a name and optional declarators. + * ----------------------------------------------------------------------------- */ + +void Swig_name_object_set(Hash *namehash, String *name, SwigType *decl, DOH *object) { + DOH *n; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_object_set: '%s', '%s'\n", name, decl); +#endif + n = Getattr(namehash, name); + if (!n) { + n = NewHash(); + Setattr(namehash, name, n); + Delete(n); + } + /* Add an object based on the declarator value */ + if (!decl) { + Setattr(n, "start", object); + } else { + SwigType *cd = Copy(decl); + Setattr(n, cd, object); + Delete(cd); + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_object_get() + * + * Return an object associated with an optional class prefix, name, and + * declarator. This function operates according to name matching rules + * described for the %rename directive in the SWIG manual. + * ----------------------------------------------------------------------------- */ + +static DOH *get_object(Hash *n, String *decl) { + DOH *rn = 0; + if (!n) + return 0; + if (decl) { + rn = Getattr(n, decl); + } else { + rn = Getattr(n, "start"); + } + return rn; +} + +static +DOH *name_object_get(Hash *namehash, String *tname, SwigType *decl, SwigType *ncdecl) { + DOH *rn = 0; + Hash *n = Getattr(namehash, tname); + if (n) { + rn = get_object(n, decl); + if ((!rn) && ncdecl) + rn = get_object(n, ncdecl); + if (!rn) + rn = get_object(n, 0); + } + return rn; +} + +DOH *Swig_name_object_get(Hash *namehash, String *prefix, String *name, SwigType *decl) { + String *tname = NewStringEmpty(); + DOH *rn = 0; + char *ncdecl = 0; + + if (!namehash) + return 0; + + /* DB: This removed to more tightly control feature/name matching */ + /* if ((decl) && (SwigType_isqualifier(decl))) { + ncdecl = strchr(Char(decl),'.'); + ncdecl++; + } + */ +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_object_get: '%s' '%s', '%s'\n", prefix, name, decl); +#endif + + + /* Perform a class-based lookup (if class prefix supplied) */ + if (prefix) { + if (Len(prefix)) { + Printf(tname, "%s::%s", prefix, name); + rn = name_object_get(namehash, tname, decl, ncdecl); + if (!rn) { + String *cls = Swig_scopename_last(prefix); + if (!Equal(cls, prefix)) { + Clear(tname); + Printf(tname, "*::%s::%s", cls, name); + rn = name_object_get(namehash, tname, decl, ncdecl); + } + Delete(cls); + } + /* A template-based class lookup, check name first */ + if (!rn && SwigType_istemplate(name)) { + String *t_name = SwigType_templateprefix(name); + if (!Equal(t_name, name)) { + rn = Swig_name_object_get(namehash, prefix, t_name, decl); + } + Delete(t_name); + } + /* A template-based class lookup */ + /* + if (!rn && SwigType_istemplate(prefix)) { + String *t_prefix = SwigType_templateprefix(prefix); + if (Strcmp(t_prefix, prefix) != 0) { + String *t_name = SwigType_templateprefix(name); + rn = Swig_name_object_get(namehash, t_prefix, t_name, decl); + Delete(t_name); + } + Delete(t_prefix); + } + */ + } + /* A wildcard-based class lookup */ + if (!rn) { + Clear(tname); + Printf(tname, "*::%s", name); + rn = name_object_get(namehash, tname, decl, ncdecl); + } + } else { + /* Lookup in the global namespace only */ + Clear(tname); + Printf(tname, "::%s", name); + rn = name_object_get(namehash, tname, decl, ncdecl); + } + /* Catch-all */ + if (!rn) { + rn = name_object_get(namehash, name, decl, ncdecl); + } + if (!rn && Swig_scopename_check(name)) { + String *nprefix = NewStringEmpty(); + String *nlast = NewStringEmpty(); + Swig_scopename_split(name, &nprefix, &nlast); + rn = name_object_get(namehash, nlast, decl, ncdecl); + Delete(nlast); + Delete(nprefix); + } + + Delete(tname); + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_object_get: found %d\n", rn ? 1 : 0); +#endif + + return rn; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_object_inherit() + * + * Implements name-based inheritance scheme. + * ----------------------------------------------------------------------------- */ + +void Swig_name_object_inherit(Hash *namehash, String *base, String *derived) { + Iterator ki; + String *bprefix; + String *dprefix; + char *cbprefix; + int plen; + + if (!namehash) + return; + + bprefix = NewStringf("%s::", base); + dprefix = NewStringf("%s::", derived); + cbprefix = Char(bprefix); + plen = strlen(cbprefix); + for (ki = First(namehash); ki.key; ki = Next(ki)) { + char *k = Char(ki.key); + if (strncmp(k, cbprefix, plen) == 0) { + Iterator oi; + String *nkey = NewStringf("%s%s", dprefix, k + plen); + Hash *n = ki.item; + Hash *newh = Getattr(namehash, nkey); + if (!newh) { + newh = NewHash(); + Setattr(namehash, nkey, newh); + Delete(newh); + } + for (oi = First(n); oi.key; oi = Next(oi)) { + if (!Getattr(newh, oi.key)) { + String *ci = Copy(oi.item); + Setattr(newh, oi.key, ci); + Delete(ci); + } + } + Delete(nkey); + } + } + Delete(bprefix); + Delete(dprefix); +} + +/* ----------------------------------------------------------------------------- + * merge_features() + * + * Given a hash, this function merges the features in the hash into the node. + * ----------------------------------------------------------------------------- */ + +static void merge_features(Hash *features, Node *n) { + Iterator ki; + + if (!features) + return; + for (ki = First(features); ki.key; ki = Next(ki)) { + String *ci = Copy(ki.item); + Setattr(n, ki.key, ci); + Delete(ci); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_features_get() + * + * Attaches any features in the features hash to the node that matches + * the declaration, decl. + * ----------------------------------------------------------------------------- */ + +static +void features_get(Hash *features, const String *tname, SwigType *decl, SwigType *ncdecl, Node *node) { + Node *n = Getattr(features, tname); +#ifdef SWIG_DEBUG + Printf(stdout, " features_get: %s\n", tname); +#endif + if (n) { + merge_features(get_object(n, 0), node); + if (ncdecl) + merge_features(get_object(n, ncdecl), node); + merge_features(get_object(n, decl), node); + } +} + +void Swig_features_get(Hash *features, String *prefix, String *name, SwigType *decl, Node *node) { + char *ncdecl = 0; + String *rdecl = 0; + String *rname = 0; + if (!features) + return; + + /* MM: This removed to more tightly control feature/name matching */ + /* + if ((decl) && (SwigType_isqualifier(decl))) { + ncdecl = strchr(Char(decl),'.'); + ncdecl++; + } + */ + + /* very specific hack for template constructors/destructors */ + if (name && SwigType_istemplate(name)) { + String *nodetype = nodeType(node); + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + String *nprefix = NewStringEmpty(); + String *nlast = NewStringEmpty(); + String *tprefix; + Swig_scopename_split(name, &nprefix, &nlast); + tprefix = SwigType_templateprefix(nlast); + Delete(nlast); + if (Len(nprefix)) { + Append(nprefix, "::"); + Append(nprefix, tprefix); + Delete(tprefix); + rname = nprefix; + } else { + rname = tprefix; + Delete(nprefix); + } + rdecl = Copy(decl); + Replaceall(rdecl, name, rname); + decl = rdecl; + name = rname; + } + } + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_features_get: '%s' '%s' '%s'\n", prefix, name, decl); +#endif + + /* Global features */ + features_get(features, "", 0, 0, node); + if (name) { + String *tname = NewStringEmpty(); + /* add features for 'root' template */ + if (SwigType_istemplate(name)) { + String *dname = SwigType_templateprefix(name); + features_get(features, dname, decl, ncdecl, node); + Delete(dname); + } + /* Catch-all */ + features_get(features, name, decl, ncdecl, node); + /* Perform a class-based lookup (if class prefix supplied) */ + if (prefix) { + /* A class-generic feature */ + if (Len(prefix)) { + Printf(tname, "%s::", prefix); + features_get(features, tname, decl, ncdecl, node); + } + /* A wildcard-based class lookup */ + Clear(tname); + Printf(tname, "*::%s", name); + features_get(features, tname, decl, ncdecl, node); + /* A specific class lookup */ + if (Len(prefix)) { + /* A template-based class lookup */ + if (SwigType_istemplate(prefix)) { + String *tprefix = SwigType_templateprefix(prefix); + Clear(tname); + Printf(tname, "%s::%s", tprefix, name); + features_get(features, tname, decl, ncdecl, node); + Delete(tprefix); + } + Clear(tname); + Printf(tname, "%s::%s", prefix, name); + features_get(features, tname, decl, ncdecl, node); + } + } else { + /* Lookup in the global namespace only */ + Clear(tname); + Printf(tname, "::%s", name); + features_get(features, tname, decl, ncdecl, node); + } + Delete(tname); + } + if (name && SwigType_istemplate(name)) { + /* add features for complete template type */ + String *dname = Swig_symbol_template_deftype(name, 0); + if (!Equal(dname, name)) { + Swig_features_get(features, prefix, dname, decl, node); + } + Delete(dname); + } + + if (rname) + Delete(rname); + if (rdecl) + Delete(rdecl); +} + + +/* ----------------------------------------------------------------------------- + * Swig_feature_set() + * + * Sets a feature name and value. Also sets optional feature attributes as + * passed in by featureattribs. Optional feature attributes are given a full name + * concatenating the feature name plus ':' plus the attribute name. + * ----------------------------------------------------------------------------- */ + +void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, String *value, Hash *featureattribs) { + Hash *n; + Hash *fhash; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_feature_set: '%s' '%s' '%s' '%s'\n", name, decl, featurename, value); +#endif + + n = Getattr(features, name); + if (!n) { + n = NewHash(); + Setattr(features, name, n); + Delete(n); + } + if (!decl) { + fhash = Getattr(n, "start"); + if (!fhash) { + fhash = NewHash(); + Setattr(n, "start", fhash); + Delete(fhash); + } + } else { + fhash = Getattr(n, decl); + if (!fhash) { + String *cdecl_ = Copy(decl); + fhash = NewHash(); + Setattr(n, cdecl_, fhash); + Delete(cdecl_); + Delete(fhash); + } + } + if (value) { + Setattr(fhash, featurename, value); + } else { + Delattr(fhash, featurename); + } + + { + /* Add in the optional feature attributes */ + Hash *attribs = featureattribs; + while (attribs) { + String *attribname = Getattr(attribs, "name"); + String *featureattribname = NewStringf("%s:%s", featurename, attribname); + if (value) { + String *attribvalue = Getattr(attribs, "value"); + Setattr(fhash, featureattribname, attribvalue); + } else { + Delattr(fhash, featureattribname); + } + attribs = nextSibling(attribs); + Delete(featureattribname); + } + } + + if (name && SwigType_istemplate(name)) { + String *dname = Swig_symbol_template_deftype(name, 0); + if (Strcmp(dname, name)) { + Swig_feature_set(features, dname, decl, featurename, value, featureattribs); + } + Delete(dname); + } +} + +/* ----------------------------------------------------------------------------- + * The rename/namewarn engine + * + * Code below was in parser.y for a while + * ----------------------------------------------------------------------------- */ + +static Hash *namewarn_hash = 0; +Hash *Swig_name_namewarn_hash() { + if (!namewarn_hash) + namewarn_hash = NewHash(); + return namewarn_hash; +} + +static Hash *rename_hash = 0; +Hash *Swig_name_rename_hash() { + if (!rename_hash) + rename_hash = NewHash(); + return rename_hash; +} + +static List *namewarn_list = 0; +List *Swig_name_namewarn_list() { + if (!namewarn_list) + namewarn_list = NewList(); + return namewarn_list; +} + +static List *rename_list = 0; +List *Swig_name_rename_list() { + if (!rename_list) + rename_list = NewList(); + return rename_list; +} + +/* ----------------------------------------------------------------------------- + * int Swig_need_name_warning(Node *n) + * + * Detects if a node needs name warnings + * + * ----------------------------------------------------------------------------- */ + +int Swig_need_name_warning(Node *n) { + int need = 1; + /* + we don't use name warnings for: + - class forwards, no symbol is generated at the target language. + - template declarations, only for real instances using %template(name). + - typedefs, they have no effect at the target language. + */ + if (checkAttribute(n, "nodeType", "classforward")) { + need = 0; + } else if (checkAttribute(n, "storage", "typedef")) { + need = 0; + } else if (Getattr(n, "hidden")) { + need = 0; + } else if (Getattr(n, "ignore")) { + need = 0; + } else if (Getattr(n, "templatetype")) { + need = 0; + } + return need; +} + +/* ----------------------------------------------------------------------------- + * int Swig_need_redefined_warn() + * + * Detects when a redefined object needs a warning + * + * ----------------------------------------------------------------------------- */ + +static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) { + /* they must have the same type */ + String *ta = nodeType(a); + String *tb = nodeType(b); + if (Cmp(ta, tb) != 0) + return 0; + + /* cdecl case */ + if (Cmp(ta, "cdecl") == 0) { + /* typedef */ + String *a_storage = Getattr(a, "storage"); + String *b_storage = Getattr(b, "storage"); + + if ((Cmp(a_storage, "typedef") == 0) + || (Cmp(b_storage, "typedef") == 0)) { + if (Cmp(a_storage, b_storage) == 0) { + String *a_type = (Getattr(a, "type")); + String *b_type = (Getattr(b, "type")); + if (Cmp(a_type, b_type) == 0) + return 1; + } + return 0; + } + + /* static functions */ + if ((Cmp(a_storage, "static") == 0) + || (Cmp(b_storage, "static") == 0)) { + if (Cmp(a_storage, b_storage) != 0) + return 0; + } + + /* friend methods */ + + if (!a_inclass || (Cmp(a_storage, "friend") == 0)) { + /* check declaration */ + + String *a_decl = (Getattr(a, "decl")); + String *b_decl = (Getattr(b, "decl")); + if (Cmp(a_decl, b_decl) == 0) { + /* check return type */ + String *a_type = (Getattr(a, "type")); + String *b_type = (Getattr(b, "type")); + if (Cmp(a_type, b_type) == 0) { + /* check parameters */ + Parm *ap = (Getattr(a, "parms")); + Parm *bp = (Getattr(b, "parms")); + while (ap && bp) { + SwigType *at = Getattr(ap, "type"); + SwigType *bt = Getattr(bp, "type"); + if (Cmp(at, bt) != 0) + return 0; + ap = nextSibling(ap); + bp = nextSibling(bp); + } + if (ap || bp) { + return 0; + } else { + Node *a_template = Getattr(a, "template"); + Node *b_template = Getattr(b, "template"); + /* Not equivalent if one is a template instantiation (via %template) and the other is a non-templated function */ + if ((a_template && !b_template) || (!a_template && b_template)) + return 0; + } + return 1; + } + } + } + } else { + /* %constant case */ + String *a_storage = Getattr(a, "storage"); + String *b_storage = Getattr(b, "storage"); + if ((Cmp(a_storage, "%constant") == 0) + || (Cmp(b_storage, "%constant") == 0)) { + if (Cmp(a_storage, b_storage) == 0) { + String *a_type = (Getattr(a, "type")); + String *b_type = (Getattr(b, "type")); + if ((Cmp(a_type, b_type) == 0) + && (Cmp(Getattr(a, "value"), Getattr(b, "value")) == 0)) + return 1; + } + return 0; + } + } + return 0; +} + +int Swig_need_redefined_warn(Node *a, Node *b, int InClass) { + String *a_name = Getattr(a, "name"); + String *b_name = Getattr(b, "name"); + String *a_symname = Getattr(a, "sym:name"); + String *b_symname = Getattr(b, "sym:name"); + /* always send a warning if a 'rename' is involved */ + if ((a_symname && !Equal(a_symname, a_name)) + || (b_symname && !Equal(b_symname, b_name))) { + if (!Equal(a_name, b_name)) { + return 1; + } + } + + + return !nodes_are_equivalent(a, b, InClass); +} + + +/* ----------------------------------------------------------------------------- + * int Swig_need_protected(Node* n) + * + * Detects when we need to fully register the protected member. + * This is basically any protected members when the allprotected mode is set. + * Otherwise we take just the protected virtual methods and non-static methods + * (potentially virtual methods) as well as constructors/destructors. + * + * ----------------------------------------------------------------------------- */ + +int Swig_need_protected(Node *n) { + String *nodetype = nodeType(n); + if (checkAttribute(n, "access", "protected")) { + if ((Equal(nodetype, "cdecl"))) { + if (Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode()) { + return 1; + } + if (SwigType_isfunction(Getattr(n, "decl"))) { + String *storage = Getattr(n, "storage"); + /* The function is declared virtual, or it has no storage. This eliminates typedef, static etc. */ + return !storage || Equal(storage, "virtual"); + } + } else if (Equal(nodetype, "constructor") || Equal(nodetype, "destructor")) { + return 1; + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_nameobj_add() + * + * Add nameobj (rename/namewarn) + * + * ----------------------------------------------------------------------------- */ + +static List *Swig_make_attrlist(const char *ckey) { + List *list = NewList(); + const char *cattr = strchr(ckey, '$'); + if (cattr) { + String *nattr; + const char *rattr = strchr(++cattr, '$'); + while (rattr) { + nattr = NewStringWithSize(cattr, rattr - cattr); + Append(list, nattr); + Delete(nattr); + cattr = rattr + 1; + rattr = strchr(cattr, '$'); + } + nattr = NewString(cattr); + Append(list, nattr); + Delete(nattr); + } else { + Append(list, "nodeType"); + } + return list; +} + +static void Swig_name_object_attach_keys(const char *keys[], Hash *nameobj) { + Node *kw = nextSibling(nameobj); + List *matchlist = 0; + while (kw) { + Node *next = nextSibling(kw); + String *kname = Getattr(kw, "name"); + char *ckey = kname ? Char(kname) : 0; + if (ckey) { + const char **rkey; + int isnotmatch = 0; + int isrxsmatch = 0; + if ((strncmp(ckey, "match", 5) == 0) + || (isnotmatch = (strncmp(ckey, "notmatch", 8) == 0)) + || (isrxsmatch = (strncmp(ckey, "rxsmatch", 8) == 0)) + || (isnotmatch = isrxsmatch = (strncmp(ckey, "notrxsmatch", 11) == 0))) { + Hash *mi = NewHash(); + List *attrlist = Swig_make_attrlist(ckey); + if (!matchlist) + matchlist = NewList(); + Setattr(mi, "value", Getattr(kw, "value")); + Setattr(mi, "attrlist", attrlist); +#ifdef SWIG_DEBUG + if (isrxsmatch) + Printf(stdout, "rxsmatch to use: %s %s %s\n", ckey, Getattr(kw, "value"), attrlist); +#endif + if (isnotmatch) + SetFlag(mi, "notmatch"); + if (isrxsmatch) + SetFlag(mi, "rxsmatch"); + Delete(attrlist); + Append(matchlist, mi); + Delete(mi); + removeNode(kw); + } else { + for (rkey = keys; *rkey != 0; ++rkey) { + if (strcmp(ckey, *rkey) == 0) { + Setattr(nameobj, *rkey, Getattr(kw, "value")); + removeNode(kw); + } + } + } + } + kw = next; + } + if (matchlist) { + Setattr(nameobj, "matchlist", matchlist); + Delete(matchlist); + } +} + +void Swig_name_nameobj_add(Hash *name_hash, List *name_list, String *prefix, String *name, SwigType *decl, Hash *nameobj) { + String *nname = 0; + if (name && Len(name)) { + String *target_fmt = Getattr(nameobj, "targetfmt"); + nname = prefix ? NewStringf("%s::%s", prefix, name) : NewString(name); + if (target_fmt) { + String *tmp = NewStringf(target_fmt, nname); + Delete(nname); + nname = tmp; + } + } + + if (!nname || !Len(nname) || Getattr(nameobj, "fullname") || /* any of these options trigger a 'list' nameobj */ + Getattr(nameobj, "sourcefmt") || Getattr(nameobj, "matchlist")) { + if (decl) + Setattr(nameobj, "decl", decl); + if (nname && Len(nname)) + Setattr(nameobj, "targetname", nname); + /* put the new nameobj at the beginnig of the list, such that the + last inserted rule take precedence */ + Insert(name_list, 0, nameobj); + } else { + /* here we add an old 'hash' nameobj, simple and fast */ + Swig_name_object_set(name_hash, nname, decl, nameobj); + } + Delete(nname); +} + +/* ----------------------------------------------------------------------------- + * int Swig_name_match_nameobj() + * + * Apply and check the nameobj's math list to the node + * + * ----------------------------------------------------------------------------- */ + +static DOH *Swig_get_lattr(Node *n, List *lattr) { + DOH *res = 0; + int ilen = Len(lattr); + int i; + for (i = 0; n && (i < ilen); ++i) { + String *nattr = Getitem(lattr, i); + res = Getattr(n, nattr); +#ifdef SWIG_DEBUG + if (!res) { + Printf(stdout, "missing %s %s %s\n", nattr, Getattr(n, "name"), Getattr(n, "member")); + } else { + Printf(stdout, "lattr %d %s %s\n", i, nattr, DohIsString(res) ? res : Getattr(res, "name")); + } +#endif + n = res; + } + return res; +} + +#if defined(HAVE_RXSPENCER) +#include <sys/types.h> +#include <rxspencer/regex.h> +#define USE_RXSPENCER +#endif + +#if defined(USE_RXSPENCER) +int Swig_name_rxsmatch_value(String *mvalue, String *value) { + int match = 0; + char *cvalue = Char(value); + char *cmvalue = Char(mvalue); + regex_t compiled; + int retval = regcomp(&compiled, cmvalue, REG_EXTENDED | REG_NOSUB); + if (retval != 0) + return 0; + retval = regexec(&compiled, cvalue, 0, 0, 0); + match = (retval == REG_NOMATCH) ? 0 : 1; +#ifdef SWIG_DEBUG + Printf(stdout, "rxsmatch_value: %s %s %d\n", cvalue, cmvalue, match); +#endif + regfree(&compiled); + return match; +} +#else +int Swig_name_rxsmatch_value(String *mvalue, String *value) { + (void) mvalue; + (void) value; + return 0; +} +#endif + +int Swig_name_match_value(String *mvalue, String *value) { +#if defined(SWIG_USE_SIMPLE_MATCHOR) + int match = 0; + char *cvalue = Char(value); + char *cmvalue = Char(mvalue); + char *sep = strchr(cmvalue, '|'); + while (sep && !match) { + match = strncmp(cvalue, cmvalue, sep - cmvalue) == 0; +#ifdef SWIG_DEBUG + Printf(stdout, "match_value: %s %s %d\n", cvalue, cmvalue, match); +#endif + cmvalue = sep + 1; + sep = strchr(cmvalue, '|'); + } + if (!match) { + match = strcmp(cvalue, cmvalue) == 0; +#ifdef SWIG_DEBUG + Printf(stdout, "match_value: %s %s %d\n", cvalue, cmvalue, match); +#endif + } + return match; +#else + return Equal(mvalue, value); +#endif +} + + +int Swig_name_match_nameobj(Hash *rn, Node *n) { + int match = 1; + List *matchlist = Getattr(rn, "matchlist"); +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_match_nameobj: %s\n", Getattr(n, "name")); +#endif + if (matchlist) { + int ilen = Len(matchlist); + int i; + for (i = 0; match && (i < ilen); ++i) { + Node *mi = Getitem(matchlist, i); + List *lattr = Getattr(mi, "attrlist"); + String *nval = Swig_get_lattr(n, lattr); + int notmatch = GetFlag(mi, "notmatch"); + int rxsmatch = GetFlag(mi, "rxsmatch"); +#ifdef SWIG_DEBUG + Printf(stdout, "mi %d %s re %d not %d \n", i, nval, notmatch, rxsmatch); + if (rxsmatch) { + Printf(stdout, "rxsmatch %s\n", lattr); + } +#endif + match = 0; + if (nval) { + String *kwval = Getattr(mi, "value"); + match = rxsmatch ? Swig_name_rxsmatch_value(kwval, nval) + : Swig_name_match_value(kwval, nval); +#ifdef SWIG_DEBUG + Printf(stdout, "val %s %s %d %d \n", nval, kwval, match, ilen); +#endif + } + if (notmatch) + match = !match; + } + } +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_match_nameobj: %d\n", match); +#endif + return match; +} + +/* ----------------------------------------------------------------------------- + * Hash *Swig_name_nameobj_lget() + * + * Get a nameobj (rename/namewarn) from the list of filters + * + * ----------------------------------------------------------------------------- */ + +Hash *Swig_name_nameobj_lget(List *namelist, Node *n, String *prefix, String *name, String *decl) { + Hash *res = 0; + if (namelist) { + int len = Len(namelist); + int i; + int match = 0; + for (i = 0; !match && (i < len); i++) { + Hash *rn = Getitem(namelist, i); + String *rdecl = Getattr(rn, "decl"); + if (rdecl && (!decl || !Equal(rdecl, decl))) { + continue; + } else if (Swig_name_match_nameobj(rn, n)) { + String *tname = Getattr(rn, "targetname"); + if (tname) { + String *sfmt = Getattr(rn, "sourcefmt"); + String *sname = 0; + int fullname = GetFlag(rn, "fullname"); + int rxstarget = GetFlag(rn, "rxstarget"); + if (sfmt) { + if (fullname && prefix) { + String *pname = NewStringf("%s::%s", prefix, name); + sname = NewStringf(sfmt, pname); + Delete(pname); + } else { + sname = NewStringf(sfmt, name); + } + } else { + if (fullname && prefix) { + sname = NewStringf("%s::%s", prefix, name); + } else { + sname = name; + DohIncref(name); + } + } + match = rxstarget ? Swig_name_rxsmatch_value(tname, sname) : Swig_name_match_value(tname, sname); + Delete(sname); + } else { + match = 1; + } + } + if (match) { + res = rn; + break; + } + } + } + return res; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_namewarn_add + * + * Add a namewarn objects + * + * ----------------------------------------------------------------------------- */ + +void Swig_name_namewarn_add(String *prefix, String *name, SwigType *decl, Hash *namewrn) { + const char *namewrn_keys[] = { "rename", "error", "fullname", "sourcefmt", "targetfmt", 0 }; + Swig_name_object_attach_keys(namewrn_keys, namewrn); + Swig_name_nameobj_add(Swig_name_namewarn_hash(), Swig_name_namewarn_list(), prefix, name, decl, namewrn); +} + +/* ----------------------------------------------------------------------------- + * Hash *Swig_name_namewarn_get() + * + * Return the namewarn object, if there is one. + * + * ----------------------------------------------------------------------------- */ + +Hash *Swig_name_namewarn_get(Node *n, String *prefix, String *name, SwigType *decl) { + if (!namewarn_hash && !namewarn_list) + return 0; + if (n) { + /* Return in the obvious cases */ + if (!name || !Swig_need_name_warning(n)) { + return 0; + } else { + String *access = Getattr(n, "access"); + int is_public = !access || Equal(access, "public"); + if (!is_public && !Swig_need_protected(n)) { + return 0; + } + } + } + if (name) { + /* Check to see if the name is in the hash */ + Hash *wrn = Swig_name_object_get(Swig_name_namewarn_hash(), prefix, name, decl); + if (wrn && !Swig_name_match_nameobj(wrn, n)) + wrn = 0; + if (!wrn) { + wrn = Swig_name_nameobj_lget(Swig_name_namewarn_list(), n, prefix, name, decl); + } + if (wrn && Getattr(wrn, "error")) { + if (n) { + Swig_error(Getfile(n), Getline(n), "%s\n", Getattr(wrn, "name")); + } else { + Swig_error(cparse_file, cparse_line, "%s\n", Getattr(wrn, "name")); + } + } + return wrn; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * String *Swig_name_warning() + * + * Return the name warning, if there is one. + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_warning(Node *n, String *prefix, String *name, SwigType *decl) { + Hash *wrn = Swig_name_namewarn_get(n, prefix, name, decl); + return (name && wrn) ? Getattr(wrn, "name") : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_rename_add() + * + * Manage the rename objects + * + * ----------------------------------------------------------------------------- */ + +static void single_rename_add(String *prefix, String *name, SwigType *decl, Hash *newname) { + Swig_name_nameobj_add(Swig_name_rename_hash(), Swig_name_rename_list(), prefix, name, decl, newname); +} + +/* Add a new rename. Works much like new_feature including default argument handling. */ +void Swig_name_rename_add(String *prefix, String *name, SwigType *decl, Hash *newname, ParmList *declaratorparms) { + + ParmList *declparms = declaratorparms; + + const char *rename_keys[] = { "fullname", "sourcefmt", "targetfmt", "continue", "rxstarget", 0 }; + Swig_name_object_attach_keys(rename_keys, newname); + + /* Add the name */ + single_rename_add(prefix, name, decl, newname); + + /* Add extra names if there are default parameters in the parameter list */ + if (decl) { + int constqualifier = SwigType_isconst(decl); + while (declparms) { + if (ParmList_has_defaultargs(declparms)) { + + /* Create a parameter list for the new rename 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 *newdecl = Copy(decl); + Delete(SwigType_pop_function(newdecl)); /* remove the old parameter list from newdecl */ + SwigType_add_function(newdecl, newparms); + if (constqualifier) + SwigType_add_qualifier(newdecl, "const"); + + single_rename_add(prefix, name, newdecl, newname); + declparms = newparms; + Delete(newdecl); + } else { + declparms = 0; + } + } + } +} + + +/* Create a name applying rename/namewarn if needed */ +static String *apply_rename(String *newname, int fullname, String *prefix, String *name) { + String *result = 0; + if (newname && Len(newname)) { + if (Strcmp(newname, "$ignore") == 0) { + result = Copy(newname); + } else { + char *cnewname = Char(newname); + if (cnewname) { + int destructor = name && (*(Char(name)) == '~'); + String *fmt = newname; + /* use name as a fmt, but avoid C++ "%" and "%=" operators */ + if (Len(newname) > 1 && strchr(cnewname, '%') && !(strcmp(cnewname, "%=") == 0)) { + if (fullname && prefix) { + result = NewStringf(fmt, prefix, name); + } else { + result = NewStringf(fmt, name); + } + } else { + result = Copy(newname); + } + if (destructor && result && (*(Char(result)) != '~')) { + Insert(result, 0, "~"); + } + } + } + } + + return result; +} + +/* ----------------------------------------------------------------------------- + * String *Swig_name_make() + * + * Make a name after applying all the rename/namewarn objects + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_make(Node *n, String *prefix, const_String_or_char_ptr cname, SwigType *decl, String *oldname) { + String *nname = 0; + String *result = 0; + String *name = NewString(cname); + Hash *wrn = 0; + String *rdecl = 0; + String *rname = 0; + + /* very specific hack for template constructors/destructors */ +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_make: looking for %s %s %s %s\n", prefix, name, decl, oldname); +#endif + + if (name && n && SwigType_istemplate(name)) { + String *nodetype = nodeType(n); + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + String *nprefix = NewStringEmpty(); + String *nlast = NewStringEmpty(); + String *tprefix; + Swig_scopename_split(name, &nprefix, &nlast); + tprefix = SwigType_templateprefix(nlast); + Delete(nlast); + if (Len(nprefix)) { + Append(nprefix, "::"); + Append(nprefix, tprefix); + Delete(tprefix); + rname = nprefix; + } else { + rname = tprefix; + Delete(nprefix); + } + rdecl = Copy(decl); + Replaceall(rdecl, name, rname); +#ifdef SWIG_DEBUG + Printf(stdout, "SWIG_name_make: use new name %s %s : %s %s\n", name, decl, rname, rdecl); +#endif + decl = rdecl; + Delete(name); + name = rname; + } + } + + + if (rename_hash || rename_list || namewarn_hash || namewarn_list) { + Hash *rn = Swig_name_object_get(Swig_name_rename_hash(), prefix, name, decl); + if (!rn || !Swig_name_match_nameobj(rn, n)) { + rn = Swig_name_nameobj_lget(Swig_name_rename_list(), n, prefix, name, decl); + if (rn) { + String *sfmt = Getattr(rn, "sourcefmt"); + int fullname = GetFlag(rn, "fullname"); + if (fullname && prefix) { + String *sname = NewStringf("%s::%s", prefix, name); + Delete(name); + name = sname; + prefix = 0; + } + if (sfmt) { + String *sname = NewStringf(sfmt, name); + Delete(name); + name = sname; + } + } + } + if (rn) { + String *newname = Getattr(rn, "name"); + int fullname = GetFlag(rn, "fullname"); + result = apply_rename(newname, fullname, prefix, name); + } + if (result && !Equal(result, name)) { + /* operators in C++ allow aliases, we look for them */ + char *cresult = Char(result); + if (cresult && (strncmp(cresult, "operator ", 9) == 0)) { + String *nresult = Swig_name_make(n, prefix, result, decl, oldname); + if (!Equal(nresult, result)) { + Delete(result); + result = nresult; + } else { + Delete(nresult); + } + } + } + nname = result ? result : name; + wrn = Swig_name_namewarn_get(n, prefix, nname, decl); + if (wrn) { + String *rename = Getattr(wrn, "rename"); + if (rename) { + String *msg = Getattr(wrn, "name"); + int fullname = GetFlag(wrn, "fullname"); + if (result) + Delete(result); + result = apply_rename(rename, fullname, prefix, name); + if ((msg) && (Len(msg))) { + if (!Getmeta(nname, "already_warned")) { + if (n) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0, Getfile(n), Getline(n), "%s\n", msg); + SWIG_WARN_NODE_END(n); + } else { + Swig_warning(0, Getfile(name), Getline(name), "%s\n", msg); + } + Setmeta(nname, "already_warned", "1"); + } + } + } + } + } + if (!result || !Len(result)) { + if (result) + Delete(result); + if (oldname) { + result = NewString(oldname); + } else { + result = NewString(cname); + } + } + Delete(name); + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_make: result '%s' '%s'\n", cname, result); +#endif + + return result; +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_inherit() + * + * Inherit namewarn,rename, and feature objects + * + * ----------------------------------------------------------------------------- */ + +void Swig_name_inherit(String *base, String *derived) { + /* Printf(stdout,"base = '%s', derived = '%s'\n", base, derived); */ + Swig_name_object_inherit(Swig_name_rename_hash(), base, derived); + Swig_name_object_inherit(Swig_name_namewarn_hash(), base, derived); + Swig_name_object_inherit(Swig_cparse_features(), base, derived); +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_decl() + * + * Return a stringified version of a C/C++ declaration without the return type. + * The node passed in is expected to be a function. Some example return values: + * "MyNameSpace::MyTemplate<MyNameSpace::ABC >::~MyTemplate()" + * "MyNameSpace::ABC::ABC(int,double)" + * "MyNameSpace::ABC::constmethod(int) const" + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_decl(Node *n) { + String *qname; + String *decl; + String *qualifier = Swig_symbol_qualified(n); + String *name = Swig_scopename_last(Getattr(n, "name")); + if (qualifier) + qualifier = SwigType_namestr(qualifier); + + /* Very specific hack for template constructors/destructors */ + if (SwigType_istemplate(name)) { + String *nodetype = nodeType(n); + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + String *nprefix = NewStringEmpty(); + String *nlast = NewStringEmpty(); + String *tprefix; + Swig_scopename_split(name, &nprefix, &nlast); + tprefix = SwigType_templateprefix(nlast); + Delete(nlast); + Delete(name); + name = tprefix; + } + } + + qname = NewString(""); + if (qualifier && Len(qualifier) > 0) + Printf(qname, "%s::", qualifier); + Printf(qname, "%s", SwigType_str(name, 0)); + + decl = NewStringf("%s(%s)%s", qname, ParmList_errorstr(Getattr(n, "parms")), SwigType_isconst(Getattr(n, "decl")) ? " const" : ""); + + Delete(name); + Delete(qualifier); + Delete(qname); + + return decl; +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_fulldecl() + * + * Return a stringified version of a C/C++ declaration including the return type. + * The node passed in is expected to be a function. Some example return values: + * "MyNameSpace::MyTemplate<MyNameSpace::ABC >::~MyTemplate()" + * "MyNameSpace::ABC::ABC(int,double)" + * "int * MyNameSpace::ABC::constmethod(int) const" + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_fulldecl(Node *n) { + String *decl = Swig_name_decl(n); + String *type = Getattr(n, "type"); + String *nodetype = nodeType(n); + String *fulldecl; + /* add on the return type */ + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + fulldecl = decl; + } else { + String *t = SwigType_str(type, 0); + fulldecl = NewStringf("%s %s", t, decl); + Delete(decl); + Delete(t); + } + return fulldecl; +} + diff --git a/Source/Swig/parms.c b/Source/Swig/parms.c new file mode 100644 index 0000000..c13c24c --- /dev/null +++ b/Source/Swig/parms.c @@ -0,0 +1,196 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * parms.c + * + * Parameter list class. + * ----------------------------------------------------------------------------- */ + +char cvsroot_parms_c[] = "$Id: parms.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" + +/* ------------------------------------------------------------------------ + * NewParm() + * + * Create a new parameter from datatype 'type' and name 'name'. + * ------------------------------------------------------------------------ */ + +Parm *NewParm(SwigType *type, const_String_or_char_ptr name) { + Parm *p = NewHash(); + set_nodeType(p, "parm"); + if (type) { + SwigType *ntype = Copy(type); + Setattr(p, "type", ntype); + Delete(ntype); + } + Setattr(p, "name", name); + return p; +} + +/* ------------------------------------------------------------------------ + * CopyParm() + * ------------------------------------------------------------------------ */ + +Parm *CopyParm(Parm *p) { + Parm *np = NewHash(); + Iterator ki; + for (ki = First(p); ki.key; ki = Next(ki)) { + if (DohIsString(ki.item)) { + DOH *c = Copy(ki.item); + Setattr(np,ki.key,c); + Delete(c); + } + } + Setfile(np, Getfile(p)); + Setline(np, Getline(p)); + return np; +} + +/* ------------------------------------------------------------------ + * CopyParmListMax() + * CopyParmList() + * ------------------------------------------------------------------ */ + +ParmList *CopyParmListMax(ParmList *p, int count) { + Parm *np; + Parm *pp = 0; + Parm *fp = 0; + + if (!p) + return 0; + + while (p) { + if (count == 0) break; + np = CopyParm(p); + if (pp) { + set_nextSibling(pp, np); + Delete(np); + } else { + fp = np; + } + pp = np; + p = nextSibling(p); + count--; + } + return fp; +} + +ParmList *CopyParmList(ParmList *p) { + return CopyParmListMax(p,-1); +} + +/* ----------------------------------------------------------------------------- + * int ParmList_numrequired(). Return number of required arguments + * ----------------------------------------------------------------------------- */ + +int ParmList_numrequired(ParmList *p) { + int i = 0; + while (p) { + SwigType *t = Getattr(p, "type"); + String *value = Getattr(p, "value"); + if (value) + return i; + if (!(SwigType_type(t) == T_VOID)) + i++; + else + break; + p = nextSibling(p); + } + return i; +} + +/* ----------------------------------------------------------------------------- + * int ParmList_len() + * ----------------------------------------------------------------------------- */ + +int ParmList_len(ParmList *p) { + int i = 0; + while (p) { + i++; + p = nextSibling(p); + } + return i; +} + +/* --------------------------------------------------------------------- + * ParmList_str() + * + * Generates a string of parameters + * ---------------------------------------------------------------------- */ + +String *ParmList_str(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + String *pstr = SwigType_str(Getattr(p, "type"), Getattr(p, "name")); + Append(out, pstr); + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + return out; +} + +/* --------------------------------------------------------------------- + * ParmList_str_defaultargs() + * + * Generates a string of parameters including default arguments + * ---------------------------------------------------------------------- */ + +String *ParmList_str_defaultargs(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + String *value = Getattr(p, "value"); + String *pstr = SwigType_str(Getattr(p, "type"), Getattr(p, "name")); + Append(out, pstr); + if (value) { + Printf(out, "=%s", value); + } + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + return out; +} + +/* --------------------------------------------------------------------- + * ParmList_protostr() + * + * Generate a prototype string. + * ---------------------------------------------------------------------- */ + +String *ParmList_protostr(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + String *pstr = SwigType_str(Getattr(p, "type"), 0); + Append(out, pstr); + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + return out; +} + +/* --------------------------------------------------------------------- + * ParmList_has_defaultargs() + * + * Returns 1 if the parameter list passed in is has one or more default + * arguments. Otherwise returns 0. + * ---------------------------------------------------------------------- */ + +int ParmList_has_defaultargs(ParmList *p) { + while (p) { + if (Getattr(p, "value")) { + return 1; + } + p = nextSibling(p); + } + return 0; +} diff --git a/Source/Swig/scanner.c b/Source/Swig/scanner.c new file mode 100644 index 0000000..328a491 --- /dev/null +++ b/Source/Swig/scanner.c @@ -0,0 +1,1227 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * scanner.c + * + * This file implements a general purpose C/C++ compatible lexical scanner. + * This scanner isn't intended to be plugged directly into a parser built + * with yacc. Rather, it contains a lot of generic code that could be used + * to easily construct yacc-compatible scanners. + * ----------------------------------------------------------------------------- */ + +char cvsroot_scanner_c[] = "$Id: scanner.c 11470 2009-07-29 20:50:39Z wsfulton $"; + +#include "swig.h" +#include <ctype.h> + +extern String *cparse_file; +extern int cparse_start_line; + +struct Scanner { + String *text; /* Current token value */ + List *scanobjs; /* Objects being scanned */ + String *str; /* Current object being scanned */ + char *idstart; /* Optional identifier start characters */ + int nexttoken; /* Next token to be returned */ + int start_line; /* Starting line of certain declarations */ + int line; + int yylen; /* Length of text pushed into text */ + String *file; + String *error; /* Last error message (if any) */ + int error_line; /* Error line number */ + int freeze_line; /* Suspend line number updates */ +}; + +/* ----------------------------------------------------------------------------- + * NewScanner() + * + * Create a new scanner object + * ----------------------------------------------------------------------------- */ + +Scanner *NewScanner(void) { + Scanner *s; + s = (Scanner *) malloc(sizeof(Scanner)); + s->line = 1; + s->file = 0; + s->nexttoken = -1; + s->start_line = 1; + s->yylen = 0; + s->idstart = NULL; + s->scanobjs = NewList(); + s->text = NewStringEmpty(); + s->str = 0; + s->error = 0; + s->freeze_line = 0; + return s; +} + +/* ----------------------------------------------------------------------------- + * DelScanner() + * + * Delete a scanner object. + * ----------------------------------------------------------------------------- */ + +void DelScanner(Scanner * s) { + assert(s); + Delete(s->scanobjs); + Delete(s->text); + Delete(s->file); + Delete(s->error); + Delete(s->str); + free(s->idstart); + free(s); +} + +/* ----------------------------------------------------------------------------- + * Scanner_clear() + * + * Clear the contents of a scanner object. + * ----------------------------------------------------------------------------- */ + +void Scanner_clear(Scanner * s) { + assert(s); + Delete(s->str); + Clear(s->text); + Clear(s->scanobjs); + Delete(s->error); + s->str = 0; + s->error = 0; + s->line = 1; + s->nexttoken = -1; + s->start_line = 0; + s->yylen = 0; +} + +/* ----------------------------------------------------------------------------- + * Scanner_push() + * + * Push some new text into the scanner. The scanner will start parsing this text + * immediately before returning to the old text. + * ----------------------------------------------------------------------------- */ + +void Scanner_push(Scanner * s, String *txt) { + assert(s && txt); + Push(s->scanobjs, txt); + if (s->str) { + Setline(s->str,s->line); + Delete(s->str); + } + s->str = txt; + DohIncref(s->str); + s->line = Getline(txt); +} + +/* ----------------------------------------------------------------------------- + * Scanner_pushtoken() + * + * Push a token into the scanner. This token will be returned on the next + * call to Scanner_token(). + * ----------------------------------------------------------------------------- */ + +void Scanner_pushtoken(Scanner * s, int nt, const_String_or_char_ptr val) { + assert(s); + assert((nt >= 0) && (nt < SWIG_MAXTOKENS)); + s->nexttoken = nt; + if ( Char(val) != Char(s->text) ) { + Clear(s->text); + Append(s->text,val); + } +} + +/* ----------------------------------------------------------------------------- + * Scanner_set_location() + * + * Set the file and line number location of the scanner. + * ----------------------------------------------------------------------------- */ + +void Scanner_set_location(Scanner * s, String *file, int line) { + Setline(s->str, line); + Setfile(s->str, file); + s->line = line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_file() + * + * Get the current file. + * ----------------------------------------------------------------------------- */ + +String *Scanner_file(Scanner * s) { + return Getfile(s->str); +} + +/* ----------------------------------------------------------------------------- + * Scanner_line() + * + * Get the current line number + * ----------------------------------------------------------------------------- */ +int Scanner_line(Scanner * s) { + return s->line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_start_line() + * + * Get the line number on which the current token starts + * ----------------------------------------------------------------------------- */ +int Scanner_start_line(Scanner * s) { + return s->start_line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_idstart() + * + * Change the set of additional characters that can be used to start an identifier. + * ----------------------------------------------------------------------------- */ + +void Scanner_idstart(Scanner * s, const char *id) { + free(s->idstart); + s->idstart = Swig_copy_string(id); +} + +/* ----------------------------------------------------------------------------- + * nextchar() + * + * Returns the next character from the scanner or 0 if end of the string. + * ----------------------------------------------------------------------------- */ +static char nextchar(Scanner * s) { + int nc; + if (!s->str) + return 0; + while ((nc = Getc(s->str)) == EOF) { + Delete(s->str); + s->str = 0; + Delitem(s->scanobjs, 0); + if (Len(s->scanobjs) == 0) + return 0; + s->str = Getitem(s->scanobjs, 0); + if (s->str) { + s->line = Getline(s->str); + DohIncref(s->str); + } + } + if ((nc == '\n') && (!s->freeze_line)) + s->line++; + Putc(nc,s->text); + return (char)nc; +} + +/* ----------------------------------------------------------------------------- + * set_error() + * + * Sets error information on the scanner. + * ----------------------------------------------------------------------------- */ + +static void set_error(Scanner *s, int line, const_String_or_char_ptr msg) { + s->error_line = line; + s->error = NewString(msg); +} + +/* ----------------------------------------------------------------------------- + * Scanner_errmsg() + * Scanner_errline() + * + * Returns error information (if any) + * ----------------------------------------------------------------------------- */ + +String * +Scanner_errmsg(Scanner *s) { + return s->error; +} + +int +Scanner_errline(Scanner *s) { + return s->error_line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_freeze_line() + * + * Freezes the current line number. + * ----------------------------------------------------------------------------- */ + +void +Scanner_freeze_line(Scanner *s, int val) { + s->freeze_line = val; +} + +/* ----------------------------------------------------------------------------- + * retract() + * + * Retract n characters + * ----------------------------------------------------------------------------- */ +static void retract(Scanner * s, int n) { + int i, l; + char *str; + + str = Char(s->text); + l = Len(s->text); + assert(n <= l); + for (i = 0; i < n; i++) { + if (str[l - 1] == '\n') { + if (!s->freeze_line) s->line--; + } + Seek(s->str, -1, SEEK_CUR); + Delitem(s->text, DOH_END); + } +} + +/* ----------------------------------------------------------------------------- + * get_escape() + * + * Get escape sequence. Called when a backslash is found in a string + * ----------------------------------------------------------------------------- */ + +static void get_escape(Scanner *s) { + int result = 0; + int state = 0; + int c; + + while (1) { + c = nextchar(s); + if (c == 0) + break; + switch (state) { + case 0: + if (c == 'n') { + Delitem(s->text, DOH_END); + Append(s->text,"\n"); + return; + } + if (c == 'r') { + Delitem(s->text, DOH_END); + Append(s->text,"\r"); + return; + } + if (c == 't') { + Delitem(s->text, DOH_END); + Append(s->text,"\t"); + return; + } + if (c == 'a') { + Delitem(s->text, DOH_END); + Append(s->text,"\a"); + return; + } + if (c == 'b') { + Delitem(s->text, DOH_END); + Append(s->text,"\b"); + return; + } + if (c == 'f') { + Delitem(s->text, DOH_END); + Append(s->text,"\f"); + return; + } + if (c == '\\') { + Delitem(s->text, DOH_END); + Append(s->text,"\\"); + return; + } + if (c == 'v') { + Delitem(s->text, DOH_END); + Append(s->text,"\v"); + return; + } + if (c == 'e') { + Delitem(s->text, DOH_END); + Append(s->text,"\033"); + return; + } + if (c == '\'') { + Delitem(s->text, DOH_END); + Append(s->text,"\'"); + return; + } + if (c == '\"') { + Delitem(s->text, DOH_END); + Append(s->text,"\""); + return; + } + if (c == '\n') { + Delitem(s->text, DOH_END); + return; + } + if (isdigit(c)) { + state = 10; + result = (c - '0'); + Delitem(s->text, DOH_END); + } else if (c == 'x') { + state = 20; + Delitem(s->text, DOH_END); + } else { + char tmp[3]; + tmp[0] = '\\'; + tmp[1] = (char)c; + tmp[2] = 0; + Delitem(s->text, DOH_END); + Append(s->text, tmp); + return; + } + break; + case 10: + if (!isdigit(c)) { + retract(s,1); + Putc((char)result,s->text); + return; + } + result = (result << 3) + (c - '0'); + Delitem(s->text, DOH_END); + break; + case 20: + if (!isxdigit(c)) { + retract(s,1); + Putc((char)result, s->text); + return; + } + if (isdigit(c)) + result = (result << 4) + (c - '0'); + else + result = (result << 4) + (10 + tolower(c) - 'a'); + Delitem(s->text, DOH_END); + break; + } + } + return; +} + +/* ----------------------------------------------------------------------------- + * look() + * + * Return the raw value of the next token. + * ----------------------------------------------------------------------------- */ + +static int look(Scanner * s) { + int state; + int c = 0; + + state = 0; + Clear(s->text); + s->start_line = s->line; + Setfile(s->text, Getfile(s->str)); + while (1) { + switch (state) { + case 0: + if ((c = nextchar(s)) == 0) + return (0); + + /* Process delimiters */ + + if (c == '\n') { + return SWIG_TOKEN_ENDLINE; + } else if (!isspace(c)) { + retract(s, 1); + state = 1000; + Clear(s->text); + Setline(s->text, s->line); + Setfile(s->text, Getfile(s->str)); + } + break; + + case 1000: + if ((c = nextchar(s)) == 0) + return (0); + if (c == '%') + state = 4; /* Possibly a SWIG directive */ + + /* Look for possible identifiers */ + + else if ((isalpha(c)) || (c == '_') || + (s->idstart && strchr(s->idstart, c))) + state = 7; + + /* Look for single character symbols */ + + else if (c == '(') + return SWIG_TOKEN_LPAREN; + else if (c == ')') + return SWIG_TOKEN_RPAREN; + else if (c == ';') + return SWIG_TOKEN_SEMI; + else if (c == ',') + return SWIG_TOKEN_COMMA; + else if (c == '*') + state = 220; + else if (c == '}') + return SWIG_TOKEN_RBRACE; + else if (c == '{') + return SWIG_TOKEN_LBRACE; + else if (c == '=') + state = 33; + else if (c == '+') + state = 200; + else if (c == '-') + state = 210; + else if (c == '&') + state = 31; + else if (c == '|') + state = 32; + else if (c == '^') + state = 230; + else if (c == '<') + state = 60; + else if (c == '>') + state = 61; + else if (c == '~') + return SWIG_TOKEN_NOT; + else if (c == '!') + state = 3; + else if (c == '\\') + return SWIG_TOKEN_BACKSLASH; + else if (c == '[') + return SWIG_TOKEN_LBRACKET; + else if (c == ']') + return SWIG_TOKEN_RBRACKET; + else if (c == '@') + return SWIG_TOKEN_AT; + else if (c == '$') + state = 75; + else if (c == '#') + return SWIG_TOKEN_POUND; + else if (c == '?') + return SWIG_TOKEN_QUESTION; + + /* Look for multi-character sequences */ + + else if (c == '/') { + state = 1; /* Comment (maybe) */ + s->start_line = s->line; + } + else if (c == '\"') { + state = 2; /* Possibly a string */ + s->start_line = s->line; + Clear(s->text); + } + + else if (c == ':') + state = 5; /* maybe double colon */ + else if (c == '0') + state = 83; /* An octal or hex value */ + else if (c == '\'') { + s->start_line = s->line; + Clear(s->text); + state = 9; /* A character constant */ + } else if (c == '`') { + s->start_line = s->line; + Clear(s->text); + state = 900; + } + + else if (c == '.') + state = 100; /* Maybe a number, maybe just a period */ + else if (isdigit(c)) + state = 8; /* A numerical value */ + else + state = 99; /* An error */ + break; + + case 1: /* Comment block */ + if ((c = nextchar(s)) == 0) + return (0); + if (c == '/') { + state = 10; /* C++ style comment */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + Append(s->text, "//"); + } else if (c == '*') { + state = 11; /* C style comment */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + Append(s->text, "/*"); + } else if (c == '=') { + return SWIG_TOKEN_DIVEQUAL; + } else { + retract(s, 1); + return SWIG_TOKEN_SLASH; + } + break; + case 10: /* C++ style comment */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\n') { + retract(s,1); + return SWIG_TOKEN_COMMENT; + } else { + state = 10; + } + break; + case 11: /* C style comment block */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '*') { + state = 12; + } else { + state = 11; + } + break; + case 12: /* Still in C style comment */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '*') { + state = 12; + } else if (c == '/') { + return SWIG_TOKEN_COMMENT; + } else { + state = 11; + } + break; + + case 2: /* Processing a string */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated string\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\"') { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_STRING; + } else if (c == '\\') { + Delitem(s->text, DOH_END); + get_escape(s); + } else + state = 2; + break; + + case 3: /* Maybe a not equals */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LNOT; + else if (c == '=') + return SWIG_TOKEN_NOTEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_LNOT; + } + break; + + case 31: /* AND or Logical AND or ANDEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_AND; + else if (c == '&') + return SWIG_TOKEN_LAND; + else if (c == '=') + return SWIG_TOKEN_ANDEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_AND; + } + break; + + case 32: /* OR or Logical OR */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_OR; + else if (c == '|') + return SWIG_TOKEN_LOR; + else if (c == '=') + return SWIG_TOKEN_OREQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_OR; + } + break; + + case 33: /* EQUAL or EQUALTO */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_EQUAL; + else if (c == '=') + return SWIG_TOKEN_EQUALTO; + else { + retract(s, 1); + return SWIG_TOKEN_EQUAL; + } + break; + + case 4: /* A wrapper generator directive (maybe) */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_PERCENT; + if (c == '{') { + state = 40; /* Include block */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + s->start_line = s->line; + } else if (s->idstart && strchr(s->idstart, '%') && + ((isalpha(c)) || (c == '_'))) { + state = 7; + } else if (c == '=') { + return SWIG_TOKEN_MODEQUAL; + } else { + retract(s, 1); + return SWIG_TOKEN_PERCENT; + } + break; + + case 40: /* Process an include block */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated block\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '%') + state = 41; + break; + case 41: /* Still processing include block */ + if ((c = nextchar(s)) == 0) { + set_error(s,s->start_line,"Unterminated code block"); + return 0; + } + if (c == '}') { + Delitem(s->text, DOH_END); + Delitem(s->text, DOH_END); + Seek(s->text,0,SEEK_SET); + return SWIG_TOKEN_CODEBLOCK; + } else { + state = 40; + } + break; + + case 5: /* Maybe a double colon */ + + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_COLON; + if (c == ':') + state = 50; + else { + retract(s, 1); + return SWIG_TOKEN_COLON; + } + break; + + case 50: /* DCOLON, DCOLONSTAR */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DCOLON; + else if (c == '*') + return SWIG_TOKEN_DCOLONSTAR; + else { + retract(s, 1); + return SWIG_TOKEN_DCOLON; + } + break; + + case 60: /* shift operators */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LESSTHAN; + if (c == '<') + state = 240; + else if (c == '=') + return SWIG_TOKEN_LTEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_LESSTHAN; + } + break; + case 61: + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_GREATERTHAN; + if (c == '>') + state = 250; + else if (c == '=') + return SWIG_TOKEN_GTEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_GREATERTHAN; + } + break; + case 7: /* Identifier */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_ID; + if (isalnum(c) || (c == '_') || (c == '$')) { + state = 7; + } else { + retract(s, 1); + return SWIG_TOKEN_ID; + } + break; + + case 75: /* Special identifier $ */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DOLLAR; + if (isalnum(c) || (c == '_') || (c == '*') || (c == '&')) { + state = 7; + } else { + retract(s,1); + if (Len(s->text) == 1) return SWIG_TOKEN_DOLLAR; + return SWIG_TOKEN_ID; + } + break; + + case 8: /* A numerical digit */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (c == '.') { + state = 81; + } else if ((c == 'e') || (c == 'E')) { + state = 82; + } else if ((c == 'f') || (c == 'F')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_FLOAT; + } else if (isdigit(c)) { + state = 8; + } else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 81: /* A floating pointer number of some sort */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DOUBLE; + if (isdigit(c)) + state = 81; + else if ((c == 'e') || (c == 'E')) + state = 820; + else if ((c == 'f') || (c == 'F')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_FLOAT; + } else if ((c == 'l') || (c == 'L')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_DOUBLE; + } else { + retract(s, 1); + return (SWIG_TOKEN_DOUBLE); + } + break; + case 82: + if ((c = nextchar(s)) == 0) { + retract(s, 1); + return SWIG_TOKEN_INT; + } + if ((isdigit(c)) || (c == '-') || (c == '+')) + state = 86; + else { + retract(s, 2); + return (SWIG_TOKEN_INT); + } + break; + case 820: + /* Like case 82, but we've seen a decimal point. */ + if ((c = nextchar(s)) == 0) { + retract(s, 1); + return SWIG_TOKEN_DOUBLE; + } + if ((isdigit(c)) || (c == '-') || (c == '+')) + state = 86; + else { + retract(s, 2); + return (SWIG_TOKEN_DOUBLE); + } + break; + case 83: + /* Might be a hexadecimal or octal number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (isdigit(c)) + state = 84; + else if ((c == 'x') || (c == 'X')) + state = 85; + else if (c == '.') + state = 81; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 84: + /* This is an octal number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (isdigit(c)) + state = 84; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 85: + /* This is an hex number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (isxdigit(c)) + state = 85; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + + case 86: + /* Rest of floating point number */ + + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DOUBLE; + if (isdigit(c)) + state = 86; + else if ((c == 'f') || (c == 'F')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_FLOAT; + } else if ((c == 'l') || (c == 'L')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_DOUBLE; + } else { + retract(s, 1); + return SWIG_TOKEN_DOUBLE; + } + break; + + case 87: + /* A long integer of some sort */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LONG; + if ((c == 'u') || (c == 'U')) { + return SWIG_TOKEN_ULONG; + } else if ((c == 'l') || (c == 'L')) { + state = 870; + } else { + retract(s, 1); + return SWIG_TOKEN_LONG; + } + break; + + /* A long long integer */ + + case 870: + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LONGLONG; + if ((c == 'u') || (c == 'U')) { + return SWIG_TOKEN_ULONGLONG; + } else { + retract(s, 1); + return SWIG_TOKEN_LONGLONG; + } + + /* An unsigned number */ + case 88: + + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_UINT; + if ((c == 'l') || (c == 'L')) { + state = 880; + } else { + retract(s, 1); + return SWIG_TOKEN_UINT; + } + break; + + /* Possibly an unsigned long long or unsigned long */ + case 880: + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_ULONG; + if ((c == 'l') || (c == 'L')) + return SWIG_TOKEN_ULONGLONG; + else { + retract(s, 1); + return SWIG_TOKEN_ULONG; + } + + /* A character constant */ + case 9: + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\'') { + Delitem(s->text, DOH_END); + return (SWIG_TOKEN_CHAR); + } else if (c == '\\') { + Delitem(s->text, DOH_END); + get_escape(s); + } + break; + + /* A period or maybe a floating point number */ + + case 100: + if ((c = nextchar(s)) == 0) + return (0); + if (isdigit(c)) + state = 81; + else { + retract(s, 1); + return SWIG_TOKEN_PERIOD; + } + break; + + case 200: /* PLUS, PLUSPLUS, PLUSEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_PLUS; + else if (c == '+') + return SWIG_TOKEN_PLUSPLUS; + else if (c == '=') + return SWIG_TOKEN_PLUSEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_PLUS; + } + break; + + case 210: /* MINUS, MINUSMINUS, MINUSEQUAL, ARROW */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_MINUS; + else if (c == '-') + return SWIG_TOKEN_MINUSMINUS; + else if (c == '=') + return SWIG_TOKEN_MINUSEQUAL; + else if (c == '>') + state = 211; + else { + retract(s, 1); + return SWIG_TOKEN_MINUS; + } + break; + + case 211: /* ARROW, ARROWSTAR */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_ARROW; + else if (c == '*') + return SWIG_TOKEN_ARROWSTAR; + else { + retract(s, 1); + return SWIG_TOKEN_ARROW; + } + break; + + + case 220: /* STAR, TIMESEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_STAR; + else if (c == '=') + return SWIG_TOKEN_TIMESEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_STAR; + } + break; + + case 230: /* XOR, XOREQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_XOR; + else if (c == '=') + return SWIG_TOKEN_XOREQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_XOR; + } + break; + + case 240: /* LSHIFT, LSEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LSHIFT; + else if (c == '=') + return SWIG_TOKEN_LSEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_LSHIFT; + } + break; + + case 250: /* RSHIFT, RSEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_RSHIFT; + else if (c == '=') + return SWIG_TOKEN_RSEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_RSHIFT; + } + break; + + + /* An illegal character */ + + /* Reverse string */ + case 900: + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '`') { + Delitem(s->text, DOH_END); + return (SWIG_TOKEN_RSTRING); + } + break; + + default: + return SWIG_TOKEN_ILLEGAL; + } + } +} + +/* ----------------------------------------------------------------------------- + * Scanner_token() + * + * Real entry point to return the next token. Returns 0 if at end of input. + * ----------------------------------------------------------------------------- */ + +int Scanner_token(Scanner * s) { + int t; + Delete(s->error); + if (s->nexttoken >= 0) { + t = s->nexttoken; + s->nexttoken = -1; + return t; + } + s->start_line = 0; + t = look(s); + if (!s->start_line) { + Setline(s->text,s->line); + } else { + Setline(s->text,s->start_line); + } + return t; +} + +/* ----------------------------------------------------------------------------- + * Scanner_text() + * + * Return the lexene associated with the last returned token. + * ----------------------------------------------------------------------------- */ + +String *Scanner_text(Scanner * s) { + return s->text; +} + +/* ----------------------------------------------------------------------------- + * Scanner_skip_line() + * + * Skips to the end of a line + * ----------------------------------------------------------------------------- */ + +void Scanner_skip_line(Scanner * s) { + char c; + int done = 0; + Clear(s->text); + Setfile(s->text, Getfile(s->str)); + Setline(s->text, s->line); + while (!done) { + if ((c = nextchar(s)) == 0) + return; + if (c == '\\') { + c = nextchar(s); + } else if (c == '\n') { + done = 1; + } + } + return; +} + +/* ----------------------------------------------------------------------------- + * Scanner_skip_balanced() + * + * Skips a piece of code enclosed in begin/end symbols such as '{...}' or + * (...). Ignores symbols inside comments or strings. + * ----------------------------------------------------------------------------- */ + +int Scanner_skip_balanced(Scanner * s, int startchar, int endchar) { + char c; + int num_levels = 1; + int l; + int state = 0; + char temp[2] = { 0, 0 }; + l = s->line; + temp[0] = (char) startchar; + Clear(s->text); + Setfile(s->text, Getfile(s->str)); + Setline(s->text, s->line); + + Append(s->text, temp); + while (num_levels > 0) { + if ((c = nextchar(s)) == 0) { + return -1; + } + switch (state) { + case 0: + if (c == startchar) + num_levels++; + else if (c == endchar) + num_levels--; + else if (c == '/') + state = 10; + else if (c == '\"') + state = 20; + else if (c == '\'') + state = 30; + break; + case 10: + if (c == '/') + state = 11; + else if (c == '*') + state = 12; + else + state = 0; + break; + case 11: + if (c == '\n') + state = 0; + else + state = 11; + break; + case 12: + if (c == '*') + state = 13; + break; + case 13: + if (c == '*') + state = 13; + else if (c == '/') + state = 0; + else + state = 12; + break; + case 20: + if (c == '\"') + state = 0; + else if (c == '\\') + state = 21; + break; + case 21: + state = 20; + break; + case 30: + if (c == '\'') + state = 0; + else if (c == '\\') + state = 31; + break; + case 31: + state = 30; + break; + default: + break; + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Scanner_isoperator() + * + * Returns 0 or 1 depending on whether or not a token corresponds to a C/C++ + * operator. + * ----------------------------------------------------------------------------- */ + +int +Scanner_isoperator(int tokval) { + if (tokval >= 100) return 1; + return 0; +} diff --git a/Source/Swig/stype.c b/Source/Swig/stype.c new file mode 100644 index 0000000..68696ec --- /dev/null +++ b/Source/Swig/stype.c @@ -0,0 +1,1105 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * stype.c + * + * This file provides general support for datatypes that are encoded in + * the form of simple strings. + * ----------------------------------------------------------------------------- */ + +char cvsroot_stype_c[] = "$Id: stype.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * The purpose of this module is to provide a general purpose type representation + * based on simple text strings. + * + * General idea: + * + * Types are represented by a base type (e.g., "int") and a collection of + * type operators applied to the base (e.g., pointers, arrays, etc...). + * + * Encoding: + * + * Types are encoded as strings of type constructors such as follows: + * + * String Encoding C Example + * --------------- --------- + * p.p.int int ** + * a(300).a(400).int int [300][400] + * p.q(const).char char const * + * + * All type constructors are denoted by a trailing '.': + * + * 'p.' = Pointer (*) + * 'r.' = Reference (&) + * 'a(n).' = Array of size n [n] + * 'f(..,..).' = Function with arguments (args) + * 'q(str).' = Qualifier (such as const or volatile) (const, volatile) + * 'm(qual).' = Pointer to member (qual::*) + * + * The encoding follows the order that you might describe a type in words. + * For example "p.a(200).int" is "A pointer to array of int's" and + * "p.q(const).char" is "a pointer to a const char". + * + * This representation of types is fairly convenient because ordinary string + * operations can be used for type manipulation. For example, a type could be + * formed by combining two strings such as the following: + * + * "p.p." + "a(400).int" = "p.p.a(400).int" + * + * Similarly, one could strip a 'const' declaration from a type doing something + * like this: + * + * Replace(t,"q(const).","",DOH_REPLACE_ANY) + * + * For the most part, this module tries to minimize the use of special + * characters (*, [, <, etc...) in its type encoding. One reason for this + * is that SWIG might be extended to encode data in formats such as XML + * where you might want to do this: + * + * <function> + * <type>p.p.int</type> + * ... + * </function> + * + * Or alternatively, + * + * <function type="p.p.int" ...>blah</function> + * + * In either case, it's probably best to avoid characters such as '&', '*', or '<'. + * + * Why not use C syntax? Well, C syntax is fairly complicated to parse + * and not particularly easy to manipulate---especially for adding, deleting and + * composing type constructors. The string representation presented here makes + * this pretty easy. + * + * Why not use a bunch of nested data structures? Are you kidding? How + * would that be easier to use than a few simple string operations? + * ----------------------------------------------------------------------------- */ + + +SwigType *NewSwigType(int t) { + switch (t) { + case T_BOOL: + return NewString("bool"); + break; + case T_INT: + return NewString("int"); + break; + case T_UINT: + return NewString("unsigned int"); + break; + case T_SHORT: + return NewString("short"); + break; + case T_USHORT: + return NewString("unsigned short"); + break; + case T_LONG: + return NewString("long"); + break; + case T_ULONG: + return NewString("unsigned long"); + break; + case T_FLOAT: + return NewString("float"); + break; + case T_DOUBLE: + return NewString("double"); + break; + case T_COMPLEX: + return NewString("complex"); + break; + case T_CHAR: + return NewString("char"); + break; + case T_SCHAR: + return NewString("signed char"); + break; + case T_UCHAR: + return NewString("unsigned char"); + break; + case T_STRING:{ + SwigType *t = NewString("char"); + SwigType_add_pointer(t); + return t; + break; + } + case T_LONGLONG: + return NewString("long long"); + break; + case T_ULONGLONG: + return NewString("unsigned long long"); + break; + case T_VOID: + return NewString("void"); + break; + default: + break; + } + return NewStringEmpty(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_push() + * + * Push a type constructor onto the type + * ----------------------------------------------------------------------------- */ + +void SwigType_push(SwigType *t, String *cons) { + if (!cons) + return; + if (!Len(cons)) + return; + + if (Len(t)) { + char *c = Char(cons); + if (c[strlen(c) - 1] != '.') + Insert(t, 0, "."); + } + Insert(t, 0, cons); +} + +/* ----------------------------------------------------------------------------- + * SwigType_ispointer_return() + * + * Testing functions for querying a raw datatype + * ----------------------------------------------------------------------------- */ + +int SwigType_ispointer_return(SwigType *t) { + char *c; + int idx; + if (!t) + return 0; + c = Char(t); + idx = strlen(c) - 4; + if (idx >= 0) { + return (strcmp(c + idx, ").p.") == 0); + } + return 0; +} + +int SwigType_isreference_return(SwigType *t) { + char *c; + int idx; + if (!t) + return 0; + c = Char(t); + idx = strlen(c) - 4; + if (idx >= 0) { + return (strcmp(c + idx, ").r.") == 0); + } + return 0; +} + +int SwigType_isconst(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + String *q = SwigType_parm(t); + if (strstr(Char(q), "const")) { + Delete(q); + return 1; + } + Delete(q); + } + /* Hmmm. Might be const through a typedef */ + if (SwigType_issimple(t)) { + int ret; + SwigType *td = SwigType_typedef_resolve(t); + if (td) { + ret = SwigType_isconst(td); + Delete(td); + return ret; + } + } + return 0; +} + +int SwigType_ismutable(SwigType *t) { + int r; + SwigType *qt = SwigType_typedef_resolve_all(t); + if (SwigType_isreference(qt) || SwigType_isarray(qt)) { + Delete(SwigType_pop(qt)); + } + r = SwigType_isconst(qt); + Delete(qt); + return r ? 0 : 1; +} + +int SwigType_isenum(SwigType *t) { + char *c = Char(t); + if (!t) + return 0; + if (strncmp(c, "enum ", 5) == 0) { + return 1; + } + return 0; +} + +int SwigType_issimple(SwigType *t) { + char *c = Char(t); + if (!t) + return 0; + while (*c) { + if (*c == '<') { + int nest = 1; + c++; + while (*c && nest) { + if (*c == '<') + nest++; + if (*c == '>') + nest--; + c++; + } + c--; + } + if (*c == '.') + return 0; + c++; + } + return 1; +} + +/* ----------------------------------------------------------------------------- + * SwigType_default() + * + * Create the default string for this datatype. This takes a type and strips it + * down to its most primitive form--resolving all typedefs and removing operators. + * + * Rules: + * Pointers: p.SWIGTYPE + * References: r.SWIGTYPE + * Arrays: a().SWIGTYPE + * Types: SWIGTYPE + * MemberPointer: m(CLASS).SWIGTYPE + * Enums: enum SWIGTYPE + * + * Note: if this function is applied to a primitive type, it returns NULL. This + * allows recursive application for special types like arrays. + * ----------------------------------------------------------------------------- */ + +#ifdef SWIG_DEFAULT_CACHE +static Hash *default_cache = 0; +#endif + +#define SWIG_NEW_TYPE_DEFAULT +/* The new default type resolution method: + +1.- It preserves the original mixed types, then it goes 'backward' + first deleting the qualifier, then the inner types + + typedef A *Aptr; + const Aptr&; + r.q(const).Aptr -> r.q(const).p.SWIGTYPE + r.q(const).p.SWIGTYPE -> r.p.SWIGTYPE + r.p.SWIGTYPE -> r.SWIGTYPE + r.SWIGTYPE -> SWIGTYPE + + + enum Hello {}; + const Hello& hi; + r.q(const).Hello -> r.q(const).enum SWIGTYPE + r.q(const).enum SWIGTYPE -> r.enum SWIGTYPE + r.enum SWIGTYPE -> r.SWIGTYPE + r.SWIGTYPE -> SWIGTYPE + + int a[2][4]; + a(2).a(4).int -> a(ANY).a(ANY).SWIGTYPE + a(ANY).a(ANY).SWIGTYPE -> a(ANY).a().SWIGTYPE + a(ANY).a().SWIGTYPE -> a(ANY).p.SWIGTYPE + a(ANY).p.SWIGTYPE -> a(ANY).SWIGTYPE + a(ANY).SWIGTYPE -> a().SWIGTYPE + a().SWIGTYPE -> p.SWIGTYPE + p.SWIGTYPE -> SWIGTYPE +*/ + +static +void SwigType_add_default(String *def, SwigType *nr) { + if (Strcmp(nr, "SWIGTYPE") == 0) { + Append(def, "SWIGTYPE"); + } else { + String *q = SwigType_isqualifier(nr) ? SwigType_pop(nr) : 0; + if (q && strstr(Char(nr), "SWIGTYPE")) { + Append(def, nr); + } else { + String *nd = SwigType_default(nr); + if (nd) { + String *bdef = nd; + if (q) { + bdef = NewStringf("%s%s", q, nd); + if ((Strcmp(nr, bdef) == 0)) { + Delete(bdef); + bdef = nd; + } else { + Delete(nd); + } + } + Append(def, bdef); + Delete(bdef); + } else { + Append(def, nr); + } + } + Delete(q); + } +} + + +SwigType *SwigType_default(SwigType *t) { + String *r1, *def; + String *r = 0; + char *cr; + +#ifdef SWIG_DEFAULT_CACHE + if (!default_cache) + default_cache = NewHash(); + + r = Getattr(default_cache, t); + if (r) { + return Copy(r); + } +#endif + + if (SwigType_isvarargs(t)) { + return 0; + } + + r = t; + while ((r1 = SwigType_typedef_resolve(r))) { + if (r != t) + Delete(r); + r = r1; + } + if (SwigType_isqualifier(r)) { + String *q; + if (r == t) + r = Copy(t); + q = SwigType_pop(r); + if (strstr(Char(r), "SWIGTYPE")) { + Delete(q); + def = r; + return def; + } + Delete(q); + } + cr = Char(r); + if (strcmp(cr, "p.SWIGTYPE") == 0) { + def = NewString("SWIGTYPE"); + } else if (SwigType_ispointer(r)) { +#ifdef SWIG_NEW_TYPE_DEFAULT + SwigType *nr = Copy(r); + SwigType_del_pointer(nr); + def = SwigType_isfunction(nr) ? NewStringEmpty() : NewString("p."); + SwigType_add_default(def, nr); + Delete(nr); +#else + def = NewString("p.SWIGTYPE"); +#endif + } else if (strcmp(cr, "r.SWIGTYPE") == 0) { + def = NewString("SWIGTYPE"); + } else if (SwigType_isreference(r)) { +#ifdef SWIG_NEW_TYPE_DEFAULT + SwigType *nr = Copy(r); + SwigType_del_reference(nr); + def = NewString("r."); + SwigType_add_default(def, nr); + Delete(nr); +#else + def = NewString("r.SWIGTYPE"); +#endif + } else if (SwigType_isarray(r)) { + if (strcmp(cr, "a().SWIGTYPE") == 0) { + def = NewString("p.SWIGTYPE"); + } else if (strcmp(cr, "a(ANY).SWIGTYPE") == 0) { + def = NewString("a().SWIGTYPE"); + } else { + int i, empty = 0; + int ndim = SwigType_array_ndim(r); + SwigType *nr = Copy(r); + for (i = 0; i < ndim; i++) { + String *dim = SwigType_array_getdim(r, i); + if (!Len(dim)) { + char *c = Char(nr); + empty = strstr(c, "a(ANY).") != c; + } + Delete(dim); + } + if (empty) { + def = NewString("a()."); + } else { + def = NewString("a(ANY)."); + } +#ifdef SWIG_NEW_TYPE_DEFAULT + SwigType_del_array(nr); + SwigType_add_default(def, nr); +#else + Append(def, "SWIGTYPE"); +#endif + Delete(nr); + } + } else if (SwigType_ismemberpointer(r)) { + if (strcmp(cr, "m(CLASS).SWIGTYPE") == 0) { + def = NewString("p.SWIGTYPE"); + } else { + def = NewString("m(CLASS).SWIGTYPE"); + } + } else if (SwigType_isenum(r)) { + if (strcmp(cr, "enum SWIGTYPE") == 0) { + def = NewString("SWIGTYPE"); + } else { + def = NewString("enum SWIGTYPE"); + } + } else if (SwigType_isfunction(r)) { + if (strcmp(cr, "f(ANY).SWIGTYPE") == 0) { + def = NewString("p.SWIGTYPE"); + } else { + def = NewString("p.f(ANY).SWIGTYPE"); + } + } else { + def = NewString("SWIGTYPE"); + } + if (r != t) + Delete(r); + if (Equal(def, t)) { + Delete(def); + def = 0; + } +#ifdef SWIG_DEFAULT_CACHE + /* The cache produces strange results, see enum_template.i case */ + if (def) { + String *cdef = Copy(def); + Setattr(default_cache, t, cdef); + Delete(cdef); + } +#endif + + /* Printf(stderr,"type : def %s : %s\n", t, def); */ + + return def; +} + +/* ----------------------------------------------------------------------------- + * SwigType_namestr() + * + * Returns a string of the base type. Takes care of template expansions + * ----------------------------------------------------------------------------- */ + +String *SwigType_namestr(const SwigType *t) { + String *r; + String *suffix; + List *p; + int i, sz; + char *d = Char(t); + char *c = strstr(d, "<("); + + if (!c || !strstr(c + 2, ")>")) + return NewString(t); + + r = NewStringWithSize(d, c - d); + if (*(c - 1) == '<') + Putc(' ', r); + Putc('<', r); + + p = SwigType_parmlist(c + 1); + sz = Len(p); + for (i = 0; i < sz; i++) { + String *str = SwigType_str(Getitem(p, i), 0); + /* Avoid creating a <: token, which is the same as [ in C++ - put a space after '<'. */ + if (i == 0 && Len(str)) + Putc(' ', r); + Append(r, str); + if ((i + 1) < sz) + Putc(',', r); + Delete(str); + } + Putc(' ', r); + Putc('>', r); + suffix = SwigType_templatesuffix(t); + Append(r, suffix); + Delete(suffix); + Delete(p); + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_str() + * + * Create a C string representation of a datatype. + * ----------------------------------------------------------------------------- */ + +String *SwigType_str(SwigType *s, const_String_or_char_ptr id) { + String *result; + String *element = 0, *nextelement; + List *elements; + int nelements, i; + + if (id) { + result = NewString(id); + } else { + result = NewStringEmpty(); + } + + elements = SwigType_split(s); + nelements = Len(elements); + + if (nelements > 0) { + element = Getitem(elements, 0); + } + /* Now, walk the type list and start emitting */ + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i + 1); + } else { + nextelement = 0; + } + if (SwigType_isqualifier(element)) { + DOH *q = 0; + q = SwigType_parm(element); + Insert(result, 0, " "); + Insert(result, 0, q); + Delete(q); + } else if (SwigType_ispointer(element)) { + Insert(result, 0, "*"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_ismemberpointer(element)) { + String *q; + q = SwigType_parm(element); + Insert(result, 0, "::*"); + Insert(result, 0, q); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + Delete(q); + } else if (SwigType_isreference(element)) { + Insert(result, 0, "&"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_isarray(element)) { + DOH *size; + Append(result, "["); + size = SwigType_parm(element); + Append(result, size); + Append(result, "]"); + Delete(size); + } else if (SwigType_isfunction(element)) { + DOH *parms, *p; + int j, plen; + Append(result, "("); + parms = SwigType_parmlist(element); + plen = Len(parms); + for (j = 0; j < plen; j++) { + p = SwigType_str(Getitem(parms, j), 0); + Append(result, p); + if (j < (plen - 1)) + Append(result, ","); + } + Append(result, ")"); + Delete(parms); + } else { + if (strcmp(Char(element), "v(...)") == 0) { + Insert(result, 0, "..."); + } else { + String *bs = SwigType_namestr(element); + Insert(result, 0, " "); + Insert(result, 0, bs); + Delete(bs); + } + } + element = nextelement; + } + Delete(elements); + Chop(result); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_ltype(SwigType *ty) + * + * Create a locally assignable type + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_ltype(SwigType *s) { + String *result; + String *element; + SwigType *td, *tc = 0; + List *elements; + int nelements, i; + int firstarray = 1; + int notypeconv = 0; + + result = NewStringEmpty(); + tc = Copy(s); + /* Nuke all leading qualifiers */ + while (SwigType_isqualifier(tc)) { + Delete(SwigType_pop(tc)); + } + if (SwigType_issimple(tc)) { + /* Resolve any typedef definitions */ + SwigType *tt = Copy(tc); + td = 0; + while ((td = SwigType_typedef_resolve(tt))) { + if (td && (SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td))) { + /* We need to use the typedef type */ + Delete(tt); + tt = td; + break; + } else if (td) { + Delete(tt); + tt = td; + } + } + if (td) { + Delete(tc); + tc = td; + } + } + elements = SwigType_split(tc); + nelements = Len(elements); + + /* Now, walk the type list and start emitting */ + for (i = 0; i < nelements; i++) { + element = Getitem(elements, i); + /* when we see a function, we need to preserve the following types */ + if (SwigType_isfunction(element)) { + notypeconv = 1; + } + if (SwigType_isqualifier(element)) { + /* Do nothing. Ignore */ + } else if (SwigType_ispointer(element)) { + Append(result, element); + firstarray = 0; + } else if (SwigType_ismemberpointer(element)) { + Append(result, element); + firstarray = 0; + } else if (SwigType_isreference(element)) { + if (notypeconv) { + Append(result, element); + } else { + Append(result, "p."); + } + firstarray = 0; + } else if (SwigType_isarray(element) && firstarray) { + if (notypeconv) { + Append(result, element); + } else { + Append(result, "p."); + } + firstarray = 0; + } else if (SwigType_isenum(element)) { + int anonymous_enum = (Cmp(element, "enum ") == 0); + if (notypeconv || !anonymous_enum) { + Append(result, element); + } else { + Append(result, "int"); + } + } else { + Append(result, element); + } + } + Delete(elements); + Delete(tc); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_lstr(DOH *s, DOH *id) + * + * Produces a type-string that is suitable as a lvalue in an expression. + * That is, a type that can be freely assigned a value without violating + * any C assignment rules. + * + * - Qualifiers such as 'const' and 'volatile' are stripped. + * - Arrays are converted into a *single* pointer (i.e., + * double [][] becomes double *). + * - References are converted into a pointer. + * - Typedef names that refer to read-only types will be replaced + * with an equivalent assignable version. + * -------------------------------------------------------------------- */ + +String *SwigType_lstr(SwigType *s, const_String_or_char_ptr id) { + String *result; + SwigType *tc; + + tc = SwigType_ltype(s); + result = SwigType_str(tc, id); + Delete(tc); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_rcaststr() + * + * Produces a casting string that maps the type returned by lstr() to the real + * datatype printed by str(). + * ----------------------------------------------------------------------------- */ + +String *SwigType_rcaststr(SwigType *s, const_String_or_char_ptr name) { + String *result, *cast; + String *element = 0, *nextelement; + SwigType *td, *rs, *tc = 0; + List *elements; + int nelements, i; + int clear = 1; + int firstarray = 1; + int isreference = 0; + int isarray = 0; + + result = NewStringEmpty(); + + if (SwigType_isconst(s)) { + tc = Copy(s); + Delete(SwigType_pop(tc)); + rs = tc; + } else { + rs = s; + } + + if ((SwigType_isconst(rs) || SwigType_isarray(rs) || SwigType_isreference(rs))) { + td = 0; + } else { + td = SwigType_typedef_resolve(rs); + } + + if (td) { + if ((SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td))) { + elements = SwigType_split(td); + } else { + elements = SwigType_split(rs); + } + Delete(td); + } else { + elements = SwigType_split(rs); + } + nelements = Len(elements); + if (nelements > 0) { + element = Getitem(elements, 0); + } + /* Now, walk the type list and start emitting */ + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i + 1); + } else { + nextelement = 0; + } + if (SwigType_isqualifier(element)) { + DOH *q = 0; + q = SwigType_parm(element); + Insert(result, 0, " "); + Insert(result, 0, q); + Delete(q); + clear = 0; + } else if (SwigType_ispointer(element)) { + Insert(result, 0, "*"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + firstarray = 0; + } else if (SwigType_ismemberpointer(element)) { + String *q; + Insert(result, 0, "::*"); + q = SwigType_parm(element); + Insert(result, 0, q); + Delete(q); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + firstarray = 0; + } else if (SwigType_isreference(element)) { + Insert(result, 0, "&"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + isreference = 1; + } else if (SwigType_isarray(element)) { + DOH *size; + if (firstarray && !isreference) { + Append(result, "(*)"); + firstarray = 0; + } else { + Append(result, "["); + size = SwigType_parm(element); + Append(result, size); + Append(result, "]"); + Delete(size); + clear = 0; + } + isarray = 1; + } else if (SwigType_isfunction(element)) { + DOH *parms, *p; + int j, plen; + Append(result, "("); + parms = SwigType_parmlist(element); + plen = Len(parms); + for (j = 0; j < plen; j++) { + p = SwigType_str(Getitem(parms, j), 0); + Append(result, p); + Delete(p); + if (j < (plen - 1)) + Append(result, ","); + } + Append(result, ")"); + Delete(parms); + } else { + String *bs = SwigType_namestr(element); + Insert(result, 0, " "); + Insert(result, 0, bs); + Delete(bs); + } + element = nextelement; + } + Delete(elements); + if (clear) { + cast = NewStringEmpty(); + } else { + cast = NewStringf("(%s)", result); + } + if (name) { + if (isreference) { + if (isarray) + Clear(cast); + Append(cast, "*"); + } + Append(cast, name); + } + Delete(result); + Delete(tc); + return cast; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_lcaststr() + * + * Casts a variable from the real type to the local datatype. + * ----------------------------------------------------------------------------- */ + +String *SwigType_lcaststr(SwigType *s, const_String_or_char_ptr name) { + String *result; + + result = NewStringEmpty(); + + if (SwigType_isarray(s)) { + String *lstr = SwigType_lstr(s, 0); + Printf(result, "(%s)%s", lstr, name); + Delete(lstr); + } else if (SwigType_isreference(s)) { + String *str = SwigType_str(s, 0); + Printf(result, "(%s)", str); + Delete(str); + if (name) + Append(result, name); + } else if (SwigType_isqualifier(s)) { + String *lstr = SwigType_lstr(s, 0); + Printf(result, "(%s)%s", lstr, name); + Delete(lstr); + } else { + if (name) + Append(result, name); + } + return result; +} + + +/* keep old mangling since Java codes need it */ +String *SwigType_manglestr_default(SwigType *s) { + char *c; + String *result = 0; + String *base = 0; + SwigType *lt; + SwigType *sr = SwigType_typedef_qualified(s); + SwigType *ss = SwigType_typedef_resolve_all(sr); + + s = ss; + + if (SwigType_istemplate(ss)) { + SwigType *ty = Swig_symbol_template_deftype(ss, 0); + Delete(ss); + ss = ty; + s = ss; + } + Delete(sr); + + lt = SwigType_ltype(s); + result = SwigType_prefix(lt); + base = SwigType_base(lt); + + c = Char(result); + while (*c) { + if (!isalnum((int) *c)) + *c = '_'; + c++; + } + if (SwigType_istemplate(base)) { + String *b = SwigType_namestr(base); + Delete(base); + base = b; + } + + Replace(base, "struct ", "", DOH_REPLACE_ANY); /* This might be problematic */ + Replace(base, "class ", "", DOH_REPLACE_ANY); + Replace(base, "union ", "", DOH_REPLACE_ANY); + Replace(base, "enum ", "", DOH_REPLACE_ANY); + + c = Char(base); + while (*c) { + if (*c == '<') + *c = 'T'; + else if (*c == '>') + *c = 't'; + else if (*c == '*') + *c = 'p'; + else if (*c == '[') + *c = 'a'; + else if (*c == ']') + *c = 'A'; + else if (*c == '&') + *c = 'R'; + else if (*c == '(') + *c = 'f'; + else if (*c == ')') + *c = 'F'; + else if (!isalnum((int) *c)) + *c = '_'; + c++; + } + Append(result, base); + Insert(result, 0, "_"); + Delete(lt); + Delete(base); + if (ss) + Delete(ss); + return result; +} + +String *SwigType_manglestr(SwigType *s) { + return SwigType_manglestr_default(s); +} + +/* ----------------------------------------------------------------------------- + * SwigType_typename_replace() + * + * Replaces a typename in a type with something else. Needed for templates. + * ----------------------------------------------------------------------------- */ + +void SwigType_typename_replace(SwigType *t, String *pat, String *rep) { + String *nt; + int i, ilen; + List *elem; + + if (!Strstr(t, pat)) + return; + + if (Equal(t, pat)) { + Replace(t, pat, rep, DOH_REPLACE_ANY); + return; + } + nt = NewStringEmpty(); + elem = SwigType_split(t); + ilen = Len(elem); + for (i = 0; i < ilen; i++) { + String *e = Getitem(elem, i); + if (SwigType_issimple(e)) { + if (Equal(e, pat)) { + /* Replaces a type of the form 'pat' with 'rep<args>' */ + Replace(e, pat, rep, DOH_REPLACE_ANY); + } else if (SwigType_istemplate(e)) { + /* Replaces a type of the form 'pat<args>' with 'rep' */ + if (Equal(e, pat)) { + String *repbase = SwigType_templateprefix(rep); + Replace(e, pat, repbase, DOH_REPLACE_ID | DOH_REPLACE_FIRST); + Delete(repbase); + } + { + String *tsuffix; + List *tparms = SwigType_parmlist(e); + int j, jlen; + String *nt = SwigType_templateprefix(e); + Append(nt, "<("); + jlen = Len(tparms); + for (j = 0; j < jlen; j++) { + SwigType_typename_replace(Getitem(tparms, j), pat, rep); + Append(nt, Getitem(tparms, j)); + if (j < (jlen - 1)) + Putc(',', nt); + } + tsuffix = SwigType_templatesuffix(e); + Printf(nt, ")>%s", tsuffix); + Delete(tsuffix); + Clear(e); + Append(e, nt); + Delete(nt); + Delete(tparms); + } + } else if (Swig_scopename_check(e)) { + String *first, *rest; + first = Swig_scopename_first(e); + rest = Swig_scopename_suffix(e); + SwigType_typename_replace(rest, pat, rep); + SwigType_typename_replace(first, pat, rep); + Clear(e); + Printv(e, first, "::", rest, NIL); + Delete(first); + Delete(rest); + } + } else if (SwigType_isfunction(e)) { + int j, jlen; + List *fparms = SwigType_parmlist(e); + Clear(e); + Append(e, "f("); + jlen = Len(fparms); + for (j = 0; j < jlen; j++) { + SwigType_typename_replace(Getitem(fparms, j), pat, rep); + Append(e, Getitem(fparms, j)); + if (j < (jlen - 1)) + Putc(',', e); + } + Append(e, ")."); + Delete(fparms); + } else if (SwigType_isarray(e)) { + Replace(e, pat, rep, DOH_REPLACE_ID); + } + Append(nt, e); + } + Clear(t); + Append(t, nt); + Delete(nt); + Delete(elem); +} + +/* ----------------------------------------------------------------------------- + * SwigType_check_decl() + * + * Checks type declarators for a match + * ----------------------------------------------------------------------------- */ + +int SwigType_check_decl(SwigType *ty, const SwigType *decl) { + SwigType *t, *t1, *t2; + int r; + t = SwigType_typedef_resolve_all(ty); + t1 = SwigType_strip_qualifiers(t); + t2 = SwigType_prefix(t1); + r = Equal(t2, decl); + Delete(t); + Delete(t1); + Delete(t2); + return r == 1; +} diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h new file mode 100644 index 0000000..a39a2ad --- /dev/null +++ b/Source/Swig/swig.h @@ -0,0 +1,403 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swig.h + * + * Header file for the SWIG core. + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 11473 2009-07-30 06:06:49Z wsfulton $ */ + +#ifndef SWIGCORE_H_ +#define SWIGCORE_H_ + +#ifndef MACSWIG +#include "swigconfig.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "doh.h" + +/* Status codes */ + +#define SWIG_OK 1 +#define SWIG_ERROR 0 +#define SWIG_NOWRAP 0 + +/* Short names for common data types */ + + typedef DOH String; + typedef DOH Hash; + typedef DOH List; + typedef DOH String_or_char; + typedef DOH File; + typedef DOH Parm; + typedef DOH ParmList; + typedef DOH Node; + typedef DOH Symtab; + typedef DOH Typetab; + typedef DOH SwigType; + +/* --- Legacy DataType interface. These type codes are provided solely + for backwards compatibility with older modules --- */ + +/* --- The ordering of type values is used to determine type-promotion + in the parser. Do not change */ + +/* Numeric types */ + +#define T_BOOL 1 +#define T_SCHAR 2 +#define T_UCHAR 3 +#define T_SHORT 4 +#define T_USHORT 5 +#define T_ENUM 6 +#define T_INT 7 +#define T_UINT 8 +#define T_LONG 9 +#define T_ULONG 10 +#define T_LONGLONG 11 +#define T_ULONGLONG 12 +#define T_FLOAT 20 +#define T_DOUBLE 21 +#define T_LONGDOUBLE 22 +#define T_FLTCPLX 23 +#define T_DBLCPLX 24 +#define T_NUMERIC 25 + +#define T_COMPLEX T_DBLCPLX + +/* non-numeric */ + +#define T_CHAR 29 +#define T_WCHAR 30 +#define T_USER 31 +#define T_VOID 32 +#define T_STRING 33 +#define T_POINTER 34 +#define T_REFERENCE 35 +#define T_ARRAY 36 +#define T_FUNCTION 37 +#define T_MPOINTER 38 +#define T_VARARGS 39 +#define T_SYMBOL 98 +#define T_ERROR 99 + + +/* --- File interface --- */ + +#include "swigfile.h" + +/* --- Command line parsing --- */ + +#include "swigopt.h" + +/* --- Scanner Interface --- */ + +#include "swigscan.h" + +/* --- Functions for manipulating the string-based type encoding --- */ + + extern SwigType *NewSwigType(int typecode); + extern SwigType *SwigType_del_element(SwigType *t); + extern SwigType *SwigType_add_pointer(SwigType *t); + extern SwigType *SwigType_add_memberpointer(SwigType *t, const_String_or_char_ptr qual); + extern SwigType *SwigType_del_memberpointer(SwigType *t); + extern SwigType *SwigType_del_pointer(SwigType *t); + extern SwigType *SwigType_add_array(SwigType *t, const_String_or_char_ptr size); + extern SwigType *SwigType_del_array(SwigType *t); + extern SwigType *SwigType_pop_arrays(SwigType *t); + extern SwigType *SwigType_add_reference(SwigType *t); + extern SwigType *SwigType_del_reference(SwigType *t); + extern SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual); + extern SwigType *SwigType_del_qualifier(SwigType *t); + extern SwigType *SwigType_add_function(SwigType *t, ParmList *parms); + extern SwigType *SwigType_add_template(SwigType *t, ParmList *parms); + extern SwigType *SwigType_pop_function(SwigType *t); + extern ParmList *SwigType_function_parms(SwigType *t); + extern List *SwigType_split(const SwigType *t); + extern String *SwigType_pop(SwigType *t); + extern void SwigType_push(SwigType *t, SwigType *s); + extern List *SwigType_parmlist(const SwigType *p); + extern String *SwigType_parm(String *p); + extern String *SwigType_str(SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_lstr(SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_rcaststr(SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_lcaststr(SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_manglestr(SwigType *t); + extern SwigType *SwigType_ltype(SwigType *t); + extern int SwigType_ispointer(SwigType *t); + extern int SwigType_ispointer_return(SwigType *t); + extern int SwigType_isfunctionpointer(SwigType *t); + extern int SwigType_ismemberpointer(SwigType *t); + extern int SwigType_isreference(SwigType *t); + extern int SwigType_isreference_return(SwigType *t); + extern int SwigType_isarray(SwigType *t); + extern int SwigType_prefix_is_simple_1D_array(SwigType *t); + extern int SwigType_isfunction(SwigType *t); + extern int SwigType_isqualifier(SwigType *t); + extern int SwigType_isconst(SwigType *t); + extern int SwigType_issimple(SwigType *t); + extern int SwigType_ismutable(SwigType *t); + extern int SwigType_isvarargs(const SwigType *t); + extern int SwigType_istemplate(const SwigType *t); + extern int SwigType_isenum(SwigType *t); + extern int SwigType_check_decl(SwigType *t, const_String_or_char_ptr decl); + extern SwigType *SwigType_strip_qualifiers(SwigType *t); + extern SwigType *SwigType_functionpointer_decompose(SwigType *t); + extern String *SwigType_base(const SwigType *t); + extern String *SwigType_namestr(const SwigType *t); + extern String *SwigType_templateprefix(const SwigType *t); + extern String *SwigType_templatesuffix(const SwigType *t); + extern String *SwigType_templateargs(const SwigType *t); + extern String *SwigType_prefix(const SwigType *t); + extern int SwigType_array_ndim(SwigType *t); + extern String *SwigType_array_getdim(SwigType *t, int n); + extern void SwigType_array_setdim(SwigType *t, int n, const_String_or_char_ptr rep); + extern SwigType *SwigType_array_type(SwigType *t); + extern String *SwigType_default(SwigType *t); + extern void SwigType_typename_replace(SwigType *t, String *pat, String *rep); + extern SwigType *SwigType_alttype(SwigType *t, int ltmap); + + extern void SwigType_template_defargs(Parm *parms, Parm *targs, Symtab *tscope, Symtab *tsdecl); + extern SwigType *SwigType_template_deftype(const SwigType *type, Symtab *tscope); + +/* --- Type-system managment --- */ + extern void SwigType_typesystem_init(void); + extern int SwigType_typedef(SwigType *type, const_String_or_char_ptr name); + extern int SwigType_typedef_class(const_String_or_char_ptr name); + extern int SwigType_typedef_using(const_String_or_char_ptr qname); + extern void SwigType_inherit(String *subclass, String *baseclass, String *cast, String *conversioncode); + extern int SwigType_issubtype(SwigType *subtype, SwigType *basetype); + extern void SwigType_scope_alias(String *aliasname, Typetab *t); + extern void SwigType_using_scope(Typetab *t); + extern void SwigType_new_scope(const_String_or_char_ptr name); + extern void SwigType_inherit_scope(Typetab *scope); + extern Typetab *SwigType_pop_scope(void); + extern Typetab *SwigType_set_scope(Typetab *h); + extern void SwigType_print_scope(Typetab *t); + extern SwigType *SwigType_typedef_resolve(const SwigType *t); + extern SwigType *SwigType_typedef_resolve_all(SwigType *t); + extern SwigType *SwigType_typedef_qualified(SwigType *t); + extern int SwigType_istypedef(SwigType *t); + extern int SwigType_isclass(SwigType *t); + extern void SwigType_attach_symtab(Symtab *syms); + extern void SwigType_remember(SwigType *t); + extern void SwigType_remember_clientdata(SwigType *t, const_String_or_char_ptr clientdata); + extern void SwigType_remember_mangleddata(String *mangled, const_String_or_char_ptr clientdata); + extern void (*SwigType_remember_trace(void (*tf) (SwigType *, String *, String *))) (SwigType *, String *, String *); + extern void SwigType_emit_type_table(File *f_headers, File *f_table); + extern int SwigType_type(SwigType *t); + +/* --- Symbol table module --- */ + + extern void Swig_symbol_init(void); + extern void Swig_symbol_setscopename(const_String_or_char_ptr name); + extern String *Swig_symbol_getscopename(void); + extern String *Swig_symbol_qualifiedscopename(Symtab *symtab); + extern Symtab *Swig_symbol_newscope(void); + extern Symtab *Swig_symbol_setscope(Symtab *); + extern Symtab *Swig_symbol_getscope(const_String_or_char_ptr symname); + extern Symtab *Swig_symbol_current(void); + extern Symtab *Swig_symbol_popscope(void); + extern Node *Swig_symbol_add(const_String_or_char_ptr symname, Node *node); + extern void Swig_symbol_cadd(const_String_or_char_ptr symname, Node *node); + extern Node *Swig_symbol_clookup(const_String_or_char_ptr symname, Symtab *tab); + extern Node *Swig_symbol_clookup_check(const_String_or_char_ptr symname, Symtab *tab, int (*check) (Node *)); + extern Symtab *Swig_symbol_cscope(const_String_or_char_ptr symname, Symtab *tab); + extern Node *Swig_symbol_clookup_local(const_String_or_char_ptr symname, Symtab *tab); + extern Node *Swig_symbol_clookup_local_check(const_String_or_char_ptr symname, Symtab *tab, int (*check) (Node *)); + extern String *Swig_symbol_qualified(Node *node); + extern Node *Swig_symbol_isoverloaded(Node *node); + extern void Swig_symbol_remove(Node *node); + extern void Swig_symbol_alias(const_String_or_char_ptr aliasname, Symtab *tab); + extern void Swig_symbol_inherit(Symtab *tab); + extern SwigType *Swig_symbol_type_qualify(const SwigType *ty, Symtab *tab); + extern String *Swig_symbol_string_qualify(String *s, Symtab *tab); + extern SwigType *Swig_symbol_typedef_reduce(SwigType *ty, Symtab *tab); + + extern ParmList *Swig_symbol_template_defargs(Parm *parms, Parm *targs, Symtab *tscope, Symtab *tsdecl); + extern SwigType *Swig_symbol_template_deftype(const SwigType *type, Symtab *tscope); + extern SwigType *Swig_symbol_template_param_eval(const SwigType *p, Symtab *symtab); + +/* --- Parameters and Parameter Lists --- */ + +#include "swigparm.h" + +extern String *ParmList_errorstr(ParmList *); +extern int ParmList_is_compactdefargs(ParmList *p); + +/* --- Parse tree support --- */ + +#include "swigtree.h" + +/* -- Wrapper function Object */ + +#include "swigwrap.h" + +/* --- Naming functions --- */ + + extern void Swig_name_register(const_String_or_char_ptr method, const_String_or_char_ptr format); + extern void Swig_name_unregister(const_String_or_char_ptr method); + extern String *Swig_name_mangle(const_String_or_char_ptr s); + extern String *Swig_name_wrapper(const_String_or_char_ptr fname); + extern String *Swig_name_member(const_String_or_char_ptr classname, const_String_or_char_ptr mname); + extern String *Swig_name_get(const_String_or_char_ptr vname); + extern String *Swig_name_set(const_String_or_char_ptr vname); + extern String *Swig_name_construct(const_String_or_char_ptr classname); + extern String *Swig_name_copyconstructor(const_String_or_char_ptr classname); + extern String *Swig_name_destroy(const_String_or_char_ptr classname); + extern String *Swig_name_disown(const_String_or_char_ptr classname); + + extern void Swig_naming_init(void); + extern void Swig_name_namewarn_add(String *prefix, String *name, SwigType *decl, Hash *namewrn); + extern Hash *Swig_name_namewarn_get(Node *n, String *prefix, String *name, SwigType *decl); + extern void Swig_name_rename_add(String *prefix, String *name, SwigType *decl, Hash *namewrn, ParmList *declaratorparms); + extern void Swig_name_inherit(String *base, String *derived); + extern int Swig_need_protected(Node *n); + extern int Swig_need_name_warning(Node *n); + extern int Swig_need_redefined_warn(Node *a, Node *b, int InClass); + + extern String *Swig_name_make(Node *n, String *prefix, const_String_or_char_ptr cname, SwigType *decl, String *oldname); + extern String *Swig_name_warning(Node *n, String *prefix, String *name, SwigType *decl); + extern String *Swig_name_decl(Node *n); + extern String *Swig_name_fulldecl(Node *n); + +/* --- parameterized rename functions --- */ + + extern void Swig_name_object_set(Hash *namehash, String *name, SwigType *decl, DOH *object); + extern DOH *Swig_name_object_get(Hash *namehash, String *prefix, String *name, SwigType *decl); + extern void Swig_name_object_inherit(Hash *namehash, String *base, String *derived); + extern void Swig_features_get(Hash *features, String *prefix, String *name, SwigType *decl, Node *n); + extern void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, String *value, Hash *featureattribs); + +/* --- Misc --- */ + extern char *Swig_copy_string(const char *c); + extern void Swig_set_fakeversion(const char *version); + extern const char *Swig_package_version(void); + extern void Swig_banner(File *f); + extern void Swig_banner_target_lang(File *f, const_String_or_char_ptr commentchar); + extern String *Swig_strip_c_comments(const String *s); + extern String *Swig_filename_escape(String *filename); + extern void Swig_filename_correct(String *filename); + extern String *Swig_string_escape(String *s); + extern String *Swig_string_mangle(const String *s); + extern void Swig_scopename_split(const String *s, String **prefix, String **last); + extern String *Swig_scopename_prefix(const String *s); + extern String *Swig_scopename_last(const String *s); + extern String *Swig_scopename_first(const String *s); + extern String *Swig_scopename_suffix(const String *s); + extern int Swig_scopename_check(const String *s); + extern String *Swig_string_lower(String *s); + extern String *Swig_string_upper(String *s); + extern String *Swig_string_title(String *s); + + extern void Swig_init(void); + extern void Swig_warn(const char *filename, int line, const char *msg); + + extern int Swig_value_wrapper_mode(int mode); + + +#define WARNING(msg) Swig_warn(__FILE__,__LINE__,msg) + + typedef enum { EMF_STANDARD, EMF_MICROSOFT } ErrorMessageFormat; + + extern void Swig_warning(int num, const_String_or_char_ptr filename, int line, const char *fmt, ...); + extern void Swig_error(const_String_or_char_ptr filename, int line, const char *fmt, ...); + extern int Swig_error_count(void); + extern void Swig_error_silent(int s); + extern void Swig_warnfilter(const_String_or_char_ptr wlist, int val); + extern void Swig_warnall(void); + extern int Swig_warn_count(void); + extern void Swig_error_msg_format(ErrorMessageFormat format); + +/* --- C Wrappers --- */ + extern String *Swig_cparm_name(Parm *p, int i); + extern String *Swig_wrapped_var_type(SwigType *t, int varcref); + extern int Swig_cargs(Wrapper *w, ParmList *l); + extern String *Swig_cresult(SwigType *t, const_String_or_char_ptr name, const_String_or_char_ptr decl); + + extern String *Swig_cfunction_call(const_String_or_char_ptr name, ParmList *parms); + extern String *Swig_cconstructor_call(const_String_or_char_ptr name); + extern String *Swig_cppconstructor_call(const_String_or_char_ptr name, ParmList *parms); + extern String *Swig_unref_call(Node *n); + extern String *Swig_ref_call(Node *n, const String *lname); + extern String *Swig_cdestructor_call(Node *n); + extern String *Swig_cppdestructor_call(Node *n); + extern String *Swig_cmemberset_call(const_String_or_char_ptr name, SwigType *type, String *self, int varcref); + extern String *Swig_cmemberget_call(const_String_or_char_ptr name, SwigType *t, String *self, int varcref); + + extern int Swig_add_extension_code(Node *n, const String *function_name, ParmList *parms, SwigType *return_type, const String *code, int cplusplus, const String *self); + +/* --- Transformations --- */ + + extern int Swig_MethodToFunction(Node *n, String *classname, int flags, SwigType *director_type, int is_director); + extern int Swig_ConstructorToFunction(Node *n, String *classname, String *none_comparison, String *director_ctor, int cplus, int flags); + extern int Swig_DestructorToFunction(Node *n, String *classname, int cplus, int flags); + extern int Swig_MembersetToFunction(Node *n, String *classname, int flags, String **call); + extern int Swig_MembergetToFunction(Node *n, String *classname, int flags); + extern int Swig_VargetToFunction(Node *n, int flags); + extern int Swig_VarsetToFunction(Node *n, int flags); + +#define CWRAP_EXTEND 0x01 +#define CWRAP_SMART_POINTER 0x02 +#define CWRAP_NATURAL_VAR 0x04 +#define CWRAP_DIRECTOR_ONE_CALL 0x08 +#define CWRAP_DIRECTOR_TWO_CALLS 0x10 +#define CWRAP_ALL_PROTECTED_ACCESS 0x20 + +/* --- Director Helpers --- */ + extern Node *Swig_methodclass(Node *n); + extern int Swig_directorclass(Node *n); + extern Node *Swig_directormap(Node *n, String *type); + +/* --- Legacy Typemap API (somewhat simplified, ha!) --- */ + + extern void Swig_typemap_init(void); + extern void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *pattern, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs); + extern int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcpattern, ParmList *pattern); + extern void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *pattern); + extern int Swig_typemap_apply(ParmList *srcpat, ParmList *destpat); + extern void Swig_typemap_clear_apply(ParmList *pattern); + extern void Swig_typemap_debug(void); + + extern String *Swig_typemap_lookup(const_String_or_char_ptr tmap_method, Node *n, const_String_or_char_ptr lname, Wrapper *f); + extern String *Swig_typemap_lookup_out(const_String_or_char_ptr tmap_method, Node *n, const_String_or_char_ptr lname, Wrapper *f, String *actioncode); + extern void Swig_typemap_new_scope(void); + extern Hash *Swig_typemap_pop_scope(void); + + extern void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f); + +/* --- Code fragment support --- */ + + extern void Swig_fragment_register(Node *fragment); + extern void Swig_fragment_emit(String *name); + extern void Swig_fragment_clear(String *section); + +/* hacks defined in C++ ! */ + extern int Swig_director_mode(void); + extern int Swig_director_protected_mode(void); + extern int Swig_all_protected_mode(void); + extern void Wrapper_director_mode_set(int); + extern void Wrapper_director_protected_mode_set(int); + extern void Wrapper_all_protected_mode_set(int); + extern void Language_replace_special_variables(String *method, String *tm, Parm *parm); + + +/* -- template init -- */ + extern void SwigType_template_init(void); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Source/Swig/swigfile.h b/Source/Swig/swigfile.h new file mode 100644 index 0000000..92c7945 --- /dev/null +++ b/Source/Swig/swigfile.h @@ -0,0 +1,40 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigfile.h + * + * File handling functions in the SWIG core + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 9603 2006-12-05 21:47:01Z beazley $ */ + +extern List *Swig_add_directory(const_String_or_char_ptr dirname); +extern void Swig_push_directory(const_String_or_char_ptr dirname); +extern void Swig_pop_directory(void); +extern String *Swig_last_file(void); +extern List *Swig_search_path(void); +extern FILE *Swig_include_open(const_String_or_char_ptr name); +extern FILE *Swig_open(const_String_or_char_ptr name); +extern String *Swig_read_file(FILE *f); +extern String *Swig_include(const_String_or_char_ptr name); +extern String *Swig_include_sys(const_String_or_char_ptr name); +extern int Swig_insert_file(const_String_or_char_ptr name, File *outfile); +extern void Swig_set_push_dir(int dopush); +extern int Swig_get_push_dir(void); +extern void Swig_register_filebyname(const_String_or_char_ptr filename, File *outfile); +extern File *Swig_filebyname(const_String_or_char_ptr filename); +extern char *Swig_file_suffix(const_String_or_char_ptr filename); +extern char *Swig_file_basename(const_String_or_char_ptr filename); +extern char *Swig_file_filename(const_String_or_char_ptr filename); +extern char *Swig_file_dirname(const_String_or_char_ptr filename); + +/* Delimiter used in accessing files and directories */ + +#if defined(MACSWIG) +# define SWIG_FILE_DELIMITER ":" +#elif defined(_WIN32) +# define SWIG_FILE_DELIMITER "\\" +#else +# define SWIG_FILE_DELIMITER "/" +#endif diff --git a/Source/Swig/swigopt.h b/Source/Swig/swigopt.h new file mode 100644 index 0000000..11eb5ba --- /dev/null +++ b/Source/Swig/swigopt.h @@ -0,0 +1,16 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigopt.h + * + * Header file for the SWIG command line processing functions + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 9622 2006-12-19 03:49:17Z beazley $ */ + + extern void Swig_init_args(int argc, char **argv); + extern void Swig_mark_arg(int n); + extern int Swig_check_marked(int n); + extern void Swig_check_options(int check_input); + extern void Swig_arg_error(void); diff --git a/Source/Swig/swigparm.h b/Source/Swig/swigparm.h new file mode 100644 index 0000000..49ae799 --- /dev/null +++ b/Source/Swig/swigparm.h @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigparm.h + * + * Functions related to the handling of function/method parameters and + * parameter lists. + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 9629 2006-12-30 18:27:47Z beazley $ */ + +/* Individual parameters */ +extern Parm *NewParm(SwigType *type, const_String_or_char_ptr name); +extern Parm *CopyParm(Parm *p); + +/* Parameter lists */ +extern ParmList *CopyParmList(ParmList *); +extern ParmList *CopyParmListMax(ParmList *, int count); +extern int ParmList_len(ParmList *); +extern int ParmList_numrequired(ParmList *); +extern int ParmList_has_defaultargs(ParmList *p); + +/* Output functions */ +extern String *ParmList_str(ParmList *); +extern String *ParmList_str_defaultargs(ParmList *); +extern String *ParmList_protostr(ParmList *); + + diff --git a/Source/Swig/swigscan.h b/Source/Swig/swigscan.h new file mode 100644 index 0000000..3403098 --- /dev/null +++ b/Source/Swig/swigscan.h @@ -0,0 +1,108 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigscan.h + * + * C/C++ scanner. + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 9633 2007-01-10 23:43:07Z beazley $ */ + +typedef struct Scanner Scanner; + +extern Scanner *NewScanner(void); +extern void DelScanner(Scanner *); +extern void Scanner_clear(Scanner *); +extern void Scanner_push(Scanner *, String *); +extern void Scanner_pushtoken(Scanner *, int, const_String_or_char_ptr value); +extern int Scanner_token(Scanner *); +extern String *Scanner_text(Scanner *); +extern void Scanner_skip_line(Scanner *); +extern int Scanner_skip_balanced(Scanner *, int startchar, int endchar); +extern void Scanner_set_location(Scanner *, String *file, int line); +extern String *Scanner_file(Scanner *); +extern int Scanner_line(Scanner *); +extern int Scanner_start_line(Scanner *); +extern void Scanner_idstart(Scanner *, const char *idchar); +extern String *Scanner_errmsg(Scanner *); +extern int Scanner_errline(Scanner *); +extern int Scanner_isoperator(int tokval); +extern void Scanner_freeze_line(Scanner *s, int val); + +/* Note: Tokens in range 100+ are for C/C++ operators */ + +#define SWIG_MAXTOKENS 200 +#define SWIG_TOKEN_LPAREN 1 /* ( */ +#define SWIG_TOKEN_RPAREN 2 /* ) */ +#define SWIG_TOKEN_SEMI 3 /* ; */ +#define SWIG_TOKEN_LBRACE 4 /* { */ +#define SWIG_TOKEN_RBRACE 5 /* } */ +#define SWIG_TOKEN_LBRACKET 6 /* [ */ +#define SWIG_TOKEN_RBRACKET 7 /* ] */ +#define SWIG_TOKEN_BACKSLASH 8 /* \ */ +#define SWIG_TOKEN_ENDLINE 9 /* \n */ +#define SWIG_TOKEN_STRING 10 /* "str" */ +#define SWIG_TOKEN_POUND 11 /* # */ +#define SWIG_TOKEN_COLON 12 /* : */ +#define SWIG_TOKEN_DCOLON 13 /* :: */ +#define SWIG_TOKEN_DCOLONSTAR 14 /* ::* */ +#define SWIG_TOKEN_ID 15 /* identifer */ +#define SWIG_TOKEN_FLOAT 16 /* 3.1415F */ +#define SWIG_TOKEN_DOUBLE 17 /* 3.1415 */ +#define SWIG_TOKEN_INT 18 /* 314 */ +#define SWIG_TOKEN_UINT 19 /* 314U */ +#define SWIG_TOKEN_LONG 20 /* 314L */ +#define SWIG_TOKEN_ULONG 21 /* 314UL */ +#define SWIG_TOKEN_CHAR 22 /* 'charconst' */ +#define SWIG_TOKEN_PERIOD 23 /* . */ +#define SWIG_TOKEN_AT 24 /* @ */ +#define SWIG_TOKEN_DOLLAR 25 /* $ */ +#define SWIG_TOKEN_CODEBLOCK 26 /* %{ ... %} ... */ +#define SWIG_TOKEN_RSTRING 27 /* `charconst` */ +#define SWIG_TOKEN_LONGLONG 28 /* 314LL */ +#define SWIG_TOKEN_ULONGLONG 29 /* 314ULL */ +#define SWIG_TOKEN_QUESTION 30 /* ? */ +#define SWIG_TOKEN_COMMENT 31 /* C or C++ comment */ +#define SWIG_TOKEN_ILLEGAL 99 +#define SWIG_TOKEN_ERROR -1 + +#define SWIG_TOKEN_COMMA 101 /* , */ +#define SWIG_TOKEN_STAR 102 /* * */ +#define SWIG_TOKEN_TIMES 102 /* * */ +#define SWIG_TOKEN_EQUAL 103 /* = */ +#define SWIG_TOKEN_EQUALTO 104 /* == */ +#define SWIG_TOKEN_NOTEQUAL 105 /* != */ +#define SWIG_TOKEN_PLUS 106 /* + */ +#define SWIG_TOKEN_MINUS 107 /* - */ +#define SWIG_TOKEN_AND 108 /* & */ +#define SWIG_TOKEN_LAND 109 /* && */ +#define SWIG_TOKEN_OR 110 /* | */ +#define SWIG_TOKEN_LOR 111 /* || */ +#define SWIG_TOKEN_XOR 112 /* ^ */ +#define SWIG_TOKEN_LESSTHAN 113 /* < */ +#define SWIG_TOKEN_GREATERTHAN 114 /* > */ +#define SWIG_TOKEN_LTEQUAL 115 /* <= */ +#define SWIG_TOKEN_GTEQUAL 116 /* >= */ +#define SWIG_TOKEN_NOT 117 /* ~ */ +#define SWIG_TOKEN_LNOT 118 /* ! */ +#define SWIG_TOKEN_SLASH 119 /* / */ +#define SWIG_TOKEN_DIVIDE 119 /* / */ +#define SWIG_TOKEN_PERCENT 120 /* % */ +#define SWIG_TOKEN_MODULO 120 /* % */ +#define SWIG_TOKEN_LSHIFT 121 /* << */ +#define SWIG_TOKEN_RSHIFT 122 /* >> */ +#define SWIG_TOKEN_PLUSPLUS 123 /* ++ */ +#define SWIG_TOKEN_MINUSMINUS 124 /* -- */ +#define SWIG_TOKEN_PLUSEQUAL 125 /* += */ +#define SWIG_TOKEN_MINUSEQUAL 126 /* -= */ +#define SWIG_TOKEN_TIMESEQUAL 127 /* *= */ +#define SWIG_TOKEN_DIVEQUAL 128 /* /= */ +#define SWIG_TOKEN_ANDEQUAL 129 /* &= */ +#define SWIG_TOKEN_OREQUAL 130 /* |= */ +#define SWIG_TOKEN_XOREQUAL 131 /* ^= */ +#define SWIG_TOKEN_LSEQUAL 132 /* <<= */ +#define SWIG_TOKEN_RSEQUAL 133 /* >>= */ +#define SWIG_TOKEN_MODEQUAL 134 /* %= */ +#define SWIG_TOKEN_ARROW 135 /* -> */ +#define SWIG_TOKEN_ARROWSTAR 136 /* ->* */ diff --git a/Source/Swig/swigtree.h b/Source/Swig/swigtree.h new file mode 100644 index 0000000..5b43006 --- /dev/null +++ b/Source/Swig/swigtree.h @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigtree.h + * + * These functions are used to access and manipulate the SWIG parse tree. + * The structure of this tree is modeled directly after XML-DOM. The attribute + * and function names are meant to be similar. + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 9622 2006-12-19 03:49:17Z beazley $ */ + +/* Macros to traverse the DOM tree */ + +#define nodeType(x) Getattr(x,"nodeType") +#define parentNode(x) Getattr(x,"parentNode") +#define previousSibling(x) Getattr(x,"previousSibling") +#define nextSibling(x) Getattr(x,"nextSibling") +#define firstChild(x) Getattr(x,"firstChild") +#define lastChild(x) Getattr(x,"lastChild") + +/* Macros to set up the DOM tree (mostly used by the parser) */ + +#define set_nodeType(x,v) Setattr(x,"nodeType",v) +#define set_parentNode(x,v) Setattr(x,"parentNode",v) +#define set_previousSibling(x,v) Setattr(x,"previousSibling",v) +#define set_nextSibling(x,v) Setattr(x,"nextSibling",v) +#define set_firstChild(x,v) Setattr(x,"firstChild",v) +#define set_lastChild(x,v) Setattr(x,"lastChild",v) + +/* Utility functions */ + +extern int checkAttribute(Node *obj, const_String_or_char_ptr name, const_String_or_char_ptr value); +extern void appendChild(Node *node, Node *child); +extern void prependChild(Node *node, Node *child); +extern void removeNode(Node *node); +extern Node *copyNode(Node *node); + +/* Node restoration/restore functions */ + +extern void Swig_require(const char *ns, Node *node, ...); +extern void Swig_save(const char *ns, Node *node, ...); +extern void Swig_restore(Node *node); + +/* Debugging of parse trees */ + +extern void Swig_print_tags(File *obj, Node *root); +extern void Swig_print_tree(Node *obj); +extern void Swig_print_node(Node *obj); diff --git a/Source/Swig/swigwrap.h b/Source/Swig/swigwrap.h new file mode 100644 index 0000000..0dcf880 --- /dev/null +++ b/Source/Swig/swigwrap.h @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * swigwrap.h + * + * Functions related to wrapper objects. + * ----------------------------------------------------------------------------- */ + +/* $Id: swig.h 9635 2007-01-12 01:44:16Z beazley $ */ + +typedef struct Wrapper { + Hash *localh; + String *def; + String *locals; + String *code; +} Wrapper; + +extern Wrapper *NewWrapper(void); +extern void DelWrapper(Wrapper *w); +extern void Wrapper_compact_print_mode_set(int flag); +extern void Wrapper_pretty_print(String *str, File *f); +extern void Wrapper_compact_print(String *str, File *f); +extern void Wrapper_print(Wrapper *w, File *f); +extern int Wrapper_add_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl); +extern int Wrapper_add_localv(Wrapper *w, const_String_or_char_ptr name, ...); +extern int Wrapper_check_local(Wrapper *w, const_String_or_char_ptr name); +extern char *Wrapper_new_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl); +extern char *Wrapper_new_localv(Wrapper *w, const_String_or_char_ptr name, ...); diff --git a/Source/Swig/symbol.c b/Source/Swig/symbol.c new file mode 100644 index 0000000..efafaca --- /dev/null +++ b/Source/Swig/symbol.c @@ -0,0 +1,1916 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * symbol.c + * + * This file implements the SWIG symbol table. See details below. + * ----------------------------------------------------------------------------- */ + +char cvsroot_symbol_c[] = "$Id: symbol.c 11097 2009-01-30 10:27:37Z bhy $"; + +#include "swig.h" +#include "swigwarn.h" +#include <ctype.h> + +/* #define SWIG_DEBUG*/ +/* ----------------------------------------------------------------------------- + * Synopsis + * + * This module provides symbol table management for all of SWIG. In previous + * releases, the management of symbols was rather haphazard. This module tries + * to correct that. + * + * All symbols are associated with simple identifiers. For example, here are some + * declarations that generate symbol table entries: + * + * decl symbol + * -------------- ------------ + * void foo(int); foo + * int x; x + * typedef int *blah; blah + * + * Associated with each symbol is a Hash table that can contain any set of + * attributes that make sense for that object. For example: + * + * typedef int *blah; ----> "name" : 'blah' + * "type" : 'int' + * "decl" : 'p.' + * "storage" : 'typedef' + * + * In some cases, the symbol table needs to manage overloaded entries. For instance, + * overloaded functions. In this case, a linked list is built. The "sym:nextSibling" + * attribute is reserved to hold a link to the next entry. For example: + * + * int foo(int); --> "name" : "foo" "name" : "foo" + * int foo(int,double); "type" : "int" "type" : "int" + * "decl" : "f(int)." "decl" : "f(int,double)." + * ... ... + * "sym:nextSibling" : --------> "sym:nextSibling": --------> ... + * + * When more than one symbol has the same name, the symbol declarator is + * used to detect duplicates. For example, in the above case, foo(int) and + * foo(int,double) are different because their "decl" attribute is different. + * However, if a third declaration "foo(int)" was made, it would generate a + * conflict (due to having a declarator that matches a previous entry). + * + * Structures and classes: + * + * C/C++ symbol tables are normally managed in a few different spaces. The + * most visible namespace is reserved for functions, variables, typedef, enum values + * and such. In C, a separate tag-space is reserved for 'struct name', 'class name', + * and 'union name' declarations. In SWIG, a single namespace is used for everything + * this means that certain incompatibilities will arise with some C programs. For instance: + * + * struct Foo { + * ... + * } + * + * int Foo(); // Error. Name clash. Works in C though + * + * Due to the unified namespace for structures, special handling is performed for + * the following: + * + * typedef struct Foo { + * + * } Foo; + * + * In this case, the symbol table contains an entry for the structure itself. The + * typedef is left out of the symbol table. + * + * Target language vs C: + * + * The symbol tables are normally managed *in the namespace of the target language*. + * This means that name-collisions can be resolved using %rename and related + * directives. A quirk of this is that sometimes the symbol tables need to + * be used for C type resolution as well. To handle this, each symbol table + * also has a C-symbol table lurking behind the scenes. This is used to locate + * symbols in the C namespace. However, this symbol table is not used for error + * reporting nor is it used for anything else during code generation. + * + * Symbol table structure: + * + * Symbol tables themselves are a special kind of node that is organized just like + * a normal parse tree node. Symbol tables are organized in a tree that can be + * traversed using the SWIG-DOM API. The following attributes names are reserved. + * + * name -- Name of the scope defined by the symbol table (if any) + * This name is the C-scope name and is not affected by + * %renaming operations + * symtab -- Hash table mapping identifiers to nodes. + * csymtab -- Hash table mapping C identifiers to nodes. + * + * Reserved attributes on symbol objects: + * + * When a symbol is placed in the symbol table, the following attributes + * are set: + * + * sym:name -- Symbol name + * sym:nextSibling -- Next symbol (if overloaded) + * sym:previousSibling -- Previous symbol (if overloaded) + * sym:symtab -- Symbol table object holding the symbol + * sym:overloaded -- Set to the first symbol if overloaded + * + * These names are modeled after XML namespaces. In particular, every attribute + * pertaining to symbol table management is prefaced by the "sym:" prefix. + * + * An example dump of the parse tree showing symbol table entries for the + * following code should clarify this: + * + * namespace OuterNamespace { + * namespace InnerNamespace { + * class Class { + * }; + * struct Struct { + * int Var; + * }; + * } + * } + * + * +++ namespace ---------------------------------------- + * | sym:name - "OuterNamespace" + * | symtab - 0xa064bf0 + * | sym:symtab - 0xa041690 + * | sym:overname - "__SWIG_0" + * + * +++ namespace ---------------------------------------- + * | sym:name - "InnerNamespace" + * | symtab - 0xa064cc0 + * | sym:symtab - 0xa064bf0 + * | sym:overname - "__SWIG_0" + * + * +++ class ---------------------------------------- + * | sym:name - "Class" + * | symtab - 0xa064d80 + * | sym:symtab - 0xa064cc0 + * | sym:overname - "__SWIG_0" + * | + * +++ class ---------------------------------------- + * | sym:name - "Struct" + * | symtab - 0xa064f00 + * | sym:symtab - 0xa064cc0 + * | sym:overname - "__SWIG_0" + * + * +++ cdecl ---------------------------------------- + * | sym:name - "Var" + * | sym:symtab - 0xa064f00 + * | sym:overname - "__SWIG_0" + * | + * + * + * Each class and namespace has its own scope and thus a new symbol table (sym) + * is created. The sym attribute is only set for the first entry in the symbol + * table. The sym:symtab entry points to the symbol table in which the symbol + * exists, so for example, Struct is in the scope OuterNamespace::InnerNamespace + * so sym:symtab points to this symbol table (0xa064cc0). + * + * ----------------------------------------------------------------------------- */ + +static Hash *current = 0; /* The current symbol table hash */ +static Hash *ccurrent = 0; /* The current c symbol table hash */ +static Hash *current_symtab = 0; /* Current symbol table node */ +static Hash *symtabs = 0; /* Hash of all symbol tables by fully-qualified name */ +static Hash *global_scope = 0; /* Global scope */ + +/* common attribute keys, to avoid calling find_key all the times */ + + + +#if 0 +void Swig_symbol_dump_symtable() { + Printf(stdout, "DUMPING SYMTABLE start =======================================\n"); + { + Hash *cst = Getattr(current_symtab, "csymtab"); + Swig_print_tree(cst); + /* + Swig_print_tree(Getattr(cst, "NumSpace")); + */ + } + Printf(stdout, "DUMPING SYMTABLE end =======================================\n"); +} +#endif + +/* ----------------------------------------------------------------------------- + * Swig_symbol_init() + * + * Create a new symbol table object + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_init() { + + current = NewHash(); + current_symtab = NewHash(); + ccurrent = NewHash(); + set_nodeType(current_symtab, "symboltable"); + Setattr(current_symtab, "symtab", current); + Delete(current); + Setattr(current_symtab, "csymtab", ccurrent); + Delete(ccurrent); + + /* Set the global scope */ + symtabs = NewHash(); + Setattr(symtabs, "", current_symtab); + Delete(current_symtab); + global_scope = current_symtab; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_setscopename() + * + * Set the C scopename of the current symbol table. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_setscopename(const_String_or_char_ptr name) { + String *qname; + /* assert(!Getattr(current_symtab,"name")); */ + Setattr(current_symtab, "name", name); + + /* Set nested scope in parent */ + + qname = Swig_symbol_qualifiedscopename(current_symtab); + + /* Save a reference to this scope */ + Setattr(symtabs, qname, current_symtab); + Delete(qname); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_getscopename() + * + * Get the C scopename of the current symbol table + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_getscopename() { + return Getattr(current_symtab, "name"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_getscope() + * + * Given a fully qualified C scopename, this function returns a symbol table + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_getscope(const_String_or_char_ptr name) { + if (!symtabs) + return 0; + if (Equal("::", (const_String_or_char_ptr ) name)) + name = ""; + return Getattr(symtabs, name); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_qualifiedscopename() + * + * Get the fully qualified C scopename of a symbol table. Note, this only pertains + * to the C/C++ scope name. It is not affected by renaming. + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_qualifiedscopename(Symtab *symtab) { + String *result = 0; + Hash *parent; + String *name; + if (!symtab) + symtab = current_symtab; + parent = Getattr(symtab, "parentNode"); + if (parent) { + result = Swig_symbol_qualifiedscopename(parent); + } + name = Getattr(symtab, "name"); + if (name) { + if (!result) { + result = NewStringEmpty(); + } + if (Len(result)) { + Printv(result, "::", name, NIL); + } else { + Append(result, name); + } + } + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_newscope() + * + * Create a new scope. Returns the newly created scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_newscope() { + Hash *n; + Hash *hsyms, *h; + + hsyms = NewHash(); + h = NewHash(); + + set_nodeType(h, "symboltable"); + Setattr(h, "symtab", hsyms); + Delete(hsyms); + set_parentNode(h, current_symtab); + + n = lastChild(current_symtab); + if (!n) { + set_firstChild(current_symtab, h); + } else { + set_nextSibling(n, h); + Delete(h); + } + set_lastChild(current_symtab, h); + current = hsyms; + ccurrent = NewHash(); + Setattr(h, "csymtab", ccurrent); + Delete(ccurrent); + current_symtab = h; + return h; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_setscope() + * + * Set the current scope. Returns the previous current scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_setscope(Symtab *sym) { + Symtab *ret = current_symtab; + current_symtab = sym; + current = Getattr(sym, "symtab"); + assert(current); + ccurrent = Getattr(sym, "csymtab"); + assert(ccurrent); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_popscope() + * + * Pop out of the current scope. Returns the popped scope and sets the + * scope to the parent scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_popscope() { + Hash *h = current_symtab; + current_symtab = Getattr(current_symtab, "parentNode"); + assert(current_symtab); + current = Getattr(current_symtab, "symtab"); + assert(current); + ccurrent = Getattr(current_symtab, "csymtab"); + assert(ccurrent); + return h; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_current() + * + * Return the current symbol table. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_current() { + return current_symtab; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_alias() + * + * Makes an alias for a symbol in the global symbol table. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_alias(const_String_or_char_ptr aliasname, Symtab *s) { + String *qname = Swig_symbol_qualifiedscopename(current_symtab); + if (qname) { + Printf(qname, "::%s", aliasname); + } else { + qname = NewString(aliasname); + } + if (!Getattr(symtabs, qname)) { + Setattr(symtabs, qname, s); + } + Delete(qname); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_inherit() + * + * Inherit symbols from another scope. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_inherit(Symtab *s) { + int i, ilen; + List *inherit = Getattr(current_symtab, "inherit"); + if (!inherit) { + inherit = NewList(); + Setattr(current_symtab, "inherit", inherit); + Delete(inherit); + } + + if (s == current_symtab) { + Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(s), Getline(s), "Recursive scope inheritance of '%s'.\n", Getattr(s, "name")); + return; + } + assert(s != current_symtab); + ilen = Len(inherit); + for (i = 0; i < ilen; i++) { + Node *n = Getitem(inherit, i); + if (n == s) + return; /* Already inherited */ + } + Append(inherit, s); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_cadd() + * + * Adds a node to the C symbol table only. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_cadd(const_String_or_char_ptr name, Node *n) { + Node *append = 0; + + Node *cn; + /* There are a few options for weak symbols. A "weak" symbol + is any symbol that can be replaced by another symbol in the C symbol + table. An example would be a forward class declaration. A forward + class sits in the symbol table until a real class declaration comes along. + + Certain symbols are marked as "sym:typename". These are important + symbols related to the C++ type-system and take precedence in the C + symbol table. An example might be code like this: + + template<class T> T foo(T x); + int foo(int); + + In this case, the template is marked with "sym:typename" so that it + stays in the C symbol table (so that it can be expanded using %template). + */ + + if (!name) + return; + if (SwigType_istemplate(name)) { + String *cname = NewString(name); + String *dname = Swig_symbol_template_deftype(cname, 0); + if (!Equal(dname, name)) { + Swig_symbol_cadd(dname, n); + } + Delete(dname); + Delete(cname); + } +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_cadd %s %x\n", name, n); +#endif + cn = Getattr(ccurrent, name); + + if (cn && (Getattr(cn, "sym:typename"))) { + /* The node in the C symbol table is a typename. Do nothing */ + /* We might append the symbol at the end */ + append = n; + } else if (cn && (Getattr(cn, "sym:weak"))) { + /* The node in the symbol table is weak. Replace it */ + if (checkAttribute(cn, "nodeType", "template") + && checkAttribute(cn, "templatetype", "classforward")) { + /* The node is a template classforward declaration, and the + default template parameters here take precedence. */ + ParmList *pc = Getattr(cn, "templateparms"); + ParmList *pn = Getattr(n, "templateparms"); +#ifdef SWIG_DEBUG + Printf(stderr, "found template classforward %s\n", Getattr(cn, "name")); +#endif + while (pc && pn) { + String *value = Getattr(pc, "value"); + if (value) { +#ifdef SWIG_DEBUG + Printf(stderr, "add default template value %s %s\n", Getattr(pc, "name"), value); +#endif + Setattr(pn, "value", value); + } + pc = nextSibling(pc); + pn = nextSibling(pn); + } + Setattr(n, "templateparms", Getattr(cn, "templateparms")); + } + Setattr(ccurrent, name, n); + + } else if (cn && (Getattr(n, "sym:weak"))) { + /* The node being added is weak. Don't worry about it */ + } else if (cn && (Getattr(n, "sym:typename"))) { + /* The node being added is a typename. We definitely add it */ + Setattr(ccurrent, name, n); + append = cn; + } else if (cn && (Checkattr(cn, "nodeType", "templateparm"))) { + Swig_error(Getfile(n), Getline(n), "Declaration of '%s' shadows template parameter,\n", name); + Swig_error(Getfile(cn), Getline(cn), "previous template parameter declaration '%s'.\n", name); + return; + } else if (cn) { + append = n; + } else if (!cn) { + /* No conflict. Add the symbol */ + Setattr(ccurrent, name, n); + } + + /* Multiple entries in the C symbol table. We append to to the symbol table */ + if (append) { + Node *fn, *pn = 0; + cn = Getattr(ccurrent, name); + fn = cn; + while (fn) { + pn = fn; + if (fn == append) { + /* already added. Bail */ + return; + } + fn = Getattr(fn, "csym:nextSibling"); + } + if (pn) { + Setattr(pn, "csym:nextSibling", append); + } + } + + /* Special typedef handling. When a typedef node is added to the symbol table, we + might have to add a type alias. This would occur if the typedef mapped to another + scope in the system. For example: + + class Foo { + }; + + typedef Foo OtherFoo; + + In this case, OtherFoo becomes an alias for Foo. */ + + { + Node *td = n; + while (td && Checkattr(td, "nodeType", "cdecl") && Checkattr(td, "storage", "typedef")) { + SwigType *type; + Node *td1; + type = Copy(Getattr(td, "type")); + SwigType_push(type, Getattr(td, "decl")); + td1 = Swig_symbol_clookup(type, 0); + + /* Fix pathetic case #1214313: + + class Foo + { + }; + + typedef Foo FooBar; + + class CBaz + { + public: + typedef FooBar Foo; + }; + + ie, when Foo -> FooBar -> Foo, jump one scope up when possible. + + */ + if (td1 && Checkattr(td1, "storage", "typedef")) { + String *st = Getattr(td1, "type"); + String *sn = Getattr(td, "name"); + if (st && sn && Equal(st, sn)) { + Symtab *sc = Getattr(current_symtab, "parentNode"); + if (sc) + td1 = Swig_symbol_clookup(type, sc); + } + } + + Delete(type); + if (td1 == td) + break; + td = td1; + if (td) { + Symtab *st = Getattr(td, "symtab"); + if (st) { + Swig_symbol_alias(Getattr(n, "name"), st); + break; + } + } + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_add() + * + * Adds a node to the symbol table. Returns the node itself if successfully + * added. Otherwise, it returns the symbol table entry of the conflicting node. + * + * Also places the symbol in a behind-the-scenes C symbol table. This is needed + * for namespace support, type resolution, and other issues. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_add(const_String_or_char_ptr symname, Node *n) { + Hash *c, *cn, *cl = 0; + SwigType *decl, *ndecl; + String *cstorage, *nstorage; + int nt = 0, ct = 0; + int pn = 0; + int u1 = 0, u2 = 0; + String *name, *overname; + + /* See if the node has a name. If so, we place in the C symbol table for this + scope. We don't worry about overloading here---the primary purpose of this + is to record information for type/name resolution for later. Conflicts + in C namespaces are errors, but these will be caught by the C++ compiler + when compiling the wrapper code */ + + + /* There are a few options for weak symbols. A "weak" symbol + is any symbol that can be replaced by another symbol in the C symbol + table. An example would be a forward class declaration. A forward + class sits in the symbol table until a real class declaration comes along. + + Certain symbols are marked as "sym:typename". These are important + symbols related to the C++ type-system and take precedence in the C + symbol table. An example might be code like this: + + template<class T> T foo(T x); + int foo(int); + + In this case, the template is marked with "sym:typename" so that it + stays in the C symbol table (so that it can be expanded using %template). + */ + + name = Getattr(n, "name"); + if (name && Len(name)) { + Swig_symbol_cadd(name, n); + } + + /* No symbol name defined. We return. */ + if (!symname) { + Setattr(n, "sym:symtab", current_symtab); + return n; + } + + /* If node is ignored. We don't proceed any further */ + if (GetFlag(n, "feature:ignore")) + return n; + + /* See if the symbol already exists in the table */ + c = Getattr(current, symname); + + /* Check for a weak symbol. A weak symbol is allowed to be in the + symbol table, but is silently overwritten by other symbols. An example + would be a forward class declaration. For instance: + + class Foo; + + In this case, "Foo" sits in the symbol table. However, the + definition of Foo would replace the entry if it appeared later. */ + + if (c && Getattr(c, "sym:weak")) { + c = 0; + } + if (c) { + /* There is a symbol table conflict. There are a few cases to consider here: + (1) A conflict between a class/enum and a typedef declaration is okay. + In this case, the symbol table entry is set to the class/enum declaration + itself, not the typedef. + + (2) A conflict between namespaces is okay--namespaces are open + + (3) Otherwise, overloading is only allowed for functions + */ + + /* Check for namespaces */ + String *ntype = Getattr(n, "nodeType"); + if ((Equal(ntype, Getattr(c, "nodeType"))) && ((Equal(ntype, "namespace")))) { + Node *cl, *pcl = 0; + cl = c; + while (cl) { + pcl = cl; + cl = Getattr(cl, "sym:nextSibling"); + } + Setattr(pcl, "sym:nextSibling", n); + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + Setattr(n, "sym:previousSibling", pcl); + return n; + } + if (Getattr(n, "allows_typedef")) + nt = 1; + if (Getattr(c, "allows_typedef")) + ct = 1; + if (nt || ct) { + Node *td, *other; + String *s; + /* At least one of the nodes allows typedef overloading. Make sure that + both don't--this would be a conflict */ + + if (nt && ct) + return c; + + /* Figure out which node allows the typedef */ + if (nt) { + td = n; + other = c; + } else { + td = c; + other = n; + } + /* Make sure the other node is a typedef */ + s = Getattr(other, "storage"); + if (!s || (!Equal(s, "typedef"))) + return c; /* No. This is a conflict */ + + /* Hmmm. This appears to be okay. Make sure the symbol table refers to the allow_type node */ + + if (td != c) { + Setattr(current, symname, td); + Setattr(td, "sym:symtab", current_symtab); + Setattr(td, "sym:name", symname); + } + return n; + } + + decl = Getattr(c, "decl"); + ndecl = Getattr(n, "decl"); + + { + String *nt1, *nt2; + nt1 = Getattr(n, "nodeType"); + if (Equal(nt1, "template")) + nt1 = Getattr(n, "templatetype"); + nt2 = Getattr(c, "nodeType"); + if (Equal(nt2, "template")) + nt2 = Getattr(c, "templatetype"); + if (Equal(nt1, "using")) + u1 = 1; + if (Equal(nt2, "using")) + u2 = 1; + + if ((!Equal(nt1, nt2)) && !(u1 || u2)) + return c; + } + if (!(u1 || u2)) { + if ((!SwigType_isfunction(decl)) || (!SwigType_isfunction(ndecl))) { + /* Symbol table conflict */ + return c; + } + } + + /* Hmmm. Declarator seems to indicate that this is a function */ + /* Look at storage class to see if compatible */ + cstorage = Getattr(c, "storage"); + nstorage = Getattr(n, "storage"); + + /* If either one is declared as typedef, forget it. We're hosed */ + if (Cmp(cstorage, "typedef") == 0) { + return c; + } + if (Cmp(nstorage, "typedef") == 0) { + return c; + } + + /* Okay. Walk down the list of symbols and see if we get a declarator match */ + { + String *nt = Getattr(n, "nodeType"); + int n_template = Equal(nt, "template") && Checkattr(n, "templatetype", "cdecl"); + int n_plain_cdecl = Equal(nt, "cdecl"); + cn = c; + pn = 0; + while (cn) { + decl = Getattr(cn, "decl"); + if (!(u1 || u2)) { + if (Cmp(ndecl, decl) == 0) { + /* Declarator conflict */ + /* Now check we don't have a non-templated function overloaded by a templated function with same params, + * eg void foo(); template<typename> void foo(); */ + String *cnt = Getattr(cn, "nodeType"); + int cn_template = Equal(cnt, "template") && Checkattr(cn, "templatetype", "cdecl"); + int cn_plain_cdecl = Equal(cnt, "cdecl"); + if (!((n_template && cn_plain_cdecl) || (cn_template && n_plain_cdecl))) { + /* found a conflict */ + return cn; + } + } + } + cl = cn; + cn = Getattr(cn, "sym:nextSibling"); + pn++; + } + } + /* Well, we made it this far. Guess we can drop the symbol in place */ + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + /* Printf(stdout,"%s %x\n", Getattr(n,"sym:overname"), current_symtab); */ + assert(!Getattr(n, "sym:overname")); + overname = NewStringf("__SWIG_%d", pn); + Setattr(n, "sym:overname", overname); + /*Printf(stdout,"%s %s %s\n", symname, Getattr(n,"decl"), Getattr(n,"sym:overname")); */ + Setattr(cl, "sym:nextSibling", n); + Setattr(n, "sym:previousSibling", cl); + Setattr(cl, "sym:overloaded", c); + Setattr(n, "sym:overloaded", c); + Delete(overname); + return n; + } + + /* No conflict. Just add it */ + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + /* Printf(stdout,"%s\n", Getattr(n,"sym:overname")); */ + overname = NewStringf("__SWIG_%d", pn); + Setattr(n, "sym:overname", overname); + Delete(overname); + /* Printf(stdout,"%s %s %s\n", symname, Getattr(n,"decl"), Getattr(n,"sym:overname")); */ + Setattr(current, symname, n); + return n; +} + +/* ----------------------------------------------------------------------------- + * symbol_lookup() + * + * Internal function to handle fully qualified symbol table lookups. This + * works from the symbol table supplied in symtab and unwinds its way out + * towards the global scope. + * + * This function operates in the C namespace, not the target namespace. + * + * The check function is an optional callback that can be used to verify a particular + * symbol match. This is only used in some of the more exotic parts of SWIG. For instance, + * verifying that a class hierarchy implements all pure virtual methods. + * ----------------------------------------------------------------------------- */ + +static Node *_symbol_lookup(const String *name, Symtab *symtab, int (*check) (Node *n)) { + Node *n; + List *inherit; + Hash *sym = Getattr(symtab, "csymtab"); + if (Getmark(symtab)) + return 0; + Setmark(symtab, 1); + + + n = Getattr(sym, name); + +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_look %s %x %x %s\n", name, n, symtab, Getattr(symtab, "name")); +#endif + + if (n) { + /* if a check-function is defined. Call it to determine a match */ + if (check) { + int c = check(n); + if (c == 1) { + Setmark(symtab, 0); + return n; + } + if (c < 0) { + /* Terminate the search right away */ + Setmark(symtab, 0); + return 0; + } + } else { + Setmark(symtab, 0); + return n; + } + } + + if (!n && SwigType_istemplate(name)) { + String *dname = 0; + Setmark(symtab, 0); + dname = Swig_symbol_template_deftype(name, symtab); + if (!Equal(dname, name)) { + n = _symbol_lookup(dname, symtab, check); + } + Delete(dname); + if (n) + return n; + } + + inherit = Getattr(symtab, "inherit"); + if (inherit) { + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + n = _symbol_lookup(name, Getitem(inherit, i), check); + if (n) { + Setmark(symtab, 0); + return n; + } + } + } + + Setmark(symtab, 0); + return 0; +} + +static Node *symbol_lookup(const_String_or_char_ptr name, Symtab *symtab, int (*check) (Node *n)) { + Node *n = 0; + if (DohCheck(name)) { + n = _symbol_lookup(name, symtab, check); + } else { + String *sname = NewString(name); + n = _symbol_lookup(sname, symtab, check); + Delete(sname); + } + return n; +} + + + +/* ----------------------------------------------------------------------------- + * symbol_lookup_qualified() + * ----------------------------------------------------------------------------- */ + +static Node *symbol_lookup_qualified(const_String_or_char_ptr name, Symtab *symtab, const String *prefix, int local, int (*checkfunc) (Node *n)) { + /* This is a little funky, we search by fully qualified names */ + + if (!symtab) + return 0; + if (!prefix) { + Node *n; + String *bname; + String *prefix; + Swig_scopename_split(name, &prefix, &bname); + n = symbol_lookup_qualified(bname, symtab, prefix, local, checkfunc); + Delete(bname); + Delete(prefix); + return n; + } else { + Symtab *st; + Node *n = 0; + /* Make qualified name of current scope */ + String *qalloc = 0; + String *qname = Swig_symbol_qualifiedscopename(symtab); + const String *cqname; + if (qname) { + if (Len(qname)) { + if (prefix && Len(prefix)) { + Printv(qname, "::", prefix, NIL); + } + } else { + Append(qname, prefix); + } + qalloc = qname; + cqname = qname; + } else { + cqname = prefix; + } + st = Getattr(symtabs, cqname); + /* Found a scope match */ + if (st) { + if (!name) { + if (qalloc) + Delete(qalloc); + return st; + } + n = symbol_lookup(name, st, checkfunc); + } + if (qalloc) + Delete(qalloc); + + if (!n) { + if (!local) { + Node *pn = Getattr(symtab, "parentNode"); + if (pn) + n = symbol_lookup_qualified(name, pn, prefix, local, checkfunc); + } else { + n = 0; + } + } + return n; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup() + * + * Look up a symbol in the symbol table. This uses the C name, not scripting + * names. Note: If we come across a using a directive, we follow it to + * to get the real node. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup(const_String_or_char_ptr name, Symtab *n) { + Hash *hsym = 0; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + if (n) { + hsym = n; + } + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, 0); + } + Delete(nname); + } else { + String *prefix = Swig_scopename_prefix(name); + if (prefix) { + s = symbol_lookup_qualified(name, hsym, 0, 0, 0); + Delete(prefix); + if (!s) { + return 0; + } + } + } + } + if (!s) { + while (hsym) { + s = symbol_lookup(name, hsym, 0); + if (s) + break; + hsym = Getattr(hsym, "parentNode"); + if (!hsym) + break; + } + } + + if (!s) { + return 0; + } + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + String *uname = Getattr(s, "uname"); + Symtab *un = Getattr(s, "sym:symtab"); + Node *ss = (!Equal(name, uname) || (un != n)) ? Swig_symbol_clookup(uname, un) : 0; /* avoid infinity loop */ + if (!ss) { + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", Getattr(s, "uname")); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_check() + * + * This function is identical to Swig_symbol_clookup() except that it + * accepts a callback function that is invoked to determine a symbol match. + * The purpose of this function is to support complicated algorithms that need + * to examine multiple definitions of the same symbol that might appear in an + * inheritance hierarchy. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_check(const_String_or_char_ptr name, Symtab *n, int (*checkfunc) (Node *n)) { + Hash *hsym = 0; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + if (n) { + hsym = n; + } + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, checkfunc); + } + Delete(nname); + } else { + String *prefix = Swig_scopename_prefix(name); + if (prefix) { + s = symbol_lookup_qualified(name, hsym, 0, 0, checkfunc); + Delete(prefix); + if (!s) { + return 0; + } + } + } + } + if (!s) { + while (hsym) { + s = symbol_lookup(name, hsym, checkfunc); + if (s) + break; + hsym = Getattr(hsym, "parentNode"); + if (!hsym) + break; + } + } + if (!s) { + return 0; + } + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + Node *ss; + ss = Swig_symbol_clookup(Getattr(s, "uname"), Getattr(s, "sym:symtab")); + if (!ss && !checkfunc) { + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", Getattr(s, "uname")); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_local() + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_local(const_String_or_char_ptr name, Symtab *n) { + Hash *h, *hsym; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + h = ccurrent; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + hsym = n; + h = Getattr(n, "csymtab"); + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, 0); + } + Delete(nname); + } else { + s = symbol_lookup_qualified(name, hsym, 0, 0, 0); + } + } + if (!s) { + s = symbol_lookup(name, hsym, 0); + } + if (!s) + return 0; + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + Node *ss = Swig_symbol_clookup_local(Getattr(s, "uname"), Getattr(s, "sym:symtab")); + if (!ss) { + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", Getattr(s, "uname")); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_local_check() + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_local_check(const_String_or_char_ptr name, Symtab *n, int (*checkfunc) (Node *)) { + Hash *h, *hsym; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + h = ccurrent; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + hsym = n; + h = Getattr(n, "csymtab"); + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, checkfunc); + } + Delete(nname); + } else { + s = symbol_lookup_qualified(name, hsym, 0, 0, checkfunc); + } + } + if (!s) { + s = symbol_lookup(name, hsym, checkfunc); + } + if (!s) + return 0; + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + Node *ss = Swig_symbol_clookup_local_check(Getattr(s, "uname"), Getattr(s, "sym:symtab"), checkfunc); + if (!ss && !checkfunc) { + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", Getattr(s, "uname")); + } + s = ss; + } + return s; +} + + +/* ----------------------------------------------------------------------------- + * Swig_symbol_cscope() + * + * Look up a scope name. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_cscope(const_String_or_char_ptr name, Symtab *symtab) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) + return symbol_lookup_qualified(0, global_scope, name, 0, 0); + return symbol_lookup_qualified(0, symtab, name, 0, 0); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_remove() + * + * Remove a symbol. If the symbol is an overloaded function and the symbol removed + * is not the last in the list of overloaded functions, then the overloaded + * names (sym:overname attribute) are changed to start from zero, eg __SWIG_0. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_remove(Node *n) { + Symtab *symtab; + String *symname; + String *overname; + Node *symprev; + Node *symnext; + Node *fixovername = 0; + symtab = Getattr(n, "sym:symtab"); /* Get symbol table object */ + symtab = Getattr(symtab, "symtab"); /* Get actual hash table of symbols */ + symname = Getattr(n, "sym:name"); + symprev = Getattr(n, "sym:previousSibling"); + symnext = Getattr(n, "sym:nextSibling"); + + /* If previous symbol, just fix the links */ + if (symprev) { + if (symnext) { + Setattr(symprev, "sym:nextSibling", symnext); + fixovername = symprev; /* fix as symbol to remove is somewhere in the middle of the linked list */ + } else { + Delattr(symprev, "sym:nextSibling"); + } + } else { + /* If no previous symbol, see if there is a next symbol */ + if (symnext) { + Setattr(symtab, symname, symnext); + fixovername = symnext; /* fix as symbol to remove is at head of linked list */ + } else { + Delattr(symtab, symname); + } + } + if (symnext) { + if (symprev) { + Setattr(symnext, "sym:previousSibling", symprev); + } else { + Delattr(symnext, "sym:previousSibling"); + } + } + Delattr(n, "sym:symtab"); + Delattr(n, "sym:previousSibling"); + Delattr(n, "sym:nextSibling"); + Delattr(n, "csym:nextSibling"); + Delattr(n, "sym:overname"); + Delattr(n, "csym:previousSibling"); + Delattr(n, "sym:overloaded"); + n = 0; + + if (fixovername) { + Node *nn = fixovername; + Node *head = fixovername; + int pn = 0; + + /* find head of linked list */ + while (nn) { + head = nn; + nn = Getattr(nn, "sym:previousSibling"); + } + + /* adjust all the sym:overname strings to start from 0 and increment by one */ + nn = head; + while (nn) { + assert(Getattr(nn, "sym:overname")); + Delattr(nn, "sym:overname"); + overname = NewStringf("__SWIG_%d", pn); + Setattr(nn, "sym:overname", overname); + Delete(overname); + pn++; + nn = Getattr(nn, "sym:nextSibling"); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_qualified() + * + * Return the qualified name of a symbol + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_qualified(Node *n) { + Hash *symtab; + if (Checkattr(n, "nodeType", "symboltable")) { + symtab = n; + } else { + symtab = Getattr(n, "sym:symtab"); + } + if (!symtab) + return NewStringEmpty(); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qscope %s %x %s\n", Getattr(n, "name"), symtab, Getattr(symtab, "name")); +#endif + return Swig_symbol_qualifiedscopename(symtab); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_isoverloaded() + * + * Check if a symbol is overloaded. Returns the first symbol if so. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_isoverloaded(Node *n) { + return Getattr(n, "sym:overloaded"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_type_qualify() + * + * Create a fully qualified type name + * ----------------------------------------------------------------------------- */ + +/* This cache produces problems with OSS, don't active it */ +/* #define SWIG_TEMPLATE_QUALIFY_CACHE */ +static SwigType *Swig_symbol_template_qualify(const SwigType *e, Symtab *st) { + String *tprefix, *tsuffix; + SwigType *qprefix; + List *targs; + Node *tempn; + Symtab *tscope; + Iterator ti; +#ifdef SWIG_TEMPLATE_QUALIFY_CACHE + static Hash *qualify_cache = 0; + String *scopetype = st ? NewStringf("%s::%s", Getattr(st, "name"), e) + : NewStringf("%s::%s", Swig_symbol_getscopename(), e); + if (!qualify_cache) { + qualify_cache = NewHash(); + } + if (scopetype) { + String *cres = Getattr(qualify_cache, scopetype); + if (cres) { + Delete(scopetype); + return Copy(cres); + } + } +#endif + + tprefix = SwigType_templateprefix(e); + tsuffix = SwigType_templatesuffix(e); + qprefix = Swig_symbol_type_qualify(tprefix, st); + targs = SwigType_parmlist(e); + tempn = Swig_symbol_clookup_local(tprefix, st); + tscope = tempn ? Getattr(tempn, "sym:symtab") : 0; + Append(qprefix, "<("); + for (ti = First(targs); ti.item;) { + String *vparm; + String *qparm = Swig_symbol_type_qualify(ti.item, st); + if (tscope && (tscope != st)) { + String *ty = Swig_symbol_type_qualify(qparm, tscope); + Delete(qparm); + qparm = ty; + } + + vparm = Swig_symbol_template_param_eval(qparm, st); + Append(qprefix, vparm); + ti = Next(ti); + if (ti.item) { + Putc(',', qprefix); + } + Delete(qparm); + Delete(vparm); + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(tprefix); + Delete(tsuffix); + Delete(targs); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_temp_qual %s %s\n", e, qprefix); +#endif +#ifdef SWIG_TEMPLATE_QUALIFY_CACHE + Setattr(qualify_cache, scopetype, qprefix); + Delete(scopetype); +#endif + + return qprefix; +} + + +static int no_constructor(Node *n) { + return !Checkattr(n, "nodeType", "constructor"); +} + +SwigType *Swig_symbol_type_qualify(const SwigType *t, Symtab *st) { + List *elements; + String *result = NewStringEmpty(); + int i, len; + char *c = Char(t); + if (strncmp(c, "::", 2) == 0) { + Append(result, t); + return result; + } + + elements = SwigType_split(t); + + len = Len(elements); + for (i = 0; i < len; i++) { + String *e = Getitem(elements, i); + if (SwigType_issimple(e)) { + Node *n = Swig_symbol_clookup_check(e, st, no_constructor); + if (n) { + String *name = Getattr(n, "name"); + Clear(e); + Append(e, name); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qual_ei %d %s %s %x\n", i, name, e, st); +#endif + if (!Swig_scopename_check(name)) { + String *qname = Swig_symbol_qualified(n); + if (qname && Len(qname)) { + Insert(e, 0, "::"); + Insert(e, 0, qname); + } +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qual_sc %d %s %s %x\n", i, qname, e, st); +#endif + Delete(qname); + } + } else if (SwigType_istemplate(e)) { + SwigType *ty = Swig_symbol_template_qualify(e, st); + Clear(e); + Append(e, ty); + Delete(ty); + } + if (strncmp(Char(e), "::", 2) == 0) { + Delitem(e, 0); + Delitem(e, 0); + } + Append(result, e); + } else if (SwigType_isfunction(e)) { + List *parms = SwigType_parmlist(e); + String *s = NewString("f("); + Iterator pi = First(parms); + while (pi.item) { + String *pf = Swig_symbol_type_qualify(pi.item, st); + Append(s, pf); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + Delete(pf); + } + Append(s, ")."); + Append(result, s); + Delete(parms); + Delete(s); + } else { + Append(result, e); + } + } + Delete(elements); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qualify %s %s %x %s\n", t, result, st, st ? Getattr(st, "name") : 0); +#endif + + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_template_reduce() + * Resolves template parameter types + * For example: + * typedef int Int; + * typedef Int Integer; + * with input: + * Foo<(Int,Integer)> + * returns: + * Foo<(int,int)> + * ----------------------------------------------------------------------------- */ + +static +SwigType *Swig_symbol_template_reduce(SwigType *qt, Symtab *ntab) { + Parm *p; + String *templateargs = SwigType_templateargs(qt); + List *parms = SwigType_parmlist(templateargs); + Iterator pi = First(parms); + String *tprefix = SwigType_templateprefix(qt); + String *tsuffix = SwigType_templatesuffix(qt); + String *qprefix = SwigType_typedef_qualified(tprefix); + Append(qprefix, "<("); + while ((p = pi.item)) { + String *np; + String *tp = Swig_symbol_typedef_reduce(p, ntab); + String *qp = Swig_symbol_type_qualify(tp, ntab); + Node *n = Swig_symbol_clookup(qp, ntab); + if (n) { + String *qual = Swig_symbol_qualified(n); + np = Copy(Getattr(n, "name")); + Delete(tp); + tp = np; + if (qual && Len(qual)) { + Insert(np, 0, "::"); + Insert(np, 0, qual); + } + Delete(qual); + } else { + np = qp; + } + Append(qprefix, np); + pi = Next(pi); + if (pi.item) { + Append(qprefix, ","); + } + Delete(qp); + Delete(tp); + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(parms); + Delete(tprefix); + Delete(tsuffix); + Delete(templateargs); + return qprefix; +} + + +/* ----------------------------------------------------------------------------- + * Swig_symbol_typedef_reduce() + * + * Chase a typedef through symbol tables looking for a match. + * ----------------------------------------------------------------------------- */ + +SwigType *Swig_symbol_typedef_reduce(SwigType *ty, Symtab *tab) { + SwigType *prefix, *base; + Node *n; + String *nt; + + base = SwigType_base(ty); + prefix = SwigType_prefix(ty); + + n = Swig_symbol_clookup(base, tab); + if (!n) { + if (SwigType_istemplate(ty)) { + SwigType *qt = Swig_symbol_template_reduce(base, tab); + Append(prefix, qt); + Delete(qt); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (a) %s %s\n", ty, prefix); +#endif + Delete(base); + return prefix; + } else { + Delete(prefix); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (b) %s %s\n", ty, ty); +#endif + return Copy(ty); + } + } + nt = Getattr(n, "nodeType"); + if (Equal(nt, "using")) { + String *uname = Getattr(n, "uname"); + if (uname) { + n = Swig_symbol_clookup(base, Getattr(n, "sym:symtab")); + if (!n) { + Delete(base); + Delete(prefix); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (c) %s %s\n", ty, ty); +#endif + return Copy(ty); + } + } + } + if (Equal(nt, "cdecl")) { + String *storage = Getattr(n, "storage"); + if (storage && (Equal(storage, "typedef"))) { + SwigType *decl; + SwigType *rt; + SwigType *qt; + Symtab *ntab; + SwigType *nt = Copy(Getattr(n, "type")); + + /* Fix for case 'typedef struct Hello hello;' */ + { + const char *dclass[3] = { "struct ", "union ", "class " }; + int i; + char *c = Char(nt); + for (i = 0; i < 3; i++) { + if (strstr(c, dclass[i]) == c) { + Replace(nt, dclass[i], "", DOH_REPLACE_FIRST); + } + } + } + decl = Getattr(n, "decl"); + if (decl) { + SwigType_push(nt, decl); + } + SwigType_push(nt, prefix); + Delete(base); + Delete(prefix); + ntab = Getattr(n, "sym:symtab"); + rt = Swig_symbol_typedef_reduce(nt, ntab); + qt = Swig_symbol_type_qualify(rt, ntab); + if (SwigType_istemplate(qt)) { + SwigType *qtr = Swig_symbol_template_reduce(qt, ntab); + Delete(qt); + qt = qtr; + } + Delete(nt); + Delete(rt); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (d) %s %s\n", qt, ty); +#endif + return qt; + } + } + Delete(base); + Delete(prefix); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (e) %s %s\n", ty, ty); +#endif + return Copy(ty); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_string_qualify() + * + * This function takes a string and looks for identifiers. Identifiers are + * then qualified according to scope rules. This function is used in a number + * of settings including expression evaluation, scoping of conversion operators, + * and so forth. + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_string_qualify(String *s, Symtab *st) { + int have_id = 0; + String *id = NewStringEmpty(); + String *r = NewStringEmpty(); + char *c = Char(s); + while (*c) { + if (isalpha((int) *c) || (*c == '_') || (*c == ':')) { + Putc(*c, id); + have_id = 1; + } else { + if (have_id) { + String *qid = Swig_symbol_type_qualify(id, st); + Append(r, qid); + Clear(id); + Delete(qid); + have_id = 0; + } + Putc(*c, r); + } + c++; + } + if (have_id) { + String *qid = Swig_symbol_type_qualify(id, st); + Append(r, qid); + Delete(qid); + } + Delete(id); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_symbol_template_defargs() + * + * Apply default arg from generic template default args + * Returns a parameter list which contains missing default arguments (if any) + * Note side effects: parms will also contain the extra parameters in its list + * (but only if non-zero). + * ----------------------------------------------------------------------------- */ + + +ParmList *Swig_symbol_template_defargs(Parm *parms, Parm *targs, Symtab *tscope, Symtab *tsdecl) { + ParmList *expandedparms = parms; + if (Len(parms) < Len(targs)) { + Parm *lp = parms; + Parm *p = lp; + Parm *tp = targs; + while (p && tp) { + p = nextSibling(p); + tp = nextSibling(tp); + if (p) + lp = p; + } + while (tp) { + String *value = Getattr(tp, "value"); + if (value) { + Parm *cp; + Parm *ta = targs; + Parm *p = parms; + SwigType *nt = Swig_symbol_string_qualify(value, tsdecl); + SwigType *ntq = 0; +#ifdef SWIG_DEBUG + Printf(stderr, "value %s %s %s\n", value, nt, tsdecl ? Getattr(tsdecl, "name") : tsdecl); +#endif + while (p && ta) { + String *name = Getattr(ta, "name"); + String *pvalue = Getattr(p, "value"); + String *value = pvalue ? pvalue : Getattr(p, "type"); + String *ttq = Swig_symbol_type_qualify(value, tscope); + /* value = SwigType_typedef_resolve_all(value); */ + Replaceid(nt, name, ttq); + p = nextSibling(p); + ta = nextSibling(ta); + Delete(ttq); + } + ntq = Swig_symbol_type_qualify(nt, tsdecl); + if (SwigType_istemplate(ntq)) { + String *ty = Swig_symbol_template_deftype(ntq, tscope); + Delete(ntq); + ntq = ty; + } + /* Printf(stderr,"value %s %s %s\n",value,ntr,ntq); */ + cp = NewParm(ntq, 0); + if (lp) + set_nextSibling(lp, cp); + else + expandedparms = CopyParm(cp); + lp = cp; + tp = nextSibling(tp); + Delete(cp); + Delete(nt); + Delete(ntq); + } else { + tp = 0; + } + } + } + return expandedparms; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_template_deftype() + * + * Apply default args to generic template type + * ----------------------------------------------------------------------------- */ + +#define SWIG_TEMPLATE_DEFTYPE_CACHE +SwigType *Swig_symbol_template_deftype(const SwigType *type, Symtab *tscope) { + String *result = NewStringEmpty(); + List *elements = SwigType_split(type); + int len = Len(elements); + int i; +#ifdef SWIG_TEMPLATE_DEFTYPE_CACHE + static Hash *deftype_cache = 0; + String *scopetype = tscope ? NewStringf("%s::%s", Getattr(tscope, "name"), type) + : NewStringf("%s::%s", Swig_symbol_getscopename(), type); + if (!deftype_cache) { + deftype_cache = NewHash(); + } + if (scopetype) { + String *cres = Getattr(deftype_cache, scopetype); + if (cres) { + Append(result, cres); + Delete(scopetype); + return result; + } + } +#endif + +#ifdef SWIG_DEBUG + Printf(stderr, "finding deftype %s\n", type); +#endif + + for (i = 0; i < len; i++) { + String *e = Getitem(elements, i); + if (SwigType_isfunction(e)) { + String *s = NewString("f("); + List *parms = SwigType_parmlist(e); + Iterator pi = First(parms); + while (pi.item) { + String *pf = SwigType_istemplate(e) ? Swig_symbol_template_deftype(pi.item, tscope) + : Swig_symbol_type_qualify(pi.item, tscope); + Append(s, pf); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + Delete(pf); + } + Append(s, ")."); + Append(result, s); + Delete(s); + Delete(parms); + } else if (SwigType_istemplate(e)) { + String *prefix = SwigType_prefix(e); + String *base = SwigType_base(e); + String *tprefix = SwigType_templateprefix(base); + String *targs = SwigType_templateargs(base); + String *tsuffix = SwigType_templatesuffix(base); + ParmList *tparms = SwigType_function_parms(targs); + Node *tempn = Swig_symbol_clookup_local(tprefix, tscope); + if (!tempn && tsuffix && Len(tsuffix)) { + tempn = Swig_symbol_clookup(tprefix, 0); + } +#ifdef SWIG_DEBUG + Printf(stderr, "deftype type %s %s %d\n", e, tprefix, (long) tempn); +#endif + if (tempn) { + ParmList *tnargs = Getattr(tempn, "templateparms"); + ParmList *expandedparms; + Parm *p; + Symtab *tsdecl = Getattr(tempn, "sym:symtab"); + +#ifdef SWIG_DEBUG + Printf(stderr, "deftype type %s %s %s\n", tprefix, targs, tsuffix); +#endif + Append(tprefix, "<("); + expandedparms = Swig_symbol_template_defargs(tparms, tnargs, tscope, tsdecl); + p = expandedparms; + tscope = tsdecl; + while (p) { + SwigType *ptype = Getattr(p, "type"); + SwigType *ttr = ptype ? ptype : Getattr(p, "value"); + SwigType *ttf = Swig_symbol_type_qualify(ttr, tscope); + SwigType *ttq = Swig_symbol_template_param_eval(ttf, tscope); +#ifdef SWIG_DEBUG + Printf(stderr, "arg type %s\n", ttq); +#endif + if (SwigType_istemplate(ttq)) { + SwigType *ttd = Swig_symbol_template_deftype(ttq, tscope); + Delete(ttq); + ttq = ttd; +#ifdef SWIG_DEBUG + Printf(stderr, "arg deftype %s\n", ttq); +#endif + } + Append(tprefix, ttq); + p = nextSibling(p); + if (p) + Putc(',', tprefix); + Delete(ttf); + Delete(ttq); + } + Append(tprefix, ")>"); + Append(tprefix, tsuffix); + Append(prefix, tprefix); +#ifdef SWIG_DEBUG + Printf(stderr, "deftype %s %s \n", type, tprefix); +#endif + Append(result, prefix); + } else { + Append(result, e); + } + Delete(prefix); + Delete(base); + Delete(tprefix); + Delete(tsuffix); + Delete(targs); + Delete(tparms); + } else { + Append(result, e); + } + } + Delete(elements); +#ifdef SWIG_TEMPLATE_DEFTYPE_CACHE + Setattr(deftype_cache, scopetype, result); + Delete(scopetype); +#endif + + return result; +} + +SwigType *Swig_symbol_template_param_eval(const SwigType *p, Symtab *symtab) { + String *value = Copy(p); + Node *lastnode = 0; + while (1) { + Node *n = Swig_symbol_clookup(value, symtab); + if (n == lastnode) + break; + lastnode = n; + if (n) { + String *nt = Getattr(n, "nodeType"); + if (Equal(nt, "enumitem")) { + /* An enum item. Generate a fully qualified name */ + String *qn = Swig_symbol_qualified(n); + if (qn && Len(qn)) { + Append(qn, "::"); + Append(qn, Getattr(n, "name")); + Delete(value); + value = qn; + continue; + } else { + Delete(qn); + break; + } + } else if ((Equal(nt, "cdecl"))) { + String *nv = Getattr(n, "value"); + if (nv) { + Delete(value); + value = Copy(nv); + continue; + } + } + } + break; + } + return value; +} diff --git a/Source/Swig/tree.c b/Source/Swig/tree.c new file mode 100644 index 0000000..877b624 --- /dev/null +++ b/Source/Swig/tree.c @@ -0,0 +1,376 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * tree.c + * + * This file provides some general purpose functions for manipulating + * parse trees. + * ----------------------------------------------------------------------------- */ + +char cvsroot_tree_c[] = "$Id: tree.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" +#include <stdarg.h> +#include <assert.h> + +/* ----------------------------------------------------------------------------- + * Swig_print_tags() + * + * Dump the tag structure of a parse tree to standard output + * ----------------------------------------------------------------------------- */ + +void Swig_print_tags(DOH *obj, DOH *root) { + DOH *croot, *newroot; + DOH *cobj; + + if (!root) + croot = NewStringEmpty(); + else + croot = root; + + while (obj) { + Printf(stdout, "%s . %s (%s:%d)\n", croot, nodeType(obj), Getfile(obj), Getline(obj)); + cobj = firstChild(obj); + if (cobj) { + newroot = NewStringf("%s . %s", croot, nodeType(obj)); + Swig_print_tags(cobj, newroot); + Delete(newroot); + } + obj = nextSibling(obj); + } + if (!root) + Delete(croot); +} + +static int indent_level = 0; + +static void print_indent(int l) { + int i; + for (i = 0; i < indent_level; i++) { + fputc(' ', stdout); + } + if (l) { + fputc('|', stdout); + fputc(' ', stdout); + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_print_node(Node *n) + * ----------------------------------------------------------------------------- */ + +void Swig_print_node(Node *obj) { + Iterator ki; + Node *cobj; + + print_indent(0); + Printf(stdout, "+++ %s ----------------------------------------\n", nodeType(obj)); + ki = First(obj); + while (ki.key) { + String *k = ki.key; + if ((Cmp(k, "nodeType") == 0) || (Cmp(k, "firstChild") == 0) || (Cmp(k, "lastChild") == 0) || + (Cmp(k, "parentNode") == 0) || (Cmp(k, "nextSibling") == 0) || (Cmp(k, "previousSibling") == 0) || (*(Char(k)) == '$')) { + /* Do nothing */ + } else if (Cmp(k, "parms") == 0) { + print_indent(2); + Printf(stdout, "%-12s - %s\n", k, ParmList_protostr(Getattr(obj, k))); + } else { + DOH *o; + char *trunc = ""; + print_indent(2); + if (DohIsString(Getattr(obj, k))) { + o = Str(Getattr(obj, k)); + if (Len(o) > 80) { + trunc = "..."; + } + Printf(stdout, "%-12s - \"%(escape)-0.80s%s\"\n", k, o, trunc); + Delete(o); + } else { + Printf(stdout, "%-12s - 0x%x\n", k, Getattr(obj, k)); + } + } + ki = Next(ki); + } + cobj = firstChild(obj); + if (cobj) { + indent_level += 6; + Printf(stdout, "\n"); + Swig_print_tree(cobj); + indent_level -= 6; + } else { + print_indent(1); + Printf(stdout, "\n"); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_print_tree() + * + * Dump the tree structure of a parse tree to standard output + * ----------------------------------------------------------------------------- */ + +void Swig_print_tree(DOH *obj) { + while (obj) { + Swig_print_node(obj); + obj = nextSibling(obj); + } +} + +/* ----------------------------------------------------------------------------- + * appendChild() + * + * Appends a new child to a node + * ----------------------------------------------------------------------------- */ + +void appendChild(Node *node, Node *chd) { + Node *lc; + + if (!chd) + return; + + lc = lastChild(node); + if (!lc) { + set_firstChild(node, chd); + } else { + set_nextSibling(lc, chd); + set_previousSibling(chd, lc); + } + while (chd) { + lc = chd; + set_parentNode(chd, node); + chd = nextSibling(chd); + } + set_lastChild(node, lc); +} + +/* ----------------------------------------------------------------------------- + * prependChild() + * + * Prepends a new child to a node + * ----------------------------------------------------------------------------- */ + +void prependChild(Node *node, Node *chd) { + Node *fc; + + if (!chd) + return; + + fc = firstChild(node); + if (fc) { + set_nextSibling(chd, fc); + set_previousSibling(fc, chd); + } + set_firstChild(node, chd); + while (chd) { + set_parentNode(chd, node); + chd = nextSibling(chd); + } +} + +/* ----------------------------------------------------------------------------- + * removeNode() + * + * Removes a node from the parse tree. Detaches it from its parent's child list. + * ----------------------------------------------------------------------------- */ + +void removeNode(Node *n) { + Node *parent; + Node *prev; + Node *next; + + parent = parentNode(n); + if (!parent) return; + + prev = previousSibling(n); + next = nextSibling(n); + if (prev) { + set_nextSibling(prev, next); + } else { + if (parent) { + set_firstChild(parent, next); + } + } + if (next) { + set_previousSibling(next, prev); + } else { + if (parent) { + set_lastChild(parent, prev); + } + } + + /* Delete attributes */ + Delattr(n,"parentNode"); + Delattr(n,"nextSibling"); + Delattr(n,"prevSibling"); +} + +/* ----------------------------------------------------------------------------- + * copyNode() + * + * Copies a node, but only copies simple attributes (no lists, hashes). + * ----------------------------------------------------------------------------- */ + +Node *copyNode(Node *n) { + Iterator ki; + Node *c = NewHash(); + for (ki = First(n); ki.key; ki = Next(ki)) { + if (DohIsString(ki.item)) { + Setattr(c, ki.key, Copy(ki.item)); + } + } + Setfile(c, Getfile(n)); + Setline(c, Getline(n)); + return c; +} + +/* ----------------------------------------------------------------------------- + * checkAttribute() + * ----------------------------------------------------------------------------- */ + +int checkAttribute(Node *n, const_String_or_char_ptr name, const_String_or_char_ptr value) { + String *v = Getattr(n, name); + return v ? Equal(v, value) : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_require() + * ns - namespace for the view name for saving any attributes under + * n - node + * ... - list of attribute names of type char* + * This method checks that the attribute names exist in the node n and asserts if + * not. Assert will only occur unless the attribute is optional. An attribute is + * optional if it is prefixed by ?, eg "?value". If the attribute name is prefixed + * by * or ?, eg "*value" then a copy of the attribute is saved. The saved + * attributes will be restored on a subsequent call to Swig_restore(). All the + * saved attributes are saved in the view namespace (prefixed by ns). + * This function can be called more than once with different namespaces. + * ----------------------------------------------------------------------------- */ + +void Swig_require(const char *ns, Node *n, ...) { + va_list ap; + char *name; + DOH *obj; + + va_start(ap, n); + name = va_arg(ap, char *); + while (name) { + int newref = 0; + int opt = 0; + if (*name == '*') { + newref = 1; + name++; + } else if (*name == '?') { + newref = 1; + opt = 1; + name++; + } + obj = Getattr(n, name); + if (!opt && !obj) { + Printf(stderr, "%s:%d. Fatal error (Swig_require). Missing attribute '%s' in node '%s'.\n", Getfile(n), Getline(n), name, nodeType(n)); + assert(obj); + } + if (!obj) + obj = DohNone; + if (newref) { + /* Save a copy of the attribute */ + Setattr(n, NewStringf("%s:%s", ns, name), obj); + } + name = va_arg(ap, char *); + } + va_end(ap); + + /* Save the view */ + { + String *view = Getattr(n, "view"); + if (view) { + if (Strcmp(view, ns) != 0) { + Setattr(n, NewStringf("%s:view", ns), view); + Setattr(n, "view", ns); + } + } else { + Setattr(n, "view", ns); + } + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_save() + * Same as Swig_require(), but all attribute names are optional and all attributes + * are saved, ie behaves as if all the attribute names were prefixed by ?. + * ----------------------------------------------------------------------------- */ + +void Swig_save(const char *ns, Node *n, ...) { + va_list ap; + char *name; + DOH *obj; + + va_start(ap, n); + name = va_arg(ap, char *); + while (name) { + if (*name == '*') { + name++; + } else if (*name == '?') { + name++; + } + obj = Getattr(n, name); + if (!obj) + obj = DohNone; + + /* Save a copy of the attribute */ + if (Setattr(n, NewStringf("%s:%s", ns, name), obj)) { + Printf(stderr, "Swig_save('%s','%s'): Warning, attribute '%s' was already saved.\n", ns, nodeType(n), name); + } + name = va_arg(ap, char *); + } + va_end(ap); + + /* Save the view */ + { + String *view = Getattr(n, "view"); + if (view) { + if (Strcmp(view, ns) != 0) { + Setattr(n, NewStringf("%s:view", ns), view); + Setattr(n, "view", ns); + } + } else { + Setattr(n, "view", ns); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_restore() + * Restores attributes saved by a previous call to Swig_require() or Swig_save(). + * ----------------------------------------------------------------------------- */ + +void Swig_restore(Node *n) { + String *temp; + int len; + List *l; + String *ns; + Iterator ki; + + ns = Getattr(n, "view"); + assert(ns); + + l = NewList(); + + temp = NewStringf("%s:", ns); + len = Len(temp); + + for (ki = First(n); ki.key; ki = Next(ki)) { + if (Strncmp(temp, ki.key, len) == 0) { + Append(l, ki.key); + } + } + for (ki = First(l); ki.item; ki = Next(ki)) { + DOH *obj = Getattr(n, ki.item); + Setattr(n, Char(ki.item) + len, obj); + Delattr(n, ki.item); + } + Delete(l); + Delete(temp); +} diff --git a/Source/Swig/typemap.c b/Source/Swig/typemap.c new file mode 100644 index 0000000..ebda595 --- /dev/null +++ b/Source/Swig/typemap.c @@ -0,0 +1,1936 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * typemap.c + * + * A somewhat generalized implementation of SWIG1.1 typemaps. + * ----------------------------------------------------------------------------- */ + +char cvsroot_typemap_c[] = "$Id: typemap.c 11506 2009-08-05 21:40:49Z wsfulton $"; + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +#if 0 +#define SWIG_DEBUG +#endif + +static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f); + +/* ----------------------------------------------------------------------------- + * Typemaps are stored in a collection of nested hash tables. Something like + * this: + * + * [ type ] + * +-------- [ name ] + * +-------- [ name ] + * + * Each hash table [ type ] or [ name ] then contains references to the + * different typemap methods. These are referenced by names such as + * "tmap:in", "tmap:out", "tmap:argout", and so forth. + * + * The object corresponding to a specific typemap method has the following attributes: + * + * "type" - Typemap type + * "pname" - Parameter name + * "code" - Typemap code + * "typemap" - Descriptive text describing the actual map + * "locals" - Local variables (if any) + * "kwargs" - Typemap attributes + * + * Example for a typemap method named "in": + * %typemap(in, warning="987:my warning", noblock=1) int &my_int (int tmp) "$1 = $input;" + * + * "type" - r.int + * "pname" - my_int + * "code" - $1 = $input; + * "typemap" - typemap(in) int &my_int + * "locals" - int tmp + * "kwargs" - warning="987:my typemap warning", foo=123 + * + * ----------------------------------------------------------------------------- */ + +#define MAX_SCOPE 32 + + +static Hash *typemaps[MAX_SCOPE]; +static int tm_scope = 0; + +static Hash *get_typemap(int tm_scope, SwigType *type) { + Hash *tm = 0; + SwigType *dtype = 0; + if (SwigType_istemplate(type)) { + String *ty = Swig_symbol_template_deftype(type, 0); + dtype = Swig_symbol_type_qualify(ty, 0); + /* Printf(stderr,"gettm %s %s\n", type, dtype); */ + type = dtype; + Delete(ty); + } + tm = Getattr(typemaps[tm_scope], type); + + + if (dtype) { + if (!tm) { + String *t_name = SwigType_templateprefix(type); + if (!Equal(t_name, type)) { + tm = Getattr(typemaps[tm_scope], t_name); + } + Delete(t_name); + } + Delete(dtype); + } + + return tm; +} + +static void set_typemap(int tm_scope, SwigType *type, Hash *tm) { + SwigType *dtype = 0; + if (SwigType_istemplate(type)) { + String *ty = Swig_symbol_template_deftype(type, 0); + dtype = Swig_symbol_type_qualify(ty, 0); + /* Printf(stderr,"settm %s %s\n", type, dtype); */ + type = dtype; + Delete(ty); + } else { + dtype = Copy(type); + type = dtype; + } + Setattr(typemaps[tm_scope], type, tm); + Delete(dtype); +} + + +/* ----------------------------------------------------------------------------- + * Swig_typemap_init() + * + * Initialize the typemap system + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_init() { + int i; + for (i = 0; i < MAX_SCOPE; i++) { + typemaps[i] = 0; + } + typemaps[0] = NewHash(); + tm_scope = 0; +} + +static String *typemap_method_name(const_String_or_char_ptr tmap_method) { + static Hash *names = 0; + String *s; + /* Due to "interesting" object-identity semantics of DOH, + we have to make sure that we only intern strings without object + identity into the hash table. + + (typemap_attach_kwargs calls typemap_method_name several times with + the "same" String *tmap_method (i.e., same object identity) but differing + string values.) + + Most other callers work around this by using char* rather than + String *. + -- mkoeppe, Jun 17, 2003 + */ + const char *method_without_object_identity = Char(tmap_method); + if (!names) + names = NewHash(); + s = Getattr(names, method_without_object_identity); + if (s) + return s; + s = NewStringf("tmap:%s", tmap_method); + Setattr(names, method_without_object_identity, s); + Delete(s); + return s; +} + +#if 0 +/* ----------------------------------------------------------------------------- + * Swig_typemap_new_scope() + * + * Create a new typemap scope + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_new_scope() { + tm_scope++; + typemaps[tm_scope] = NewHash(); +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_pop_scope() + * + * Pop the last typemap scope off + * ----------------------------------------------------------------------------- */ + +Hash *Swig_typemap_pop_scope() { + if (tm_scope > 0) { + return typemaps[tm_scope--]; + } + return 0; +} +#endif + +/* ----------------------------------------------------------------------------- + * Swig_typemap_register() + * + * Add a new multi-argument typemap + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs) { + Hash *tm; + Hash *tm1; + Hash *tm2; + Parm *np; + String *tm_method; + SwigType *type; + String *pname; + + if (!parms) + return; + tm_method = typemap_method_name(tmap_method); + + /* Register the first type in the parameter list */ + + type = Getattr(parms, "type"); + pname = Getattr(parms, "name"); + + /* See if this type has been seen before */ + tm = get_typemap(tm_scope, type); + if (!tm) { + tm = NewHash(); + set_typemap(tm_scope, type, tm); + Delete(tm); + } + if (pname) { + /* See if parameter has been seen before */ + tm1 = Getattr(tm, pname); + if (!tm1) { + tm1 = NewHash(); + Setattr(tm, pname, tm1); + Delete(tm1); + } + tm = tm1; + } + + /* Now see if this typemap method has been seen before */ + tm2 = Getattr(tm, tm_method); + if (!tm2) { + tm2 = NewHash(); + Setattr(tm, tm_method, tm2); + Delete(tm2); + } + + /* For a multi-argument typemap, the typemap code and information + is really only stored in the last argument. However, to + make this work, we perform a really neat trick using + the typemap operator name. + + For example, consider this typemap + + %typemap(in) (int foo, int *bar, char *blah[]) { + ... + } + + To store it, we look at typemaps for the following: + + operator type-name + ---------------------------------------------- + "in" int foo + "in-int+foo:" int *bar + "in-int+foo:-p.int+bar: char *blah[] + + Notice how the operator expands to encode information about + previous arguments. + + */ + + np = nextSibling(parms); + if (np) { + /* Make an entirely new operator key */ + String *newop = NewStringf("%s-%s+%s:", tmap_method, type, pname); + /* Now reregister on the remaining arguments */ + Swig_typemap_register(newop, np, code, locals, kwargs); + + /* Setattr(tm2,newop,newop); */ + Delete(newop); + } else { + String *str = SwigType_str(type, pname); + String *typemap = NewStringf("typemap(%s) %s", tmap_method, str); + ParmList *clocals = CopyParmList(locals); + ParmList *ckwargs = CopyParmList(kwargs); + + Setattr(tm2, "code", code); + Setattr(tm2, "type", type); + Setattr(tm2, "typemap", typemap); + if (pname) { + Setattr(tm2, "pname", pname); + } + Setattr(tm2, "locals", clocals); + Setattr(tm2, "kwargs", ckwargs); + + Delete(clocals); + Delete(ckwargs); + + Delete(str); + Delete(typemap); + } +} + +/* ----------------------------------------------------------------------------- + * typemap_get() + * + * Retrieve typemap information from current scope. + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_get(SwigType *type, const_String_or_char_ptr name, int scope) { + Hash *tm, *tm1; + /* See if this type has been seen before */ + if ((scope < 0) || (scope > tm_scope)) + return 0; + tm = get_typemap(scope, type); + if (!tm) { + return 0; + } + if ((name) && Len(name)) { + tm1 = Getattr(tm, name); + return tm1; + } + return tm; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_copy() + * + * Copy a typemap + * ----------------------------------------------------------------------------- */ + +int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcparms, ParmList *parms) { + Hash *tm = 0; + String *tm_method; + Parm *p; + String *pname; + SwigType *ptype; + int ts = tm_scope; + String *tm_methods, *newop; + if (ParmList_len(parms) != ParmList_len(srcparms)) + return -1; + + tm_method = typemap_method_name(tmap_method); + while (ts >= 0) { + p = srcparms; + tm_methods = NewString(tm_method); + while (p) { + ptype = Getattr(p, "type"); + pname = Getattr(p, "name"); + + /* Lookup the type */ + tm = typemap_get(ptype, pname, ts); + if (!tm) + break; + + tm = Getattr(tm, tm_methods); + if (!tm) + break; + + /* Got a match. Look for next typemap */ + newop = NewStringf("%s-%s+%s:", tm_methods, ptype, pname); + Delete(tm_methods); + tm_methods = newop; + p = nextSibling(p); + } + Delete(tm_methods); + + if (!p && tm) { + + /* Got some kind of match */ + Swig_typemap_register(tmap_method, parms, Getattr(tm, "code"), Getattr(tm, "locals"), Getattr(tm, "kwargs")); + return 0; + } + ts--; + } + /* Not found */ + return -1; + +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_clear() + * + * Delete a multi-argument typemap + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *parms) { + SwigType *type; + String *name; + Parm *p; + String *newop; + Hash *tm = 0; + + /* This might not work */ + newop = NewString(tmap_method); + p = parms; + while (p) { + type = Getattr(p, "type"); + name = Getattr(p, "name"); + tm = typemap_get(type, name, tm_scope); + if (!tm) + return; + p = nextSibling(p); + if (p) + Printf(newop, "-%s+%s:", type, name); + } + if (tm) { + tm = Getattr(tm, typemap_method_name(newop)); + if (tm) { + Delattr(tm, "code"); + Delattr(tm, "locals"); + Delattr(tm, "kwargs"); + } + } + Delete(newop); +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_apply() + * + * Multi-argument %apply directive. This is pretty horrible so I sure hope + * it works. + * ----------------------------------------------------------------------------- */ + +static int count_args(String *s) { + /* Count up number of arguments */ + int na = 0; + char *c = Char(s); + while (*c) { + if (*c == '+') + na++; + c++; + } + return na; +} + +int Swig_typemap_apply(ParmList *src, ParmList *dest) { + String *ssig, *dsig; + Parm *p, *np, *lastp, *dp, *lastdp = 0; + int narg = 0; + int ts = tm_scope; + SwigType *type = 0, *name; + Hash *tm, *sm; + int match = 0; + + /* Printf(stdout,"apply : %s --> %s\n", ParmList_str(src), ParmList_str(dest)); */ + + /* Create type signature of source */ + ssig = NewStringEmpty(); + dsig = NewStringEmpty(); + p = src; + dp = dest; + lastp = 0; + while (p) { + lastp = p; + lastdp = dp; + np = nextSibling(p); + if (np) { + Printf(ssig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name")); + Printf(dsig, "-%s+%s:", Getattr(dp, "type"), Getattr(dp, "name")); + narg++; + } + p = np; + dp = nextSibling(dp); + } + + /* make sure a typemap node exists for the last destination node */ + type = Getattr(lastdp, "type"); + tm = get_typemap(tm_scope, type); + if (!tm) { + tm = NewHash(); + set_typemap(tm_scope, type, tm); + Delete(tm); + } + name = Getattr(lastdp, "name"); + if (name) { + Hash *tm1 = Getattr(tm, name); + if (!tm1) { + tm1 = NewHash(); + Setattr(tm, NewString(name), tm1); + Delete(tm1); + } + tm = tm1; + } + + /* This is a little nasty. We need to go searching for all possible typemaps in the + source and apply them to the target */ + + type = Getattr(lastp, "type"); + name = Getattr(lastp, "name"); + + while (ts >= 0) { + + /* See if there is a matching typemap in this scope */ + sm = typemap_get(type, name, ts); + + /* if there is not matching, look for a typemap in the + original typedef, if any, like in: + + typedef unsigned long size_t; + ... + %apply(size_t) {my_size}; ==> %apply(unsigned long) {my_size}; + */ + if (!sm) { + SwigType *ntype = SwigType_typedef_resolve(type); + if (ntype && (Cmp(ntype, type) != 0)) { + sm = typemap_get(ntype, name, ts); + } + Delete(ntype); + } + + if (sm) { + /* Got a typemap. Need to only merge attributes for methods that match our signature */ + Iterator ki; + match = 1; + for (ki = First(sm); ki.key; ki = Next(ki)) { + /* Check for a signature match with the source signature */ + if ((count_args(ki.key) == narg) && (Strstr(ki.key, ssig))) { + String *oldm; + /* A typemap we have to copy */ + String *nkey = Copy(ki.key); + Replace(nkey, ssig, dsig, DOH_REPLACE_ANY); + + /* Make sure the typemap doesn't already exist in the target map */ + + oldm = Getattr(tm, nkey); + if (!oldm || (!Getattr(tm, "code"))) { + String *code; + ParmList *locals; + ParmList *kwargs; + Hash *sm1 = ki.item; + + code = Getattr(sm1, "code"); + locals = Getattr(sm1, "locals"); + kwargs = Getattr(sm1, "kwargs"); + if (code) { + Replace(nkey, dsig, "", DOH_REPLACE_ANY); + Replace(nkey, "tmap:", "", DOH_REPLACE_ANY); + Swig_typemap_register(nkey, dest, code, locals, kwargs); + } + } + Delete(nkey); + } + } + } + ts--; + } + Delete(ssig); + Delete(dsig); + return match; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_clear_apply() + * + * %clear directive. Clears all typemaps for a type (in the current scope only). + * ----------------------------------------------------------------------------- */ + +/* Multi-argument %clear directive */ +void Swig_typemap_clear_apply(Parm *parms) { + String *tsig; + Parm *p, *np, *lastp; + int narg = 0; + Hash *tm; + String *name; + + /* Create a type signature of the parameters */ + tsig = NewStringEmpty(); + p = parms; + lastp = 0; + while (p) { + lastp = p; + np = nextSibling(p); + if (np) { + Printf(tsig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name")); + narg++; + } + p = np; + } + tm = get_typemap(tm_scope, Getattr(lastp, "type")); + if (!tm) { + Delete(tsig); + return; + } + name = Getattr(lastp, "name"); + if (name) { + tm = Getattr(tm, name); + } + if (tm) { + /* Clear typemaps that match our signature */ + Iterator ki, ki2; + char *ctsig = Char(tsig); + for (ki = First(tm); ki.key; ki = Next(ki)) { + char *ckey = Char(ki.key); + if (strncmp(ckey, "tmap:", 5) == 0) { + int na = count_args(ki.key); + if ((na == narg) && strstr(ckey, ctsig)) { + Hash *h = ki.item; + for (ki2 = First(h); ki2.key; ki2 = Next(ki2)) { + Delattr(h, ki2.key); + } + } + } + } + } + Delete(tsig); +} + +/* Internal function to strip array dimensions. */ +static SwigType *strip_arrays(SwigType *type) { + SwigType *t; + int ndim; + int i; + t = Copy(type); + ndim = SwigType_array_ndim(t); + for (i = 0; i < ndim; i++) { + SwigType_array_setdim(t, i, "ANY"); + } + return t; +} + +/* ----------------------------------------------------------------------------- + * typemap_search() + * + * Search for a typemap match. Tries to find the most specific typemap + * that includes a 'code' attribute. + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type, const_String_or_char_ptr name, SwigType **matchtype) { + Hash *result = 0, *tm, *tm1, *tma; + Hash *backup = 0; + SwigType *noarrays = 0; + SwigType *primitive = 0; + SwigType *ctype = 0; + int ts; + int isarray; + const String *cname = 0; + SwigType *unstripped = 0; + String *tm_method = typemap_method_name(tmap_method); + + if ((name) && Len(name)) + cname = name; + ts = tm_scope; + + while (ts >= 0) { + ctype = type; + while (ctype) { + /* Try to get an exact type-match */ + tm = get_typemap(ts, ctype); + if (tm && cname) { + tm1 = Getattr(tm, cname); + if (tm1) { + result = Getattr(tm1, tm_method); /* See if there is a type-name match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + backup = result; + } + } + if (tm) { + result = Getattr(tm, tm_method); /* See if there is simply a type match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + backup = result; + } + isarray = SwigType_isarray(ctype); + if (isarray) { + /* If working with arrays, strip away all of the dimensions and replace with "ANY". + See if that generates a match */ + if (!noarrays) { + noarrays = strip_arrays(ctype); + } + tma = get_typemap(ts, noarrays); + if (tma && cname) { + tm1 = Getattr(tma, cname); + if (tm1) { + result = Getattr(tm1, tm_method); /* type-name match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + backup = result; + } + } + if (tma) { + result = Getattr(tma, tm_method); /* type match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + backup = result; + } + Delete(noarrays); + noarrays = 0; + } + + /* No match so far. If the type is unstripped, we'll strip its + qualifiers and check. Otherwise, we'll try to resolve a typedef */ + + if (!unstripped) { + unstripped = ctype; + ctype = SwigType_strip_qualifiers(ctype); + if (!Equal(ctype, unstripped)) + continue; /* Types are different */ + Delete(ctype); + ctype = unstripped; + unstripped = 0; + } + { + String *octype; + if (unstripped) { + Delete(ctype); + ctype = unstripped; + unstripped = 0; + } + octype = ctype; + ctype = SwigType_typedef_resolve(ctype); + if (octype != type) + Delete(octype); + } + } + + /* Hmmm. Well, no match seems to be found at all. See if there is some kind of default mapping */ + + primitive = SwigType_default(type); + while (primitive) { + tm = get_typemap(ts, primitive); + if (tm && cname) { + tm1 = Getattr(tm, cname); + if (tm1) { + result = Getattr(tm1, tm_method); /* See if there is a type-name match */ + if (result) + goto ret_result; + } + } + if (tm) { /* See if there is simply a type match */ + result = Getattr(tm, tm_method); + if (result) + goto ret_result; + } + { + SwigType *nprim = SwigType_default(primitive); + Delete(primitive); + primitive = nprim; + } + } + if (ctype != type) { + Delete(ctype); + ctype = 0; + } + ts--; /* Hmmm. Nothing found in this scope. Guess we'll go try another scope */ + } + result = backup; + +ret_result: + if (noarrays) + Delete(noarrays); + if (primitive) + Delete(primitive); + if ((unstripped) && (unstripped != type)) + Delete(unstripped); + if (matchtype) { + *matchtype = Copy(ctype); + } + if (type != ctype) + Delete(ctype); + return result; +} + + +/* ----------------------------------------------------------------------------- + * typemap_search_multi() + * + * Search for a multi-argument typemap. + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_search_multi(const_String_or_char_ptr tmap_method, ParmList *parms, int *nmatch) { + SwigType *type; + SwigType *mtype = 0; + String *name; + String *newop; + Hash *tm, *tm1; + + if (!parms) { + *nmatch = 0; + return 0; + } + type = Getattr(parms, "type"); + name = Getattr(parms, "name"); + + /* Try to find a match on the first type */ + tm = typemap_search(tmap_method, type, name, &mtype); + if (tm) { + if (mtype && SwigType_isarray(mtype)) { + Setattr(parms, "tmap:match", mtype); + } + Delete(mtype); + newop = NewStringf("%s-%s+%s:", tmap_method, type, name); + tm1 = typemap_search_multi(newop, nextSibling(parms), nmatch); + if (tm1) + tm = tm1; + if (Getattr(tm, "code")) { + *(nmatch) = *nmatch + 1; + } else { + tm = 0; + } + Delete(newop); + } + return tm; +} + + +/* ----------------------------------------------------------------------------- + * typemap_replace_vars() + * + * Replaces typemap variables on a string. index is the $n variable. + * type and pname are the type and parameter name. + * ----------------------------------------------------------------------------- */ + +static void replace_local_types(ParmList *p, const String *name, const String *rep) { + SwigType *t; + while (p) { + t = Getattr(p, "type"); + Replace(t, name, rep, DOH_REPLACE_ANY); + p = nextSibling(p); + } +} + +static int check_locals(ParmList *p, const char *s) { + while (p) { + char *c = GetChar(p, "type"); + if (strstr(c, s)) + return 1; + p = nextSibling(p); + } + return 0; +} + +static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, SwigType *rtype, String *pname, String *lname, int index) { + char var[512]; + char *varname; + SwigType *ftype; + int bare_substitution_count = 0; + + Replaceall(s, "$typemap", "$TYPEMAP"); /* workaround for $type substitution below */ + + ftype = SwigType_typedef_resolve_all(type); + + if (!pname) + pname = lname; + { + Parm *p; + int rep = 0; + p = locals; + while (p) { + if (Strchr(Getattr(p, "type"), '$')) + rep = 1; + p = nextSibling(p); + } + if (!rep) + locals = 0; + } + + sprintf(var, "$%d_", index); + varname = &var[strlen(var)]; + + /* If the original datatype was an array. We're going to go through and substitute + its array dimensions */ + + if (SwigType_isarray(type) || SwigType_isarray(ftype)) { + String *size; + int ndim; + int i; + if (SwigType_array_ndim(type) != SwigType_array_ndim(ftype)) + type = ftype; + ndim = SwigType_array_ndim(type); + size = NewStringEmpty(); + for (i = 0; i < ndim; i++) { + String *dim = SwigType_array_getdim(type, i); + if (index == 1) { + char t[32]; + sprintf(t, "$dim%d", i); + Replace(s, t, dim, DOH_REPLACE_ANY); + replace_local_types(locals, t, dim); + } + sprintf(varname, "dim%d", i); + Replace(s, var, dim, DOH_REPLACE_ANY); + replace_local_types(locals, var, dim); + if (Len(size)) + Putc('*', size); + Append(size, dim); + Delete(dim); + } + sprintf(varname, "size"); + Replace(s, var, size, DOH_REPLACE_ANY); + replace_local_types(locals, var, size); + Delete(size); + } + + /* Parameter name substitution */ + if (index == 1) { + Replace(s, "$parmname", pname, DOH_REPLACE_ANY); + } + strcpy(varname, "name"); + Replace(s, var, pname, DOH_REPLACE_ANY); + + /* Type-related stuff */ + { + SwigType *star_type, *amp_type, *base_type, *lex_type; + SwigType *ltype, *star_ltype, *amp_ltype; + String *mangle, *star_mangle, *amp_mangle, *base_mangle, *base_name; + String *descriptor, *star_descriptor, *amp_descriptor; + String *ts; + char *sc; + + sc = Char(s); + + if (strstr(sc, "type") || check_locals(locals, "type")) { + /* Given type : $type */ + ts = SwigType_str(type, 0); + if (index == 1) { + Replace(s, "$type", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$type", type); + } + strcpy(varname, "type"); + Replace(s, var, ts, DOH_REPLACE_ANY); + replace_local_types(locals, var, type); + Delete(ts); + sc = Char(s); + } + if (strstr(sc, "ltype") || check_locals(locals, "ltype")) { + /* Local type: $ltype */ + ltype = SwigType_ltype(type); + ts = SwigType_str(ltype, 0); + if (index == 1) { + Replace(s, "$ltype", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$ltype", ltype); + } + strcpy(varname, "ltype"); + Replace(s, var, ts, DOH_REPLACE_ANY); + replace_local_types(locals, var, ltype); + Delete(ts); + Delete(ltype); + sc = Char(s); + } + if (strstr(sc, "mangle") || strstr(sc, "descriptor")) { + /* Mangled type */ + + mangle = SwigType_manglestr(type); + if (index == 1) + Replace(s, "$mangle", mangle, DOH_REPLACE_ANY); + strcpy(varname, "mangle"); + Replace(s, var, mangle, DOH_REPLACE_ANY); + + descriptor = NewStringf("SWIGTYPE%s", mangle); + + if (index == 1) + if (Replace(s, "$descriptor", descriptor, DOH_REPLACE_ANY)) + SwigType_remember(type); + + strcpy(varname, "descriptor"); + if (Replace(s, var, descriptor, DOH_REPLACE_ANY)) + SwigType_remember(type); + + Delete(descriptor); + Delete(mangle); + } + + /* One pointer level removed */ + /* This creates variables of the form + $*n_type + $*n_ltype + */ + + if (SwigType_ispointer(ftype) || (SwigType_isarray(ftype)) || (SwigType_isreference(ftype))) { + if (!(SwigType_isarray(type) || SwigType_ispointer(type) || SwigType_isreference(type))) { + star_type = Copy(ftype); + } else { + star_type = Copy(type); + } + if (!SwigType_isreference(star_type)) { + if (SwigType_isarray(star_type)) { + SwigType_del_element(star_type); + } else { + SwigType_del_pointer(star_type); + } + ts = SwigType_str(star_type, 0); + if (index == 1) { + Replace(s, "$*type", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$*type", star_type); + } + sprintf(varname, "$*%d_type", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, star_type); + Delete(ts); + } else { + SwigType_del_element(star_type); + } + star_ltype = SwigType_ltype(star_type); + ts = SwigType_str(star_ltype, 0); + if (index == 1) { + Replace(s, "$*ltype", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$*ltype", star_ltype); + } + sprintf(varname, "$*%d_ltype", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, star_ltype); + Delete(ts); + Delete(star_ltype); + + star_mangle = SwigType_manglestr(star_type); + if (index == 1) + Replace(s, "$*mangle", star_mangle, DOH_REPLACE_ANY); + + sprintf(varname, "$*%d_mangle", index); + Replace(s, varname, star_mangle, DOH_REPLACE_ANY); + + star_descriptor = NewStringf("SWIGTYPE%s", star_mangle); + if (index == 1) + if (Replace(s, "$*descriptor", star_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(star_type); + sprintf(varname, "$*%d_descriptor", index); + if (Replace(s, varname, star_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(star_type); + + Delete(star_descriptor); + Delete(star_mangle); + Delete(star_type); + } else { + /* TODO: Signal error if one of the $* substitutions is + requested */ + } + /* One pointer level added */ + amp_type = Copy(type); + SwigType_add_pointer(amp_type); + ts = SwigType_str(amp_type, 0); + if (index == 1) { + Replace(s, "$&type", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$&type", amp_type); + } + sprintf(varname, "$&%d_type", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, amp_type); + Delete(ts); + + amp_ltype = SwigType_ltype(type); + SwigType_add_pointer(amp_ltype); + ts = SwigType_str(amp_ltype, 0); + + if (index == 1) { + Replace(s, "$<ype", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$<ype", amp_ltype); + } + sprintf(varname, "$&%d_ltype", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, amp_ltype); + Delete(ts); + Delete(amp_ltype); + + amp_mangle = SwigType_manglestr(amp_type); + if (index == 1) + Replace(s, "$&mangle", amp_mangle, DOH_REPLACE_ANY); + sprintf(varname, "$&%d_mangle", index); + Replace(s, varname, amp_mangle, DOH_REPLACE_ANY); + + amp_descriptor = NewStringf("SWIGTYPE%s", amp_mangle); + if (index == 1) + if (Replace(s, "$&descriptor", amp_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(amp_type); + sprintf(varname, "$&%d_descriptor", index); + if (Replace(s, varname, amp_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(amp_type); + + Delete(amp_descriptor); + Delete(amp_mangle); + Delete(amp_type); + + /* Base type */ + if (SwigType_isarray(type)) { + SwigType *bt = Copy(type); + Delete(SwigType_pop_arrays(bt)); + base_type = SwigType_str(bt, 0); + Delete(bt); + } else { + base_type = SwigType_base(type); + } + + base_name = SwigType_namestr(base_type); + if (index == 1) { + Replace(s, "$basetype", base_name, DOH_REPLACE_ANY); + replace_local_types(locals, "$basetype", base_name); + } + strcpy(varname, "basetype"); + Replace(s, var, base_type, DOH_REPLACE_ANY); + replace_local_types(locals, var, base_name); + + base_mangle = SwigType_manglestr(base_type); + if (index == 1) + Replace(s, "$basemangle", base_mangle, DOH_REPLACE_ANY); + strcpy(varname, "basemangle"); + Replace(s, var, base_mangle, DOH_REPLACE_ANY); + Delete(base_mangle); + Delete(base_type); + Delete(base_name); + + lex_type = SwigType_base(rtype); + if (index == 1) + Replace(s, "$lextype", lex_type, DOH_REPLACE_ANY); + strcpy(varname, "lextype"); + Replace(s, var, lex_type, DOH_REPLACE_ANY); + Delete(lex_type); + } + + /* Replace any $n. with (&n)-> */ + { + char temp[64]; + sprintf(var, "$%d.", index); + sprintf(temp, "(&$%d)->", index); + Replace(s, var, temp, DOH_REPLACE_ANY); + } + + /* Replace the bare $n variable */ + sprintf(var, "$%d", index); + bare_substitution_count = Replace(s, var, lname, DOH_REPLACE_ANY); + Delete(ftype); + return bare_substitution_count; +} + +/* ------------------------------------------------------------------------ + * static typemap_locals() + * + * Takes a string, a parameter list and a wrapper function argument and + * creates the local variables. + * ------------------------------------------------------------------------ */ + +static void typemap_locals(DOHString * s, ParmList *l, Wrapper *f, int argnum) { + Parm *p; + char *new_name; + + p = l; + while (p) { + SwigType *pt = Getattr(p, "type"); + SwigType *at = SwigType_alttype(pt, 1); + String *pn = Getattr(p, "name"); + String *value = Getattr(p, "value"); + if (at) + pt = at; + if (pn) { + if (Len(pn) > 0) { + String *str; + int isglobal = 0; + + str = NewStringEmpty(); + + if (strncmp(Char(pn), "_global_", 8) == 0) { + isglobal = 1; + } + + /* If the user gave us $type as the name of the local variable, we'll use + the passed datatype instead */ + + if ((argnum >= 0) && (!isglobal)) { + Printf(str, "%s%d", pn, argnum); + } else { + Append(str, pn); + } + if (isglobal && Wrapper_check_local(f, str)) { + p = nextSibling(p); + Delete(str); + if (at) + Delete(at); + continue; + } + if (value) { + String *pstr = SwigType_str(pt, str); + new_name = Wrapper_new_localv(f, str, pstr, "=", value, NIL); + Delete(pstr); + } else { + String *pstr = SwigType_str(pt, str); + new_name = Wrapper_new_localv(f, str, pstr, NIL); + Delete(pstr); + } + if (!isglobal) { + /* Substitute */ + Replace(s, pn, new_name, DOH_REPLACE_ID | DOH_REPLACE_NOQUOTE); + } + Delete(str); + } + } + p = nextSibling(p); + if (at) + Delete(at); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_lookup() + * + * Attach one or more typemaps to a node and optionally generate the typemap contents + * into the wrapper. + * + * Looks for a typemap matching the given type and name and attaches the typemap code + * and any typemap attributes to the provided node. + * + * The node should contain the "type" and "name" attributes for the typemap match on. + * input. The typemap code and typemap attribute values are attached onto the node + * prefixed with "tmap:". For example with tmap_method="in", the typemap code can be retrieved + * with a call to Getattr(node, "tmap:in") (this is also the string returned) and the + * "noblock" attribute can be retrieved with a call to Getattr(node, "tmap:in:noblock"). + * + * tmap_method - typemap method, eg "in", "out", "newfree" + * node - the node to attach the typemap and typemap attributes to + * lname - name of variable to substitute $1, $2 etc for + * f - wrapper code to generate into if non null + * actioncode - code to generate into f before the out typemap code, unless + * the optimal attribute is set in the out typemap in which case + * $1 in the out typemap will be replaced by the code in actioncode. + * ----------------------------------------------------------------------------- */ + +static String *Swig_typemap_lookup_impl(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) { + SwigType *type; + SwigType *mtype = 0; + String *pname; + Hash *tm = 0; + String *s = 0; + String *sdef = 0; + ParmList *locals; + ParmList *kw; + char temp[256]; + String *symname; + String *cname = 0; + String *clname = 0; + char *cop = Char(tmap_method); + int optimal_attribute = 0; + int optimal_substitution = 0; + int num_substitutions = 0; + + /* special case, we need to check for 'ref' call + and set the default code 'sdef' */ + if (node && Cmp(tmap_method, "newfree") == 0) { + sdef = Swig_ref_call(node, lname); + } + + type = Getattr(node, "type"); + if (!type) + return sdef; + + pname = Getattr(node, "name"); + +#if 1 + if (pname && node && checkAttribute(node, "kind", "function")) { + /* + For functions, look qualified names first, such as + + struct Foo { + int *foo(int bar) -> Foo::foo + }; + */ + Symtab *st = Getattr(node, "sym:symtab"); + String *qsn = st ? Swig_symbol_string_qualify(pname, st) : 0; + if (qsn) { + if (Len(qsn) && !Equal(qsn, pname)) { + tm = typemap_search(tmap_method, type, qsn, &mtype); + if (tm && (!Getattr(tm, "pname") || strstr(Char(Getattr(tm, "type")), "SWIGTYPE"))) { + tm = 0; + } + } + Delete(qsn); + } + } + if (!tm) +#endif + tm = typemap_search(tmap_method, type, pname, &mtype); + if (!tm) + return sdef; + + s = Getattr(tm, "code"); + if (!s) + return sdef; + + /* Empty typemap. No match */ + if (Cmp(s, "pass") == 0) + return sdef; + + s = Copy(s); /* Make a local copy of the typemap code */ + + /* Attach kwargs - ie the typemap attributes */ + kw = Getattr(tm, "kwargs"); + while (kw) { + String *value = Copy(Getattr(kw, "value")); + String *kwtype = Getattr(kw, "type"); + char *ckwname = Char(Getattr(kw, "name")); + if (kwtype) { + String *mangle = Swig_string_mangle(kwtype); + Append(value, mangle); + Delete(mangle); + } + sprintf(temp, "%s:%s", cop, ckwname); + Setattr(node, typemap_method_name(temp), value); + if (Cmp(temp, "out:optimal") == 0) + optimal_attribute = (Cmp(value, "0") != 0) ? 1 : 0; + Delete(value); + kw = nextSibling(kw); + } + + if (optimal_attribute) { + /* Note: "out" typemap is the only typemap that will have the "optimal" attribute set. + * If f and actioncode are NULL, then the caller is just looking to attach the "out" attributes + * ie, not use the typemap code, otherwise both f and actioncode must be non null. */ + if (actioncode) { + clname = Copy(actioncode); + /* check that the code in the typemap can be used in this optimal way. + * The code should be in the form "result = ...;\n". We need to extract + * the "..." part. This may not be possible for various reasons, eg + * code added by %exception. This optimal code generation is bit of a + * hack and circumvents the normal requirement for a temporary variable + * to hold the result returned from a wrapped function call. + */ + if (Strncmp(clname, "result = ", 9) == 0) { + int numreplacements = Replace(clname, "result = ", "", DOH_REPLACE_ID_BEGIN); + if (numreplacements == 1) { + numreplacements = Replace(clname, ";\n", "", DOH_REPLACE_ID_END); + if (numreplacements == 1) { + if (Strchr(clname, ';') == 0) { + lname = clname; + actioncode = 0; + optimal_substitution = 1; + } + } + } + } + if (!optimal_substitution) { + Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_IGNORED, Getfile(node), Getline(node), "Method %s usage of the optimal attribute in the out typemap at %s:%d ignored as the following cannot be used to generate optimal code: %s\n", Swig_name_decl(node), Getfile(s), Getline(s), clname); + Delattr(node, "tmap:out:optimal"); + } + } else { + assert(!f); + } + } + if (actioncode) { + assert(f); + Append(f->code, actioncode); + } + + /* emit local variables declared in typemap, eg emit declarations for aa and bb in: + * %typemap(in) foo (int aa, int bb) "..." */ + locals = Getattr(tm, "locals"); + if (locals) + locals = CopyParmList(locals); + + if (pname) { + if (SwigType_istemplate(pname)) { + cname = SwigType_namestr(pname); + pname = cname; + } + } + if (SwigType_istemplate((char *) lname)) { + clname = SwigType_namestr((char *) lname); + lname = clname; + } + + if (mtype && SwigType_isarray(mtype)) { + num_substitutions = typemap_replace_vars(s, locals, mtype, type, pname, (char *) lname, 1); + } else { + num_substitutions = typemap_replace_vars(s, locals, type, type, pname, (char *) lname, 1); + } + if (optimal_substitution && num_substitutions > 1) + Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE, Getfile(node), Getline(node), "Multiple calls to %s might be generated due to optimal attribute usage in the out typemap at %s:%d.\n", Swig_name_decl(node), Getfile(s), Getline(s)); + + if (locals && f) { + typemap_locals(s, locals, f, -1); + } + + { + ParmList *parm_sublist = NewParm(type, pname); + Setattr(parm_sublist, "lname", lname); + replace_embedded_typemap(s, parm_sublist, f); + Delete(parm_sublist); + } + + Replace(s, "$name", pname, DOH_REPLACE_ANY); + + symname = Getattr(node, "sym:name"); + if (symname) { + Replace(s, "$symname", symname, DOH_REPLACE_ANY); + } + + Setattr(node, typemap_method_name(tmap_method), s); + if (locals) { + sprintf(temp, "%s:locals", cop); + Setattr(node, typemap_method_name(temp), locals); + Delete(locals); + } + + if (Checkattr(tm, "type", "SWIGTYPE")) { + sprintf(temp, "%s:SWIGTYPE", cop); + Setattr(node, typemap_method_name(temp), "1"); + } + + /* Look for warnings */ + { + String *w; + sprintf(temp, "%s:warning", cop); + w = Getattr(node, typemap_method_name(temp)); + if (w) { + Swig_warning(0, Getfile(node), Getline(node), "%s\n", w); + } + } + + /* Look for code fragments */ + { + String *fragment; + sprintf(temp, "%s:fragment", cop); + fragment = Getattr(node, typemap_method_name(temp)); + if (fragment) { + String *fname = Copy(fragment); + Setfile(fname, Getfile(node)); + Setline(fname, Getline(node)); + Swig_fragment_emit(fname); + Delete(fname); + } + } + + Delete(cname); + Delete(clname); + Delete(mtype); + if (sdef) { /* put 'ref' and 'newfree' codes together */ + String *p = NewStringf("%s\n%s", sdef, s); + Delete(s); + Delete(sdef); + s = p; + } + Delete(actioncode); + return s; +} + +String *Swig_typemap_lookup_out(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) { + assert(actioncode); + assert(Cmp(tmap_method, "out") == 0); + return Swig_typemap_lookup_impl(tmap_method, node, lname, f, actioncode); +} + +String *Swig_typemap_lookup(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f) { + return Swig_typemap_lookup_impl(tmap_method, node, lname, f, 0); +} + +/* ----------------------------------------------------------------------------- + * typemap_attach_kwargs() + * + * If this hash (tm) contains a linked list of parameters under its "kwargs" + * attribute, add keys for each of those named keyword arguments to this + * parameter for later use. + * For example, attach the typemap attributes to p: + * %typemap(in, foo="xyz") ... + * A new attribute called "tmap:in:foo" with value "xyz" is attached to p. + * ----------------------------------------------------------------------------- */ + +static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr tmap_method, Parm *p) { + String *temp = NewStringEmpty(); + Parm *kw = Getattr(tm, "kwargs"); + while (kw) { + String *value = Copy(Getattr(kw, "value")); + String *type = Getattr(kw, "type"); + if (type) { + Hash *v = NewHash(); + Setattr(v, "type", type); + Setattr(v, "value", value); + Delete(value); + value = v; + } + Clear(temp); + Printf(temp, "%s:%s", tmap_method, Getattr(kw, "name")); + Setattr(p, typemap_method_name(temp), value); + Delete(value); + kw = nextSibling(kw); + } + Clear(temp); + Printf(temp, "%s:match_type", tmap_method); + Setattr(p, typemap_method_name(temp), Getattr(tm, "type")); + Delete(temp); +} + +/* ----------------------------------------------------------------------------- + * typemap_warn() + * + * If any warning message is attached to this parameter's "tmap:<method>:warning" + * attribute, print that warning message. + * ----------------------------------------------------------------------------- */ + +static void typemap_warn(const_String_or_char_ptr tmap_method, Parm *p) { + String *temp = NewStringf("%s:warning", tmap_method); + String *w = Getattr(p, typemap_method_name(temp)); + Delete(temp); + if (w) { + Swig_warning(0, Getfile(p), Getline(p), "%s\n", w); + } +} + +static void typemap_emit_code_fragments(const_String_or_char_ptr tmap_method, Parm *p) { + String *temp = NewStringf("%s:fragment", tmap_method); + String *f = Getattr(p, typemap_method_name(temp)); + if (f) { + String *fname = Copy(f); + Setfile(fname, Getfile(p)); + Setline(fname, Getline(p)); + Swig_fragment_emit(fname); + Delete(fname); + } + Delete(temp); +} + +static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) { + Parm *kw = Getattr(tm, "kwargs"); + while (kw) { + String *kname = Getattr(kw, "name"); + if (Equal(kname, name)) { + return Getattr(kw, "value"); + } + kw = nextSibling(kw); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_attach_parms() + * + * Given a parameter list, this function attaches all of the typemaps and typemap + * attributes to the parameter for each type in the parameter list. + * + * This function basically provides the typemap code and typemap attribute values as + * attributes on each parameter prefixed with "tmap:". For example with tmap_method="in", the typemap + * code can be retrieved for the first parameter with a call to Getattr(parm, "tmap:in") + * and the "numinputs" attribute can be retrieved with a call to Getattr(parm, "tmap:in:numinputs"). + * + * tmap_method - typemap method, eg "in", "out", "newfree" + * parms - parameter list to attach each typemap and all typemap attributes + * f - wrapper code to generate into if non null + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f) { + Parm *p, *firstp; + Hash *tm; + int nmatch = 0; + int i; + String *s; + ParmList *locals; + int argnum = 0; + char temp[256]; + char *cop = Char(tmap_method); + String *kwmatch = 0; + p = parms; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_typemap_attach_parms: %s\n", tmap_method); +#endif + + while (p) { + argnum++; + nmatch = 0; +#ifdef SWIG_DEBUG + Printf(stdout, "parms: %s %s %s\n", tmap_method, Getattr(p, "name"), Getattr(p, "type")); +#endif + tm = typemap_search_multi(tmap_method, p, &nmatch); +#ifdef SWIG_DEBUG + if (tm) + Printf(stdout, "found: %s\n", tm); +#endif + if (!tm) { + p = nextSibling(p); + continue; + } + /* + Check if the typemap requires to match the type of another + typemap, for example: + + %typemap(in) SWIGTYPE * (int var) {...} + %typemap(freearg,match="in") SWIGTYPE * {if (var$argnum) ...} + + here, the freearg typemap requires the "in" typemap to match, + or the 'var$argnum' variable will not exist. + */ + kwmatch = typemap_get_option(tm, "match"); + if (kwmatch) { + String *tmname = NewStringf("tmap:%s", kwmatch); + String *tmin = Getattr(p, tmname); + Delete(tmname); +#ifdef SWIG_DEBUG + if (tm) + Printf(stdout, "matching: %s\n", kwmatch); +#endif + if (tmin) { + String *tmninp = NewStringf("tmap:%s:numinputs", kwmatch); + String *ninp = Getattr(p, tmninp); + Delete(tmninp); + if (ninp && Equal(ninp, "0")) { + p = nextSibling(p); + continue; + } else { + SwigType *typetm = Getattr(tm, "type"); + String *temp = NewStringf("tmap:%s:match_type", kwmatch); + SwigType *typein = Getattr(p, temp); + Delete(temp); + if (!Equal(typein, typetm)) { + p = nextSibling(p); + continue; + } else { + int nnmatch; + Hash *tmapin = typemap_search_multi(kwmatch, p, &nnmatch); + String *tmname = Getattr(tm, "pname"); + String *tnname = Getattr(tmapin, "pname"); + if (!(tmname && tnname && Equal(tmname, tnname)) && !(!tmname && !tnname)) { + p = nextSibling(p); + continue; + } + } + + } + } else { + p = nextSibling(p); + continue; + } + } + + s = Getattr(tm, "code"); + if (!s) { + p = nextSibling(p); + continue; + } +#ifdef SWIG_DEBUG + if (s) + Printf(stdout, "code: %s\n", s); +#endif + + /* Empty typemap. No match */ + if (Cmp(s, "pass") == 0) { + p = nextSibling(p); + continue; + } + + s = Copy(s); + locals = Getattr(tm, "locals"); + if (locals) + locals = CopyParmList(locals); + firstp = p; +#ifdef SWIG_DEBUG + Printf(stdout, "nmatch: %d\n", nmatch); +#endif + for (i = 0; i < nmatch; i++) { + SwigType *type; + String *pname; + String *lname; + SwigType *mtype; + + + type = Getattr(p, "type"); + pname = Getattr(p, "name"); + lname = Getattr(p, "lname"); + mtype = Getattr(p, "tmap:match"); + + if (mtype) { + typemap_replace_vars(s, locals, mtype, type, pname, lname, i + 1); + Delattr(p, "tmap:match"); + } else { + typemap_replace_vars(s, locals, type, type, pname, lname, i + 1); + } + + if (Checkattr(tm, "type", "SWIGTYPE")) { + sprintf(temp, "%s:SWIGTYPE", cop); + Setattr(p, typemap_method_name(temp), "1"); + } + p = nextSibling(p); + } + + if (locals && f) { + typemap_locals(s, locals, f, argnum); + } + + replace_embedded_typemap(s, firstp, f); + + /* Replace the argument number */ + sprintf(temp, "%d", argnum); + Replace(s, "$argnum", temp, DOH_REPLACE_ANY); + + /* Attach attributes to object */ +#ifdef SWIG_DEBUG + Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), s); +#endif + Setattr(firstp, typemap_method_name(tmap_method), s); /* Code object */ + + if (locals) { + sprintf(temp, "%s:locals", cop); + Setattr(firstp, typemap_method_name(temp), locals); + Delete(locals); + } + + /* Attach a link to the next parameter. Needed for multimaps */ + sprintf(temp, "%s:next", cop); + Setattr(firstp, typemap_method_name(temp), p); + + /* Attach kwargs */ + typemap_attach_kwargs(tm, tmap_method, firstp); + + /* Print warnings, if any */ + typemap_warn(tmap_method, firstp); + + /* Look for code fragments */ + typemap_emit_code_fragments(tmap_method, firstp); + + /* increase argnum to consider numinputs */ + argnum += nmatch - 1; + Delete(s); +#ifdef SWIG_DEBUG + Printf(stdout, "res: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), Getattr(firstp, typemap_method_name(tmap_method))); +#endif + + } +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_typemap_attach_parms: end\n"); +#endif + +} + +/* Splits the arguments of an embedded typemap */ +static List *split_embedded_typemap(String *s) { + List *args = 0; + char *c, *start; + int level = 0; + int angle_level = 0; + int leading = 1; + + args = NewList(); + c = strchr(Char(s), '('); + assert(c); + c++; + + start = c; + while (*c) { + if (*c == '\"') { + c++; + while (*c) { + if (*c == '\\') { + c++; + } else { + if (*c == '\"') + break; + } + c++; + } + } + if ((level == 0) && angle_level == 0 && ((*c == ',') || (*c == ')'))) { + String *tmp = NewStringWithSize(start, c - start); + Append(args, tmp); + Delete(tmp); + start = c + 1; + leading = 1; + if (*c == ')') + break; + c++; + continue; + } + if (*c == '(') + level++; + if (*c == ')') + level--; + if (*c == '<') + angle_level++; + if (*c == '>') + angle_level--; + if (isspace((int) *c) && leading) + start++; + if (!isspace((int) *c)) + leading = 0; + c++; + } + return args; +} + +/* ----------------------------------------------------------------------------- + * replace_embedded_typemap() + * + * This function replaces the special variable macro $typemap(...) with typemap + * code. The general form of $typemap is as follows: + * + * $typemap(method, typelist, var1=value, var2=value, ...) + * + * where varx parameters are optional and undocumented; they were used in an earlier version of $typemap. + * A search is made using the typemap matching rules of form: + * + * %typemap(method) typelist {...} + * + * and if found will substitute in the typemap contents, making appropriate variable replacements. + * + * For example: + * $typemap(in, int) # simple usage matching %typemap(in) int { ... } + * $typemap(in, int b) # simple usage matching %typemap(in) int b { ... } or above %typemap + * $typemap(in, (Foo<int, bool> a, int b)) # multi-argument typemap matching %typemap(in) (Foo<int, bool> a, int b) {...} + * ----------------------------------------------------------------------------- */ + +static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f) { + char *start = 0; + while ((start = strstr(Char(s), "$TYPEMAP("))) { /* note $typemap capitalisation to $TYPEMAP hack */ + + /* Gather the parameters */ + char *end = 0, *c; + int level = 0; + String *dollar_typemap; + int syntax_error = 1; + c = start; + while (*c) { + if (*c == '(') + level++; + if (*c == ')') { + level--; + if (level == 0) { + end = c + 1; + break; + } + } + c++; + } + if (end) { + dollar_typemap = NewStringWithSize(start, (end - start)); + syntax_error = 0; + } else { + dollar_typemap = NewStringWithSize(start, (c - start)); + } + + if (!syntax_error) { + List *l; + String *tmap_method; + Hash *vars; + syntax_error = 1; + + /* Split apart each parameter in $typemap(...) */ + l = split_embedded_typemap(dollar_typemap); + + if (Len(l) >= 2) { + ParmList *to_match_parms; + tmap_method = Getitem(l, 0); + + /* the second parameter might contain multiple sub-parameters for multi-argument + * typemap matching, so split these parameters apart */ + to_match_parms = Swig_cparse_parms(Getitem(l, 1)); + if (to_match_parms) { + Parm *p = to_match_parms; + Parm *sub_p = parm_sublist; + String *empty_string = NewStringEmpty(); + String *lname = empty_string; + while (p) { + if (sub_p) { + lname = Getattr(sub_p, "lname"); + sub_p = nextSibling(sub_p); + } + Setattr(p, "lname", lname); + p = nextSibling(p); + } + Delete(empty_string); + } + + /* process optional extra parameters - the variable replacements (undocumented) */ + vars = NewHash(); + { + int i, ilen; + ilen = Len(l); + for (i = 2; i < ilen; i++) { + String *parm = Getitem(l, i); + char *eq = strchr(Char(parm), '='); + char *c = Char(parm); + if (eq && (eq - c > 0)) { + String *name = NewStringWithSize(c, eq - c); + String *value = NewString(eq + 1); + Insert(name, 0, "$"); + Setattr(vars, name, value); + } else { + to_match_parms = 0; /* error - variable replacement parameters must be of form varname=value */ + } + } + } + + /* Perform a typemap search */ + if (to_match_parms) { + static int already_substituting = 0; + String *tm; + String *attr; + int match = 0; +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_typemap_attach_parms: embedded\n"); +#endif + if (!already_substituting) { + already_substituting = 1; + Swig_typemap_attach_parms(tmap_method, to_match_parms, f); + already_substituting = 0; + + /* Look for the typemap code */ + attr = NewStringf("tmap:%s", tmap_method); + tm = Getattr(to_match_parms, attr); + if (tm) { + Printf(attr, "%s", ":next"); + /* fail if multi-argument lookup requested in $typemap(...) and the lookup failed */ + if (!Getattr(to_match_parms, attr)) { + /* Replace parameter variables */ + Iterator ki; + for (ki = First(vars); ki.key; ki = Next(ki)) { + Replace(tm, ki.key, ki.item, DOH_REPLACE_ANY); + } + /* offer the target language module the chance to make special variable substitutions */ + Language_replace_special_variables(tmap_method, tm, to_match_parms); + /* finish up - do the substitution */ + Replace(s, dollar_typemap, tm, DOH_REPLACE_ANY); + Delete(tm); + match = 1; + } + } + + if (!match) { + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Swig_error(Getfile(s), Getline(s), "No typemap found for %s\n", dtypemap); + Delete(dtypemap); + } + Delete(attr); + } else { + /* simple recursive call check, but prevents using an embedded typemap that contains another embedded typemap */ + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Swig_error(Getfile(s), Getline(s), "Recursive $typemap calls not supported - %s\n", dtypemap); + Delete(dtypemap); + } + syntax_error = 0; + } + Delete(vars); + } + Delete(l); + } + + if (syntax_error) { + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Swig_error(Getfile(s), Getline(s), "Syntax error in: %s\n", dtypemap); + Delete(dtypemap); + } + Replace(s, dollar_typemap, "<error in embedded typemap>", DOH_REPLACE_ANY); + Delete(dollar_typemap); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_debug() + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_debug() { + int ts; + Printf(stdout, "---[ typemaps ]--------------------------------------------------------------\n"); + + ts = tm_scope; + while (ts >= 0) { + Printf(stdout, "::: scope %d\n\n", ts); + Printf(stdout, "%s\n", typemaps[ts]); + ts--; + } + Printf(stdout, "-----------------------------------------------------------------------------\n"); +} diff --git a/Source/Swig/typeobj.c b/Source/Swig/typeobj.c new file mode 100644 index 0000000..085fda3 --- /dev/null +++ b/Source/Swig/typeobj.c @@ -0,0 +1,1095 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * typeobj.c + * + * This file provides functions for constructing, manipulating, and testing + * type objects. Type objects are merely the raw low-level representation + * of C++ types. They do not incorporate high-level type system features + * like typedef, namespaces, etc. + * ----------------------------------------------------------------------------- */ + +char cvsroot_typeobj_c[] = "$Id: typeobj.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" +#include <ctype.h> + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * This file provides a collection of low-level functions for constructing and + * manipulating C++ data types. In SWIG, C++ datatypes are encoded as simple + * text strings. This representation is compact, easy to debug, and easy to read. + * + * General idea: + * + * Types are represented by a base type (e.g., "int") and a collection of + * type operators applied to the base (e.g., pointers, arrays, etc...). + * + * Encoding: + * + * Types are encoded as strings of type constructors such as follows: + * + * String Encoding C Example + * --------------- --------- + * p.p.int int ** + * a(300).a(400).int int [300][400] + * p.q(const).char char const * + * + * All type constructors are denoted by a trailing '.': + * + * 'p.' = Pointer (*) + * 'r.' = Reference (&) + * 'a(n).' = Array of size n [n] + * 'f(..,..).' = Function with arguments (args) + * 'q(str).' = Qualifier (such as const or volatile) (const, volatile) + * 'm(qual).' = Pointer to member (qual::*) + * + * The encoding follows the order that you might describe a type in words. + * For example "p.a(200).int" is "A pointer to array of int's" and + * "p.q(const).char" is "a pointer to a const char". + * + * This representation of types is fairly convenient because ordinary string + * operations can be used for type manipulation. For example, a type could be + * formed by combining two strings such as the following: + * + * "p.p." + "a(400).int" = "p.p.a(400).int" + * + * For C++, typenames may be parameterized using <(...)>. Here are some + * examples: + * + * String Encoding C++ Example + * --------------- ------------ + * p.vector<(int)> vector<int> * + * r.foo<(int,p.double)> foo<int,double *> & + * + * Contents of this file: + * + * Most of this functions in this file pertain to the low-level manipulation + * of type objects. There are constructor functions like this: + * + * SwigType_add_pointer() + * SwigType_add_reference() + * SwigType_add_array() + * + * These are used to build new types. There are also functions to undo these + * operations. For example: + * + * SwigType_del_pointer() + * SwigType_del_reference() + * SwigType_del_array() + * + * In addition, there are query functions + * + * SwigType_ispointer() + * SwigType_isreference() + * SwigType_isarray() + * + * Finally, there are some data extraction functions that can be used to + * extract array dimensions, template arguments, and so forth. + * + * It is very important for developers to realize that the functions in this + * module do *NOT* incorporate higher-level type system features like typedef. + * For example, you could have C code like this: + * + * typedef int *intptr; + * + * In this case, a SwigType of type 'intptr' will be treated as a simple type and + * functions like SwigType_ispointer() will evaluate as false. It is strongly + * advised that developers use the TypeSys_* interface to check types in a more + * reliable manner. + * ----------------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------------- + * NewSwigType() + * + * Constructs a new type object. Eventually, it would be nice for this function + * to accept an initial value in the form a C/C++ abstract type (currently unimplemented). + * ----------------------------------------------------------------------------- */ + +#ifdef NEW +SwigType *NewSwigType(const_String_or_char_ptr initial) { + return NewString(initial); +} + +#endif + +/* The next few functions are utility functions used in the construction and + management of types */ + +/* ----------------------------------------------------------------------------- + * static element_size() + * + * This utility function finds the size of a single type element in a type string. + * Type elements are always delimited by periods, but may be nested with + * parentheses. A nested element is always handled as a single item. + * + * Returns the integer size of the element (which can be used to extract a + * substring, to chop the element off, or for other purposes). + * ----------------------------------------------------------------------------- */ + +static int element_size(char *c) { + int nparen; + char *s = c; + while (*c) { + if (*c == '.') { + c++; + return (int) (c - s); + } else if (*c == '(') { + nparen = 1; + c++; + while (*c) { + if (*c == '(') + nparen++; + if (*c == ')') { + nparen--; + if (nparen == 0) + break; + } + c++; + } + } + if (*c) + c++; + } + return (int) (c - s); +} + +/* ----------------------------------------------------------------------------- + * SwigType_del_element() + * + * Deletes one type element from the type. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_del_element(SwigType *t) { + int sz = element_size(Char(t)); + Delslice(t, 0, sz); + return t; +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop() + * + * Pop one type element off the type. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_pop(SwigType *t) { + SwigType *result; + char *c; + int sz; + + c = Char(t); + if (!*c) + return 0; + + sz = element_size(c); + result = NewStringWithSize(c, sz); + Delslice(t, 0, sz); + c = Char(t); + if (*c == '.') { + Delitem(t, 0); + } + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_parm() + * + * Returns the parameter of an operator as a string + * ----------------------------------------------------------------------------- */ + +String *SwigType_parm(SwigType *t) { + char *start, *c; + int nparens = 0; + + c = Char(t); + while (*c && (*c != '(') && (*c != '.')) + c++; + if (!*c || (*c == '.')) + return 0; + c++; + start = c; + while (*c) { + if (*c == ')') { + if (nparens == 0) + break; + nparens--; + } else if (*c == '(') { + nparens++; + } + c++; + } + return NewStringWithSize(start, (int) (c - start)); +} + +/* ----------------------------------------------------------------------------- + * SwigType_split() + * + * Splits a type into it's component parts and returns a list of string. + * ----------------------------------------------------------------------------- */ + +List *SwigType_split(const SwigType *t) { + String *item; + List *list; + char *c; + int len; + + c = Char(t); + list = NewList(); + while (*c) { + len = element_size(c); + item = NewStringWithSize(c, len); + Append(list, item); + Delete(item); + c = c + len; + if (*c == '.') + c++; + } + return list; +} + +/* ----------------------------------------------------------------------------- + * SwigType_parmlist() + * + * Splits a comma separated list of parameters into its component parts + * The input is expected to contain the parameter list within () brackets + * Returns 0 if no argument list in the input, ie there are no round brackets () + * Returns an empty List if there are no parameters in the () brackets + * For example: + * + * Foo(std::string,p.f().Bar<(int,double)>) + * + * returns 2 elements in the list: + * std::string + * p.f().Bar<(int,double)> + * ----------------------------------------------------------------------------- */ + +List *SwigType_parmlist(const String *p) { + String *item = 0; + List *list; + char *c; + char *itemstart; + int size; + + assert(p); + c = Char(p); + while (*c && (*c != '(') && (*c != '.')) + c++; + if (!*c) + return 0; + assert(*c != '.'); /* p is expected to contain sub elements of a type */ + c++; + list = NewList(); + itemstart = c; + while (*c) { + if (*c == ',') { + size = (int) (c - itemstart); + item = NewStringWithSize(itemstart, size); + Append(list, item); + Delete(item); + itemstart = c + 1; + } else if (*c == '(') { + int nparens = 1; + c++; + while (*c) { + if (*c == '(') + nparens++; + if (*c == ')') { + nparens--; + if (nparens == 0) + break; + } + c++; + } + } else if (*c == ')') { + break; + } + if (*c) + c++; + } + size = (int) (c - itemstart); + if (size > 0) { + item = NewStringWithSize(itemstart, size); + Append(list, item); + } + Delete(item); + return list; +} + +/* ----------------------------------------------------------------------------- + * Pointers + * + * SwigType_add_pointer() + * SwigType_del_pointer() + * SwigType_ispointer() + * + * Add, remove, and test if a type is a pointer. The deletion and query + * functions take into account qualifiers (if any). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_pointer(SwigType *t) { + Insert(t, 0, "p."); + return t; +} + +SwigType *SwigType_del_pointer(SwigType *t) { + char *c, *s; + c = Char(t); + s = c; + /* Skip qualifiers, if any */ + if (strncmp(c, "q(", 2) == 0) { + c = strchr(c, '.'); + assert(c); + c++; + } + if (strncmp(c, "p.", 2)) { + printf("Fatal error. SwigType_del_pointer applied to non-pointer.\n"); + abort(); + } + Delslice(t, 0, (c - s) + 2); + return t; +} + +int SwigType_ispointer(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + /* Skip qualifiers, if any */ + if (strncmp(c, "q(", 2) == 0) { + c = strchr(c, '.'); + if (!c) + return 0; + c++; + } + if (strncmp(c, "p.", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * References + * + * SwigType_add_reference() + * SwigType_del_reference() + * SwigType_isreference() + * + * Add, remove, and test if a type is a reference. The deletion and query + * functions take into account qualifiers (if any). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_reference(SwigType *t) { + Insert(t, 0, "r."); + return t; +} + +SwigType *SwigType_del_reference(SwigType *t) { + char *c = Char(t); + int check = strncmp(c, "r.", 2); + assert(check == 0); + Delslice(t, 0, 2); + return t; +} + +int SwigType_isreference(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "r.", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Qualifiers + * + * SwigType_add_qualifier() + * SwigType_del_qualifier() + * SwigType_is_qualifier() + * + * Adds type qualifiers like "const" and "volatile". When multiple qualifiers + * are added to a type, they are combined together into a single qualifier. + * Repeated qualifications have no effect. Moreover, the order of qualifications + * is alphabetical---meaning that "const volatile" and "volatile const" are + * stored in exactly the same way as "q(const volatile)". + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual) { + char temp[256], newq[256]; + int sz, added = 0; + char *q, *cqual; + + char *c = Char(t); + cqual = Char(qual); + + if (!(strncmp(c, "q(", 2) == 0)) { + sprintf(temp, "q(%s).", cqual); + Insert(t, 0, temp); + return t; + } + + /* The type already has a qualifier on it. In this case, we first check to + see if the qualifier is already specified. In that case do nothing. + If it is a new qualifier, we add it to the qualifier list in alphabetical + order */ + + sz = element_size(c); + strncpy(temp, c, (sz < 256) ? sz : 256); + + if (strstr(temp, cqual)) { + /* Qualifier already added */ + return t; + } + + /* Add the qualifier to the existing list. */ + + strcpy(newq, "q("); + q = temp + 2; + q = strtok(q, " )."); + while (q) { + if (strcmp(cqual, q) < 0) { + /* New qualifier is less that current qualifier. We need to insert it */ + strcat(newq, cqual); + strcat(newq, " "); + strcat(newq, q); + added = 1; + } else { + strcat(newq, q); + } + q = strtok(NULL, " )."); + if (q) { + strcat(newq, " "); + } + } + if (!added) { + strcat(newq, " "); + strcat(newq, cqual); + } + strcat(newq, ")."); + Delslice(t, 0, sz); + Insert(t, 0, newq); + return t; +} + +SwigType *SwigType_del_qualifier(SwigType *t) { + char *c = Char(t); + int check = strncmp(c, "q(", 2); + assert(check == 0); + Delslice(t, 0, element_size(c)); + return t; +} + +int SwigType_isqualifier(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Function Pointers + * ----------------------------------------------------------------------------- */ + +int SwigType_isfunctionpointer(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "p.f(", 4) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_functionpointer_decompose + * + * Decompose the function pointer into the parameter list and the return type + * t - input and on completion contains the return type + * returns the function's parameters + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_functionpointer_decompose(SwigType *t) { + String *p; + assert(SwigType_isfunctionpointer(t)); + p = SwigType_pop(t); + Delete(p); + p = SwigType_pop(t); + return p; +} + +/* ----------------------------------------------------------------------------- + * Member Pointers + * + * SwigType_add_memberpointer() + * SwigType_del_memberpointer() + * SwigType_ismemberpointer() + * + * Add, remove, and test for C++ pointer to members. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_memberpointer(SwigType *t, const_String_or_char_ptr name) { + String *temp = NewStringf("m(%s).", name); + Insert(t, 0, temp); + Delete(temp); + return t; +} + +SwigType *SwigType_del_memberpointer(SwigType *t) { + char *c = Char(t); + int check = strncmp(c, "m(", 2); + assert(check == 0); + Delslice(t, 0, element_size(c)); + return t; +} + +int SwigType_ismemberpointer(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "m(", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Arrays + * + * SwigType_add_array() + * SwigType_del_array() + * SwigType_isarray() + * + * Utility functions: + * + * SwigType_array_ndim() - Calculate number of array dimensions. + * SwigType_array_getdim() - Get array dimension + * SwigType_array_setdim() - Set array dimension + * SwigType_array_type() - Return array type + * SwigType_pop_arrays() - Remove all arrays + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_array(SwigType *t, const_String_or_char_ptr size) { + char temp[512]; + strcpy(temp, "a("); + strcat(temp, Char(size)); + strcat(temp, ")."); + Insert(t, 0, temp); + return t; +} + +SwigType *SwigType_del_array(SwigType *t) { + char *c = Char(t); + int check = strncmp(c, "a(", 2); + assert(check == 0); + Delslice(t, 0, element_size(c)); + return t; +} + +int SwigType_isarray(SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "a(", 2) == 0) { + return 1; + } + return 0; +} +/* + * SwigType_prefix_is_simple_1D_array + * + * Determine if the type is a 1D array type that is treated as a pointer within SWIG + * eg Foo[], Foo[3] return true, but Foo[3][3], Foo*[], Foo*[3], Foo**[] return false + */ +int SwigType_prefix_is_simple_1D_array(SwigType *t) { + char *c = Char(t); + + if (c && (strncmp(c, "a(", 2) == 0)) { + c = strchr(c, '.'); + c++; + return (*c == 0); + } + return 0; +} + + +/* Remove all arrays */ +SwigType *SwigType_pop_arrays(SwigType *t) { + String *ta; + assert(SwigType_isarray(t)); + ta = NewStringEmpty(); + while (SwigType_isarray(t)) { + SwigType *td = SwigType_pop(t); + Append(ta, td); + Delete(td); + } + return ta; +} + +/* Return number of array dimensions */ +int SwigType_array_ndim(SwigType *t) { + int ndim = 0; + char *c = Char(t); + + while (c && (strncmp(c, "a(", 2) == 0)) { + c = strchr(c, '.'); + c++; + ndim++; + } + return ndim; +} + +/* Get nth array dimension */ +String *SwigType_array_getdim(SwigType *t, int n) { + char *c = Char(t); + while (c && (strncmp(c, "a(", 2) == 0) && (n > 0)) { + c = strchr(c, '.'); + c++; + n--; + } + if (n == 0) { + String *dim = SwigType_parm(c); + if (SwigType_istemplate(dim)) { + String *ndim = SwigType_namestr(dim); + Delete(dim); + dim = ndim; + } + + return dim; + } + + return 0; +} + +/* Replace nth array dimension */ +void SwigType_array_setdim(SwigType *t, int n, const_String_or_char_ptr rep) { + String *result = 0; + char temp; + char *start; + char *c = Char(t); + + start = c; + if (strncmp(c, "a(", 2)) + abort(); + + while (c && (strncmp(c, "a(", 2) == 0) && (n > 0)) { + c = strchr(c, '.'); + c++; + n--; + } + if (n == 0) { + temp = *c; + *c = 0; + result = NewString(start); + Printf(result, "a(%s)", rep); + *c = temp; + c = strchr(c, '.'); + Append(result, c); + } + Clear(t); + Append(t, result); + Delete(result); +} + +/* Return base type of an array */ +SwigType *SwigType_array_type(SwigType *ty) { + SwigType *t; + t = Copy(ty); + while (SwigType_isarray(t)) { + Delete(SwigType_pop(t)); + } + return t; +} + + +/* ----------------------------------------------------------------------------- + * Functions + * + * SwigType_add_function() + * SwigType_del_function() + * SwigType_isfunction() + * SwigType_pop_function() + * + * Add, remove, and test for function types. + * ----------------------------------------------------------------------------- */ + +/* Returns the function type, t, constructed from the parameters, parms */ +SwigType *SwigType_add_function(SwigType *t, ParmList *parms) { + String *pstr; + Parm *p; + + Insert(t, 0, ")."); + pstr = NewString("f("); + p = parms; + for (p = parms; p; p = nextSibling(p)) { + if (p != parms) + Putc(',', pstr); + Append(pstr, Getattr(p, "type")); + } + Insert(t, 0, pstr); + Delete(pstr); + return t; +} + +SwigType *SwigType_pop_function(SwigType *t) { + SwigType *f = 0; + SwigType *g = 0; + char *c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + f = SwigType_pop(t); + c = Char(t); + } + if (strncmp(c, "f(", 2)) { + printf("Fatal error. SwigType_pop_function applied to non-function.\n"); + abort(); + } + g = SwigType_pop(t); + if (f) + SwigType_push(g, f); + Delete(f); + return g; +} + +int SwigType_isfunction(SwigType *t) { + char *c; + if (!t) { + return 0; + } + c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + /* Might be a 'const' function. Try to skip over the 'const' */ + c = strchr(c, '.'); + if (c) + c++; + else + return 0; + } + if (strncmp(c, "f(", 2) == 0) { + return 1; + } + return 0; +} + +ParmList *SwigType_function_parms(SwigType *t) { + List *l = SwigType_parmlist(t); + Hash *p, *pp = 0, *firstp = 0; + Iterator o; + + for (o = First(l); o.item; o = Next(o)) { + p = NewParm(o.item, 0); + if (!firstp) + firstp = p; + if (pp) { + set_nextSibling(pp, p); + Delete(p); + } + pp = p; + } + Delete(l); + return firstp; +} + +int SwigType_isvarargs(const SwigType *t) { + if (Strcmp(t, "v(...)") == 0) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * Templates + * + * SwigType_add_template() + * + * Template handling. + * ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * SwigType_add_template() + * + * Adds a template to a type. This template is encoded in the SWIG type + * mechanism and produces a string like this: + * + * vector<int *> ----> "vector<(p.int)>" + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_template(SwigType *t, ParmList *parms) { + Parm *p; + + Append(t, "<("); + p = parms; + for (p = parms; p; p = nextSibling(p)) { + String *v; + if (Getattr(p, "default")) + continue; + if (p != parms) + Append(t, ","); + v = Getattr(p, "value"); + if (v) { + Append(t, v); + } else { + Append(t, Getattr(p, "type")); + } + } + Append(t, ")>"); + return t; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_templateprefix() + * + * Returns the prefix before the first template definition. + * For example: + * + * Foo<(p.int)>::bar + * + * returns "Foo" + * ----------------------------------------------------------------------------- */ + +String *SwigType_templateprefix(const SwigType *t) { + const char *s = Char(t); + const char *c = strstr(s, "<("); + return c ? NewStringWithSize(s, c - s) : NewString(s); +} + +/* ----------------------------------------------------------------------------- + * SwigType_templatesuffix() + * + * Returns text after a template substitution. Used to handle scope names + * for example: + * + * Foo<(p.int)>::bar + * + * returns "::bar" + * ----------------------------------------------------------------------------- */ + +String *SwigType_templatesuffix(const SwigType *t) { + const char *c; + c = Char(t); + while (*c) { + if ((*c == '<') && (*(c + 1) == '(')) { + int nest = 1; + c++; + while (*c && nest) { + if (*c == '<') + nest++; + if (*c == '>') + nest--; + c++; + } + return NewString(c); + } + c++; + } + return NewStringEmpty(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_templateargs() + * + * Returns the template arguments + * For example: + * + * Foo<(p.int)>::bar + * + * returns "<(p.int)>" + * ----------------------------------------------------------------------------- */ + +String *SwigType_templateargs(const SwigType *t) { + const char *c; + const char *start; + c = Char(t); + while (*c) { + if ((*c == '<') && (*(c + 1) == '(')) { + int nest = 1; + start = c; + c++; + while (*c && nest) { + if (*c == '<') + nest++; + if (*c == '>') + nest--; + c++; + } + return NewStringWithSize(start, c - start); + } + c++; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_istemplate() + * + * Tests a type to see if it includes template parameters + * ----------------------------------------------------------------------------- */ + +int SwigType_istemplate(const SwigType *t) { + char *ct = Char(t); + ct = strstr(ct, "<("); + if (ct && (strstr(ct + 2, ")>"))) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_base() + * + * This function returns the base of a type. For example, if you have a + * type "p.p.int", the function would return "int". + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_base(const SwigType *t) { + char *c; + char *lastop = 0; + c = Char(t); + + lastop = c; + + /* Search for the last type constructor separator '.' */ + while (*c) { + if (*c == '.') { + if (*(c + 1)) { + lastop = c + 1; + } + c++; + continue; + } + if (*c == '<') { + /* Skip over template---it's part of the base name */ + int ntemp = 1; + c++; + while ((*c) && (ntemp > 0)) { + if (*c == '>') + ntemp--; + else if (*c == '<') + ntemp++; + c++; + } + if (ntemp) + break; + continue; + } + if (*c == '(') { + /* Skip over params */ + int nparen = 1; + c++; + while ((*c) && (nparen > 0)) { + if (*c == '(') + nparen++; + else if (*c == ')') + nparen--; + c++; + } + if (nparen) + break; + continue; + } + c++; + } + return NewString(lastop); +} + +/* ----------------------------------------------------------------------------- + * SwigType_prefix() + * + * Returns the prefix of a datatype. For example, the prefix of the + * type "p.p.int" is "p.p.". + * ----------------------------------------------------------------------------- */ + +String *SwigType_prefix(const SwigType *t) { + char *c, *d; + String *r = 0; + + c = Char(t); + d = c + strlen(c); + + /* Check for a type constructor */ + if ((d > c) && (*(d - 1) == '.')) + d--; + + while (d > c) { + d--; + if (*d == '>') { + int nest = 1; + d--; + while ((d > c) && (nest)) { + if (*d == '>') + nest++; + if (*d == '<') + nest--; + d--; + } + } + if (*d == ')') { + /* Skip over params */ + int nparen = 1; + d--; + while ((d > c) && (nparen)) { + if (*d == ')') + nparen++; + if (*d == '(') + nparen--; + d--; + } + } + + if (*d == '.') { + char t = *(d + 1); + *(d + 1) = 0; + r = NewString(c); + *(d + 1) = t; + return r; + } + } + return NewStringEmpty(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_strip_qualifiers() + * + * Strip all qualifiers from a type and return a new type + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_strip_qualifiers(SwigType *t) { + static Hash *memoize_stripped = 0; + SwigType *r; + List *l; + Iterator ei; + + if (!memoize_stripped) + memoize_stripped = NewHash(); + r = Getattr(memoize_stripped, t); + if (r) + return Copy(r); + + l = SwigType_split(t); + r = NewStringEmpty(); + + for (ei = First(l); ei.item; ei = Next(ei)) { + if (SwigType_isqualifier(ei.item)) + continue; + Append(r, ei.item); + } + Delete(l); + { + String *key, *value; + key = Copy(t); + value = Copy(r); + Setattr(memoize_stripped, key, value); + Delete(key); + Delete(value); + } + return r; +} diff --git a/Source/Swig/typesys.c b/Source/Swig/typesys.c new file mode 100644 index 0000000..5778c45 --- /dev/null +++ b/Source/Swig/typesys.c @@ -0,0 +1,2074 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * typesys.c + * + * SWIG type system management. These functions are used to manage + * the C++ type system including typenames, typedef, type scopes, + * inheritance, and namespaces. Generation of support code for the + * run-time type checker is also handled here. + * ----------------------------------------------------------------------------- */ + +char cvsroot_typesys_c[] = "$Id: typesys.c 11097 2009-01-30 10:27:37Z bhy $"; + +#include "swig.h" +#include "cparse.h" + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * The purpose of this module is to manage type names and scoping issues related + * to the C++ type system. The primary use is tracking typenames through typedef + * and inheritance. + * + * New typenames are introduced by typedef, class, and enum declarations. + * Each type is declared in a scope. This is either the global scope, a + * class, or a namespace. For example: + * + * typedef int A; // Typename A, in global scope + * namespace Foo { + * typedef int A; // Typename A, in scope Foo:: + * } + * class Bar { // Typename Bar, in global scope + * typedef int A; // Typename A, in scope Bar:: + * } + * + * To manage scopes, the type system is constructed as a tree of hash tables. Each + * hash table contains the following attributes: + * + * "name" - Scope name + * "qname" - Fully qualified typename + * "typetab" - Type table containing typenames and typedef information + * "symtab" - Hash table of symbols defined in a scope + * "inherit" - List of inherited scopes + * "parent" - Parent scope + * + * Typedef information is stored in the "typetab" hash table. For example, + * if you have these declarations: + * + * typedef int A; + * typedef A B; + * typedef B *C; + * + * typetab is built as follows: + * + * "A" : "int" + * "B" : "A" + * "C" : "p.B" + * + * To resolve a type back to its root type, one repeatedly expands on the type base. + * For example: + * + * C *[40] ---> a(40).p.C (string type representation, see stype.c) + * ---> a(40).p.p.B (C --> p.B) + * ---> a(40).p.p.A (B --> A) + * ---> a(40).p.p.int (A --> int) + * + * For inheritance, SWIG tries to resolve types back to the base class. For instance, if + * you have this: + * + * class Foo { + * public: + * typedef int Integer; + * }; + * + * class Bar : public Foo { + * void blah(Integer x); + * } + * + * The argument type of Bar::blah will be set to Foo::Integer. + * + * The scope-inheritance mechanism is used to manage C++ namespace aliases. + * For example, if you have this: + * + * namespace Foo { + * typedef int Integer; + * } + * + * namespace F = Foo; + * + * In this case, "F::" is defined as a scope that "inherits" from Foo. Internally, + * "F::" will merely be an empty scope that refers to Foo. SWIG will never + * place new type information into a namespace alias---attempts to do so + * will generate a warning message (in the parser) and will place information into + * Foo instead. + * + *----------------------------------------------------------------------------- */ + +static Typetab *current_scope = 0; /* Current type scope */ +static Hash *current_typetab = 0; /* Current type table */ +static Hash *current_symtab = 0; /* Current symbol table */ +static Typetab *global_scope = 0; /* The global scope */ +static Hash *scopes = 0; /* Hash table containing fully qualified scopes */ + +/* Performance optimization */ +#define SWIG_TYPEDEF_RESOLVE_CACHE +static Hash *typedef_resolve_cache = 0; +static Hash *typedef_all_cache = 0; +static Hash *typedef_qualified_cache = 0; + +static Typetab *SwigType_find_scope(Typetab *s, String *nameprefix); + +/* common attribute keys, to avoid calling find_key all the times */ + +/* + Enable this one if your language fully support SwigValueWrapper<T>. + + Leaving at '0' keeps the old swig behavior, which is not + always safe, but is well known. + + Setting at '1' activates the new scheme, which is always safe but + it requires all the typemaps to be ready for that. + +*/ +static int value_wrapper_mode = 0; +int Swig_value_wrapper_mode(int mode) { + value_wrapper_mode = mode; + return mode; +} + + +static void flush_cache() { + typedef_resolve_cache = 0; + typedef_all_cache = 0; + typedef_qualified_cache = 0; +} + +/* Initialize the scoping system */ + +void SwigType_typesystem_init() { + if (global_scope) + Delete(global_scope); + if (scopes) + Delete(scopes); + + current_scope = NewHash(); + global_scope = current_scope; + + Setattr(current_scope, "name", ""); /* No name for global scope */ + current_typetab = NewHash(); + Setattr(current_scope, "typetab", current_typetab); + + current_symtab = 0; + scopes = NewHash(); + Setattr(scopes, "", current_scope); +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef() + * + * Defines a new typedef in the current scope. Returns -1 if the type name is + * already defined. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef(SwigType *type, const_String_or_char_ptr name) { + if (Getattr(current_typetab, name)) + return -1; /* Already defined */ + if (Strcmp(type, name) == 0) { /* Can't typedef a name to itself */ + return 0; + } + + /* Check if 'type' is already a scope. If so, we create an alias in the type + system for it. This is needed to make strange nested scoping problems work + correctly. */ + { + Typetab *t = SwigType_find_scope(current_scope, type); + if (t) { + SwigType_new_scope(name); + SwigType_inherit_scope(t); + SwigType_pop_scope(); + } + } + Setattr(current_typetab, name, type); + flush_cache(); + return 0; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_class() + * + * Defines a class in the current scope. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef_class(const_String_or_char_ptr name) { + String *cname; + /* Printf(stdout,"class : '%s'\n", name); */ + if (Getattr(current_typetab, name)) + return -1; /* Already defined */ + cname = NewString(name); + Setmeta(cname, "class", "1"); + Setattr(current_typetab, cname, cname); + Delete(cname); + flush_cache(); + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_scope_name() + * + * Returns the qualified scope name of a type table + * ----------------------------------------------------------------------------- */ + +String *SwigType_scope_name(Typetab *ttab) { + String *qname = NewString(Getattr(ttab, "name")); + ttab = Getattr(ttab, "parent"); + while (ttab) { + String *pname = Getattr(ttab, "name"); + if (Len(pname)) { + Insert(qname, 0, "::"); + Insert(qname, 0, pname); + } + ttab = Getattr(ttab, "parent"); + } + return qname; +} + +/* ----------------------------------------------------------------------------- + * SwigType_new_scope() + * + * Creates a new scope + * ----------------------------------------------------------------------------- */ + +void SwigType_new_scope(const_String_or_char_ptr name) { + Typetab *s; + Hash *ttab; + String *qname; + + if (!name) { + name = "<unnamed>"; + } + s = NewHash(); + Setattr(s, "name", name); + Setattr(s, "parent", current_scope); + ttab = NewHash(); + Setattr(s, "typetab", ttab); + + /* Build fully qualified name and */ + qname = SwigType_scope_name(s); + Setattr(scopes, qname, s); + Setattr(s, "qname", qname); + Delete(qname); + + current_scope = s; + current_typetab = ttab; + current_symtab = 0; + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_inherit_scope() + * + * Makes the current scope inherit from another scope. This is used for both + * C++ class inheritance, namespaces, and namespace aliases. + * ----------------------------------------------------------------------------- */ + +void SwigType_inherit_scope(Typetab *scope) { + List *inherits; + int i, len; + inherits = Getattr(current_scope, "inherit"); + if (!inherits) { + inherits = NewList(); + Setattr(current_scope, "inherit", inherits); + Delete(inherits); + } + assert(scope != current_scope); + + len = Len(inherits); + for (i = 0; i < len; i++) { + Node *n = Getitem(inherits, i); + if (n == scope) + return; + } + Append(inherits, scope); +} + +/* ----------------------------------------------------------------------------- + * SwigType_scope_alias() + * + * Creates a scope-alias. + * ----------------------------------------------------------------------------- */ + +void SwigType_scope_alias(String *aliasname, Typetab *ttab) { + String *q; + /* Printf(stdout,"alias: '%s' '%x'\n", aliasname, ttab); */ + q = SwigType_scope_name(current_scope); + if (Len(q)) { + Append(q, "::"); + } + Append(q, aliasname); + Setattr(scopes, q, ttab); + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_using_scope() + * + * Import another scope into this scope. + * ----------------------------------------------------------------------------- */ + +void SwigType_using_scope(Typetab *scope) { + SwigType_inherit_scope(scope); + { + List *ulist; + int i, len; + ulist = Getattr(current_scope, "using"); + if (!ulist) { + ulist = NewList(); + Setattr(current_scope, "using", ulist); + Delete(ulist); + } + assert(scope != current_scope); + len = Len(ulist); + for (i = 0; i < len; i++) { + Typetab *n = Getitem(ulist, i); + if (n == scope) + return; + } + Append(ulist, scope); + } + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop_scope() + * + * Pop off the last scope and perform a merge operation. Returns the hash + * table for the scope that was popped off. + * ----------------------------------------------------------------------------- */ + +Typetab *SwigType_pop_scope() { + Typetab *t, *old = current_scope; + t = Getattr(current_scope, "parent"); + if (!t) + t = global_scope; + current_scope = t; + current_typetab = Getattr(t, "typetab"); + current_symtab = Getattr(t, "symtab"); + flush_cache(); + return old; +} + +/* ----------------------------------------------------------------------------- + * SwigType_set_scope() + * + * Set the scope. Returns the old scope. + * ----------------------------------------------------------------------------- */ + +Typetab *SwigType_set_scope(Typetab *t) { + Typetab *old = current_scope; + if (!t) + t = global_scope; + current_scope = t; + current_typetab = Getattr(t, "typetab"); + current_symtab = Getattr(t, "symtab"); + flush_cache(); + return old; +} + +/* ----------------------------------------------------------------------------- + * SwigType_attach_symtab() + * + * Attaches a symbol table to a type scope + * ----------------------------------------------------------------------------- */ + +void SwigType_attach_symtab(Symtab *sym) { + Setattr(current_scope, "symtab", sym); + current_symtab = sym; +} + +/* ----------------------------------------------------------------------------- + * SwigType_print_scope() + * + * Debugging function for printing out current scope + * ----------------------------------------------------------------------------- */ + +void SwigType_print_scope(Typetab *t) { + Hash *ttab; + Iterator i, j; + + for (i = First(scopes); i.key; i = Next(i)) { + t = i.item; + ttab = Getattr(i.item, "typetab"); + + Printf(stdout, "Type scope '%s' (%x)\n", i.key, i.item); + { + List *inherit = Getattr(i.item, "inherit"); + if (inherit) { + Iterator j; + for (j = First(inherit); j.item; j = Next(j)) { + Printf(stdout, " Inherits from '%s' (%x)\n", Getattr(j.item, "qname"), j.item); + } + } + } + Printf(stdout, "-------------------------------------------------------------\n"); + for (j = First(ttab); j.key; j = Next(j)) { + Printf(stdout, "%40s -> %s\n", j.key, j.item); + } + } +} + +static Typetab *SwigType_find_scope(Typetab *s, String *nameprefix) { + Typetab *ss; + String *nnameprefix = 0; + static int check_parent = 1; + + /* Printf(stdout,"find_scope: %x(%s) '%s'\n", s, Getattr(s,"name"), nameprefix); */ + + if (SwigType_istemplate(nameprefix)) { + nnameprefix = SwigType_typedef_resolve_all(nameprefix); + nameprefix = nnameprefix; + } + + ss = s; + while (ss) { + String *full; + String *qname = Getattr(ss, "qname"); + if (qname) { + full = NewStringf("%s::%s", qname, nameprefix); + } else { + full = NewString(nameprefix); + } + if (Getattr(scopes, full)) { + s = Getattr(scopes, full); + } else { + s = 0; + } + Delete(full); + if (s) { + if (nnameprefix) + Delete(nnameprefix); + return s; + } + if (!s) { + /* Check inheritance */ + List *inherit; + inherit = Getattr(ss, "using"); + if (inherit) { + Typetab *ttab; + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + int oldcp = check_parent; + ttab = Getitem(inherit, i); + check_parent = 0; + s = SwigType_find_scope(ttab, nameprefix); + check_parent = oldcp; + if (s) { + if (nnameprefix) + Delete(nnameprefix); + return s; + } + } + } + } + if (!check_parent) + break; + ss = Getattr(ss, "parent"); + } + if (nnameprefix) + Delete(nnameprefix); + return 0; +} + +/* ----------------------------------------------------------------------------- + * typedef_resolve() + * + * Resolves a typedef and returns a new type string. Returns 0 if there is no + * typedef mapping. base is a name without qualification. + * Internal function. + * ----------------------------------------------------------------------------- */ + +static Typetab *resolved_scope = 0; + +/* Internal function */ + +static SwigType *_typedef_resolve(Typetab *s, String *base, int look_parent) { + Hash *ttab; + SwigType *type = 0; + List *inherit; + Typetab *parent; + + /* if (!s) return 0; *//* now is checked bellow */ + /* Printf(stdout,"Typetab %s : %s\n", Getattr(s,"name"), base); */ + + if (!Getmark(s)) { + Setmark(s, 1); + + ttab = Getattr(s, "typetab"); + type = Getattr(ttab, base); + if (type) { + resolved_scope = s; + Setmark(s, 0); + } else { + /* Hmmm. Not found in my scope. It could be in an inherited scope */ + inherit = Getattr(s, "inherit"); + if (inherit) { + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + type = _typedef_resolve(Getitem(inherit, i), base, 0); + if (type) { + Setmark(s, 0); + break; + } + } + } + if (!type) { + /* Hmmm. Not found in my scope. check parent */ + if (look_parent) { + parent = Getattr(s, "parent"); + type = parent ? _typedef_resolve(parent, base, 1) : 0; + } + } + Setmark(s, 0); + } + } + return type; +} + +static SwigType *typedef_resolve(Typetab *s, String *base) { + return _typedef_resolve(s, base, 1); +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_resolve() + * ----------------------------------------------------------------------------- */ + +/* #define SWIG_DEBUG */ +SwigType *SwigType_typedef_resolve(const SwigType *t) { + String *base; + String *type = 0; + String *r = 0; + Typetab *s; + Hash *ttab; + String *namebase = 0; + String *nameprefix = 0; + int newtype = 0; + + /* + if (!noscope) { + noscope = NewStringEmpty(); + } + */ + + resolved_scope = 0; + +#ifdef SWIG_TYPEDEF_RESOLVE_CACHE + if (!typedef_resolve_cache) { + typedef_resolve_cache = NewHash(); + } + r = Getattr(typedef_resolve_cache, t); + if (r) { + resolved_scope = Getmeta(r, "scope"); + return Copy(r); + } +#endif + + base = SwigType_base(t); + +#ifdef SWIG_DEBUG + Printf(stdout, "base = '%s' t='%s'\n", base, t); +#endif + + if (SwigType_issimple(base)) { + s = current_scope; + ttab = current_typetab; + if (strncmp(Char(base), "::", 2) == 0) { + s = global_scope; + ttab = Getattr(s, "typetab"); + Delitem(base, 0); + Delitem(base, 0); + } + /* Do a quick check in the local scope */ + type = Getattr(ttab, base); + if (type) { + resolved_scope = s; + } + if (!type) { + /* Didn't find in this scope. We need to do a little more searching */ + if (Swig_scopename_check(base)) { + /* A qualified name. */ + Swig_scopename_split(base, &nameprefix, &namebase); +#ifdef SWIG_DEBUG + Printf(stdout, "nameprefix = '%s'\n", nameprefix); +#endif + if (nameprefix) { + /* Name had a prefix on it. See if we can locate the proper scope for it */ + s = SwigType_find_scope(s, nameprefix); + + /* Couldn't locate a scope for the type. */ + if (!s) { + Delete(base); + Delete(namebase); + Delete(nameprefix); + r = 0; + goto return_result; + } + /* Try to locate the name starting in the scope */ +#ifdef SWIG_DEBUG + Printf(stdout, "namebase = '%s'\n", namebase); +#endif + type = typedef_resolve(s, namebase); + if (type) { + /* we need to look for the resolved type, this will also + fix the resolved_scope if 'type' and 'namebase' are + declared in different scopes */ + String *rtype = 0; + rtype = typedef_resolve(resolved_scope, type); + if (rtype) + type = rtype; + } +#ifdef SWIG_DEBUG + Printf(stdout, "%s type = '%s'\n", Getattr(s, "name"), type); +#endif + if ((type) && (!Swig_scopename_check(type)) && resolved_scope) { + Typetab *rtab = resolved_scope; + String *qname = Getattr(resolved_scope, "qname"); + /* If qualified *and* the typename is defined from the resolved scope, we qualify */ + if ((qname) && typedef_resolve(resolved_scope, type)) { + type = Copy(type); + Insert(type, 0, "::"); + Insert(type, 0, qname); +#ifdef SWIG_DEBUG + Printf(stdout, "qual %s \n", type); +#endif + newtype = 1; + } + resolved_scope = rtab; + } + } else { + /* Name is unqualified. */ + type = typedef_resolve(s, base); + } + } else { + /* Name is unqualified. */ + type = typedef_resolve(s, base); + } + } + + if (type && (Equal(base, type))) { + if (newtype) + Delete(type); + Delete(base); + Delete(namebase); + Delete(nameprefix); + r = 0; + goto return_result; + } + + /* If the type is a template, and no typedef was found, we need to check the + template arguments one by one to see if they can be resolved. */ + + if (!type && SwigType_istemplate(base)) { + List *tparms; + String *suffix; + int i, sz; + int rep = 0; + type = SwigType_templateprefix(base); + newtype = 1; + suffix = SwigType_templatesuffix(base); + Append(type, "<("); + tparms = SwigType_parmlist(base); + sz = Len(tparms); + for (i = 0; i < sz; i++) { + SwigType *tpr; + SwigType *tp = Getitem(tparms, i); + if (!rep) { + tpr = SwigType_typedef_resolve(tp); + } else { + tpr = 0; + } + if (tpr) { + Append(type, tpr); + Delete(tpr); + rep = 1; + } else { + Append(type, tp); + } + if ((i + 1) < sz) + Append(type, ","); + } + Append(type, ")>"); + Append(type, suffix); + Delete(suffix); + Delete(tparms); + if (!rep) { + Delete(type); + type = 0; + } + } + if (namebase) + Delete(namebase); + if (nameprefix) + Delete(nameprefix); + } else { + if (SwigType_isfunction(base)) { + List *parms; + int i, sz; + int rep = 0; + type = NewString("f("); + newtype = 1; + parms = SwigType_parmlist(base); + sz = Len(parms); + for (i = 0; i < sz; i++) { + SwigType *tpr; + SwigType *tp = Getitem(parms, i); + if (!rep) { + tpr = SwigType_typedef_resolve(tp); + } else { + tpr = 0; + } + if (tpr) { + Append(type, tpr); + Delete(tpr); + rep = 1; + } else { + Append(type, tp); + } + if ((i + 1) < sz) + Append(type, ","); + } + Append(type, ")."); + Delete(parms); + if (!rep) { + Delete(type); + type = 0; + } + } else if (SwigType_ismemberpointer(base)) { + String *rt; + String *mtype = SwigType_parm(base); + rt = SwigType_typedef_resolve(mtype); + if (rt) { + type = NewStringf("m(%s).", rt); + newtype = 1; + Delete(rt); + } + Delete(mtype); + } else { + type = 0; + } + } + r = SwigType_prefix(t); + if (!type) { + if (r && Len(r)) { + char *cr = Char(r); + if ((strstr(cr, "f(") || (strstr(cr, "m(")))) { + SwigType *rt = SwigType_typedef_resolve(r); + if (rt) { + Delete(r); + Append(rt, base); + Delete(base); + r = rt; + goto return_result; + } + } + } + Delete(r); + Delete(base); + r = 0; + goto return_result; + } + Delete(base); + Append(r, type); + if (newtype) { + Delete(type); + } + +return_result: +#ifdef SWIG_TYPEDEF_RESOLVE_CACHE + { + String *key = NewString(t); + if (r) { + SwigType *r1; + Setattr(typedef_resolve_cache, key, r); + Setmeta(r, "scope", resolved_scope); + r1 = Copy(r); + Delete(r); + r = r1; + } + Delete(key); + } +#endif + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_resolve_all() + * + * Fully resolve a type down to its most basic datatype + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_typedef_resolve_all(SwigType *t) { + SwigType *n; + SwigType *r; + + /* Check to see if the typedef resolve has been done before by checking the cache */ + if (!typedef_all_cache) { + typedef_all_cache = NewHash(); + } + r = Getattr(typedef_all_cache, t); + if (r) { + return Copy(r); + } + + /* Recursively resolve the typedef */ + r = NewString(t); + while ((n = SwigType_typedef_resolve(r))) { + Delete(r); + r = n; + } + + /* Add the typedef to the cache for next time it is looked up */ + { + String *key; + SwigType *rr = Copy(r); + key = NewString(t); + Setattr(typedef_all_cache, key, rr); + Delete(key); + Delete(rr); + } + return r; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_qualified() + * + * Given a type declaration, this function tries to fully qualify it according to + * typedef scope rules. + * Inconsistency to be fixed: ::Foo returns ::Foo, whereas ::Foo * returns Foo * + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_typedef_qualified(SwigType *t) { + List *elements; + String *result; + int i, len; + + if (strncmp(Char(t), "::", 2) == 0) { + return Copy(t); + } + + if (!typedef_qualified_cache) + typedef_qualified_cache = NewHash(); + result = Getattr(typedef_qualified_cache, t); + if (result) { + String *rc = Copy(result); + return rc; + } + + result = NewStringEmpty(); + elements = SwigType_split(t); + len = Len(elements); + for (i = 0; i < len; i++) { + String *ty = 0; + String *e = Getitem(elements, i); + if (SwigType_issimple(e)) { + if (!SwigType_istemplate(e)) { + String *isenum = 0; + if (SwigType_isenum(e)) { + isenum = NewString("enum "); + ty = NewString(Char(e) + 5); + e = ty; + } + resolved_scope = 0; + if (typedef_resolve(current_scope, e)) { + /* resolved_scope contains the scope that actually resolved the symbol */ + String *qname = Getattr(resolved_scope, "qname"); + if (qname) { + Insert(e, 0, "::"); + Insert(e, 0, qname); + } + } else { + if (Swig_scopename_check(e)) { + String *qlast; + String *qname; + Swig_scopename_split(e, &qname, &qlast); + if (qname) { + String *tqname = SwigType_typedef_qualified(qname); + Clear(e); + Printf(e, "%s::%s", tqname, qlast); + Delete(qname); + Delete(tqname); + } + Delete(qlast); + + /* Automatic template instantiation might go here??? */ + } else { + /* It's a bare name. It's entirely possible, that the + name is part of a namespace. We'll check this by unrolling + out of the current scope */ + + Typetab *cs = current_scope; + while (cs) { + String *qs = SwigType_scope_name(cs); + if (Len(qs)) { + Append(qs, "::"); + } + Append(qs, e); + if (Getattr(scopes, qs)) { + Clear(e); + Append(e, qs); + Delete(qs); + break; + } + Delete(qs); + cs = Getattr(cs, "parent"); + } + } + } + if (isenum) { + Insert(e, 0, isenum); + Delete(isenum); + } + } else { + /* Template. We need to qualify template parameters as well as the template itself */ + String *tprefix, *qprefix; + String *tsuffix; + Iterator pi; + Parm *p; + List *parms; + ty = Swig_symbol_template_deftype(e, current_symtab); + e = ty; + parms = SwigType_parmlist(e); + tprefix = SwigType_templateprefix(e); + tsuffix = SwigType_templatesuffix(e); + qprefix = SwigType_typedef_qualified(tprefix); + Append(qprefix, "<("); + pi = First(parms); + while ((p = pi.item)) { + String *qt = SwigType_typedef_qualified(p); + if (Equal(qt, p)) { /* && (!Swig_scopename_check(qt))) */ + /* No change in value. It is entirely possible that the parameter is an integer value. + If there is a symbol table associated with this scope, we're going to check for this */ + + if (current_symtab) { + Node *lastnode = 0; + String *value = Copy(p); + while (1) { + Node *n = Swig_symbol_clookup(value, current_symtab); + if (n == lastnode) + break; + lastnode = n; + if (n) { + char *ntype = Char(nodeType(n)); + if (strcmp(ntype, "enumitem") == 0) { + /* An enum item. Generate a fully qualified name */ + String *qn = Swig_symbol_qualified(n); + if (Len(qn)) { + Append(qn, "::"); + Append(qn, Getattr(n, "name")); + Delete(value); + value = qn; + continue; + } else { + Delete(qn); + break; + } + } else if ((strcmp(ntype, "cdecl") == 0) && (Getattr(n, "value"))) { + Delete(value); + value = Copy(Getattr(n, "value")); + continue; + } + } + break; + } + Append(qprefix, value); + Delete(value); + } else { + Append(qprefix, p); + } + } else { + Append(qprefix, qt); + } + Delete(qt); + pi = Next(pi); + if (pi.item) { + Append(qprefix, ","); + } + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(tsuffix); + Clear(e); + Append(e, qprefix); + Delete(tprefix); + Delete(qprefix); + Delete(parms); + } + if (strncmp(Char(e), "::", 2) == 0) { + Delitem(e, 0); + Delitem(e, 0); + } + Append(result, e); + Delete(ty); + } else if (SwigType_isfunction(e)) { + List *parms = SwigType_parmlist(e); + String *s = NewString("f("); + Iterator pi; + pi = First(parms); + while (pi.item) { + String *pq = SwigType_typedef_qualified(pi.item); + Append(s, pq); + Delete(pq); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + } + Append(s, ")."); + Append(result, s); + Delete(s); + Delete(parms); + } else if (SwigType_isarray(e)) { + String *ndim; + String *dim = SwigType_parm(e); + ndim = Swig_symbol_string_qualify(dim, 0); + Printf(result, "a(%s).", ndim); + Delete(dim); + Delete(ndim); + } else { + Append(result, e); + } + } + Delete(elements); + { + String *key, *cresult; + key = NewString(t); + cresult = NewString(result); + Setattr(typedef_qualified_cache, key, cresult); + Delete(key); + Delete(cresult); + } + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_istypedef() + * + * Checks a typename to see if it is a typedef. + * ----------------------------------------------------------------------------- */ + +int SwigType_istypedef(SwigType *t) { + String *type; + + type = SwigType_typedef_resolve(t); + if (type) { + Delete(type); + return 1; + } else { + return 0; + } +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_using() + * + * Processes a 'using' declaration to import types from one scope into another. + * Name is a qualified name like A::B. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef_using(const_String_or_char_ptr name) { + String *base; + String *td; + String *prefix; + Typetab *s; + Typetab *tt = 0; + + String *defined_name = 0; + + /* Printf(stdout,"using %s\n", name); */ + + if (!Swig_scopename_check(name)) + return -1; /* Not properly qualified */ + base = Swig_scopename_last(name); + + /* See if the base is already defined in this scope */ + if (Getattr(current_typetab, base)) { + Delete(base); + return -1; + } + + /* See if the using name is a scope */ + /* tt = SwigType_find_scope(current_scope,name); + Printf(stdout,"tt = %x, name = '%s'\n", tt, name); */ + + /* We set up a typedef B --> A::B */ + Setattr(current_typetab, base, name); + + /* Find the scope name where the symbol is defined */ + td = SwigType_typedef_resolve(name); + /* Printf(stdout,"td = '%s' %x\n", td, resolved_scope); */ + if (resolved_scope) { + defined_name = Getattr(resolved_scope, "qname"); + if (defined_name) { + defined_name = Copy(defined_name); + Append(defined_name, "::"); + Append(defined_name, base); + /* Printf(stdout,"defined_name = '%s'\n", defined_name); */ + tt = SwigType_find_scope(current_scope, defined_name); + } + } + if (td) + Delete(td); + + + /* Figure out the scope the using directive refers to */ + { + prefix = Swig_scopename_prefix(name); + s = SwigType_find_scope(current_scope, prefix); + if (s) { + Hash *ttab = Getattr(s, "typetab"); + if (!Getattr(ttab, base) && defined_name) { + Setattr(ttab, base, defined_name); + } + } + } + + if (tt) { + /* Using directive had its own scope. We need to create a new scope for it */ + SwigType_new_scope(base); + SwigType_inherit_scope(tt); + SwigType_pop_scope(); + } + + if (defined_name) + Delete(defined_name); + Delete(prefix); + Delete(base); + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_isclass() + * + * Determines if a type defines a class or not. A class is defined by + * its type-table entry maps to itself. Note: a pointer to a class is not + * a class. + * ----------------------------------------------------------------------------- */ + +int SwigType_isclass(SwigType *t) { + SwigType *qty, *qtys; + int isclass = 0; + + qty = SwigType_typedef_resolve_all(t); + qtys = SwigType_strip_qualifiers(qty); + if (SwigType_issimple(qtys)) { + String *td = SwigType_typedef_resolve(qtys); + if (td) { + Delete(td); + } + if (resolved_scope) { + isclass = 1; + } + /* Hmmm. Not a class. If a template, it might be uninstantiated */ + if (!isclass && SwigType_istemplate(qtys)) { + String *tp = SwigType_templateprefix(qtys); + if (Strcmp(tp, t) != 0) { + isclass = SwigType_isclass(tp); + } + Delete(tp); + } + } + Delete(qty); + Delete(qtys); + return isclass; +} + +/* ----------------------------------------------------------------------------- + * SwigType_type() + * + * Returns an integer code describing the datatype. This is only used for + * compatibility with SWIG1.1 language modules and is likely to go away once + * everything is based on typemaps. + * ----------------------------------------------------------------------------- */ + +int SwigType_type(SwigType *t) { + char *c; + /* Check for the obvious stuff */ + c = Char(t); + + if (strncmp(c, "p.", 2) == 0) { + if (SwigType_type(c + 2) == T_CHAR) + return T_STRING; + else + return T_POINTER; + } + if (strncmp(c, "a(", 2) == 0) + return T_ARRAY; + if (strncmp(c, "r.", 2) == 0) + return T_REFERENCE; + if (strncmp(c, "m(", 2) == 0) + return T_MPOINTER; + if (strncmp(c, "q(", 2) == 0) { + while (*c && (*c != '.')) + c++; + if (*c) + return SwigType_type(c + 1); + return T_ERROR; + } + if (strncmp(c, "f(", 2) == 0) + return T_FUNCTION; + + /* Look for basic types */ + if (strcmp(c, "int") == 0) + return T_INT; + if (strcmp(c, "long") == 0) + return T_LONG; + if (strcmp(c, "short") == 0) + return T_SHORT; + if (strcmp(c, "unsigned") == 0) + return T_UINT; + if (strcmp(c, "unsigned short") == 0) + return T_USHORT; + if (strcmp(c, "unsigned long") == 0) + return T_ULONG; + if (strcmp(c, "unsigned int") == 0) + return T_UINT; + if (strcmp(c, "char") == 0) + return T_CHAR; + if (strcmp(c, "signed char") == 0) + return T_SCHAR; + if (strcmp(c, "unsigned char") == 0) + return T_UCHAR; + if (strcmp(c, "float") == 0) + return T_FLOAT; + if (strcmp(c, "double") == 0) + return T_DOUBLE; + if (strcmp(c, "long double") == 0) + return T_LONGDOUBLE; + if (!cparse_cplusplus && (strcmp(c, "float complex") == 0)) + return T_FLTCPLX; + if (!cparse_cplusplus && (strcmp(c, "double complex") == 0)) + return T_DBLCPLX; + if (!cparse_cplusplus && (strcmp(c, "complex") == 0)) + return T_COMPLEX; + if (strcmp(c, "void") == 0) + return T_VOID; + if (strcmp(c, "bool") == 0) + return T_BOOL; + if (strcmp(c, "long long") == 0) + return T_LONGLONG; + if (strcmp(c, "unsigned long long") == 0) + return T_ULONGLONG; + if (strncmp(c, "enum ", 5) == 0) + return T_INT; + + if (strcmp(c, "v(...)") == 0) + return T_VARARGS; + /* Hmmm. Unknown type */ + if (SwigType_istypedef(t)) { + int r; + SwigType *nt = SwigType_typedef_resolve(t); + r = SwigType_type(nt); + Delete(nt); + return r; + } + return T_USER; +} + +/* ----------------------------------------------------------------------------- + * SwigType_alttype() + * + * Returns the alternative value type needed in C++ for class value + * types. When swig is not sure about using a plain $ltype value, + * since the class doesn't have a default constructor, or it can't be + * assigned, you will get back 'SwigValueWrapper<type >'. + * + * This is the default behavior unless: + * + * 1.- swig detects a default_constructor and 'setallocate:default_constructor' + * attribute. + * + * 2.- swig doesn't mark 'type' as non-assignable. + * + * 3.- the user specify that the value wrapper is not needed by using + * the %feature("novaluewrapper"), in that case the user need to type + * + * %feature("novaluewrapper") MyOpaqueClass; + * class MyOpaqueClass; + * + * Users can also force the use of the value wrapper by using the + * %feature("valuewrapper"). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_alttype(SwigType *t, int local_tmap) { + Node *n; + SwigType *w = 0; + int use_wrapper = 0; + SwigType *td = 0; + + if (!cparse_cplusplus) + return 0; + + if (value_wrapper_mode == 0) { + /* old partial use of SwigValueTypes, it can fail for opaque types */ + if (local_tmap) + return 0; + if (SwigType_isclass(t)) { + SwigType *ftd = SwigType_typedef_resolve_all(t); + td = SwigType_strip_qualifiers(ftd); + Delete(ftd); + n = Swig_symbol_clookup(td, 0); + if (n) { + if (GetFlag(n, "feature:valuewrapper")) { + use_wrapper = 1; + } else { + if (Checkattr(n, "nodeType", "class") + && (!Getattr(n, "allocate:default_constructor") + || (Getattr(n, "allocate:noassign")))) { + use_wrapper = !GetFlag(n, "feature:novaluewrapper") || GetFlag(n, "feature:nodefault"); + } + } + } else { + if (SwigType_issimple(td) && SwigType_istemplate(td)) { + use_wrapper = !n || !GetFlag(n, "feature:novaluewrapper"); + } + } + } + } else { + /* safe use of SwigValueTypes, it can fail with some typemaps */ + SwigType *ftd = SwigType_typedef_resolve_all(t); + td = SwigType_strip_qualifiers(ftd); + Delete(ftd); + if (SwigType_type(td) == T_USER) { + use_wrapper = 1; + n = Swig_symbol_clookup(td, 0); + if (n) { + if ((Checkattr(n, "nodeType", "class") + && !Getattr(n, "allocate:noassign") + && (Getattr(n, "allocate:default_constructor"))) + || (GetFlag(n, "feature:novaluewrapper"))) { + use_wrapper = GetFlag(n, "feature:valuewrapper"); + } + } + } + } + + if (use_wrapper) { + /* Need a space before the type in case it starts "::" (since the <: + * token is a digraph for [ in C++. Also need a space after the + * type in case it ends with ">" since then we form the token ">>". + */ + w = NewStringf("SwigValueWrapper< %s >", td); + } + Delete(td); + return w; +} + +/* ---------------------------------------------------------------------------- + * * * * WARNING * * * *** + * *** + * Don't even think about modifying anything below this line unless you *** + * are completely on top of *EVERY* subtle aspect of the C++ type system *** + * and you are prepared to suffer endless hours of agony trying to *** + * debug the SWIG run-time type checker after you break it. *** + * ------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * SwigType_remember() + * + * This function "remembers" a datatype that was used during wrapper code generation + * so that a type-checking table can be generated later on. It is up to the language + * modules to actually call this function--it is not done automatically. + * + * Type tracking is managed through two separate hash tables. The hash 'r_mangled' + * is mapping between mangled type names (used in the target language) and + * fully-resolved C datatypes used in the source input. The second hash 'r_resolved' + * is the inverse mapping that maps fully-resolved C datatypes to all of the mangled + * names in the scripting languages. For example, consider the following set of + * typedef declarations: + * + * typedef double Real; + * typedef double Float; + * typedef double Point[3]; + * + * Now, suppose that the types 'double *', 'Real *', 'Float *', 'double[3]', and + * 'Point' were used in an interface file and "remembered" using this function. + * The hash tables would look like this: + * + * r_mangled { + * _p_double : [ p.double, a(3).double ] + * _p_Real : [ p.double ] + * _p_Float : [ p.double ] + * _Point : [ a(3).double ] + * + * r_resolved { + * p.double : [ _p_double, _p_Real, _p_Float ] + * a(3).double : [ _p_double, _Point ] + * } + * + * Together these two hash tables can be used to determine type-equivalency between + * mangled typenames. To do this, we view the two hash tables as a large graph and + * compute the transitive closure. + * ----------------------------------------------------------------------------- */ + +static Hash *r_mangled = 0; /* Hash mapping mangled types to fully resolved types */ +static Hash *r_resolved = 0; /* Hash mapping resolved types to mangled types */ +static Hash *r_ltype = 0; /* Hash mapping mangled names to their local c type */ +static Hash *r_clientdata = 0; /* Hash mapping resolved types to client data */ +static Hash *r_mangleddata = 0; /* Hash mapping mangled types to client data */ +static Hash *r_remembered = 0; /* Hash of types we remembered already */ + +static void (*r_tracefunc) (SwigType *t, String *mangled, String *clientdata) = 0; + +void SwigType_remember_mangleddata(String *mangled, const_String_or_char_ptr clientdata) { + if (!r_mangleddata) { + r_mangleddata = NewHash(); + } + Setattr(r_mangleddata, mangled, clientdata); +} + + +void SwigType_remember_clientdata(SwigType *t, const_String_or_char_ptr clientdata) { + String *mt; + SwigType *lt; + Hash *h; + SwigType *fr; + SwigType *qr; + String *tkey; + String *cd; + Hash *lthash; + + if (!r_mangled) { + r_mangled = NewHash(); + r_resolved = NewHash(); + r_ltype = NewHash(); + r_clientdata = NewHash(); + r_remembered = NewHash(); + } + + { + String *last; + last = Getattr(r_remembered, t); + if (last && (Cmp(last, clientdata) == 0)) + return; + } + + tkey = Copy(t); + cd = clientdata ? NewString(clientdata) : NewStringEmpty(); + Setattr(r_remembered, tkey, cd); + Delete(tkey); + Delete(cd); + + mt = SwigType_manglestr(t); /* Create mangled string */ + + if (r_tracefunc) { + (*r_tracefunc) (t, mt, (String *) clientdata); + } + + if (SwigType_istypedef(t)) { + lt = Copy(t); + } else { + lt = SwigType_ltype(t); + } + + lthash = Getattr(r_ltype, mt); + if (!lthash) { + lthash = NewHash(); + Setattr(r_ltype, mt, lthash); + } + Setattr(lthash, lt, "1"); + Delete(lt); + + fr = SwigType_typedef_resolve_all(t); /* Create fully resolved type */ + qr = SwigType_typedef_qualified(fr); + Delete(fr); + + /* Added to deal with possible table bug */ + fr = SwigType_strip_qualifiers(qr); + Delete(qr); + + /*Printf(stdout,"t = '%s'\n", t); + Printf(stdout,"fr= '%s'\n\n", fr); */ + + if (t) { + char *ct = Char(t); + if (strchr(ct, '<') && !(strstr(ct, "<("))) { + Printf(stdout, "Bad template type passed to SwigType_remember: %s\n", t); + assert(0); + } + } + + h = Getattr(r_mangled, mt); + if (!h) { + h = NewHash(); + Setattr(r_mangled, mt, h); + Delete(h); + } + Setattr(h, fr, mt); + + h = Getattr(r_resolved, fr); + if (!h) { + h = NewHash(); + Setattr(r_resolved, fr, h); + Delete(h); + } + Setattr(h, mt, fr); + + if (clientdata) { + String *cd = Getattr(r_clientdata, fr); + if (cd) { + if (Strcmp(clientdata, cd) != 0) { + Printf(stderr, "*** Internal error. Inconsistent clientdata for type '%s'\n", SwigType_str(fr, 0)); + Printf(stderr, "*** '%s' != '%s'\n", clientdata, cd); + assert(0); + } + } else { + String *cstr = NewString(clientdata); + Setattr(r_clientdata, fr, cstr); + Delete(cstr); + } + } + + /* If the remembered type is a reference, we also remember the pointer version. + This is to prevent odd problems with mixing pointers and references--especially + when different functions are using different typenames (via typedef). */ + + if (SwigType_isreference(t)) { + SwigType *tt = Copy(t); + SwigType_del_reference(tt); + SwigType_add_pointer(tt); + SwigType_remember_clientdata(tt, clientdata); + } +} + +void SwigType_remember(SwigType *ty) { + SwigType_remember_clientdata(ty, 0); +} + +void (*SwigType_remember_trace(void (*tf) (SwigType *, String *, String *))) (SwigType *, String *, String *) { + void (*o) (SwigType *, String *, String *) = r_tracefunc; + r_tracefunc = tf; + return o; +} + +/* ----------------------------------------------------------------------------- + * SwigType_equivalent_mangle() + * + * Return a list of all of the mangled typenames that are equivalent to another + * mangled name. This works as follows: For each fully qualified C datatype + * in the r_mangled hash entry, we collect all of the mangled names from the + * r_resolved hash and combine them together in a list (removing duplicate entries). + * ----------------------------------------------------------------------------- */ + +List *SwigType_equivalent_mangle(String *ms, Hash *checked, Hash *found) { + List *l; + Hash *h; + Hash *ch; + Hash *mh; + + if (found) { + h = found; + } else { + h = NewHash(); + } + if (checked) { + ch = checked; + } else { + ch = NewHash(); + } + if (Getattr(ch, ms)) + goto check_exit; /* Already checked this type */ + Setattr(h, ms, "1"); + Setattr(ch, ms, "1"); + mh = Getattr(r_mangled, ms); + if (mh) { + Iterator ki; + ki = First(mh); + while (ki.key) { + Hash *rh; + if (Getattr(ch, ki.key)) { + ki = Next(ki); + continue; + } + Setattr(ch, ki.key, "1"); + rh = Getattr(r_resolved, ki.key); + if (rh) { + Iterator rk; + rk = First(rh); + while (rk.key) { + Setattr(h, rk.key, "1"); + SwigType_equivalent_mangle(rk.key, ch, h); + rk = Next(rk); + } + } + ki = Next(ki); + } + } +check_exit: + if (!found) { + l = Keys(h); + Delete(h); + Delete(ch); + return l; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * SwigType_clientdata_collect() + * + * Returns the clientdata field for a mangled type-string. + * ----------------------------------------------------------------------------- */ + +static +String *SwigType_clientdata_collect(String *ms) { + Hash *mh; + String *clientdata = 0; + + if (r_mangleddata) { + clientdata = Getattr(r_mangleddata, ms); + if (clientdata) + return clientdata; + } + + mh = Getattr(r_mangled, ms); + if (mh) { + Iterator ki; + ki = First(mh); + while (ki.key) { + clientdata = Getattr(r_clientdata, ki.key); + if (clientdata) + break; + ki = Next(ki); + } + } + return clientdata; +} + + + + +/* ----------------------------------------------------------------------------- + * SwigType_inherit() + * + * Record information about inheritance. We keep a hash table that keeps + * a mapping between base classes and all of the classes that are derived + * from them. + * + * subclass is a hash that maps base-classes to all of the classes derived from them. + * + * derived - name of derived class + * base - name of base class + * cast - additional casting code when casting from derived to base + * conversioncode - if set, overrides the default code in the function when casting + * from derived to base + * ----------------------------------------------------------------------------- */ + +static Hash *subclass = 0; +static Hash *conversions = 0; + +void SwigType_inherit(String *derived, String *base, String *cast, String *conversioncode) { + Hash *h; + String *dd = 0; + String *bb = 0; + if (!subclass) + subclass = NewHash(); + + /* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */ + + if (SwigType_istemplate(derived)) { + String *ty = SwigType_typedef_resolve_all(derived); + dd = SwigType_typedef_qualified(ty); + derived = dd; + Delete(ty); + } + if (SwigType_istemplate(base)) { + String *ty = SwigType_typedef_resolve_all(base); + bb = SwigType_typedef_qualified(ty); + base = bb; + Delete(ty); + } + + /* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */ + + h = Getattr(subclass, base); + if (!h) { + h = NewHash(); + Setattr(subclass, base, h); + Delete(h); + } + if (!Getattr(h, derived)) { + Hash *c = NewHash(); + if (cast) + Setattr(c, "cast", cast); + if (conversioncode) + Setattr(c, "convcode", conversioncode); + Setattr(h, derived, c); + Delete(c); + } + + Delete(dd); + Delete(bb); +} + +/* ----------------------------------------------------------------------------- + * SwigType_issubtype() + * + * Determines if a t1 is a subtype of t2, ie, is t1 derived from t2 + * ----------------------------------------------------------------------------- */ + +int SwigType_issubtype(SwigType *t1, SwigType *t2) { + SwigType *ft1, *ft2; + String *b1, *b2; + Hash *h; + int r = 0; + + if (!subclass) + return 0; + + ft1 = SwigType_typedef_resolve_all(t1); + ft2 = SwigType_typedef_resolve_all(t2); + b1 = SwigType_base(ft1); + b2 = SwigType_base(ft2); + + h = Getattr(subclass, b2); + if (h) { + if (Getattr(h, b1)) { + r = 1; + } + } + Delete(ft1); + Delete(ft2); + Delete(b1); + Delete(b2); + /* Printf(stdout, "issubtype(%s,%s) --> %d\n", t1, t2, r); */ + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_inherit_equiv() + * + * Modify the type table to handle C++ inheritance + * ----------------------------------------------------------------------------- */ + +void SwigType_inherit_equiv(File *out) { + String *ckey; + String *prefix, *base; + String *mprefix, *mkey; + Hash *sub; + Hash *rh; + List *rlist; + Iterator rk, bk, ck; + + if (!conversions) + conversions = NewHash(); + if (!subclass) + subclass = NewHash(); + + rk = First(r_resolved); + while (rk.key) { + /* rkey is a fully qualified type. We strip all of the type constructors off of it just to get the base */ + base = SwigType_base(rk.key); + /* Check to see whether the base is recorded in the subclass table */ + sub = Getattr(subclass, base); + Delete(base); + if (!sub) { + rk = Next(rk); + continue; + } + + /* This type has subclasses. We now need to walk through these subtypes and generate pointer converion functions */ + + rh = Getattr(r_resolved, rk.key); + rlist = NewList(); + for (ck = First(rh); ck.key; ck = Next(ck)) { + Append(rlist, ck.key); + } + /* Printf(stdout,"rk.key = '%s'\n", rk.key); + Printf(stdout,"rh = %x '%s'\n", rh,rh); */ + + bk = First(sub); + while (bk.key) { + prefix = SwigType_prefix(rk.key); + Append(prefix, bk.key); + /* Printf(stdout,"set %x = '%s' : '%s'\n", rh, SwigType_manglestr(prefix),prefix); */ + mprefix = SwigType_manglestr(prefix); + Setattr(rh, mprefix, prefix); + mkey = SwigType_manglestr(rk.key); + ckey = NewStringf("%s+%s", mprefix, mkey); + if (!Getattr(conversions, ckey)) { + String *convname = NewStringf("%sTo%s", mprefix, mkey); + String *lkey = SwigType_lstr(rk.key, 0); + String *lprefix = SwigType_lstr(prefix, 0); + Hash *subhash = Getattr(sub, bk.key); + String *convcode = Getattr(subhash, "convcode"); + if (convcode) { + char *newmemoryused = Strstr(convcode, "newmemory"); /* see if newmemory parameter is used in order to avoid unused parameter warnings */ + String *fn = Copy(convcode); + Replaceall(fn, "$from", "x"); + Printf(out, "static void *%s(void *x, int *%s) {", convname, newmemoryused ? "newmemory" : "SWIGUNUSEDPARM(newmemory)"); + Printf(out, "%s", fn); + } else { + String *cast = Getattr(subhash, "cast"); + Printf(out, "static void *%s(void *x, int *SWIGUNUSEDPARM(newmemory)) {", convname); + Printf(out, "\n return (void *)((%s) ", lkey); + if (cast) + Printf(out, "%s", cast); + Printf(out, " ((%s) x));\n", lprefix); + } + Printf(out, "}\n"); + Setattr(conversions, ckey, convname); + Delete(ckey); + Delete(lkey); + Delete(lprefix); + + /* This inserts conversions for typedefs */ + { + Hash *r = Getattr(r_resolved, prefix); + if (r) { + Iterator rrk; + rrk = First(r); + while (rrk.key) { + Iterator rlk; + String *rkeymangle; + + /* Make sure this name equivalence is not due to inheritance */ + if (Cmp(prefix, Getattr(r, rrk.key)) == 0) { + rkeymangle = Copy(mkey); + ckey = NewStringf("%s+%s", rrk.key, rkeymangle); + if (!Getattr(conversions, ckey)) { + Setattr(conversions, ckey, convname); + } + Delete(ckey); + for (rlk = First(rlist); rlk.item; rlk = Next(rlk)) { + ckey = NewStringf("%s+%s", rrk.key, rlk.item); + Setattr(conversions, ckey, convname); + Delete(ckey); + } + Delete(rkeymangle); + /* This is needed to pick up other alternative names for the same type. + Needed to make templates work */ + Setattr(rh, rrk.key, rrk.item); + } + rrk = Next(rrk); + } + } + } + Delete(convname); + } + Delete(prefix); + Delete(mprefix); + Delete(mkey); + bk = Next(bk); + } + rk = Next(rk); + Delete(rlist); + } +} + +/* Helper function to sort the mangled list */ +static int SwigType_compare_mangled(const DOH *a, const DOH *b) { + return strcmp((char *) Data(a), (char *) Data(b)); +} + +/* ----------------------------------------------------------------------------- + * SwigType_get_sorted_mangled_list() + * + * Returns the sorted list of mangled type names that should be exported into the + * wrapper file. + * ----------------------------------------------------------------------------- */ +List *SwigType_get_sorted_mangled_list() { + List *l = Keys(r_mangled); + SortList(l, SwigType_compare_mangled); + return l; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_type_table() + * + * Generate the type-table for the type-checker. + * ----------------------------------------------------------------------------- */ + +void SwigType_emit_type_table(File *f_forward, File *f_table) { + Iterator ki; + String *types, *table, *cast, *cast_init, *cast_temp; + Hash *imported_types; + List *mangled_list; + List *table_list = NewList(); + int i = 0; + + if (!r_mangled) { + r_mangled = NewHash(); + r_resolved = NewHash(); + } + + Printf(f_table, "\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */\n\n"); + + SwigType_inherit_equiv(f_table); + + /*#define DEBUG 1*/ +#ifdef DEBUG + Printf(stdout, "---r_mangled---\n"); + Printf(stdout, "%s\n", r_mangled); + + Printf(stdout, "---r_resolved---\n"); + Printf(stdout, "%s\n", r_resolved); + + Printf(stdout, "---r_ltype---\n"); + Printf(stdout, "%s\n", r_ltype); + + Printf(stdout, "---subclass---\n"); + Printf(stdout, "%s\n", subclass); + + Printf(stdout, "---conversions---\n"); + Printf(stdout, "%s\n", conversions); + + Printf(stdout, "---r_clientdata---\n"); + Printf(stdout, "%s\n", r_clientdata); + +#endif + table = NewStringEmpty(); + types = NewStringEmpty(); + cast = NewStringEmpty(); + cast_init = NewStringEmpty(); + imported_types = NewHash(); + + Printf(table, "static swig_type_info *swig_type_initial[] = {\n"); + Printf(cast_init, "static swig_cast_info *swig_cast_initial[] = {\n"); + + Printf(f_forward, "\n/* -------- TYPES TABLE (BEGIN) -------- */\n\n"); + + mangled_list = SwigType_get_sorted_mangled_list(); + for (ki = First(mangled_list); ki.item; ki = Next(ki)) { + List *el; + Iterator ei; + SwigType *lt; + SwigType *rt = 0; + String *nt; + String *ln; + String *rn; + const String *cd; + Hash *lthash; + Iterator ltiter; + Hash *nthash; + + cast_temp = NewStringEmpty(); + + Printv(types, "static swig_type_info _swigt_", ki.item, " = {", NIL); + Append(table_list, ki.item); + Printf(cast_temp, "static swig_cast_info _swigc_%s[] = {", ki.item); + i++; + + cd = SwigType_clientdata_collect(ki.item); + if (!cd) + cd = "0"; + + lthash = Getattr(r_ltype, ki.item); + nt = 0; + nthash = NewHash(); + ltiter = First(lthash); + while (ltiter.key) { + lt = ltiter.key; + rt = SwigType_typedef_resolve_all(lt); + /* we save the original type and the fully resolved version */ + ln = SwigType_lstr(lt, 0); + rn = SwigType_lstr(rt, 0); + if (Equal(ln, rn)) { + Setattr(nthash, ln, "1"); + } else { + Setattr(nthash, rn, "1"); + Setattr(nthash, ln, "1"); + } + if (SwigType_istemplate(rt)) { + String *dt = Swig_symbol_template_deftype(rt, 0); + String *dn = SwigType_lstr(dt, 0); + if (!Equal(dn, rn) && !Equal(dn, ln)) { + Setattr(nthash, dn, "1"); + } + Delete(dt); + Delete(dn); + } + + ltiter = Next(ltiter); + } + + /* now build nt */ + ltiter = First(nthash); + nt = 0; + while (ltiter.key) { + if (nt) { + Printf(nt, "|%s", ltiter.key); + } else { + nt = NewString(ltiter.key); + } + ltiter = Next(ltiter); + } + Delete(nthash); + + Printf(types, "\"%s\", \"%s\", 0, 0, (void*)%s, 0};\n", ki.item, nt, cd); + + el = SwigType_equivalent_mangle(ki.item, 0, 0); + for (ei = First(el); ei.item; ei = Next(ei)) { + String *ckey; + String *conv; + ckey = NewStringf("%s+%s", ei.item, ki.item); + conv = Getattr(conversions, ckey); + if (conv) { + Printf(cast_temp, " {&_swigt_%s, %s, 0, 0},", ei.item, conv); + } else { + Printf(cast_temp, " {&_swigt_%s, 0, 0, 0},", ei.item); + } + Delete(ckey); + + if (!Getattr(r_mangled, ei.item) && !Getattr(imported_types, ei.item)) { + Printf(types, "static swig_type_info _swigt_%s = {\"%s\", 0, 0, 0, 0, 0};\n", ei.item, ei.item); + Append(table_list, ei.item); + + Printf(cast, "static swig_cast_info _swigc_%s[] = {{&_swigt_%s, 0, 0, 0},{0, 0, 0, 0}};\n", ei.item, ei.item); + i++; + + Setattr(imported_types, ei.item, "1"); + } + } + Delete(el); + Printf(cast, "%s{0, 0, 0, 0}};\n", cast_temp); + Delete(cast_temp); + Delete(nt); + Delete(rt); + } + /* print the tables in the proper order */ + SortList(table_list, SwigType_compare_mangled); + i = 0; + for (ki = First(table_list); ki.item; ki = Next(ki)) { + Printf(f_forward, "#define SWIGTYPE%s swig_types[%d]\n", ki.item, i++); + Printf(table, " &_swigt_%s,\n", ki.item); + Printf(cast_init, " _swigc_%s,\n", ki.item); + } + if (i == 0) { + /* empty arrays are not allowed by ISO C */ + Printf(table, " NULL\n"); + Printf(cast_init, " NULL\n"); + } + + Delete(table_list); + + Delete(mangled_list); + + Printf(table, "};\n"); + Printf(cast_init, "};\n"); + Printf(f_table, "%s\n", types); + Printf(f_table, "%s\n", table); + Printf(f_table, "%s\n", cast); + Printf(f_table, "%s\n", cast_init); + Printf(f_table, "\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */\n\n"); + + Printf(f_forward, "static swig_type_info *swig_types[%d];\n", i + 1); + Printf(f_forward, "static swig_module_info swig_module = {swig_types, %d, 0, 0, 0, 0};\n", i); + Printf(f_forward, "#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)\n"); + Printf(f_forward, "#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)\n"); + Printf(f_forward, "\n/* -------- TYPES TABLE (END) -------- */\n\n"); + + Delete(types); + Delete(table); + Delete(cast); + Delete(cast_init); + Delete(imported_types); +} diff --git a/Source/Swig/warn.c b/Source/Swig/warn.c new file mode 100644 index 0000000..8f577eb --- /dev/null +++ b/Source/Swig/warn.c @@ -0,0 +1,34 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * warn.c + * + * SWIG warning framework. This was added to warn developers about + * deprecated APIs and other features. + * ----------------------------------------------------------------------------- */ + +char cvsroot_warn_c[] = "$Id: warn.c 9604 2006-12-05 21:57:44Z beazley $"; + +#include "swig.h" + +static Hash *warnings = 0; + +/* ----------------------------------------------------------------------------- + * Swig_warn() + * + * Issue a warning + * ----------------------------------------------------------------------------- */ + +void Swig_warn(const char *filename, int line, const char *msg) { + String *key; + if (!warnings) { + warnings = NewHash(); + } + key = NewStringf("%s:%d", filename, line); + if (!Getattr(warnings, key)) { + Printf(stderr, "swig-dev warning:%s:%d:%s\n", filename, line, msg); + Setattr(warnings, key, key); + } + Delete(key); +} diff --git a/Source/Swig/wrapfunc.c b/Source/Swig/wrapfunc.c new file mode 100644 index 0000000..e2f3f9c --- /dev/null +++ b/Source/Swig/wrapfunc.c @@ -0,0 +1,518 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * wrapfunc.c + * + * This file defines a object for creating wrapper functions. Primarily + * this is used for convenience since it allows pieces of a wrapper function + * to be created in a piecemeal manner. + * ----------------------------------------------------------------------------- */ + +char cvsroot_wrapfunc_c[] = "$Id: wrapfunc.c 11080 2009-01-24 13:15:51Z bhy $"; + +#include "swig.h" +#include <ctype.h> + +static int Compact_mode = 0; /* set to 0 on default */ +static int Max_line_size = 128; + +/* ----------------------------------------------------------------------------- + * NewWrapper() + * + * Create a new wrapper function object. + * ----------------------------------------------------------------------------- */ + +Wrapper *NewWrapper(void) { + Wrapper *w; + w = (Wrapper *) malloc(sizeof(Wrapper)); + w->localh = NewHash(); + w->locals = NewStringEmpty(); + w->code = NewStringEmpty(); + w->def = NewStringEmpty(); + return w; +} + +/* ----------------------------------------------------------------------------- + * DelWrapper() + * + * Delete a wrapper function object. + * ----------------------------------------------------------------------------- */ + +void DelWrapper(Wrapper *w) { + Delete(w->localh); + Delete(w->locals); + Delete(w->code); + Delete(w->def); + free(w); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_compact_print_mode_set() + * + * Set compact_mode. + * ----------------------------------------------------------------------------- */ + +void Wrapper_compact_print_mode_set(int flag) { + Compact_mode = flag; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_pretty_print() + * + * Formats a wrapper function and fixes up the indentation. + * ----------------------------------------------------------------------------- */ + +void Wrapper_pretty_print(String *str, File *f) { + String *ts; + int level = 0; + int c, i; + int empty = 1; + int indent = 2; + int plevel = 0; + int label = 0; + + ts = NewStringEmpty(); + Seek(str, 0, SEEK_SET); + while ((c = Getc(str)) != EOF) { + if (c == '\"') { + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\"') + break; + } + empty = 0; + } else if (c == '\'') { + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\'') + break; + } + empty = 0; + } else if (c == ':') { + Putc(c, ts); + if ((c = Getc(str)) == '\n') { + if (!empty && !strchr(Char(ts), '?')) + label = 1; + } + Ungetc(c, str); + } else if (c == '(') { + Putc(c, ts); + plevel += indent; + empty = 0; + } else if (c == ')') { + Putc(c, ts); + plevel -= indent; + empty = 0; + } else if (c == '{') { + Putc(c, ts); + Putc('\n', ts); + for (i = 0; i < level; i++) + Putc(' ', f); + Printf(f, "%s", ts); + Clear(ts); + level += indent; + while ((c = Getc(str)) != EOF) { + if (!isspace(c)) { + Ungetc(c, str); + break; + } + } + empty = 0; + } else if (c == '}') { + if (!empty) { + Putc('\n', ts); + for (i = 0; i < level; i++) + Putc(' ', f); + Printf(f, "%s", ts); + Clear(ts); + } + level -= indent; + Putc(c, ts); + empty = 0; + } else if (c == '\n') { + Putc(c, ts); + empty = 0; + if (!empty) { + int slevel = level; + if (label && (slevel >= indent)) + slevel -= indent; + if ((Char(ts))[0] != '#') { + for (i = 0; i < slevel; i++) + Putc(' ', f); + } + Printf(f, "%s", ts); + for (i = 0; i < plevel; i++) + Putc(' ', f); + } + Clear(ts); + label = 0; + empty = 1; + } else if (c == '/') { + empty = 0; + Putc(c, ts); + c = Getc(str); + if (c != EOF) { + Putc(c, ts); + if (c == '/') { /* C++ comment */ + while ((c = Getc(str)) != EOF) { + if (c == '\n') { + Ungetc(c, str); + break; + } + Putc(c, ts); + } + } else if (c == '*') { /* C comment */ + int endstar = 0; + while ((c = Getc(str)) != EOF) { + if (endstar && c == '/') { /* end of C comment */ + Putc(c, ts); + break; + } + endstar = (c == '*'); + Putc(c, ts); + if (c == '\n') { /* multi-line C comment. Could be improved slightly. */ + for (i = 0; i < level; i++) + Putc(' ', ts); + } + } + } + } + } else { + if (!empty || !isspace(c)) { + Putc(c, ts); + empty = 0; + } + } + } + if (!empty) + Printf(f, "%s", ts); + Delete(ts); + Printf(f, "\n"); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_compact_print() + * + * Formats a wrapper function and fixes up the indentation. + * Print out in compact format, with Compact enabled. + * ----------------------------------------------------------------------------- */ + +void Wrapper_compact_print(String *str, File *f) { + String *ts, *tf; /*temp string & temp file */ + int level = 0; + int c, i; + int empty = 1; + int indent = 2; + + ts = NewStringEmpty(); + tf = NewStringEmpty(); + Seek(str, 0, SEEK_SET); + + while ((c = Getc(str)) != EOF) { + if (c == '\"') { /* string 1 */ + empty = 0; + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\"') + break; + } + } else if (c == '\'') { /* string 2 */ + empty = 0; + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\'') + break; + } + } else if (c == '{') { /* start of {...} */ + empty = 0; + Putc(c, ts); + if (Len(tf) == 0) { + for (i = 0; i < level; i++) + Putc(' ', tf); + } else if ((Len(tf) + Len(ts)) < Max_line_size) { + Putc(' ', tf); + } else { + Putc('\n', tf); + Printf(f, "%s", tf); + Clear(tf); + for (i = 0; i < level; i++) + Putc(' ', tf); + } + Append(tf, ts); + Clear(ts); + level += indent; + while ((c = Getc(str)) != EOF) { + if (!isspace(c)) { + Ungetc(c, str); + break; + } + } + } else if (c == '}') { /* end of {...} */ + empty = 0; + if (Len(tf) == 0) { + for (i = 0; i < level; i++) + Putc(' ', tf); + } else if ((Len(tf) + Len(ts)) < Max_line_size) { + Putc(' ', tf); + } else { + Putc('\n', tf); + Printf(f, "%s", tf); + Clear(tf); + for (i = 0; i < level; i++) + Putc(' ', tf); + } + Append(tf, ts); + Putc(c, tf); + Clear(ts); + level -= indent; + } else if (c == '\n') { /* line end */ + while ((c = Getc(str)) != EOF) { + if (!isspace(c)) + break; + } + if (c == '#') { + Putc('\n', ts); + } else if (c == '}') { + Putc(' ', ts); + } else if ((c != EOF) || (Len(ts) != 0)) { + if (Len(tf) == 0) { + for (i = 0; i < level; i++) + Putc(' ', tf); + } else if ((Len(tf) + Len(ts)) < Max_line_size) { + Putc(' ', tf); + } else { + Putc('\n', tf); + Printf(f, "%s", tf); + Clear(tf); + for (i = 0; i < level; i++) + Putc(' ', tf); + } + Append(tf, ts); + Clear(ts); + } + Ungetc(c, str); + + empty = 1; + } else if (c == '/') { /* comment */ + empty = 0; + c = Getc(str); + if (c != EOF) { + if (c == '/') { /* C++ comment */ + while ((c = Getc(str)) != EOF) { + if (c == '\n') { + Ungetc(c, str); + break; + } + } + } else if (c == '*') { /* C comment */ + int endstar = 0; + while ((c = Getc(str)) != EOF) { + if (endstar && c == '/') { /* end of C comment */ + break; + } + endstar = (c == '*'); + } + } else { + Putc('/', ts); + Putc(c, ts); + } + } + } else if (c == '#') { /* Preprocessor line */ + Putc('#', ts); + while ((c = Getc(str)) != EOF) { + Putc(c, ts); + if (c == '\\') { /* Continued line of the same PP */ + c = Getc(str); + if (c == '\n') + Putc(c, ts); + else + Ungetc(c, str); + } else if (c == '\n') + break; + } + if (!empty) { + Append(tf, "\n"); + } + Append(tf, ts); + Printf(f, "%s", tf); + Clear(tf); + Clear(ts); + for (i = 0; i < level; i++) + Putc(' ', tf); + empty = 1; + } else { + if (!empty || !isspace(c)) { + Putc(c, ts); + empty = 0; + } + } + } + if (!empty) { + Append(tf, ts); + } + if (Len(tf) != 0) + Printf(f, "%s", tf); + Delete(ts); + Delete(tf); + Printf(f, "\n"); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_print() + * + * Print out a wrapper function. Does pretty or compact printing as well. + * ----------------------------------------------------------------------------- */ + +void Wrapper_print(Wrapper *w, File *f) { + String *str; + + str = NewStringEmpty(); + Printf(str, "%s\n", w->def); + Printf(str, "%s\n", w->locals); + Printf(str, "%s\n", w->code); + if (Compact_mode == 1) + Wrapper_compact_print(str, f); + else + Wrapper_pretty_print(str, f); + + Delete(str); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_add_local() + * + * Adds a new local variable declaration to a function. Returns -1 if already + * present (which may or may not be okay to the caller). + * ----------------------------------------------------------------------------- */ + +int Wrapper_add_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl) { + /* See if the local has already been declared */ + if (Getattr(w->localh, name)) { + return -1; + } + Setattr(w->localh, name, decl); + Printf(w->locals, "%s;\n", decl); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_add_localv() + * + * Same as add_local(), but allows a NULL terminated list of strings to be + * used as a replacement for decl. This saves the caller the trouble of having + * to manually construct the 'decl' string before calling. + * ----------------------------------------------------------------------------- */ + +int Wrapper_add_localv(Wrapper *w, const_String_or_char_ptr name, ...) { + va_list ap; + int ret; + String *decl; + DOH *obj; + decl = NewStringEmpty(); + va_start(ap, name); + + obj = va_arg(ap, void *); + while (obj) { + Append(decl, obj); + Putc(' ', decl); + obj = va_arg(ap, void *); + } + va_end(ap); + + ret = Wrapper_add_local(w, name, decl); + Delete(decl); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_check_local() + * + * Check to see if a local name has already been declared + * ----------------------------------------------------------------------------- */ + +int Wrapper_check_local(Wrapper *w, const_String_or_char_ptr name) { + if (Getattr(w->localh, name)) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_new_local() + * + * Adds a new local variable with a guarantee that a unique local name will be + * used. Returns the name that was actually selected. + * ----------------------------------------------------------------------------- */ + +char *Wrapper_new_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl) { + int i; + String *nname = NewString(name); + String *ndecl = NewString(decl); + char *ret; + + i = 0; + + while (Wrapper_check_local(w, nname)) { + Clear(nname); + Printf(nname, "%s%d", name, i); + i++; + } + Replace(ndecl, name, nname, DOH_REPLACE_ID); + Setattr(w->localh, nname, ndecl); + Printf(w->locals, "%s;\n", ndecl); + ret = Char(nname); + Delete(nname); + Delete(ndecl); + return ret; /* Note: nname should still exists in the w->localh hash */ +} + + +/* ----------------------------------------------------------------------------- + * Wrapper_new_localv() + * + * Same as add_local(), but allows a NULL terminated list of strings to be + * used as a replacement for decl. This saves the caller the trouble of having + * to manually construct the 'decl' string before calling. + * ----------------------------------------------------------------------------- */ + +char *Wrapper_new_localv(Wrapper *w, const_String_or_char_ptr name, ...) { + va_list ap; + char *ret; + String *decl; + DOH *obj; + decl = NewStringEmpty(); + va_start(ap, name); + + obj = va_arg(ap, void *); + while (obj) { + Append(decl, obj); + Putc(' ', decl); + obj = va_arg(ap, void *); + } + va_end(ap); + + ret = Wrapper_new_local(w, name, decl); + Delete(decl); + return ret; +} |