blob: a4cf8cebc09b05e59b1ce6681820a9a02a6e30ff [file] [log] [blame]
/* -----------------------------------------------------------------------------
* 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$";
#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-valued 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-valued 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;
}