diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/builtin.c | 8 | ||||
-rw-r--r-- | py/compile.c | 30 | ||||
-rw-r--r-- | py/intdivmod.c | 24 | ||||
-rw-r--r-- | py/intdivmod.h | 4 | ||||
-rw-r--r-- | py/malloc.c | 6 | ||||
-rw-r--r-- | py/misc.h | 1 | ||||
-rw-r--r-- | py/obj.c | 11 | ||||
-rw-r--r-- | py/obj.h | 2 | ||||
-rw-r--r-- | py/objbool.c | 10 | ||||
-rw-r--r-- | py/objdict.c | 22 | ||||
-rw-r--r-- | py/objexcept.c | 3 | ||||
-rw-r--r-- | py/objint.c | 45 | ||||
-rw-r--r-- | py/objint.h | 7 | ||||
-rw-r--r-- | py/objint_longlong.c | 16 | ||||
-rw-r--r-- | py/objint_mpz.c | 22 | ||||
-rw-r--r-- | py/objstr.c | 162 | ||||
-rw-r--r-- | py/py.mk | 2 | ||||
-rw-r--r-- | py/runtime.c | 65 | ||||
-rw-r--r-- | py/smallint.c | 53 | ||||
-rw-r--r-- | py/smallint.h | 5 | ||||
-rw-r--r-- | py/vm.c | 4 |
21 files changed, 331 insertions, 171 deletions
diff --git a/py/builtin.c b/py/builtin.c index 67b0e46a66..145bc65b14 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -231,7 +231,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) { mp_obj_t max_obj = NULL; mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) { - if (max_obj == NULL || mp_obj_less(max_obj, item)) { + if (max_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, max_obj, item)) { max_obj = item; } } @@ -243,7 +243,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) { // given many args mp_obj_t max_obj = args[0]; for (int i = 1; i < n_args; i++) { - if (mp_obj_less(max_obj, args[i])) { + if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i])) { max_obj = args[i]; } } @@ -260,7 +260,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) { mp_obj_t min_obj = NULL; mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) { - if (min_obj == NULL || mp_obj_less(item, min_obj)) { + if (min_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, item, min_obj)) { min_obj = item; } } @@ -272,7 +272,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) { // given many args mp_obj_t min_obj = args[0]; for (int i = 1; i < n_args; i++) { - if (mp_obj_less(args[i], min_obj)) { + if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj)) { min_obj = args[i]; } } diff --git a/py/compile.c b/py/compile.c index 3273abe40e..6ede842397 100644 --- a/py/compile.c +++ b/py/compile.c @@ -17,7 +17,7 @@ #include "obj.h" #include "compile.h" #include "runtime.h" -#include "intdivmod.h" +#include "smallint.h" // TODO need to mangle __attr names @@ -115,38 +115,38 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) { machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]); machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]); - machine_int_t res; if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) { - res = arg0 + arg1; + arg0 += arg1; } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) { - res = arg0 - arg1; + arg0 -= arg1; } else { // shouldn't happen assert(0); - res = 0; } - if (MP_PARSE_FITS_SMALL_INT(res)) { - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, res); + if (MP_PARSE_FITS_SMALL_INT(arg0)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0); } } break; case PN_term: if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) { - int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]); - int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]); + machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]); + machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]); if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { -#if MICROPY_EMIT_CPYTHON - // can overflow; enabled only to compare with CPython - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 * arg1); -#endif + if (!mp_small_int_mul_overflow(arg0, arg1)) { + arg0 *= arg1; + if (MP_PARSE_FITS_SMALL_INT(arg0)) { + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0); + } + } } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) { ; // pass } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) { - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_modulo(arg0, arg1)); + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1)); } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) { if (arg1 != 0) { - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_floor_divide(arg0, arg1)); + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1)); } } else { // shouldn't happen diff --git a/py/intdivmod.c b/py/intdivmod.c deleted file mode 100644 index 4cb363b511..0000000000 --- a/py/intdivmod.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "mpconfig.h" - -machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor) { - machine_int_t lsign = (dividend >= 0) ? 1 :-1; - machine_int_t rsign = (divisor >= 0) ? 1 :-1; - dividend %= divisor; - if (lsign != rsign) { - dividend += divisor; - } - return dividend; -} - - -machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom) { - machine_int_t lsign = num > 0 ? 1 : -1; - machine_int_t rsign = denom > 0 ? 1 : -1; - if (lsign == -1) {num *= -1;} - if (rsign == -1) {denom *= -1;} - if (lsign != rsign){ - return - ( num + denom - 1) / denom; - } else { - return num / denom; - } -} diff --git a/py/intdivmod.h b/py/intdivmod.h deleted file mode 100644 index 7716bd21e9..0000000000 --- a/py/intdivmod.h +++ /dev/null @@ -1,4 +0,0 @@ -// Functions for integer modulo and floor division - -machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor); -machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom); diff --git a/py/malloc.c b/py/malloc.c index 27eaac1088..4cf1b71db0 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -41,8 +41,7 @@ void *m_malloc(int num_bytes) { } void *ptr = malloc(num_bytes); if (ptr == NULL) { - printf("could not allocate memory, allocating %d bytes\n", num_bytes); - return NULL; + return m_malloc_fail(num_bytes); } #if MICROPY_MEM_STATS total_bytes_allocated += num_bytes; @@ -68,8 +67,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) { } void *new_ptr = realloc(ptr, new_num_bytes); if (new_ptr == NULL) { - printf("could not allocate memory, reallocating %d bytes\n", new_num_bytes); - return NULL; + return m_malloc_fail(new_num_bytes); } #if MICROPY_MEM_STATS // At first thought, "Total bytes allocated" should only grow, @@ -36,6 +36,7 @@ void *m_malloc(int num_bytes); void *m_malloc0(int num_bytes); void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes); void m_free(void *ptr, int num_bytes); +void *m_malloc_fail(int num_bytes); int m_get_total_bytes_allocated(void); int m_get_current_bytes_allocated(void); @@ -178,17 +178,6 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } } -bool mp_obj_less(mp_obj_t o1, mp_obj_t o2) { - if (MP_OBJ_IS_SMALL_INT(o1) && MP_OBJ_IS_SMALL_INT(o2)) { - mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1); - mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2); - return i1 < i2; - } else { - assert(0); - return false; - } -} - machine_int_t mp_obj_get_int(mp_obj_t arg) { if (arg == mp_const_false) { return 0; @@ -306,6 +306,7 @@ extern const struct _mp_obj_bool_t mp_const_false_obj; extern const struct _mp_obj_bool_t mp_const_true_obj; extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj; extern const struct _mp_obj_ellipsis_t mp_const_ellipsis_obj; +extern const struct _mp_obj_exception_t mp_const_MemoryError_obj; extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj; // General API for objects @@ -356,7 +357,6 @@ int mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); machine_int_t mp_obj_hash(mp_obj_t o_in); bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2); -bool mp_obj_less(mp_obj_t o1, mp_obj_t o2); machine_int_t mp_obj_get_int(mp_obj_t arg); bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value); diff --git a/py/objbool.c b/py/objbool.c index 6afb6e950d..84aa5a781a 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -1,3 +1,4 @@ +#include <stdlib.h> #include "nlr.h" #include "misc.h" @@ -43,12 +44,21 @@ STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) { } } +STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) { + return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in); + } + // operation not supported + return MP_OBJ_NULL; +} + const mp_obj_type_t mp_type_bool = { { &mp_type_type }, .name = MP_QSTR_bool, .print = bool_print, .make_new = bool_make_new, .unary_op = bool_unary_op, + .binary_op = bool_binary_op, }; const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false}; diff --git a/py/objdict.c b/py/objdict.c index afd1d0da0f..ad8c137489 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -32,8 +32,26 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env } STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { - // TODO create from an iterable! - return mp_obj_new_dict(0); + mp_obj_t dict; + switch (n_args) { + case 0: + dict = mp_obj_new_dict(0); + break; + + case 1: + // TODO create dict from an iterable! + assert(false); + + default: + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "dict takes at most 1 argument")); + } + + // add to the new dict any keyword args + for (const mp_obj_t *a = args + n_args; n_kw > 0; n_kw--, a += 2) { + mp_obj_dict_store(dict, a[0], a[1]); + } + + return dict; } STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) { diff --git a/py/objexcept.c b/py/objexcept.c index 0efc21d360..11651025f0 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -17,6 +17,9 @@ typedef struct _mp_obj_exception_t { mp_obj_tuple_t args; } mp_obj_exception_t; +// Instance of MemoryError exception - needed by mp_malloc_fail +const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}}; + // Instance of GeneratorExit exception - needed by generator.close() // This would belong to objgenerator.c, but to keep mp_obj_exception_t // definition module-private so far, have it here. diff --git a/py/objint.c b/py/objint.c index 3a853eab80..1ea6a4f647 100644 --- a/py/objint.c +++ b/py/objint.c @@ -17,9 +17,8 @@ #include <math.h> #endif -// This dispatcher function is expected to be independent of the implementation -// of long int -STATIC mp_obj_t int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { +// This dispatcher function is expected to be independent of the implementation of long int +STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // TODO check n_kw == 0 switch (n_args) { @@ -56,26 +55,20 @@ STATIC mp_obj_t int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE -void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { if (MP_OBJ_IS_SMALL_INT(self_in)) { print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in)); } } // This is called for operations on SMALL_INT that are not handled by mp_unary_op -mp_obj_t int_unary_op(int op, mp_obj_t o_in) { +mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { return MP_OBJ_NULL; } // This is called for operations on SMALL_INT that are not handled by mp_binary_op -mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { - if (op == MP_BINARY_OP_MULTIPLY) { - if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { - // multiply is commutative for these types, so delegate to them - return mp_binary_op(op, rhs_in, lhs_in); - } - } - return MP_OBJ_NULL; +mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } // This is called only with strings whose value doesn't fit in SMALL_INT @@ -124,11 +117,29 @@ mp_float_t mp_obj_int_as_float(mp_obj_t self_in) { #endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE +// This dispatcher function is expected to be independent of the implementation of long int +// It handles the extra cases for integer-like arithmetic +mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + if (rhs_in == mp_const_false) { + // false acts as 0 + return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0)); + } else if (rhs_in == mp_const_true) { + // true acts as 0 + return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1)); + } else if (op == MP_BINARY_OP_MULTIPLY) { + if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { + // multiply is commutative for these types, so delegate to them + return mp_binary_op(op, rhs_in, lhs_in); + } + } + return MP_OBJ_NULL; +} + const mp_obj_type_t mp_type_int = { { &mp_type_type }, .name = MP_QSTR_int, - .print = int_print, - .make_new = int_make_new, - .unary_op = int_unary_op, - .binary_op = int_binary_op, + .print = mp_obj_int_print, + .make_new = mp_obj_int_make_new, + .unary_op = mp_obj_int_unary_op, + .binary_op = mp_obj_int_binary_op, }; diff --git a/py/objint.h b/py/objint.h index 53ee49e7db..fe7f60a2d4 100644 --- a/py/objint.h +++ b/py/objint.h @@ -7,6 +7,7 @@ typedef struct _mp_obj_int_t { #endif } mp_obj_int_t; -void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind); -mp_obj_t int_unary_op(int op, mp_obj_t o_in); -mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); +void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind); +mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in); +mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); +mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index acbd477a9a..f4a65ce1d4 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -21,7 +21,7 @@ #define SUFFIX "" #endif -void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { if (MP_OBJ_IS_SMALL_INT(self_in)) { print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in)); } else { @@ -30,7 +30,7 @@ void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj } } -mp_obj_t int_unary_op(int op, mp_obj_t o_in) { +mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { mp_obj_int_t *o = o_in; switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(o->val != 0); @@ -41,7 +41,7 @@ mp_obj_t int_unary_op(int op, mp_obj_t o_in) { } } -mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { +mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { long long lhs_val; long long rhs_val; @@ -58,14 +58,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) { rhs_val = ((mp_obj_int_t*)rhs_in)->val; } else { - if (op == MP_BINARY_OP_MULTIPLY) { - if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { - // multiply is commutative for these types, so delegate to them - return mp_binary_op(op, rhs_in, lhs_in); - } - } - // unsupported operation/type - return MP_OBJ_NULL; + // delegate to generic function to check for extra cases + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } switch (op) { diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 25a069cf93..f4504415d6 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -22,7 +22,7 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { return o; } -void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { if (MP_OBJ_IS_SMALL_INT(self_in)) { print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in)); } else { @@ -34,7 +34,7 @@ void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj } } -mp_obj_t int_unary_op(int op, mp_obj_t o_in) { +mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { mp_obj_int_t *o = o_in; switch (op) { case MP_UNARY_OP_BOOL: return MP_BOOL(!mpz_is_zero(&o->mpz)); @@ -45,7 +45,7 @@ mp_obj_t int_unary_op(int op, mp_obj_t o_in) { } } -mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { +mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { const mpz_t *zlhs; const mpz_t *zrhs; mpz_t z_int; @@ -75,14 +75,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); #endif } else { - if (op == MP_BINARY_OP_MULTIPLY) { - if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) { - // multiply is commutative for these types, so delegate to them - return mp_binary_op(op, rhs_in, lhs_in); - } - } - // unsupported operation/type - return MP_OBJ_NULL; + // delegate to generic function to check for extra cases + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } if (0) { @@ -113,7 +107,7 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); - if (zlhs->neg != zrhs->neg) { + if (zlhs->neg != zrhs->neg) { if (!mpz_is_zero(&rem)) { mpz_t mpzone; mpz_init_from_int(&mpzone, -1); mpz_add_inpl(&res->mpz, &res->mpz, &mpzone); @@ -127,8 +121,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mpz_t quo; mpz_init_zero(&quo); mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); mpz_deinit(&quo); - // Check signs and do Python style modulo - if (zlhs->neg != zrhs->neg) { + // Check signs and do Python style modulo + if (zlhs->neg != zrhs->neg) { mpz_add_inpl(&res->mpz, &res->mpz, zrhs); } break; diff --git a/py/objstr.c b/py/objstr.c index a3f2d6075d..74f993a0b1 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -894,32 +894,162 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t assert(MP_OBJ_IS_STR(pattern)); GET_STR_DATA_LEN(pattern, str, len); + const byte *start_str = str; int arg_i = 0; vstr_t *vstr = vstr_new(); + pfenv_t pfenv_vstr; + pfenv_vstr.data = vstr; + pfenv_vstr.print_strn = pfenv_vstr_add_strn; + for (const byte *top = str + len; str < top; str++) { + if (*str != '%') { + vstr_add_char(vstr, *str); + continue; + } + if (++str >= top) { + break; + } if (*str == '%') { - if (++str >= top) { - break; - } - if (*str == '%') { - vstr_add_char(vstr, '%'); + vstr_add_char(vstr, '%'); + continue; + } + if (arg_i >= n_args) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string")); + } + int flags = 0; + char fill = ' '; + bool alt = false; + while (str < top) { + if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST; + else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN; + else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN; + else if (*str == '#') alt = true; + else if (*str == '0') { + flags |= PF_FLAG_PAD_AFTER_SIGN; + fill = '0'; + } else break; + str++; + } + // parse width, if it exists + int width = 0; + if (str < top) { + if (*str == '*') { + width = mp_obj_get_int(args[arg_i++]); + str++; } else { - if (arg_i >= n_args) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string")); + for (; str < top && '0' <= *str && *str <= '9'; str++) { + width = width * 10 + *str - '0'; } - switch (*str) { - case 's': - mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_STR); - break; - case 'r': - mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_REPR); + } + } + int prec = -1; + if (str < top && *str == '.') { + if (++str < top) { + if (*str == '*') { + prec = mp_obj_get_int(args[arg_i++]); + str++; + } else { + prec = 0; + for (; str < top && '0' <= *str && *str <= '9'; str++) { + prec = prec * 10 + *str - '0'; + } + } + } + } + + if (str >= top) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format")); + } + mp_obj_t arg = args[arg_i]; + switch (*str) { + case 'c': + if (MP_OBJ_IS_STR(arg)) { + uint len; + const char *s = mp_obj_str_get_data(arg, &len); + if (len != 1) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "%c requires int or char")); break; + } + pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width); + break; + } + if (arg_looks_integer(arg)) { + char ch = mp_obj_get_int(arg); + pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, ' ', width); + break; + } +#if MICROPY_ENABLE_FLOAT + // This is what CPython reports, so we report the same. + if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float")); + + } +#endif + nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required")); + break; + + case 'd': + case 'i': + case 'u': + pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 10, 'a', flags, fill, width); + break; + +#if MICROPY_ENABLE_FLOAT + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), *str, flags, fill, width, prec); + break; +#endif + + case 'o': + if (alt) { + flags |= PF_FLAG_SHOW_PREFIX; + } + pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 8, 'a', flags, fill, width); + break; + + case 'r': + case 's': + { + vstr_t *arg_vstr = vstr_new(); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, + arg_vstr, arg, *str == 'r' ? PRINT_REPR : PRINT_STR); + uint len = vstr_len(arg_vstr); + if (prec < 0) { + prec = len; + } + if (len > prec) { + len = prec; } - arg_i++; + pfenv_print_strn(&pfenv_vstr, vstr_str(arg_vstr), len, flags, ' ', width); + vstr_free(arg_vstr); + break; } - } else { - vstr_add_char(vstr, *str); + + case 'x': + if (alt) { + flags |= PF_FLAG_SHOW_PREFIX; + } + pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'a', flags, fill, width); + break; + + case 'X': + if (alt) { + flags |= PF_FLAG_SHOW_PREFIX; + } + pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'A', flags, fill, width); + break; + + default: + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "unsupported format character '%c' (0x%x) at index %d", + *str, *str, str - start_str)); } + arg_i++; } if (arg_i != n_args) { @@ -84,7 +84,7 @@ PY_O_BASENAME = \ vm.o \ showbc.o \ repl.o \ - intdivmod.o \ + smallint.o \ pfenv.o \ # prepend the build destination prefix to the py object files diff --git a/py/runtime.c b/py/runtime.c index d9e2298c4c..a5f45a2fb4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -16,7 +16,7 @@ #include "builtin.h" #include "builtintables.h" #include "bc.h" -#include "intdivmod.h" +#include "smallint.h" #include "objgenerator.h" #if 0 // print debugging info @@ -289,7 +289,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { // If long long type exists and is larger than machine_int_t, then // we can use the following code to perform overflow-checked multiplication. - // Otherwise (eg in x64 case) we must use the branching code below. + // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow. #if 0 // compute result using long long precision long long res = (long long)lhs_val * (long long)rhs_val; @@ -302,36 +302,14 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } #endif - if (lhs_val > 0) { // lhs_val is positive - if (rhs_val > 0) { // lhs_val and rhs_val are positive - if (lhs_val > (MP_SMALL_INT_MAX / rhs_val)) { - goto mul_overflow; - } - } else { // lhs_val positive, rhs_val nonpositive - if (rhs_val < (MP_SMALL_INT_MIN / lhs_val)) { - goto mul_overflow; - } - } // lhs_val positive, rhs_val nonpositive - } else { // lhs_val is nonpositive - if (rhs_val > 0) { // lhs_val is nonpositive, rhs_val is positive - if (lhs_val < (MP_SMALL_INT_MIN / rhs_val)) { - goto mul_overflow; - } - } else { // lhs_val and rhs_val are nonpositive - if (lhs_val != 0 && rhs_val < (MP_SMALL_INT_MAX / lhs_val)) { - goto mul_overflow; - } - } // End if lhs_val and rhs_val are nonpositive - } // End if lhs_val is nonpositive - - // use standard precision - return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); - - mul_overflow: - // use higher precision - lhs = mp_obj_new_int_from_ll(lhs_val); - goto generic_binary_op; - + if (mp_small_int_mul_overflow(lhs_val, rhs_val)) { + // use higher precision + lhs = mp_obj_new_int_from_ll(lhs_val); + goto generic_binary_op; + } else { + // use standard precision + return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); + } break; } case MP_BINARY_OP_FLOOR_DIVIDE: @@ -339,7 +317,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { if (rhs_val == 0) { goto zero_division; } - lhs_val = python_floor_divide(lhs_val, rhs_val); + lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val); break; #if MICROPY_ENABLE_FLOAT @@ -352,11 +330,11 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { #endif case MP_BINARY_OP_MODULO: - case MP_BINARY_OP_INPLACE_MODULO: - { - lhs_val = python_modulo(lhs_val, rhs_val); + case MP_BINARY_OP_INPLACE_MODULO: { + lhs_val = mp_small_int_modulo(lhs_val, rhs_val); break; } + case MP_BINARY_OP_POWER: case MP_BINARY_OP_INPLACE_POWER: if (rhs_val < 0) { @@ -370,21 +348,19 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { machine_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { - machine_int_t old = ans; - ans *= lhs_val; - if (ans < old) { + if (mp_small_int_mul_overflow(ans, lhs_val)) { goto power_overflow; } + ans *= lhs_val; } if (rhs_val == 1) { break; } rhs_val /= 2; - machine_int_t old = lhs_val; - lhs_val *= lhs_val; - if (lhs_val < old) { + if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { goto power_overflow; } + lhs_val *= lhs_val; } lhs_val = ans; } @@ -1034,6 +1010,11 @@ void mp_globals_set(mp_map_t *m) { map_globals = m; } +void *m_malloc_fail(int num_bytes) { + DEBUG_printf("memory allocation failed, allocating %d bytes\n", num_bytes); + nlr_jump((mp_obj_t)&mp_const_MemoryError_obj); +} + // these must correspond to the respective enum void *const mp_fun_table[MP_F_NUMBER_OF] = { mp_load_const_dec, diff --git a/py/smallint.c b/py/smallint.c new file mode 100644 index 0000000000..ac0cf2f5f9 --- /dev/null +++ b/py/smallint.c @@ -0,0 +1,53 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" + +bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) { + // Check for multiply overflow; see CERT INT32-C + if (x > 0) { // x is positive + if (y > 0) { // x and y are positive + if (x > (MP_SMALL_INT_MAX / y)) { + return true; + } + } else { // x positive, y nonpositive + if (y < (MP_SMALL_INT_MIN / x)) { + return true; + } + } // x positive, y nonpositive + } else { // x is nonpositive + if (y > 0) { // x is nonpositive, y is positive + if (x < (MP_SMALL_INT_MIN / y)) { + return true; + } + } else { // x and y are nonpositive + if (x != 0 && y < (MP_SMALL_INT_MAX / x)) { + return true; + } + } // End if x and y are nonpositive + } // End if x is nonpositive + return false; +} + +machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor) { + machine_int_t lsign = (dividend >= 0) ? 1 :-1; + machine_int_t rsign = (divisor >= 0) ? 1 :-1; + dividend %= divisor; + if (lsign != rsign) { + dividend += divisor; + } + return dividend; +} + + +machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom) { + machine_int_t lsign = num > 0 ? 1 : -1; + machine_int_t rsign = denom > 0 ? 1 : -1; + if (lsign == -1) {num *= -1;} + if (rsign == -1) {denom *= -1;} + if (lsign != rsign){ + return - ( num + denom - 1) / denom; + } else { + return num / denom; + } +} diff --git a/py/smallint.h b/py/smallint.h new file mode 100644 index 0000000000..14234fa7b8 --- /dev/null +++ b/py/smallint.h @@ -0,0 +1,5 @@ +// Functions for small integer arithmetic + +bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y); +machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor); +machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom); @@ -849,8 +849,8 @@ yield: // set file and line number that the exception occurred at // TODO: don't set traceback for exceptions re-raised by END_FINALLY. // But consider how to handle nested exceptions. - // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj) - if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj) { + // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj) + if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) { machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24); qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24); qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24); |