diff options
Diffstat (limited to 'Source/Modules/emit.cxx')
-rw-r--r-- | Source/Modules/emit.cxx | 512 |
1 files changed, 512 insertions, 0 deletions
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; +} |