diff options
Diffstat (limited to 'py/parsenum.c')
-rw-r--r-- | py/parsenum.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/py/parsenum.c b/py/parsenum.c index d3cb821a13..9729ffe64a 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -34,6 +34,7 @@ #include "obj.h" #include "parsenumbase.h" #include "parsenum.h" +#include "smallint.h" #if MICROPY_ENABLE_FLOAT #include <math.h> @@ -42,6 +43,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { const char *restrict top = str + len; bool neg = false; + mp_obj_t ret_val; // check radix base if ((base != 0 && base < 2) || base > 36) { @@ -69,16 +71,16 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { machine_int_t int_val = 0; const char *restrict str_val_start = str; for (; str < top; str++) { - machine_int_t old_val = int_val; + // get next digit as a value int dig = *str; if (unichar_isdigit(dig) && dig - '0' < base) { // 0-9 digit - int_val = base * int_val + dig - '0'; + dig = dig - '0'; } else if (base == 16) { dig |= 0x20; if ('a' <= dig && dig <= 'f') { // a-f hex digit - int_val = base * int_val + dig - 'a' + 10; + dig = dig - 'a' + 10; } else { // unknown character break; @@ -87,25 +89,31 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { // unknown character break; } - if (int_val < old_val) { - // If new value became less than previous, it's overflow + + // add next digi and check for overflow + if (mp_small_int_mul_overflow(int_val, base)) { goto overflow; - } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) { - // If signed number changed sign - it's overflow + } + int_val = int_val * base + dig; + if (!MP_SMALL_INT_FITS(int_val)) { goto overflow; } } - // check we parsed something - if (str == str_val_start) { - goto value_error; - } - // negate value if needed if (neg) { int_val = -int_val; } + // create the small int + ret_val = MP_OBJ_NEW_SMALL_INT(int_val); + +have_ret_val: + // check we parsed something + if (str == str_val_start) { + goto value_error; + } + // skip trailing space for (; str < top && unichar_isspace(*str); str++) { } @@ -116,14 +124,19 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { } // return the object - return MP_OBJ_NEW_SMALL_INT(int_val); - -value_error: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str)); + return ret_val; overflow: - // TODO reparse using bignum - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer")); + // reparse using long int + { + const char *s2 = str_val_start; + ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base); + str = s2; + goto have_ret_val; + } + +value_error: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d: '%s'", base, str)); } #define PARSE_DEC_IN_INTG (1) |