summaryrefslogtreecommitdiffstatshomepage
path: root/py/parsenum.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/parsenum.c')
-rw-r--r--py/parsenum.c49
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)