Skip to content

Commit 503d611

Browse files
committed
py: Implement long int parsing in int(...).
Addresses issue adafruit#627.
1 parent 1d56759 commit 503d611

10 files changed

Lines changed: 52 additions & 46 deletions

File tree

py/emitnative.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ STATIC void emit_native_load_const_int(emit_t *emit, qstr qst) {
704704
DEBUG_printf("load_const_int %s\n", qstr_str(st));
705705
// for viper: load integer, check fits in 32 bits
706706
emit_native_pre(emit);
707-
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_obj_new_int_from_qstr, qst, REG_ARG_1);
707+
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_load_const_int, qst, REG_ARG_1);
708708
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
709709
}
710710

py/obj.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ mp_obj_t mp_obj_new_bool(bool value);
371371
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
372372
mp_obj_t mp_obj_new_int(machine_int_t value);
373373
mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
374-
mp_obj_t mp_obj_new_int_from_qstr(qstr qst);
374+
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base);
375375
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
376376
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already);
377377
mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
@@ -445,7 +445,7 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
445445

446446
// int
447447
// For long int, returns value truncated to machine_int_t
448-
machine_int_t mp_obj_int_get(mp_obj_t self_in);
448+
machine_int_t mp_obj_int_get(mp_const_obj_t self_in);
449449
#if MICROPY_ENABLE_FLOAT
450450
mp_float_t mp_obj_int_as_float(mp_obj_t self_in);
451451
#endif

py/objint.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
139139
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
140140
// Not a small int.
141141
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
142-
mp_obj_int_t *self = self_in;
142+
const mp_obj_int_t *self = self_in;
143143
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
144144
num = self->val;
145145
#else
@@ -225,7 +225,7 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
225225
}
226226

227227
// This is called only with strings whose value doesn't fit in SMALL_INT
228-
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
228+
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
229229
nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
230230
return mp_const_none;
231231
}
@@ -254,7 +254,7 @@ mp_obj_t mp_obj_new_int(machine_int_t value) {
254254
return mp_const_none;
255255
}
256256

257-
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
257+
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
258258
return MP_OBJ_SMALL_INT_VALUE(self_in);
259259
}
260260

py/objint_longlong.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,26 +162,22 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
162162
return o;
163163
}
164164

165-
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
166-
const char *s = qstr_str(qst);
167-
long long v;
168-
char *end;
169-
// TODO: this doesn't handle Python hacked 0o octal syntax
170-
v = strtoll(s, &end, 0);
171-
if (*end != 0) {
172-
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
173-
}
165+
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
166+
// TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated
167+
// TODO check overflow
174168
mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
175169
o->base.type = &mp_type_int;
176-
o->val = v;
170+
char *endptr;
171+
o->val = strtoll(*str, &endptr, base);
172+
*str = endptr;
177173
return o;
178174
}
179175

180-
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
176+
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
181177
if (MP_OBJ_IS_SMALL_INT(self_in)) {
182178
return MP_OBJ_SMALL_INT_VALUE(self_in);
183179
} else {
184-
mp_obj_int_t *self = self_in;
180+
const mp_obj_int_t *self = self_in;
185181
return self->val;
186182
}
187183
}

py/objint_mpz.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -260,26 +260,18 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
260260
return mp_obj_new_int_from_ll(value);
261261
}
262262

263-
mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
263+
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
264264
mp_obj_int_t *o = mp_obj_int_new_mpz();
265-
uint len;
266-
const char* str = (const char*)qstr_data(qst, &len);
267-
int base = 0;
268-
int skip = mp_parse_num_base(str, len, &base);
269-
str += skip;
270-
len -= skip;
271-
uint n = mpz_set_from_str(&o->mpz, str, len, false, base);
272-
if (n != len) {
273-
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
274-
}
265+
uint n = mpz_set_from_str(&o->mpz, *str, len, neg, base);
266+
*str += n;
275267
return o;
276268
}
277269

278-
machine_int_t mp_obj_int_get(mp_obj_t self_in) {
270+
machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
279271
if (MP_OBJ_IS_SMALL_INT(self_in)) {
280272
return MP_OBJ_SMALL_INT_VALUE(self_in);
281273
} else {
282-
mp_obj_int_t *self = self_in;
274+
const mp_obj_int_t *self = self_in;
283275
return mpz_as_int(&self->mpz);
284276
}
285277
}

py/parsenum.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
4343
const char *restrict top = str + len;
4444
bool neg = false;
45+
mp_obj_t ret_val;
4546

4647
// check radix base
4748
if ((base != 0 && base < 2) || base > 36) {
@@ -96,16 +97,20 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
9697
}
9798
}
9899

99-
// check we parsed something
100-
if (str == str_val_start) {
101-
goto value_error;
102-
}
103-
104100
// negate value if needed
105101
if (neg) {
106102
int_val = -int_val;
107103
}
108104

105+
// create the small int
106+
ret_val = MP_OBJ_NEW_SMALL_INT(int_val);
107+
108+
have_ret_val:
109+
// check we parsed something
110+
if (str == str_val_start) {
111+
goto value_error;
112+
}
113+
109114
// skip trailing space
110115
for (; str < top && unichar_isspace(*str); str++) {
111116
}
@@ -116,14 +121,19 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
116121
}
117122

118123
// return the object
119-
return MP_OBJ_NEW_SMALL_INT(int_val);
120-
121-
value_error:
122-
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str));
124+
return ret_val;
123125

124126
overflow:
125-
// TODO reparse using bignum
126-
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer"));
127+
// reparse using long int
128+
{
129+
const char *s2 = str_val_start;
130+
ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
131+
str = s2;
132+
goto have_ret_val;
133+
}
134+
135+
value_error:
136+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid syntax for integer with base %d: '%s'", base, str));
127137
}
128138

129139
#define PARSE_DEC_IN_INTG (1)

py/runtime.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ void mp_deinit(void) {
9898
#endif
9999
}
100100

101+
mp_obj_t mp_load_const_int(qstr qstr) {
102+
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
103+
uint len;
104+
const byte* data = qstr_data(qstr, &len);
105+
return mp_parse_num_integer((const char*)data, len, 0);
106+
}
107+
101108
mp_obj_t mp_load_const_dec(qstr qstr) {
102109
DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
103110
uint len;
@@ -1147,8 +1154,8 @@ void *m_malloc_fail(int num_bytes) {
11471154

11481155
// these must correspond to the respective enum
11491156
void *const mp_fun_table[MP_F_NUMBER_OF] = {
1157+
mp_load_const_int,
11501158
mp_load_const_dec,
1151-
mp_obj_new_int_from_qstr,
11521159
mp_load_const_str,
11531160
mp_load_name,
11541161
mp_load_global,

py/runtime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ void mp_delete_global(qstr qstr);
7777
mp_obj_t mp_unary_op(int op, mp_obj_t arg);
7878
mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs);
7979

80+
mp_obj_t mp_load_const_int(qstr qstr);
8081
mp_obj_t mp_load_const_dec(qstr qstr);
8182
mp_obj_t mp_load_const_str(qstr qstr);
8283
mp_obj_t mp_load_const_bytes(qstr qstr);

py/runtime0.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ typedef enum {
9696
} mp_binary_op_t;
9797

9898
typedef enum {
99-
MP_F_LOAD_CONST_DEC = 0,
100-
MP_F_LOAD_CONST_INT,
99+
MP_F_LOAD_CONST_INT = 0,
100+
MP_F_LOAD_CONST_DEC,
101101
MP_F_LOAD_CONST_STR,
102102
MP_F_LOAD_NAME,
103103
MP_F_LOAD_GLOBAL,

py/vm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_
312312

313313
ENTRY(MP_BC_LOAD_CONST_INT): {
314314
DECODE_QSTR;
315-
PUSH(mp_obj_new_int_from_qstr(qst));
315+
PUSH(mp_load_const_int(qst));
316316
DISPATCH();
317317
}
318318

0 commit comments

Comments
 (0)