Straighten out handling of integer constants

This provides a generic framework to aid converting C/C++ integer and
boolean literals to target language literals, replacing custom code in
several target language backends (and fixing some bugs in that code).
This commit is contained in:
Olly Betts 2024-09-16 16:10:02 +12:00
parent 9c8186745b
commit 9cba248bec
13 changed files with 259 additions and 154 deletions

View File

@ -5,6 +5,7 @@ import enum_thorough.enum_thorough;
import enum_thorough.AnonStruct;
import enum_thorough.colour;
import enum_thorough.DifferentTypes;
import enum_thorough.Enum2995;
import enum_thorough.FirStruct;
import enum_thorough.HairStruct;
import enum_thorough.IgnoreTest;
@ -445,4 +446,11 @@ void main() {
global_enum = global_typedefaultint;
enforce(cast(int)globalDifferentTypesTest(global_enum) == 'D', "global differentTypes 6 failed");
}
// Regression tests for bad handling of bool expressions (#2995)
{
enforce(cast(int)Enum2995.T1 == 1, "Enum2995 T1 failed");
enforce(cast(int)Enum2995.T2 == 1, "Enum2995 T2 failed");
enforce(cast(int)Enum2995.F1 == 0, "Enum2995 F1 failed");
enforce(cast(int)Enum2995.F2 == 0, "Enum2995 F2 failed");
}
}

View File

@ -660,6 +660,16 @@ struct EnumCharStruct {
enumcharAE3 = '\xC6' // AE (latin1 encoded)
};
};
// We can't test this for C# and Java it seems.
#if !defined(SWIGCSHARP) && !defined(SWIGJAVA)
enum Enum2995 {
T1 = (1 == 1),
T2 = !false,
F1 = (1 != 1),
F2 = !true,
};
#endif
%}
#if defined(SWIGJAVA)

View File

@ -19,6 +19,7 @@
#include "parser.h"
#include <string.h>
#include <ctype.h>
#include <errno.h>
/* Scanner object */
static Scanner *scan = 0;
@ -654,11 +655,45 @@ int yylex(void) {
yylval.dtype = default_dtype;
yylval.dtype.type = T_ULONGLONG;
goto num_common;
num_common: {
yylval.dtype.val = NewString(Scanner_text(scan));
const char *c = Char(yylval.dtype.val);
if (c[0] == '0') {
// Convert to base 10 using strtoull().
unsigned long long value;
char *e;
errno = 0;
if (c[1] == 'b' || c[1] == 'B') {
/* strtoull() doesn't handle binary literal prefixes so skip the prefix
* and specify base 2 explicitly. */
value = strtoull(c + 2, &e, 2);
} else {
value = strtoull(c, &e, 0);
}
if (errno != ERANGE) {
while (*e && strchr("ULul", *e)) ++e;
}
if (errno != ERANGE && *e == '\0') {
yylval.dtype.numval = NewStringf("%llu", value);
} else {
// Our unsigned long long isn't wide enough or this isn't an integer.
}
} else {
const char *e = c;
while (isdigit((unsigned char)*e)) ++e;
int len = e - c;
while (*e && strchr("ULul", *e)) ++e;
if (*e == '\0') {
yylval.dtype.numval = NewStringWithSize(c, len);
}
}
return (l);
}
case NUM_BOOL:
yylval.dtype = default_dtype;
yylval.dtype.type = T_BOOL;
num_common:
yylval.dtype.val = NewString(Scanner_text(scan));
yylval.dtype.numval = NewString(Equal(yylval.dtype.val, "false") ? "0" : "1");
return (l);
case ID:

View File

@ -1664,6 +1664,44 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
// with embedded zero bytes), but handling may currently be buggy in
// places.
String *stringval;
// If type is an integer or boolean type, this is the actual value of that
// type as a base 10 integer in a String (in cases where SWIG can determine
// this value - currently that means for literals). This is useful in
// cases where we want to emit an integer or boolean literal in the target
// language - we could just try emitting the C/C++ code for the literal,
// but that won't always be correct in most target languages.
//
// SWIG doesn't attempt to evaluate constant expressions, except that it
// can handle unary - (because a negative integer literal is actually
// syntactically unary minus applied to a positive integer literal),
// unary + (for consistency with unary -) and parentheses (because
// literals in #define are often in parentheses). These operators are
// handled in the parser so whitespace is also handled within such
// expressions.
//
// Some examples:
//
// C/C++ source numval val Notes
// ------------- ----------- --------- -------
// 123 123 123
// 0x7b 123 0x7b
// 0x7B 123 0x7B
// 0173 123 0173
// 0b1111011 123 0b1111011 C++14
// -10 -10 -10 numval not set for unsigned type
// -0x00a -10 -0x00a numval not set for unsigned type
// -012 -10 -012 numval not set for unsigned type
// -0b1010 -10 -0b1010 C++14; numval not set for unsigned
// (42) 42 (42)
// +42 42 +42
// +(42) 42 +(42)
// -(42) -42 -(42) numval not set for unsigned type
// (-(42)) -42 (-(42)) numval not set for unsigned type
// false 0 false
// (false) 0 (false)
// true 1 true
// (true) 1 (true)
String *numval;
int type;
/* The type code for the argument when the top level operator is unary.
* This is useful because our grammar parses cases such as (7)*6 as a
@ -1686,6 +1724,8 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
char *id;
SwigType *type;
String *defarg;
String *stringdefarg;
String *numdefarg;
ParmList *parms;
short have_parms;
ParmList *throws;
@ -2114,6 +2154,7 @@ constant_directive : CONSTANT identifier EQUAL definetype SEMI {
Setattr($$, "type", type);
Setattr($$, "value", $definetype.val);
if ($definetype.stringval) Setattr($$, "stringval", $definetype.stringval);
if ($definetype.numval) Setattr($$, "numval", $definetype.numval);
Setattr($$, "storage", "%constant");
SetFlag($$, "feature:immutable");
add_symbols($$);
@ -2134,6 +2175,7 @@ constant_directive : CONSTANT identifier EQUAL definetype SEMI {
Setattr($$, "type", $type);
Setattr($$, "value", $def_args.val);
if ($def_args.stringval) Setattr($$, "stringval", $def_args.stringval);
if ($def_args.numval) Setattr($$, "numval", $def_args.numval);
Setattr($$, "storage", "%constant");
SetFlag($$, "feature:immutable");
add_symbols($$);
@ -2153,6 +2195,7 @@ constant_directive : CONSTANT identifier EQUAL definetype SEMI {
Setattr($$, "type", $type);
Setattr($$, "value", $def_args.val);
if ($def_args.stringval) Setattr($$, "stringval", $def_args.stringval);
if ($def_args.numval) Setattr($$, "numval", $def_args.numval);
Setattr($$, "storage", "%constant");
SetFlag($$, "feature:immutable");
add_symbols($$);
@ -3250,6 +3293,7 @@ c_decl : storage_class type declarator cpp_const initializer c_decl_tail {
Setattr($$,"parms",$declarator.parms);
Setattr($$,"value",$initializer.val);
if ($initializer.stringval) Setattr($$, "stringval", $initializer.stringval);
if ($initializer.numval) Setattr($$, "numval", $initializer.numval);
Setattr($$,"throws",$cpp_const.throws);
Setattr($$,"throw",$cpp_const.throwf);
Setattr($$,"noexcept",$cpp_const.nexcept);
@ -3481,6 +3525,7 @@ c_decl : storage_class type declarator cpp_const initializer c_decl_tail {
Setattr($$, "decl", NewStringEmpty());
Setattr($$, "value", $definetype.val);
if ($definetype.stringval) Setattr($$, "stringval", $definetype.stringval);
if ($definetype.numval) Setattr($$, "numval", $definetype.numval);
Setattr($$, "valuetype", type);
}
;
@ -3500,6 +3545,7 @@ c_decl_tail : SEMI {
Setattr($$,"parms",$declarator.parms);
Setattr($$,"value",$initializer.val);
if ($initializer.stringval) Setattr($$, "stringval", $initializer.stringval);
if ($initializer.numval) Setattr($$, "numval", $initializer.numval);
Setattr($$,"throws",$cpp_const.throws);
Setattr($$,"throw",$cpp_const.throwf);
Setattr($$,"noexcept",$cpp_const.nexcept);
@ -3813,9 +3859,12 @@ c_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
Delete(code);
}
}
if ($ctor_end.defarg) {
Setattr($$,"value",$ctor_end.defarg);
}
if ($ctor_end.defarg)
Setattr($$, "value", $ctor_end.defarg);
if ($ctor_end.stringdefarg)
Setattr($$, "stringval", $ctor_end.stringdefarg);
if ($ctor_end.numdefarg)
Setattr($$, "numval", $ctor_end.numdefarg);
Setattr($$,"throws",$ctor_end.throws);
Setattr($$,"throw",$ctor_end.throwf);
Setattr($$,"noexcept",$ctor_end.nexcept);
@ -4533,6 +4582,7 @@ templateparameter : templcpptype def_args {
Setline($$, cparse_line);
Setattr($$, "value", $def_args.val);
if ($def_args.stringval) Setattr($$, "stringval", $def_args.stringval);
if ($def_args.numval) Setattr($$, "numval", $def_args.numval);
}
| TEMPLATE LESSTHAN template_parms GREATERTHAN cpptype idcolon def_args {
$$ = NewParmWithoutFileLineInfo(NewStringf("template< %s > %s %s", ParmList_str_defaultargs($template_parms), $cpptype, $idcolon), $idcolon);
@ -4862,7 +4912,11 @@ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end {
}
SetFlag($$,"feature:new");
if ($ctor_end.defarg)
Setattr($$,"value",$ctor_end.defarg);
Setattr($$, "value", $ctor_end.defarg);
if ($ctor_end.stringdefarg)
Setattr($$, "stringval", $ctor_end.stringdefarg);
if ($ctor_end.numdefarg)
Setattr($$, "numval", $ctor_end.numdefarg);
} else {
$$ = 0;
Delete($storage_class);
@ -5233,9 +5287,12 @@ parm_no_dox : rawtype parameter_declarator {
$$ = NewParmWithoutFileLineInfo($rawtype,$parameter_declarator.id);
Setfile($$,cparse_file);
Setline($$,cparse_line);
if ($parameter_declarator.defarg) {
Setattr($$,"value",$parameter_declarator.defarg);
}
if ($parameter_declarator.defarg)
Setattr($$, "value", $parameter_declarator.defarg);
if ($parameter_declarator.stringdefarg)
Setattr($$, "stringval", $parameter_declarator.stringdefarg);
if ($parameter_declarator.numdefarg)
Setattr($$, "numval", $parameter_declarator.numdefarg);
}
| ELLIPSIS {
SwigType *t = NewString("v(...)");
@ -5314,6 +5371,7 @@ valparm : parm {
Setline($$,cparse_line);
Setattr($$,"value",$valexpr.val);
if ($valexpr.stringval) Setattr($$, "stringval", $valexpr.stringval);
if ($valexpr.numval) Setattr($$, "numval", $valexpr.numval);
}
;
@ -5359,14 +5417,20 @@ def_args : EQUAL definetype {
parameter_declarator : declarator def_args {
$$ = $declarator;
$$.defarg = $def_args.val;
$$.stringdefarg = $def_args.stringval;
$$.numdefarg = $def_args.numval;
}
| abstract_declarator def_args {
$$ = $abstract_declarator;
$$ = $abstract_declarator;
$$.defarg = $def_args.val;
$$.stringdefarg = $def_args.stringval;
$$.numdefarg = $def_args.numval;
}
| def_args {
$$ = default_decl;
$$.defarg = $def_args.val;
$$.stringdefarg = $def_args.stringval;
$$.numdefarg = $def_args.numval;
}
/* Member function pointers with qualifiers. eg.
int f(short (Funcs::*parm)(bool) const); */
@ -6491,6 +6555,9 @@ edecl : identifier {
if ($etype.stringval) {
Setattr($$, "enumstringval", $etype.stringval);
}
if ($etype.numval) {
Setattr($$, "enumnumval", $etype.numval);
}
Setattr($$,"value",$identifier);
Delete(type);
}
@ -6657,6 +6724,7 @@ valexpr : exprsimple
$$ = default_dtype;
$$.val = NewStringf("(%s)",$expr.val);
$$.stringval = Copy($expr.stringval);
$$.numval = Copy($expr.numval);
$$.type = $expr.type;
}
@ -6680,6 +6748,7 @@ valexpr : exprsimple
break;
}
$$.stringval = 0;
$$.numval = 0;
}
/* As well as C-style casts, this grammar rule currently also
* matches a binary operator with a LHS in parentheses for
@ -6707,6 +6776,7 @@ valexpr : exprsimple
SwigType_push($lhs.val,$pointer);
$$.val = NewStringf("(%s) %s", SwigType_str($lhs.val,0), $rhs.val);
$$.stringval = 0;
$$.numval = 0;
}
}
| LPAREN expr[lhs] AND RPAREN expr[rhs] %prec CAST {
@ -6716,6 +6786,7 @@ valexpr : exprsimple
SwigType_add_reference($lhs.val);
$$.val = NewStringf("(%s) %s", SwigType_str($lhs.val,0), $rhs.val);
$$.stringval = 0;
$$.numval = 0;
}
}
| LPAREN expr[lhs] LAND RPAREN expr[rhs] %prec CAST {
@ -6725,6 +6796,7 @@ valexpr : exprsimple
SwigType_add_rvalue_reference($lhs.val);
$$.val = NewStringf("(%s) %s", SwigType_str($lhs.val,0), $rhs.val);
$$.stringval = 0;
$$.numval = 0;
}
}
| LPAREN expr[lhs] pointer AND RPAREN expr[rhs] %prec CAST {
@ -6735,6 +6807,7 @@ valexpr : exprsimple
SwigType_add_reference($lhs.val);
$$.val = NewStringf("(%s) %s", SwigType_str($lhs.val,0), $rhs.val);
$$.stringval = 0;
$$.numval = 0;
}
}
| LPAREN expr[lhs] pointer LAND RPAREN expr[rhs] %prec CAST {
@ -6745,12 +6818,14 @@ valexpr : exprsimple
SwigType_add_rvalue_reference($lhs.val);
$$.val = NewStringf("(%s) %s", SwigType_str($lhs.val,0), $rhs.val);
$$.stringval = 0;
$$.numval = 0;
}
}
| AND expr {
$$ = $expr;
$$.val = NewStringf("&%s", $expr.val);
$$.stringval = 0;
$$.numval = 0;
/* Record the type code for expr so we can properly handle
* cases such as (6)&7 which get parsed using this rule then
* the rule for a C-style cast.
@ -6771,6 +6846,7 @@ valexpr : exprsimple
$$ = $expr;
$$.val = NewStringf("*%s", $expr.val);
$$.stringval = 0;
$$.numval = 0;
/* Record the type code for expr so we can properly handle
* cases such as (6)*7 which get parsed using this rule then
* the rule for a C-style cast.
@ -7038,6 +7114,22 @@ exprcompound : expr[lhs] PLUS expr[rhs] {
| MINUS expr[in] %prec UMINUS {
$$ = default_dtype;
$$.val = NewStringf("-%s",$in.val);
if ($in.numval) {
switch ($in.type) {
case T_CHAR: // Unsigned on some architectures.
case T_UCHAR:
case T_USHORT:
case T_UINT:
case T_ULONG:
case T_ULONGLONG:
// Avoid negative numval with an unsigned type.
break;
default:
$$.numval = NewStringf("-%s", $in.numval);
break;
}
Delete($in.numval);
}
$$.type = promote_type($in.type);
/* Record the type code for expr so we can properly handle
* cases such as (6)-7 which get parsed using this rule then
@ -7048,6 +7140,7 @@ exprcompound : expr[lhs] PLUS expr[rhs] {
| PLUS expr[in] %prec UMINUS {
$$ = default_dtype;
$$.val = NewStringf("+%s",$in.val);
$$.numval = $in.numval;
$$.type = promote_type($in.type);
/* Record the type code for expr so we can properly handle
* cases such as (6)+7 which get parsed using this rule then
@ -7331,10 +7424,14 @@ ctor_end : cpp_const ctor_initializer SEMI {
| EQUAL definetype SEMI {
$$ = default_decl;
$$.defarg = $definetype.val;
$$.stringdefarg = $definetype.stringval;
$$.numdefarg = $definetype.numval;
}
| exception_specification EQUAL default_delete SEMI {
$$ = default_decl;
$$.defarg = $default_delete.val;
$$.stringdefarg = $default_delete.stringval;
$$.numdefarg = $default_delete.numval;
$$.throws = $exception_specification.throws;
$$.throwf = $exception_specification.throwf;
$$.nexcept = $exception_specification.nexcept;

View File

@ -1373,10 +1373,7 @@ public:
// Deal with enum values that are not int
int swigtype = SwigType_type(Getattr(n, "type"));
if (swigtype == T_BOOL) {
const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0";
Setattr(n, "enumvalue", val);
} else if (swigtype == T_CHAR) {
if (swigtype == T_CHAR) {
String *enumstringval = Getattr(n, "enumstringval");
if (enumstringval) {
// Escape character literal for C#.
@ -1384,6 +1381,9 @@ public:
Setattr(n, "enumvalue", val);
Delete(val);
}
} else {
String *numval = Getattr(n, "enumnumval");
if (numval) Setattr(n, "enumvalue", numval);
}
{

View File

@ -946,10 +946,9 @@ public:
Setattr(n, "value", tmpValue);
// Deal with enum values that are not int
int swigtype = SwigType_type(Getattr(n, "type"));
if (swigtype == T_BOOL) {
const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0";
Setattr(n, "enumvalue", val);
{
String *numval = Getattr(n, "enumnumval");
if (numval) Setattr(n, "enumvalue", numval);
}
// Emit the enum item.

View File

@ -1826,52 +1826,28 @@ private:
return goComplexConstant(n, type);
} else if (Swig_storage_isstatic(n)) {
return goComplexConstant(n, type);
} else if (typecode == T_BOOL) {
if (Cmp(value, "true") != 0 && Cmp(value, "false") != 0) {
return goComplexConstant(n, type);
} else if (Getattr(n, "numval")) {
value = Getattr(n, "numval");
if (typecode == T_BOOL) {
copy = NewString(*Char(value) == '0' ? "false" : "true");
value = copy;
}
} else {
// Accept a 0x prefix, and strip combinations of u and l
// suffixes. Otherwise accept digits, decimal point, and
// exponentiation. Treat anything else as too complicated to
// handle as a Go constant.
// Currently numval only gets set for integer and boolean literals, so
// check for a floating point literal we can just use in Go here.
//
// Accept digits, decimal point, and exponentiation. Treat anything else
// as too complicated to handle as a Go constant.
char *p = Char(value);
int len = (int)strlen(p);
bool need_copy = false;
while (len > 0) {
char c = p[len - 1];
if (c != 'l' && c != 'L' && c != 'u' && c != 'U') {
break;
}
--len;
need_copy = true;
}
bool is_hex = false;
int i = 0;
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
i = 2;
is_hex = true;
}
for (; i < len; ++i) {
for (int i = 0; p[i]; ++i) {
switch (p[i]) {
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
break;
case 'a': case 'b': case 'c': case 'd': case 'f': case 'A': case 'B': case 'C': case 'D': case 'F':
if (!is_hex) {
return goComplexConstant(n, type);
}
break;
case '.': case 'e': case 'E': case '+': case '-':
break;
default:
return goComplexConstant(n, type);
}
}
if (need_copy) {
if (!copy) copy = Copy(value);
Replaceall(copy, p + len, "");
value = copy;
}
}
String *go_name = buildGoName(Getattr(n, "sym:name"), false, false);

View File

@ -1418,15 +1418,15 @@ public:
// Deal with enum values that are not int
int swigtype = SwigType_type(Getattr(n, "type"));
if (swigtype == T_BOOL) {
const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0";
Setattr(n, "enumvalue", val);
} else if (swigtype == T_CHAR) {
if (swigtype == T_CHAR) {
if (Getattr(n, "enumstringval")) {
String *val = NewStringf("'%(escape)s'", Getattr(n, "enumstringval"));
Setattr(n, "enumvalue", val);
Delete(val);
}
} else {
String *numval = Getattr(n, "enumnumval");
if (numval) Setattr(n, "enumvalue", numval);
}
{

View File

@ -488,7 +488,7 @@ public:
Append(decl_str, tex_name);
if (value) {
String *new_value = convertValue(value, Getattr(p, "type"));
String *new_value = convertValue(value, Getattr(p, "numval"), Getattr(p, "stringval"), Getattr(p, "type"));
if (new_value) {
value = new_value;
} else {
@ -517,23 +517,23 @@ public:
* Check if string v can be an Octave value literal,
* (eg. number or string), or translate it to an Octave literal.
* ------------------------------------------------------------ */
String *convertValue(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, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
return SwigType_ispointer(t) ? NewString("nil") : NewString("0");
if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0)
return NewString("true");
if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0)
return NewString("false");
String *convertValue(String *v, String *numval, String *stringval, SwigType *t) {
if (stringval) {
return stringval;
}
if (numval) {
if (SwigType_type(t) == T_BOOL) {
return NewString(*Char(numval) == '0' ? "false" : "true");
}
return numval;
}
if (Equal(v, "0") || Equal(v, "NULL") || Equal(v, "nullptr"))
return SwigType_ispointer(t) ? NewString("None") : NewString("0");
// FIXME: TRUE and FALSE are not standard and could be defined in other ways
if (Equal(v, "TRUE"))
return NewString("true");
if (Equal(v, "FALSE"))
return NewString("false");
return 0;
}

View File

@ -1797,7 +1797,7 @@ public:
// Write default value
if (value && !calling) {
String *new_value = convertValue(value, Getattr(p, "type"));
String *new_value = convertValue(value, Getattr(p, "numval"), Getattr(p, "stringval"), Getattr(p, "type"));
if (new_value) {
value = new_value;
} else {
@ -2035,32 +2035,12 @@ public:
String *convertIntegerValue(String *v, SwigType *resolved_type) {
const char *const s = Char(v);
char *end;
String *result = NIL;
// Check if this is an integer number in any base.
errno = 0;
long value = strtol(s, &end, 0);
if (errno == ERANGE || end == s)
if (errno == ERANGE || end == s || *end != '\0') {
return NIL;
if (*end != '\0') {
// If there is a suffix after the number, we can safely ignore "l"
// and (provided the number is unsigned) "u", and also combinations of
// these, but not anything else.
for (char *p = end; *p != '\0'; ++p) {
switch (*p) {
case 'l':
case 'L':
break;
case 'u':
case 'U':
if (value < 0)
return NIL;
break;
default:
return NIL;
}
}
}
// So now we are certain that we are indeed dealing with an integer
// that has a representation as long given by value.
@ -2073,30 +2053,14 @@ public:
}
#endif
if (Cmp(resolved_type, "bool") == 0)
if (Equal(resolved_type, "bool"))
// Allow integers as the default value for a bool parameter.
return NewString(value ? "True" : "False");
if (value == 0)
return NewString(SwigType_ispointer(resolved_type) ? "None" : "0");
// v may still be octal or hexadecimal:
const char *p = s;
if (*p == '+' || *p == '-')
++p;
if (*p == '0' && *(p+1) != 'x' && *(p+1) != 'X') {
// This must have been an octal number. This is the only case we
// cannot use in Python directly, since Python 2 and 3 use non-
// compatible representations.
result = NewString(*s == '-' ? "int(\"-" : "int(\"");
String *octal_string = NewStringWithSize(p, (int) (end - p));
Append(result, octal_string);
Append(result, "\", 8)");
Delete(octal_string);
return result;
}
result = *end == '\0' ? Copy(v) : NewStringWithSize(s, (int) (end - s));
return result;
return Copy(v);
}
/* ------------------------------------------------------------
@ -2151,30 +2115,36 @@ public:
* constant. Return an equivalent Python representation,
* or NIL if it isn't, or we are unsure.
* ------------------------------------------------------------ */
String *convertValue(String *v, SwigType *type) {
const char *const s = Char(v);
String *result = NIL;
String *convertValue(String *v, String *numval, String *stringval, SwigType *type) {
if (stringval) {
return NIL;
// FIXME: This needs more careful testing.
// return NewStringf("'%(escape)s'", stringval);
}
if (numval) {
SwigType *resolved_type = SwigType_typedef_resolve_all(type);
if (Equal(resolved_type, "bool")) {
Delete(resolved_type);
return NewString(*Char(numval) == '0' ? "False" : "True");
}
String *result = convertIntegerValue(numval, resolved_type);
Delete(resolved_type);
return result;
}
SwigType *resolved_type = SwigType_typedef_resolve_all(type);
result = convertIntegerValue(v, resolved_type);
String *result = convertDoubleValue(v);
if (!result) {
result = convertDoubleValue(v);
if (!result) {
if (Strcmp(v, "true") == 0)
result = NewString("True");
else if (Strcmp(v, "false") == 0)
result = NewString("False");
else if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
result = SwigType_ispointer(resolved_type) ? NewString("None") : NewString("0");
// This could also be an enum type, default value of which could be
// representable in Python if it doesn't include any scope (which could,
// but currently is not, translated).
else if (!Strchr(s, ':')) {
Node *lookup = Swig_symbol_clookup(v, 0);
if (lookup) {
if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0)
result = Copy(Getattr(lookup, "sym:name"));
}
if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
result = SwigType_ispointer(resolved_type) ? NewString("None") : NewString("0");
// This could also be an enum type, default value of which could be
// representable in Python if it doesn't include any scope (which could,
// but currently is not, translated).
else if (!Strchr(v, ':')) {
Node *lookup = Swig_symbol_clookup(v, 0);
if (lookup) {
if (Cmp(Getattr(lookup, "nodeType"), "enumitem") == 0)
result = Copy(Getattr(lookup, "sym:name"));
}
}
}
@ -2222,7 +2192,7 @@ public:
String *value = Getattr(p, "value");
if (value) {
String *convertedValue = convertValue(value, Getattr(p, "type"));
String *convertedValue = convertValue(value, Getattr(p, "numval"), Getattr(p, "stringval"), Getattr(p, "type"));
if (!convertedValue)
return false;
Delete(convertedValue);

View File

@ -1182,15 +1182,15 @@ int R::enumvalueDeclaration(Node *n) {
// Deal with enum values that are not int
int swigtype = SwigType_type(Getattr(n, "type"));
if (swigtype == T_BOOL) {
const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0";
Setattr(n, "enumvalue", val);
} else if (swigtype == T_CHAR) {
if (swigtype == T_CHAR) {
if (Getattr(n, "enumstringval")) {
String *val = NewStringf("'%(escape)s'", Getattr(n, "enumstringval"));
Setattr(n, "enumvalue", val);
Delete(val);
}
} else {
String *numval = Getattr(n, "enumnumval");
if (numval) Setattr(n, "enumvalue", numval);
}
if (GetFlag(parent, "scopedenum")) {

View File

@ -398,7 +398,7 @@ private:
}
if (value) {
String *new_value = convertValue(value, Getattr(p, "type"));
String *new_value = convertValue(value, Getattr(p, "numval"), Getattr(p, "stringval"), Getattr(p, "type"));
if (new_value) {
value = new_value;
} else {
@ -407,6 +407,9 @@ private:
value = Getattr(lookup, "sym:name");
}
Printf(doc, "=%s", value);
if (new_value)
Delete(new_value);
}
Delete(type_str);
Delete(made_name);
@ -768,21 +771,28 @@ private:
* Check if string v can be a Ruby value literal,
* (eg. number or string), or translate it to a Ruby literal.
* ------------------------------------------------------------ */
String *convertValue(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;
String *convertValue(String *v, String *numval, String *stringval, SwigType *type) {
if (stringval) {
return NewStringf("\"%(escape)s\"", stringval);
}
if (numval) {
SwigType *resolved_type = SwigType_typedef_resolve_all(type);
if (Equal(resolved_type, "bool")) {
Delete(resolved_type);
return NewString(*Char(numval) == '0' ? "False" : "True");
}
if (Strcmp(v, "NULL") == 0 || Strcmp(v, "nullptr") == 0)
return SwigType_ispointer(t) ? NewString("nil") : NewString("0");
if (Strcmp(v, "true") == 0 || Strcmp(v, "TRUE") == 0)
Delete(resolved_type);
if (SwigType_ispointer(type) && Equal(v, "0"))
return NewString("None");
return Copy(v);
}
if (v && Len(v) > 0) {
if (Equal(v, "NULL") || Equal(v, "nullptr"))
return SwigType_ispointer(type) ? NewString("nil") : NewString("0");
// FIXME: TRUE and FALSE are not standard and could be defined in other ways
if (Equal(v, "TRUE"))
return NewString("True");
if (Strcmp(v, "false") == 0 || Strcmp(v, "FALSE") == 0)
if (Equal(v, "FALSE"))
return NewString("False");
}
return 0;

View File

@ -355,7 +355,7 @@ int Swig_storage_isstatic(Node *n) {
*
* Takes a string object and produces a string with escape codes added to it.
* Octal escaping is used. The result is used for literal strings and characters
* in C/C++ and also Java and R.
* in C/C++ and also Java, Python, R and Ruby.
*
* The result is suitable for wrapping in single or double quotes to form a
* character or string literal.