mirror of https://github.com/swig/swig
879 lines
29 KiB
C++
879 lines
29 KiB
C++
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at https://www.swig.org/legal.html.
|
|
*
|
|
* 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.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "swigmod.h"
|
|
|
|
#define MAX_OVERLOAD 4096
|
|
|
|
/* Overload "argc" and "argv" */
|
|
String *argv_template_string;
|
|
String *argc_template_string;
|
|
|
|
namespace {
|
|
struct Overloaded {
|
|
Node *n; /* Node */
|
|
int argc; /* Argument count */
|
|
ParmList *parms; /* Parameters used for overload check */
|
|
int error; /* Ambiguity error */
|
|
bool implicitconv_function; /* For ordering implicitconv functions*/
|
|
};
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* mark_implicitconv_function()
|
|
*
|
|
* Mark function if it contains an implicitconv type in the parameter list
|
|
* ----------------------------------------------------------------------------- */
|
|
static void mark_implicitconv_function(Overloaded& onode) {
|
|
Parm *parms = onode.parms;
|
|
if (parms) {
|
|
bool is_implicitconv_function = false;
|
|
Parm *p = parms;
|
|
while (p) {
|
|
if (checkAttribute(p, "tmap:in:numinputs", "0")) {
|
|
p = Getattr(p, "tmap:in:next");
|
|
continue;
|
|
}
|
|
if (GetFlag(p, "implicitconv")) {
|
|
is_implicitconv_function = true;
|
|
break;
|
|
}
|
|
p = nextSibling(p);
|
|
}
|
|
if (is_implicitconv_function)
|
|
onode.implicitconv_function = true;
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
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;
|
|
nodes[nnodes].implicitconv_function = false;
|
|
|
|
mark_implicitconv_function(nodes[nnodes]);
|
|
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 (incomplete type checking rule - no precedence level in typecheck typemap 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 (incomplete type checking rule - no precedence level in typecheck typemap 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, "equivtype");
|
|
t1 = t1 ? 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, "equivtype");
|
|
t2 = t2 ? 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 *decl1 = Getattr(nodes[i].n, "decl");
|
|
String *decl2 = Getattr(nodes[j].n, "decl");
|
|
if (decl1 && decl2) {
|
|
/* Remove ref-qualifiers. Note that rvalue ref-qualifiers are already ignored and
|
|
* it is illegal to overload a function with and without ref-qualifiers. So with
|
|
* all the combinations of ref-qualifiers and cv-qualifiers, we just detect
|
|
* the cv-qualifier (const) overloading. */
|
|
String *d1 = Copy(decl1);
|
|
String *d2 = Copy(decl2);
|
|
if (SwigType_isreference(d1) || SwigType_isrvalue_reference(d1)) {
|
|
Delete(SwigType_pop(d1));
|
|
}
|
|
if (SwigType_isreference(d2) || SwigType_isrvalue_reference(d2)) {
|
|
Delete(SwigType_pop(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,\n", Swig_name_decl(nodes[j].n));
|
|
Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n),
|
|
"using non-const method %s instead.\n", Swig_name_decl(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,\n", Swig_name_decl(nodes[j].n));
|
|
Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n),
|
|
"using %s instead.\n", Swig_name_decl(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,\n", Swig_name_decl(nodes[j].n));
|
|
Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[i].n), Getline(nodes[i].n),
|
|
"using non-const method %s instead.\n", Swig_name_decl(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,\n", Swig_name_decl(nodes[j].n));
|
|
Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n),
|
|
"using %s instead.\n", Swig_name_decl(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 effectively ignored,\n", Swig_name_decl(nodes[j].n));
|
|
Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[i].n), Getline(nodes[i].n),
|
|
"as it is shadowed by %s.\n", Swig_name_decl(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,\n", Swig_name_decl(nodes[j].n));
|
|
Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[i].n), Getline(nodes[i].n),
|
|
"using %s instead.\n", Swig_name_decl(nodes[i].n));
|
|
}
|
|
}
|
|
nodes[j].error = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
List *result = NewList();
|
|
{
|
|
int i;
|
|
int argc_changed_index = -1;
|
|
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 ] %d %s\n", i, nodes[i].implicitconv_function, ParmList_errorstr(nodes[i].parms));
|
|
if (i == nnodes-1 || nodes[i].argc != nodes[i+1].argc) {
|
|
if (argc_changed_index+2 < nnodes && (nodes[argc_changed_index+1].argc == nodes[argc_changed_index+2].argc)) {
|
|
// Add additional implicitconv functions in same order as already ranked.
|
|
// Consider overloaded functions by argument count... only add additional implicitconv functions if
|
|
// the number of functions with the same arg count > 1, ie, only if overloaded by same argument count.
|
|
int j;
|
|
for (j = argc_changed_index + 1; j <= i; j++) {
|
|
if (nodes[j].implicitconv_function) {
|
|
SetFlag(nodes[j].n, "implicitconvtypecheckoff");
|
|
Append(result, nodes[j].n);
|
|
// Printf(stdout,"[ %d ] %d + %s\n", j, nodes[j].implicitconv_function, ParmList_errorstr(nodes[j].parms));
|
|
}
|
|
}
|
|
}
|
|
argc_changed_index = i;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* print_typecheck()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static bool print_typecheck(String *f, int j, Parm *pj, bool implicitconvtypecheckoff) {
|
|
char tmp[256];
|
|
sprintf(tmp, Char(argv_template_string), j);
|
|
String *tm = Getattr(pj, "tmap:typecheck");
|
|
if (tm) {
|
|
tm = Copy(tm);
|
|
Replaceid(tm, Getattr(pj, "lname"), "_v");
|
|
String *conv = Getattr(pj, "implicitconv");
|
|
if (conv && !implicitconvtypecheckoff) {
|
|
Replaceall(tm, "$implicitconv", conv);
|
|
} else {
|
|
Replaceall(tm, "$implicitconv", "0");
|
|
}
|
|
Replaceall(tm, "$input", tmp);
|
|
Printv(f, tm, "\n", NIL);
|
|
Delete(tm);
|
|
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, bool *check_emitted) {
|
|
int i, j;
|
|
|
|
*maxargs = 0;
|
|
*check_emitted = false;
|
|
|
|
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 = true;
|
|
for (i = 0; i < nfunc; i++) {
|
|
int fn = 0;
|
|
Node *ni = Getitem(dispatch, i);
|
|
Parm *pi = Getattr(ni, "wrap:parms");
|
|
bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0;
|
|
int num_required = emit_num_required(pi);
|
|
int num_arguments = emit_num_arguments(pi);
|
|
if (num_arguments > *maxargs)
|
|
*maxargs = num_arguments;
|
|
|
|
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);
|
|
}
|
|
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) {
|
|
tm = Copy(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 = true;
|
|
//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) {
|
|
*check_emitted = true;
|
|
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 && !implicitconvtypecheckoff) {
|
|
Replaceall(tm, "$implicitconv", conv);
|
|
} else {
|
|
Replaceall(tm, "$implicitconv", "0");
|
|
}
|
|
Replaceall(tm, "$input", tmp);
|
|
Printv(f, "{\n", tm, "}\n", NIL);
|
|
Delete(tm);
|
|
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));
|
|
Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni),
|
|
"Dispatching calls to this method may not work correctly, see the 'Typemaps and Overloading' section in the Typemaps chapter of the SWIG documentation.\n");
|
|
}
|
|
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);
|
|
|
|
if (implicitconvtypecheckoff)
|
|
Delattr(ni, "implicitconvtypecheckoff");
|
|
|
|
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).
|
|
*/
|
|
static String *overload_dispatch_fast(Node *n, const_String_or_char_ptr fmt, int *maxargs, bool *check_emitted, const_String_or_char_ptr fmt_fastdispatch) {
|
|
int i, j;
|
|
|
|
*maxargs = 0;
|
|
*check_emitted = false;
|
|
|
|
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");
|
|
bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0;
|
|
int num_required = emit_num_required(pi);
|
|
int num_arguments = emit_num_arguments(pi);
|
|
if (num_arguments > *maxargs)
|
|
*maxargs = num_arguments;
|
|
|
|
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);
|
|
}
|
|
|
|
/* 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));
|
|
|
|
bool emitcheck = false;
|
|
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) {
|
|
tm = Copy(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 */
|
|
emitcheck = false;
|
|
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 = true;
|
|
//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) {
|
|
*check_emitted = true;
|
|
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 && !implicitconvtypecheckoff) {
|
|
Replaceall(tm, "$implicitconv", conv);
|
|
} else {
|
|
Replaceall(tm, "$implicitconv", "0");
|
|
}
|
|
Replaceall(tm, "$input", tmp);
|
|
Printv(f, "{\n", tm, "}\n", NIL);
|
|
Delete(tm);
|
|
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));
|
|
Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni),
|
|
"Dispatching calls to this method may not work correctly, see the 'Typemaps and Overloading' section in the Typemaps chapter of the SWIG documentation.\n");
|
|
}
|
|
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");
|
|
|
|
// The language module may want to generate different code for last overloaded function called (with same number of arguments)
|
|
String *lfmt = ReplaceFormat(!emitcheck && fmt_fastdispatch ? fmt_fastdispatch : 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);
|
|
|
|
if (implicitconvtypecheckoff)
|
|
Delattr(ni, "implicitconvtypecheckoff");
|
|
|
|
Delete(lfmt);
|
|
Delete(coll);
|
|
}
|
|
Delete(dispatch);
|
|
return f;
|
|
}
|
|
|
|
String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxargs, bool *check_emitted, const_String_or_char_ptr fmt_fastdispatch) {
|
|
|
|
if (fast_dispatch_mode || GetFlag(n, "feature:fastdispatch")) {
|
|
return overload_dispatch_fast(n, fmt, maxargs, check_emitted, fmt_fastdispatch);
|
|
}
|
|
|
|
int i, j;
|
|
|
|
*maxargs = 0;
|
|
*check_emitted = false;
|
|
|
|
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");
|
|
bool implicitconvtypecheckoff = GetFlag(ni, "implicitconvtypecheckoff") != 0;
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
if (num_arguments) {
|
|
Printf(f, "int _v = 0;\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;
|
|
}
|
|
*check_emitted = true;
|
|
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, implicitconvtypecheckoff)) {
|
|
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));
|
|
Swig_warning(WARN_TYPEMAP_TYPECHECK_UNDEF, Getfile(ni), Getline(ni),
|
|
"Dispatching calls to this method may not work correctly, see the 'Typemaps and Overloading' section in the Typemaps chapter of the SWIG documentation.\n");
|
|
}
|
|
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 */
|
|
if (implicitconvtypecheckoff)
|
|
Delattr(ni, "implicitconvtypecheckoff");
|
|
}
|
|
Delete(dispatch);
|
|
return f;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_overload_check()
|
|
* ----------------------------------------------------------------------------- */
|
|
void Swig_overload_check(Node *n) {
|
|
Swig_overload_rank(n, false);
|
|
}
|