Python default arg improvements
Merge the code fixes from patch #294 to more reliably generate default argument values into the python layer.
This commit is contained in:
parent
4b5ed45d50
commit
adbe3f2e77
1 changed files with 130 additions and 14 deletions
|
|
@ -17,6 +17,8 @@
|
||||||
static int treduce = SWIG_cparse_template_reduce(0);
|
static int treduce = SWIG_cparse_template_reduce(0);
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define PYSHADOW_MEMBER 0x2
|
#define PYSHADOW_MEMBER 0x2
|
||||||
#define WARN_PYTHON_MULTIPLE_INH 405
|
#define WARN_PYTHON_MULTIPLE_INH 405
|
||||||
|
|
@ -1814,20 +1816,129 @@ public:
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------
|
||||||
|
* convertDoubleValue()
|
||||||
|
* Check if the given string looks like a decimal floating point constant
|
||||||
|
* and return it if it does, otherwise return NIL.
|
||||||
|
* ------------------------------------------------------------ */
|
||||||
|
String *convertDoubleValue(String *v) {
|
||||||
|
const char *const s = Char(v);
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
(void)strtod(s, &end);
|
||||||
|
if (errno != ERANGE && end != s) {
|
||||||
|
// An added complication: at least some versions of strtod() recognize
|
||||||
|
// hexadecimal floating point numbers which don't exist in Python, so
|
||||||
|
// detect them ourselves and refuse to convert them (this can't be done
|
||||||
|
// without loss of precision in general).
|
||||||
|
//
|
||||||
|
// Also don't accept neither "NAN" nor "INFINITY" (both of which
|
||||||
|
// conveniently contain "n").
|
||||||
|
if (strpbrk(s, "xXnN"))
|
||||||
|
return NIL;
|
||||||
|
|
||||||
|
// Disregard optional "f" suffix, it can be just dropped in Python as it
|
||||||
|
// uses doubles for everything anyhow.
|
||||||
|
for (char* p = end; *p != '\0'; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid unnecessary string allocation in the common case when we don't
|
||||||
|
// need to remove any suffix.
|
||||||
|
return *end == '\0' ? v : NewStringWithSize(s, end - s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------
|
/* ------------------------------------------------------------
|
||||||
* convertValue()
|
* convertValue()
|
||||||
* Check if string v can be a Python value literal or a
|
* Check if string v can be a Python value literal or a
|
||||||
* constant. Return NIL if it isn't.
|
* constant. Return NIL if it isn't.
|
||||||
* ------------------------------------------------------------ */
|
* ------------------------------------------------------------ */
|
||||||
String *convertValue(String *v, SwigType *t) {
|
String *convertValue(String *v, SwigType *t) {
|
||||||
char fc = (Char(v))[0];
|
const char *const s = Char(v);
|
||||||
if (('0' <= fc && fc <= '9') || '\'' == fc || '"' == fc) {
|
char *end;
|
||||||
/* number or string (or maybe NULL pointer) */
|
|
||||||
if (SwigType_ispointer(t) && Strcmp(v, "0") == 0)
|
// Check if this is a number in any base.
|
||||||
return NewString("None");
|
(void)strtol(s, &end, 0);
|
||||||
else
|
if (end != s) {
|
||||||
return v;
|
if (errno == ERANGE) {
|
||||||
|
// There was an overflow, we could try representing the value as Python
|
||||||
|
// long integer literal, but for now don't bother with it.
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*end != '\0') {
|
||||||
|
// If there is a suffix after the number, we can safely ignore any
|
||||||
|
// combination of "l" and "u", but not anything else (again, stuff like
|
||||||
|
// "LL" could be handled, but we don't bother to do it currently).
|
||||||
|
bool seen_long = false;
|
||||||
|
for (char* p = end; *p != '\0'; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case 'l':
|
||||||
|
case 'L':
|
||||||
|
// Bail out on "LL".
|
||||||
|
if (seen_long)
|
||||||
|
return NIL;
|
||||||
|
seen_long = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
case 'U':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Except that our suffix could actually be the fractional part of
|
||||||
|
// a floating point number, so we still have to check for this.
|
||||||
|
return convertDoubleValue(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with the values starting with 0 first as they can be octal or
|
||||||
|
// hexadecimal numbers or even pointers.
|
||||||
|
if (s[0] == '0') {
|
||||||
|
if (Len(v) == 1) {
|
||||||
|
// This is just a lone 0, but it needs to be represented differently
|
||||||
|
// in Python depending on whether it's a zero or a null pointer.
|
||||||
|
if (SwigType_ispointer(t))
|
||||||
|
return NewString("None");
|
||||||
|
else
|
||||||
|
return v;
|
||||||
|
} else if (s[1] == 'x' || s[1] == 'X') {
|
||||||
|
// This must have been a hex number, we can use it directly in Python,
|
||||||
|
// so nothing to do here.
|
||||||
|
} else {
|
||||||
|
// This must have been an octal number, we have to change its prefix
|
||||||
|
// to be "0o" in Python 3 only (and as long as we still support Python
|
||||||
|
// 2.5, this can't be done unconditionally).
|
||||||
|
if (py3) {
|
||||||
|
String *res = NewString("0o");
|
||||||
|
Append(res, NewStringWithSize(s + 1, end - s - 1));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid unnecessary string allocation in the common case when we don't
|
||||||
|
// need to remove any suffix.
|
||||||
|
return *end == '\0' ? v : NewStringWithSize(s, end - s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this is a floating point number (notice that it wasn't
|
||||||
|
// necessarily parsed as a long above, consider e.g. ".123").
|
||||||
|
if (String *res = convertDoubleValue(v)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0)
|
if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0)
|
||||||
return NewString("True");
|
return NewString("True");
|
||||||
if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0)
|
if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0)
|
||||||
|
|
@ -1835,12 +1946,15 @@ public:
|
||||||
if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
|
if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
|
||||||
return SwigType_ispointer(t) ? NewString("None") : NewString("0");
|
return SwigType_ispointer(t) ? NewString("None") : NewString("0");
|
||||||
|
|
||||||
// This could also be an enum type, default value of which is perfectly
|
// This could also be an enum type, default value of which could be
|
||||||
// representable in Python.
|
// representable in Python if it doesn't include any scope (which could,
|
||||||
Node *lookup = Swig_symbol_clookup(v, 0);
|
// but currently is not, translated).
|
||||||
if (lookup) {
|
if (!Strchr(s, ':')) {
|
||||||
if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0)
|
Node *lookup = Swig_symbol_clookup(v, 0);
|
||||||
return Getattr(lookup, "sym:name");
|
if (lookup) {
|
||||||
|
if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0)
|
||||||
|
return Getattr(lookup, "sym:name");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NIL;
|
return NIL;
|
||||||
|
|
@ -1865,13 +1979,15 @@ public:
|
||||||
Parm *pnext;
|
Parm *pnext;
|
||||||
|
|
||||||
for (p = plist; p; p = pnext) {
|
for (p = plist; p; p = pnext) {
|
||||||
|
pnext = NIL;
|
||||||
String *tm = Getattr(p, "tmap:in");
|
String *tm = Getattr(p, "tmap:in");
|
||||||
if (tm) {
|
if (tm) {
|
||||||
pnext = Getattr(p, "tmap:in:next");
|
pnext = Getattr(p, "tmap:in:next");
|
||||||
if (checkAttribute(p, "tmap:in:numinputs", "0")) {
|
if (checkAttribute(p, "tmap:in:numinputs", "0")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
if (!pnext) {
|
||||||
pnext = nextSibling(p);
|
pnext = nextSibling(p);
|
||||||
}
|
}
|
||||||
if (String *value = Getattr(p, "value")) {
|
if (String *value = Getattr(p, "value")) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue