mirror of https://github.com/swig/swig
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:
parent
9c8186745b
commit
9cba248bec
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue