diff options
106 files changed, 1962 insertions, 688 deletions
@@ -38,9 +38,9 @@ The Unix version ---------------- The "unix" port requires a standard Unix environment with gcc and GNU make. -x86 and x64 architectures are supported (i.e. x86 32- and 64-bit). ARM to -be confirmed. Porting to other architectures require writing some assembly -code for the exception handling. +x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well +as ARM. Porting to other architectures require writing some assembly code +for the exception handling. To build: diff --git a/py/builtin.c b/py/builtin.c index 67b0e46a6..22c5ecfde 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -141,7 +141,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { byte str[1] = {ord}; return mp_obj_new_str(str, 1, true); } else { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)")); } } @@ -194,7 +194,7 @@ STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) { args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2); return mp_obj_new_tuple(2, args); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in))); } } @@ -216,7 +216,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter); STATIC mp_obj_t mp_builtin_len(mp_obj_t o_in) { mp_obj_t len = mp_obj_len_maybe(o_in); if (len == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); } else { return len; } @@ -231,19 +231,19 @@ 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; } } if (max_obj == NULL) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence")); } return max_obj; } else { // 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,19 +260,19 @@ 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; } } if (min_obj == NULL) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence")); } return min_obj; } else { // 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]; } } @@ -285,7 +285,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min); STATIC mp_obj_t mp_builtin_next(mp_obj_t o) { mp_obj_t ret = mp_iternext_allow_raise(o); if (ret == MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception(&mp_type_StopIteration)); + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -301,7 +301,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { // TODO unicode return mp_obj_new_int(((const byte*)str)[0]); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len)); } } @@ -383,7 +383,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { assert(n_args >= 1); if (n_args > 1) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "must use keyword argument for key function")); } mp_obj_t self = mp_type_list.make_new((mp_obj_t)&mp_type_list, 1, 0, args); @@ -400,9 +400,13 @@ STATIC mp_obj_t mp_builtin_id(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_builtin_id); -STATIC mp_obj_t mp_builtin_getattr(mp_obj_t o_in, mp_obj_t attr) { - assert(MP_OBJ_IS_QSTR(attr)); - return mp_load_attr(o_in, MP_OBJ_QSTR_VALUE(attr)); +STATIC mp_obj_t mp_builtin_getattr(uint n_args, const mp_obj_t *args) { + assert(MP_OBJ_IS_QSTR(args[1])); + mp_obj_t defval = MP_OBJ_NULL; + if (n_args > 2) { + defval = args[2]; + } + return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(args[1]), defval); } -MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_getattr_obj, mp_builtin_getattr); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr); diff --git a/py/builtin.h b/py/builtin.h index 50269dfe1..60b7c85b8 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -33,7 +33,9 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj); MP_DECLARE_CONST_FUN_OBJ(mp_namedtuple_obj); +extern const mp_obj_module_t mp_module___main__; extern const mp_obj_module_t mp_module_array; extern const mp_obj_module_t mp_module_collections; +extern const mp_obj_module_t mp_module_io; extern const mp_obj_module_t mp_module_math; extern const mp_obj_module_t mp_module_micropython; diff --git a/py/builtinevex.c b/py/builtinevex.c index 264aa77f3..4aafbdbe6 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -29,7 +29,7 @@ STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse if (pn == MP_PARSE_NODE_NULL) { // parse error; raise exception - nlr_jump(mp_parse_make_exception(parse_error_kind)); + nlr_raise(mp_parse_make_exception(parse_error_kind)); } // compile the string diff --git a/py/builtinimport.c b/py/builtinimport.c index 8feb2a01b..ae59ea795 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -77,7 +77,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { if (lex == NULL) { // we verified the file exists using stat, but lexer could still fail - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", vstr_str(file))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", vstr_str(file))); } qstr source_name = mp_lexer_source_name(lex); @@ -99,7 +99,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { // parse error; clean up and raise exception mp_locals_set(old_locals); mp_globals_set(old_globals); - nlr_jump(mp_parse_make_exception(parse_error_kind)); + nlr_raise(mp_parse_make_exception(parse_error_kind)); } // compile the imported script @@ -122,7 +122,7 @@ void do_load(mp_obj_t module_obj, vstr_t *file) { // exception; restore context and re-raise same exception mp_locals_set(old_locals); mp_globals_set(old_globals); - nlr_jump(nlr.ret_val); + nlr_raise(nlr.ret_val); } mp_locals_set(old_locals); mp_globals_set(old_globals); @@ -148,7 +148,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { } if (level != 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_NotImplementedError, + nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, "Relative import is not implemented")); } @@ -197,7 +197,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { // fail if we couldn't find the file if (stat == MP_IMPORT_STAT_NO_EXIST) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "ImportError: No module named '%s'", qstr_str(mod_name))); } module_obj = mp_module_get(mod_name); @@ -211,7 +211,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) { vstr_add_str(&path, "__init__.py"); if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) { vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "Per PEP-420 a dir without __init__.py (%s) is a namespace package; " "namespace packages are not supported", vstr_str(&path))); } diff --git a/py/builtintables.c b/py/builtintables.c index 2cb9240bb..1edeefa44 100644 --- a/py/builtintables.c +++ b/py/builtintables.c @@ -118,9 +118,13 @@ STATIC const mp_builtin_elem_t builtin_object_table[] = { }; STATIC const mp_builtin_elem_t builtin_module_table[] = { + { MP_QSTR___main__, (mp_obj_t)&mp_module___main__ }, { MP_QSTR_micropython, (mp_obj_t)&mp_module_micropython }, { MP_QSTR_array, (mp_obj_t)&mp_module_array }, +#if MICROPY_ENABLE_MOD_IO + { MP_QSTR_io, (mp_obj_t)&mp_module_io }, +#endif { MP_QSTR_collections, (mp_obj_t)&mp_module_collections }, #if MICROPY_ENABLE_FLOAT diff --git a/py/compile.c b/py/compile.c index 3273abe40..6ede84239 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 @@ -3,6 +3,7 @@ #include <stdbool.h> #include "mpconfig.h" +#include "misc.h" #include "gc.h" #include "misc.h" diff --git a/py/intdivmod.c b/py/intdivmod.c deleted file mode 100644 index 4cb363b51..000000000 --- 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 7716bd21e..000000000 --- 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 b0094a254..a07d36002 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -42,8 +42,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; @@ -87,8 +86,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, @@ -83,7 +83,7 @@ STATIC void mp_map_rehash(mp_map_t *map) { map->all_keys_are_qstrs = 1; map->table = m_new0(mp_map_elem_t, map->alloc); for (int i = 0; i < old_alloc; i++) { - if (old_table[i].key != NULL) { + if (old_table[i].key != MP_OBJ_NULL && old_table[i].key != MP_OBJ_SENTINEL) { mp_map_lookup(map, old_table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = old_table[i].value; } } @@ -106,8 +106,6 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t // map is a hash table (not a fixed array), so do a hash lookup - machine_uint_t hash; - hash = mp_obj_hash(index); if (map->alloc == 0) { if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { mp_map_rehash(map); @@ -116,49 +114,78 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t } } + machine_uint_t hash = mp_obj_hash(index); uint pos = hash % map->alloc; + uint start_pos = pos; + mp_map_elem_t *avail_slot = NULL; for (;;) { - mp_map_elem_t *elem = &map->table[pos]; - if (elem->key == NULL) { - // not in table + mp_map_elem_t *slot = &map->table[pos]; + if (slot->key == MP_OBJ_NULL) { + // found NULL slot, so index is not in table if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { - if (map->used + 1 >= map->alloc) { - // not enough room in table, rehash it - mp_map_rehash(map); - // restart the search for the new element - pos = hash % map->alloc; - } else { - map->used += 1; - elem->key = index; - if (!MP_OBJ_IS_QSTR(index)) { - map->all_keys_are_qstrs = 0; - } - return elem; + map->used += 1; + if (avail_slot == NULL) { + avail_slot = slot; + } + slot->key = index; + slot->value = MP_OBJ_NULL; + if (!MP_OBJ_IS_QSTR(index)) { + map->all_keys_are_qstrs = 0; } + return slot; } else { - return NULL; + return MP_OBJ_NULL; } - } else if (elem->key == index || (!map->all_keys_are_qstrs && mp_obj_equal(elem->key, index))) { - // found it - /* it seems CPython does not replace the index; try x={True:'true'};x[1]='one';x - if (add_if_not_found) { - elem->key = index; + } else if (slot->key == MP_OBJ_SENTINEL) { + // found deleted slot, remember for later + if (avail_slot == NULL) { + avail_slot = slot; } - */ + } else if (slot->key == index || (!map->all_keys_are_qstrs && mp_obj_equal(slot->key, index))) { + // found index + // Note: CPython does not replace the index; try x={True:'true'};x[1]='one';x if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { - map->used--; // this leaks this memory (but see dict_get_helper) mp_map_elem_t *retval = m_new(mp_map_elem_t, 1); - retval->key = elem->key; - retval->value = elem->value; - elem->key = NULL; - elem->value = NULL; + retval->key = slot->key; + retval->value = slot->value; + // delete element in this slot + map->used--; + if (map->table[(pos + 1) % map->alloc].key == MP_OBJ_NULL) { + // optimisation if next slot is empty + slot->key = MP_OBJ_NULL; + } else { + slot->key = MP_OBJ_SENTINEL; + } return retval; } - return elem; - } else { - // not yet found, keep searching in this table - pos = (pos + 1) % map->alloc; + return slot; + } + + // not yet found, keep searching in this table + pos = (pos + 1) % map->alloc; + + if (pos == start_pos) { + // search got back to starting position, so index is not in table + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + if (avail_slot != NULL) { + // there was an available slot, so use that + map->used++; + avail_slot->key = index; + avail_slot->value = MP_OBJ_NULL; + if (!MP_OBJ_IS_QSTR(index)) { + map->all_keys_are_qstrs = 0; + } + return avail_slot; + } else { + // not enough room in table, rehash it + mp_map_rehash(map); + // restart the search for the new element + start_pos = pos = hash % map->alloc; + } + } else { + return MP_OBJ_NULL; + } } } } @@ -179,16 +206,14 @@ STATIC void mp_set_rehash(mp_set_t *set) { set->used = 0; set->table = m_new0(mp_obj_t, set->alloc); for (int i = 0; i < old_alloc; i++) { - if (old_table[i] != NULL) { - mp_set_lookup(set, old_table[i], true); + if (old_table[i] != MP_OBJ_NULL && old_table[i] != MP_OBJ_SENTINEL) { + mp_set_lookup(set, old_table[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } } m_del(mp_obj_t, old_table, old_alloc); } mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind) { - int hash; - int pos; if (set->alloc == 0) { if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { mp_set_rehash(set); @@ -196,45 +221,84 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku return NULL; } } - if (lookup_kind & MP_MAP_LOOKUP_FIRST) { - hash = 0; - pos = 0; - } else { - hash = mp_obj_hash(index);; - pos = hash % set->alloc; - } + machine_uint_t hash = mp_obj_hash(index); + uint pos = hash % set->alloc; + uint start_pos = pos; + mp_obj_t *avail_slot = NULL; for (;;) { mp_obj_t elem = set->table[pos]; if (elem == MP_OBJ_NULL) { - // not in table + // found NULL slot, so index is not in table if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { - if (set->used + 1 >= set->alloc) { + if (avail_slot == NULL) { + avail_slot = &set->table[pos]; + } + set->used++; + *avail_slot = index; + return index; + } else { + return MP_OBJ_NULL; + } + } else if (elem == MP_OBJ_SENTINEL) { + // found deleted slot, remember for later + if (avail_slot == NULL) { + avail_slot = &set->table[pos]; + } + } else if (mp_obj_equal(elem, index)) { + // found index + if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { + // delete element + set->used--; + if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) { + // optimisation if next slot is empty + set->table[pos] = MP_OBJ_NULL; + } else { + set->table[pos] = MP_OBJ_SENTINEL; + } + } + return elem; + } + + // not yet found, keep searching in this table + pos = (pos + 1) % set->alloc; + + if (pos == start_pos) { + // search got back to starting position, so index is not in table + if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) { + if (avail_slot != NULL) { + // there was an available slot, so use that + set->used++; + *avail_slot = index; + return index; + } else { // not enough room in table, rehash it mp_set_rehash(set); // restart the search for the new element - pos = hash % set->alloc; - } else { - set->used += 1; - set->table[pos] = index; - return index; + start_pos = pos = hash % set->alloc; } - } else if (lookup_kind & MP_MAP_LOOKUP_FIRST) { - pos++; } else { return MP_OBJ_NULL; } - } else if ((lookup_kind & MP_MAP_LOOKUP_FIRST) || mp_obj_equal(elem, index)) { - // found it - if (lookup_kind & MP_MAP_LOOKUP_REMOVE_IF_FOUND) { - set->used--; - set->table[pos] = NULL; + } + } +} + +mp_obj_t mp_set_remove_first(mp_set_t *set) { + for (uint pos = 0; pos < set->alloc; pos++) { + if (set->table[pos] != MP_OBJ_NULL && set->table[pos] != MP_OBJ_SENTINEL) { + mp_obj_t elem = set->table[pos]; + // delete element + set->used--; + if (set->table[(pos + 1) % set->alloc] == MP_OBJ_NULL) { + // optimisation if next slot is empty + set->table[pos] = MP_OBJ_NULL; + } else { + set->table[pos] = MP_OBJ_SENTINEL; } return elem; - } else { - // not yet found, keep searching in this table - pos = (pos + 1) % set->alloc; } } + return MP_OBJ_NULL; } void mp_set_clear(mp_set_t *set) { @@ -243,3 +307,17 @@ void mp_set_clear(mp_set_t *set) { set->used = 0; set->table = NULL; } + +#if DEBUG_PRINT +void mp_map_dump(mp_map_t *map) { + for (int i = 0; i < map->alloc; i++) { + if (map->table[i].key != NULL) { + mp_obj_print(map->table[i].key, PRINT_REPR); + } else { + printf("(nil)"); + } + printf(": %p\n", map->table[i].value); + } + printf("---\n"); +} +#endif @@ -38,6 +38,7 @@ void *m_malloc_mp_obj(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); diff --git a/py/modio.c b/py/modio.c new file mode 100644 index 000000000..ced398358 --- /dev/null +++ b/py/modio.c @@ -0,0 +1,30 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "builtin.h" + +#if MICROPY_ENABLE_MOD_IO + +STATIC const mp_map_elem_t mp_module_io_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_io) }, + // Note: mp_builtin_open_obj should be defined by port, it's not + // part of the core. + { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, +}; + +STATIC const mp_map_t mp_module_io_globals = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_io_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_io_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_io_globals_table, +}; + +const mp_obj_module_t mp_module_io = { + .base = { &mp_type_module }, + .name = MP_QSTR_io, + .globals = (mp_map_t*)&mp_module_io_globals, +}; + +#endif diff --git a/py/mpconfig.h b/py/mpconfig.h index 09cc37913..65577f06c 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -105,6 +105,11 @@ typedef double mp_float_t; #define MICROPY_ENABLE_FLOAT (0) #endif +// Whether to provide "io" module +#ifndef MICROPY_ENABLE_MOD_IO +#define MICROPY_ENABLE_MOD_IO (1) +#endif + // Whether to support slice object and correspondingly // slice subscript operators #ifndef MICROPY_ENABLE_SLICE @@ -993,8 +993,11 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { if (mpz_is_odd(n)) { mpz_mul_inpl(dest, dest, x); } - mpz_mul_inpl(x, x, x); n->len = mpn_shr(n->dig, n->dig, n->len, 1); + if (n->len == 0) { + break; + } + mpz_mul_inpl(x, x, x); } mpz_free(x); @@ -1139,6 +1142,7 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) { } #endif +// TODO check that this correctly handles overflow in all cases machine_int_t mpz_as_int(const mpz_t *i) { machine_int_t val = 0; mpz_dig_t *d = i->dig + i->len; @@ -1147,11 +1151,13 @@ machine_int_t mpz_as_int(const mpz_t *i) { machine_int_t oldval = val; val = (val << DIG_SIZE) | *d; if (val < oldval) { - // TODO need better handling of conversion overflow + // overflow, return +/- "infinity" if (i->neg == 0) { - return 0x7fffffff; + // +infinity + return ~WORD_MSBIT_HIGH; } else { - return 0x80000000; + // -infinity + return WORD_MSBIT_HIGH; } } } @@ -1163,6 +1169,28 @@ machine_int_t mpz_as_int(const mpz_t *i) { return val; } +// TODO check that this correctly handles overflow in all cases +bool mpz_as_int_checked(const mpz_t *i, machine_int_t *value) { + machine_int_t val = 0; + mpz_dig_t *d = i->dig + i->len; + + while (--d >= i->dig) { + machine_int_t oldval = val; + val = (val << DIG_SIZE) | *d; + if (val < oldval) { + // overflow + return false; + } + } + + if (i->neg != 0) { + val = -val; + } + + *value = val; + return true; +} + #if MICROPY_ENABLE_FLOAT mp_float_t mpz_as_float(const mpz_t *i) { mp_float_t val = 0; @@ -71,6 +71,7 @@ mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs); mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs); machine_int_t mpz_as_int(const mpz_t *z); +bool mpz_as_int_checked(const mpz_t *z, machine_int_t *value); #if MICROPY_ENABLE_FLOAT mp_float_t mpz_as_float(const mpz_t *z); #endif @@ -11,7 +11,11 @@ struct _nlr_buf_t { #if defined(__i386__) void *regs[6]; #elif defined(__x86_64__) + #if defined(__CYGWIN__) + void *regs[12]; + #else void *regs[8]; + #endif #elif defined(__thumb2__) void *regs[10]; #else @@ -22,3 +26,16 @@ struct _nlr_buf_t { unsigned int nlr_push(nlr_buf_t *); void nlr_pop(void); void nlr_jump(void *val) __attribute__((noreturn)); + +// use nlr_raise instead of nlr_jump so that debugging is easier +#ifndef DEBUG +#define nlr_raise(val) nlr_jump(val) +#else +#define nlr_raise(val) \ + do { \ + void *_val = val; \ + assert(_val != NULL); \ + assert(mp_obj_is_exception_instance(_val)); \ + nlr_jump(_val); \ + } while (0) +#endif diff --git a/py/nlrx64.S b/py/nlrx64.S index c5711001e..a4073981a 100644 --- a/py/nlrx64.S +++ b/py/nlrx64.S @@ -4,6 +4,8 @@ .file "nlr.s" .text +#if !defined(__CYGWIN__) + /* uint nlr_push(rdi=nlr_buf_t *nlr) */ #if !(defined(__APPLE__) && defined(__MACH__)) .globl nlr_push @@ -82,4 +84,63 @@ nlr_jump: .local nlr_top #endif .comm nlr_top,8,8 -#endif + +#else // !defined(__CYGWIN__) + +/* uint nlr_push(rcx=nlr_buf_t *nlr) */ + .globl nlr_push +nlr_push: + movq (%rsp), %rax # load return %rip + movq %rax, 16(%rcx) # store %rip into nlr_buf + movq %rbp, 24(%rcx) # store %rbp into nlr_buf + movq %rsp, 32(%rcx) # store %rsp into nlr_buf + movq %rbx, 40(%rcx) # store %rbx into nlr_buf + movq %r12, 48(%rcx) # store %r12 into nlr_buf + movq %r13, 56(%rcx) # store %r13 into nlr_buf + movq %r14, 64(%rcx) # store %r14 into nlr_buf + movq %r15, 72(%rcx) # store %r15 into + movq %rdi, 80(%rcx) # store %rdr into + movq %rsi, 88(%rcx) # store %rsi into + movq nlr_top(%rip), %rax # get last nlr_buf + movq %rax, (%rcx) # store it + movq %rcx, nlr_top(%rip) # stor new nlr_buf (to make linked list) + xorq %rax, %rax # return 0, normal return + ret # return + +/* void nlr_jump(rcx=uint val) */ + + .globl nlr_jump +nlr_jump: + movq %rcx, %rax # put return value in %rax + movq nlr_top(%rip), %rcx # get nlr_top into %rsi + movq %rax, 8(%rcx) # store return value + movq (%rcx), %rax # load prev nlr_buf + movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list) + movq 72(%rcx), %r15 # load saved %r15 + movq 64(%rcx), %r14 # load saved %r14 + movq 56(%rcx), %r13 # load saved %r13 + movq 48(%rcx), %r12 # load saved %r12 + movq 40(%rcx), %rbx # load saved %rbx + movq 32(%rcx), %rsp # load saved %rsp + movq 24(%rcx), %rbp # load saved %rbp + movq 16(%rcx), %rax # load saved %rip + movq 80(%rcx), %rdi # store %rdr into + movq 88(%rcx), %rsi # store %rsi into + movq %rax, (%rsp) # store saved %rip to stack + xorq %rax, %rax # clear return register + inc %al # increase to make 1, non-local return + ret # return + + .comm nlr_top,8,8 + + /* void nlr_pop() */ + .globl nlr_pop +nlr_pop: + movq nlr_top(%rip), %rax # get nlr_top into %rax + movq (%rax), %rax # load prev nlr_buf + movq %rax, nlr_top(%rip) # store prev nlr_buf (to unlink list) + ret # return + +#endif // !defined(__CYGWIN__) + +#endif // __x86_64__ @@ -118,12 +118,14 @@ machine_int_t mp_obj_hash(mp_obj_t o_in) { return (machine_int_t)o_in; } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) { return mp_obj_tuple_hash(o_in); + } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_type)) { + return (machine_int_t)o_in; // TODO hash class and instances // TODO delegate to __hash__ method if it exists } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unhashable type: '%s'", mp_obj_get_type_str(o_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unhashable type: '%s'", mp_obj_get_type_str(o_in))); } } @@ -172,24 +174,16 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } } - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NotImplementedError, "Equality for '%s' and '%s' types not yet implemented", mp_obj_get_type_str(o1), mp_obj_get_type_str(o2))); return false; } } -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) { + // This function essentially performs implicit type conversion to int + // Note that Python does NOT provide implicit type conversion from + // float to int in the core expression language, try some_list[1.0]. if (arg == mp_const_false) { return 0; } else if (arg == mp_const_true) { @@ -199,8 +193,26 @@ machine_int_t mp_obj_get_int(mp_obj_t arg) { } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { return mp_obj_int_get_checked(arg); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); + } +} + +// returns false if arg is not of integral type +// returns true and sets *value if it is of integral type +// can throw OverflowError if arg is of integral type, but doesn't fit in a machine_int_t +bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value) { + if (arg == mp_const_false) { + *value = 0; + } else if (arg == mp_const_true) { + *value = 1; + } else if (MP_OBJ_IS_SMALL_INT(arg)) { + *value = MP_OBJ_SMALL_INT_VALUE(arg); + } else if (MP_OBJ_IS_TYPE(arg, &mp_type_int)) { + *value = mp_obj_int_get_checked(arg); + } else { + return false; } + return true; } #if MICROPY_ENABLE_FLOAT @@ -216,7 +228,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) { } else if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { return mp_obj_float_get(arg); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); } } @@ -239,7 +251,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { } else if (MP_OBJ_IS_TYPE(arg, &mp_type_complex)) { mp_obj_complex_get(arg, real, imag); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); } } #endif @@ -250,7 +262,7 @@ void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) { } else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) { mp_obj_list_get(o, len, items); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); } } @@ -263,10 +275,10 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) { mp_obj_list_get(o, &seq_len, items); } if (seq_len != len) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", len, seq_len)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "requested length %d but object has length %d", len, seq_len)); } } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); } } @@ -278,7 +290,7 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, } else if (MP_OBJ_IS_TYPE(index, &mp_type_bool)) { i = (index == mp_const_true ? 1 : 0); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s indices must be integers, not %s", qstr_str(type->name), mp_obj_get_type_str(index))); } if (i < 0) { @@ -292,7 +304,7 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, } } else { if (i < 0 || i >= len) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%s index out of range", qstr_str(type->name))); } } return i; @@ -23,6 +23,11 @@ typedef struct _mp_obj_base_t mp_obj_base_t; #define MP_OBJ_NULL ((mp_obj_t)NULL) +// The SENTINEL object is used for various internal purposes where one needs +// an object which is unique from all other objects, including MP_OBJ_NULL. + +#define MP_OBJ_SENTINEL ((mp_obj_t)8) + // These macros check for small int, qstr or object, and access small int and qstr values // - xxxx...xxx1: a small int, bits 1 and above are the value // - xxxx...xx10: a qstr, bits 2 and above are the value @@ -103,11 +108,11 @@ typedef struct _mp_map_t { mp_map_elem_t *table; } mp_map_t; +// These can be or'd together typedef enum _mp_map_lookup_kind_t { MP_MAP_LOOKUP, // 0 MP_MAP_LOOKUP_ADD_IF_NOT_FOUND, // 1 MP_MAP_LOOKUP_REMOVE_IF_FOUND, // 2 - MP_MAP_LOOKUP_FIRST = 4, } mp_map_lookup_kind_t; void mp_map_init(mp_map_t *map, int n); @@ -117,6 +122,7 @@ void mp_map_deinit(mp_map_t *map); void mp_map_free(mp_map_t *map); mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); void mp_map_clear(mp_map_t *map); +void mp_map_dump(mp_map_t *map); // Underlying set implementation (not set object) @@ -128,6 +134,7 @@ typedef struct _mp_set_t { void mp_set_init(mp_set_t *set, int n); mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); +mp_obj_t mp_set_remove_first(mp_set_t *set); void mp_set_clear(mp_set_t *set); // Type definitions for methods @@ -306,6 +313,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,9 +364,9 @@ 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); #if MICROPY_ENABLE_FLOAT mp_float_t mp_obj_get_float(mp_obj_t self_in); void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag); @@ -438,6 +446,7 @@ typedef struct _mp_obj_dict_t { } mp_obj_dict_t; uint mp_obj_dict_len(mp_obj_t self_in); mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value); +mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key); mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in); // set diff --git a/py/objarray.c b/py/objarray.c index c91c553e3..0383cb17b 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -76,7 +76,7 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) { STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { if (n_args < 1 || n_args > 2) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected # of arguments, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unexpected # of arguments, %d given", n_args)); } // TODO check args uint l; diff --git a/py/objbool.c b/py/objbool.c index 6afb6e950..11c736e3e 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -1,3 +1,4 @@ +#include <stdlib.h> #include "nlr.h" #include "misc.h" @@ -27,7 +28,7 @@ STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp switch (n_args) { case 0: return mp_const_false; case 1: if (mp_obj_is_true(args[0])) { return mp_const_true; } else { return mp_const_false; } - default: nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bool takes at most 1 argument, %d given", n_args)); + default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bool takes at most 1 argument, %d given", n_args)); } } @@ -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/objcomplex.c b/py/objcomplex.c index 3fba56894..769977ad8 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -86,7 +86,7 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "complex takes at most 2 arguments, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "complex takes at most 2 arguments, %d given", n_args)); } } diff --git a/py/objdict.c b/py/objdict.c index afd1d0da0..c09ccfbee 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_raise(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) { @@ -53,7 +71,7 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // dict load mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); } else { return elem->value; } @@ -85,7 +103,7 @@ STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) { mp_map_elem_t *table = self->dict->map.table; for (int i = self->cur; i < max; i++) { - if (table[i].key != NULL) { + if (table[i].key != MP_OBJ_NULL && table[i].key != MP_OBJ_SENTINEL) { self->cur = i + 1; return &(table[i]); } @@ -181,7 +199,7 @@ STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp if (elem == NULL || elem->value == NULL) { if (deflt == NULL) { if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>")); } else { value = mp_const_none; } @@ -240,7 +258,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict)); mp_obj_dict_t *self = self_in; if (self->map.used == 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "popitem(): dictionary is empty")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "popitem(): dictionary is empty")); } mp_obj_dict_it_t *iter = mp_obj_new_dict_iterator(self, 0); @@ -269,7 +287,7 @@ STATIC mp_obj_t dict_update(mp_obj_t self_in, mp_obj_t iterable) { if (key == MP_OBJ_NULL || value == MP_OBJ_NULL || stop != MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception_msg( + nlr_raise(mp_obj_new_exception_msg( &mp_type_ValueError, "dictionary update sequence has the wrong length")); } else { @@ -463,6 +481,13 @@ mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { return self_in; } +mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict)); + mp_obj_dict_t *self = self_in; + dict_get_helper(&self->map, key, NULL, MP_MAP_LOOKUP_REMOVE_IF_FOUND); + return self_in; +} + mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict)); mp_obj_dict_t *self = self_in; diff --git a/py/objexcept.c b/py/objexcept.c index 0efc21d36..51e7a2615 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. @@ -45,7 +48,7 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_ mp_obj_type_t *type = type_in; if (n_kw != 0) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", mp_obj_get_type_str(type_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", mp_obj_get_type_str(type_in))); } mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args); diff --git a/py/objfilter.c b/py/objfilter.c index 466c98220..1224950bd 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -16,7 +16,7 @@ typedef struct _mp_obj_filter_t { STATIC mp_obj_t filter_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { if (n_args != 2 || n_kw != 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "filter expected 2 arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "filter expected 2 arguments")); } assert(n_args == 2); mp_obj_filter_t *o = m_new_obj(mp_obj_filter_t); diff --git a/py/objfloat.c b/py/objfloat.c index d7bc6c7ff..1d4761aca 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -57,7 +57,7 @@ STATIC mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "float takes at most 1 argument, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "float takes at most 1 argument, %d given", n_args)); } } @@ -121,7 +121,7 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) { lhs_val /= rhs_val; check_zero_division: if (isinf(lhs_val)){ // check for division by zero - nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "float division by zero")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "float division by zero")); } break; case MP_BINARY_OP_POWER: diff --git a/py/objfun.c b/py/objfun.c index 3b48b570f..d006c8715 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -30,29 +30,39 @@ STATIC void check_nargs(mp_obj_fun_native_t *self, int n_args, int n_kw) { void mp_check_nargs(int n_args, machine_uint_t n_args_min, machine_uint_t n_args_max, int n_kw, bool is_kw) { if (n_kw && !is_kw) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); } if (n_args_min == n_args_max) { if (n_args != n_args_min) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", n_args_min, n_args)); } } else { if (n_args < n_args_min) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "<fun name>() missing %d required positional arguments: <list of names of params>", n_args_min - n_args)); } else if (n_args > n_args_max) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "<fun name> expected at most %d arguments, got %d", n_args_max, n_args)); } } } +STATIC mp_obj_t fun_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + case MP_BINARY_OP_EQUAL: + // These objects can be equal only if it's the same underlying structure, + // we don't even need to check for 2nd arg type. + return MP_BOOL(lhs_in == rhs_in); + } + return NULL; +} + STATIC mp_obj_t fun_native_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_native)); mp_obj_fun_native_t *self = self_in; @@ -102,6 +112,7 @@ const mp_obj_type_t mp_type_fun_native = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_native_call, + .binary_op = fun_binary_op, }; // fun must have the correct signature for n_args fixed arguments @@ -196,7 +207,7 @@ bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, co return true; arg_error: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args)); } STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { @@ -264,7 +275,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o for (uint j = 0; j < self->n_args; j++) { if (arg_name == self->args[j]) { if (flat_args[j] != MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function got multiple values for argument '%s'", qstr_str(arg_name))); } flat_args[j] = kwargs[2 * i + 1]; @@ -273,7 +284,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_o } // Didn't find name match with positional args if (!self->takes_kw_args) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); } mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); continue2:; @@ -295,7 +306,7 @@ continue2:; // Now check that all mandatory args specified while (d >= flat_args) { if (*d-- == MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function missing required positional argument #%d", d - flat_args)); } } @@ -327,17 +338,18 @@ continue2:; if (vm_return_kind == MP_VM_RETURN_NORMAL) { return result; } else { // MP_VM_RETURN_EXCEPTION - nlr_jump(result); + nlr_raise(result); } arg_error: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args)); } const mp_obj_type_t mp_type_fun_bc = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_bc_call, + .binary_op = fun_binary_op, }; mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args_in, const byte *code) { @@ -437,10 +449,10 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_ mp_obj_fun_asm_t *self = self_in; if (n_args != self->n_args) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", self->n_args, n_args)); } if (n_kw != 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); } machine_uint_t ret; @@ -464,6 +476,7 @@ STATIC const mp_obj_type_t mp_type_fun_asm = { { &mp_type_type }, .name = MP_QSTR_function, .call = fun_asm_call, + .binary_op = fun_binary_op, }; mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun) { diff --git a/py/objgenerator.c b/py/objgenerator.c index 78694c866..975681af8 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -84,7 +84,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } if (self->sp == self->state - 1) { if (send_value != mp_const_none) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator")); } } else { *self->sp = send_value; @@ -130,12 +130,12 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o if (ret == mp_const_none || ret == MP_OBJ_NULL) { return MP_OBJ_NULL; } else { - nlr_jump(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); + nlr_raise(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret)); } case MP_VM_RETURN_YIELD: if (throw_value != MP_OBJ_NULL && mp_obj_is_subclass_fast(mp_obj_get_type(throw_value), &mp_type_GeneratorExit)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); } return ret; @@ -146,7 +146,7 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o if (mp_obj_is_subclass_fast(mp_obj_get_type(ret), &mp_type_StopIteration)) { return MP_OBJ_NULL; } else { - nlr_jump(ret); + nlr_raise(ret); } default: @@ -162,7 +162,7 @@ mp_obj_t gen_instance_iternext(mp_obj_t self_in) { STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL); if (ret == MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception(&mp_type_StopIteration)); + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -177,7 +177,7 @@ STATIC mp_obj_t gen_instance_throw(uint n_args, const mp_obj_t *args) { mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc); if (ret == MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception(&mp_type_StopIteration)); + nlr_raise(mp_obj_new_exception(&mp_type_StopIteration)); } else { return ret; } @@ -189,7 +189,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { mp_obj_t ret; switch (mp_obj_gen_resume(self_in, mp_const_none, (mp_obj_t)&mp_const_GeneratorExit_obj, &ret)) { case MP_VM_RETURN_YIELD: - nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); // Swallow StopIteration & GeneratorExit (== successful close), and re-raise any other case MP_VM_RETURN_EXCEPTION: @@ -198,7 +198,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { mp_obj_is_subclass_fast(mp_obj_get_type(ret), &mp_type_StopIteration)) { return mp_const_none; } - nlr_jump(ret); + nlr_raise(ret); default: // The only choice left is MP_VM_RETURN_NORMAL which is successful close diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index da0e4760c..f848415b8 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -30,7 +30,7 @@ STATIC mp_obj_t it_iternext(mp_obj_t self_in) { return MP_OBJ_NULL; } else { // re-raise exception - nlr_jump(nlr.ret_val); + nlr_raise(nlr.ret_val); } } } diff --git a/py/objint.c b/py/objint.c index 3a853eab8..a1d3924a2 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) { @@ -50,43 +49,37 @@ STATIC mp_obj_t int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "int takes at most 2 arguments, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "int takes at most 2 arguments, %d given", n_args)); } } #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 mp_obj_t mp_obj_new_int_from_long_str(const char *s) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build")); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ll(long long val) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); return mp_const_none; } @@ -96,7 +89,7 @@ mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) { if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } - nlr_jump(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); return mp_const_none; } @@ -104,7 +97,7 @@ mp_obj_t mp_obj_new_int(machine_int_t value) { if (MP_OBJ_FITS_SMALL_INT(value)) { return MP_OBJ_NEW_SMALL_INT(value); } - nlr_jump(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); return mp_const_none; } @@ -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 53ee49e7d..fe7f60a2d 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 acbd477a9..02389d673 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) { @@ -150,7 +144,7 @@ mp_obj_t mp_obj_new_int_from_long_str(const char *s) { // TODO: this doesn't handle Python hacked 0o octal syntax v = strtoll(s, &end, 0); if (*end != 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); } mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 27f77d14b..4ecc4017b 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; @@ -154,7 +148,7 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // TODO check conversion overflow machine_int_t irhs = mpz_as_int(zrhs); if (irhs < 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); } if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { mpz_shl_inpl(&res->mpz, zlhs, irhs); @@ -228,7 +222,7 @@ mp_obj_t mp_obj_new_int_from_long_str(const char *str) { len -= skip; uint n = mpz_set_from_str(&o->mpz, str, len, false, base); if (n != len) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); } return o; } @@ -243,8 +237,18 @@ machine_int_t mp_obj_int_get(mp_obj_t self_in) { } machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) { - // TODO: Check overflow - return mp_obj_int_get(self_in); + if (MP_OBJ_IS_SMALL_INT(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + mp_obj_int_t *self = self_in; + machine_int_t value; + if (mpz_as_int_checked(&self->mpz, &value)) { + return value; + } else { + // overflow + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "overflow converting long int to machine word")); + } + } } #if MICROPY_ENABLE_FLOAT diff --git a/py/objlist.c b/py/objlist.c index 244d4a596..620bf2944 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -59,7 +59,7 @@ STATIC mp_obj_t list_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "list takes at most 1 argument, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "list takes at most 1 argument, %d given", n_args)); } return NULL; } @@ -122,12 +122,11 @@ STATIC mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { list_extend(lhs, rhs); return o; } - case MP_BINARY_OP_MULTIPLY: - { - if (!MP_OBJ_IS_SMALL_INT(rhs)) { + case MP_BINARY_OP_MULTIPLY: { + machine_int_t n; + if (!mp_obj_get_int_maybe(rhs, &n)) { return NULL; } - int n = MP_OBJ_SMALL_INT_VALUE(rhs); mp_obj_list_t *s = list_new(o->len * n); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return s; @@ -185,7 +184,7 @@ STATIC mp_obj_t list_pop(uint n_args, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = args[0]; if (self->len == 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_IndexError, "pop from empty list")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "pop from empty list")); } uint index = mp_get_index(self->base.type, self->len, n_args == 1 ? mp_obj_new_int(-1) : args[1], false); mp_obj_t ret = self->items[index]; @@ -225,7 +224,7 @@ mp_obj_t mp_obj_list_sort(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { assert(n_args >= 1); assert(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); if (n_args > 1) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "list.sort takes no positional arguments")); } mp_obj_list_t *self = args[0]; diff --git a/py/objmap.c b/py/objmap.c index 923ca861b..42bcc436f 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -17,7 +17,7 @@ typedef struct _mp_obj_map_t { STATIC mp_obj_t map_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { if (n_args < 2 || n_kw != 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "map must have at least 2 arguments and no keyword arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "map must have at least 2 arguments and no keyword arguments")); } assert(n_args >= 2); mp_obj_map_t *o = m_new_obj_var(mp_obj_map_t, mp_obj_t, n_args - 1); diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index a9e6e7d8a..e18cd3ce5 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -102,7 +102,7 @@ STATIC void namedtuple_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } STATIC bool namedtuple_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); } STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { @@ -110,7 +110,7 @@ STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co uint num_fields = namedtuple_count_fields(type->fields); if (n_args != num_fields) { // Counts include implicit "self" - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__new__() takes %d positional arguments but %d were given", num_fields + 1, n_args + 1)); } diff --git a/py/objobject.c b/py/objobject.c index 274135c6c..56daa956d 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -15,7 +15,7 @@ const mp_obj_type_t mp_type_object; STATIC mp_obj_t object_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { if (n_args != 0 || n_kw != 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "object takes no arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "object takes no arguments")); } mp_obj_object_t *o = m_new_obj(mp_obj_object_t); diff --git a/py/objset.c b/py/objset.c index 439c6e96e..12c8cd25a 100644 --- a/py/objset.c +++ b/py/objset.c @@ -32,7 +32,7 @@ STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env, bool first = true; print(env, "{"); for (int i = 0; i < self->set.alloc; i++) { - if (self->set.table[i] != MP_OBJ_NULL) { + if (self->set.table[i] != MP_OBJ_NULL && self->set.table[i] != MP_OBJ_SENTINEL) { if (!first) { print(env, ", "); } @@ -65,7 +65,7 @@ STATIC mp_obj_t set_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "set takes at most 1 argument, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "set takes at most 1 argument, %d given", n_args)); } } @@ -83,7 +83,7 @@ STATIC mp_obj_t set_it_iternext(mp_obj_t self_in) { mp_obj_t *table = self->set->set.table; for (machine_uint_t i = self->cur; i < max; i++) { - if (table[i] != NULL) { + if (table[i] != MP_OBJ_NULL && table[i] != MP_OBJ_SENTINEL) { self->cur = i + 1; return table[i]; } @@ -307,12 +307,10 @@ STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) { STATIC mp_obj_t set_pop(mp_obj_t self_in) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); mp_obj_set_t *self = self_in; - - if (self->set.used == 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "pop from an empty set")); + mp_obj_t obj = mp_set_remove_first(&self->set); + if (obj == MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "pop from an empty set")); } - mp_obj_t obj = mp_set_lookup(&self->set, NULL, - MP_MAP_LOOKUP_REMOVE_IF_FOUND | MP_MAP_LOOKUP_FIRST); return obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(set_pop_obj, set_pop); @@ -321,7 +319,7 @@ STATIC mp_obj_t set_remove(mp_obj_t self_in, mp_obj_t item) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); mp_obj_set_t *self = self_in; if (mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_REMOVE_IF_FOUND) == MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception(&mp_type_KeyError)); + nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); } return mp_const_none; } @@ -375,6 +373,14 @@ STATIC mp_obj_t set_union(mp_obj_t self_in, mp_obj_t other_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_union_obj, set_union); +STATIC mp_obj_t set_unary_op(int op, mp_obj_t self_in) { + mp_obj_set_t *self = self_in; + switch (op) { + case MP_UNARY_OP_BOOL: return MP_BOOL(self->set.used != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->set.used); + default: return MP_OBJ_NULL; // op not supported for None + } +} STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_t args[] = {lhs, rhs}; @@ -450,6 +456,7 @@ const mp_obj_type_t mp_type_set = { .name = MP_QSTR_set, .print = set_print, .make_new = set_make_new, + .unary_op = set_unary_op, .binary_op = set_binary_op, .getiter = set_getiter, .locals_dict = (mp_obj_t)&set_locals_dict, diff --git a/py/objstr.c b/py/objstr.c index f22c6b1ba..7000ed1fb 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -102,7 +102,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ { // TODO: validate 2nd/3rd args if (!MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected")); } GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); @@ -113,7 +113,7 @@ STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ } default: - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments")); } } @@ -183,7 +183,7 @@ STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m return mp_obj_str_builder_end(o); wrong_args: - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "wrong number of arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "wrong number of arguments")); } // like strstr but with specified length and allows \0 bytes @@ -237,7 +237,7 @@ STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } else { // Message doesn't match CPython, but we don't have so much bytes as they // to spend them on verbose wording - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "index must be int")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "index must be int")); } case MP_BINARY_OP_ADD: @@ -361,7 +361,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { return mp_obj_str_builder_end(joined_str); bad_arg: - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "?str.join expecting a list of str's")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "?str.join expecting a list of str's")); } #define is_ws(c) ((c) == ' ' || (c) == '\t') @@ -528,6 +528,15 @@ static bool arg_looks_numeric(mp_obj_t arg) { ; } +static machine_int_t arg_as_int(mp_obj_t arg) { +#if MICROPY_ENABLE_FLOAT + if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { + return mp_obj_get_float(arg); + } +#endif + return mp_obj_get_int(arg); +} + mp_obj_t str_format(uint n_args, const mp_obj_t *args) { assert(MP_OBJ_IS_STR(args[0])); @@ -545,7 +554,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { vstr_add_char(vstr, '}'); continue; } - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Single '}' encountered in format string")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Single '}' encountered in format string")); } if (*str != '{') { vstr_add_char(vstr, *str); @@ -579,7 +588,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { if (str < top && (*str == 'r' || *str == 's')) { conversion = *str++; } else { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "end of format while looking for conversion specifier")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "end of format while looking for conversion specifier")); } } @@ -599,24 +608,24 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { } } if (str >= top) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "unmatched '{' in format")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "unmatched '{' in format")); } if (*str != '}') { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "expected ':' after format specifier")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expected ':' after format specifier")); } mp_obj_t arg = mp_const_none; if (field_name) { if (arg_i > 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from automatic field numbering to manual field specification")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from automatic field numbering to manual field specification")); } int index; if (str_to_int(vstr_str(field_name), &index) != vstr_len(field_name) - 1) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "attributes not supported yet")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "attributes not supported yet")); } if (index >= n_args - 1) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); } arg = args[index + 1]; arg_i = -1; @@ -624,10 +633,10 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { field_name = NULL; } else { if (arg_i < 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from manual field specification to automatic field numbering")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from manual field specification to automatic field numbering")); } if (arg_i >= n_args - 1) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); } arg = args[arg_i + 1]; arg_i++; @@ -642,7 +651,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { } else if (conversion == 'r') { print_kind = PRINT_REPR; } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown conversion specifier %c", conversion)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown conversion specifier %c", conversion)); } vstr_t *arg_vstr = vstr_new(); mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, arg_vstr, arg, print_kind); @@ -709,7 +718,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { type = *s++; } if (*s) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_KeyError, "Invalid conversion specification")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "Invalid conversion specification")); } vstr_free(format_spec); format_spec = NULL; @@ -727,10 +736,10 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { if (sign) { if (type == 's') { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Sign not allowed in string format specifier")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sign not allowed in string format specifier")); } if (type == 'c') { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Sign not allowed with integer format specifier 'c'")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Sign not allowed with integer format specifier 'c'")); } } else { sign = '-'; @@ -785,12 +794,14 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { break; default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown format code '%c' for object of type '%s'", type, mp_obj_get_type_str(arg))); } + } -#if MICROPY_ENABLE_FLOAT - } else if (arg_looks_numeric(arg)) { + // NOTE: no else here. We need the e, f, g etc formats for integer + // arguments (from above if) to take this if. + if (arg_looks_numeric(arg)) { if (!type) { // Even though the docs say that an unspecified type is the same @@ -828,6 +839,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { flags |= PF_FLAG_PAD_NAN_INF; // '{:06e}'.format(float('-inf')) should give '-00inf' switch (type) { +#if MICROPY_ENABLE_FLOAT case 'e': case 'E': case 'f': @@ -841,19 +853,18 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { flags |= PF_FLAG_ADD_PERCENT; pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg) * 100.0F, 'f', flags, fill, width, precision); break; +#endif default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown format code '%c' for object of type 'float'", type, mp_obj_get_type_str(arg))); } -#endif - } else { // arg doesn't look like a number if (align == '=') { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "'=' alignment not allowed in string format specifier")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "'=' alignment not allowed in string format specifier")); } switch (type) { @@ -876,7 +887,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Unknown format code '%c' for object of type 'str'", type, mp_obj_get_type_str(arg))); } @@ -892,36 +903,166 @@ 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_raise(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_raise(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_raise(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; } - arg_i++; +#if MICROPY_ENABLE_FLOAT + // This is what CPython reports, so we report the same. + if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float")); + + } +#endif + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required")); + break; + + case 'd': + case 'i': + case 'u': + pfenv_print_int(&pfenv_vstr, arg_as_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, arg_as_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; + } + 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, arg_as_int(arg), 1, 16, 'a', flags, fill, width); + break; + + case 'X': + if (alt) { + flags |= PF_FLAG_SHOW_PREFIX; + } + pfenv_print_int(&pfenv_vstr, arg_as_int(arg), 1, 16, 'A', flags, fill, width); + break; + + default: + nlr_raise(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) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting")); } mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); @@ -1050,7 +1191,7 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) { STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t direction) { assert(MP_OBJ_IS_STR(self_in)); if (!MP_OBJ_IS_STR(arg)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "Can't convert '%s' object to str implicitly", mp_obj_get_type_str(arg))); } @@ -1058,7 +1199,7 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t di GET_STR_DATA_LEN(arg, sep, sep_len); if (sep_len == 0) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator")); } mp_obj_t result[] = {MP_OBJ_NEW_QSTR(MP_QSTR_), MP_OBJ_NEW_QSTR(MP_QSTR_), MP_OBJ_NEW_QSTR(MP_QSTR_)}; @@ -1226,7 +1367,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { void bad_implicit_conversion(mp_obj_t self_in) __attribute__((noreturn)); void bad_implicit_conversion(mp_obj_t self_in) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "Can't convert '%s' object to str implicitly", mp_obj_get_type_str(self_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "Can't convert '%s' object to str implicitly", mp_obj_get_type_str(self_in))); } uint mp_obj_str_get_hash(mp_obj_t self_in) { diff --git a/py/objtuple.c b/py/objtuple.c index d6a5bb3d0..21313f7f9 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -67,7 +67,7 @@ mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m } default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "tuple takes at most 1 argument, %d given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "tuple takes at most 1 argument, %d given", n_args)); } } diff --git a/py/objtype.c b/py/objtype.c index f4ce6a4f8..e8201ca07 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -107,13 +107,13 @@ STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const m m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw); } if (init_ret != mp_const_none) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); } } else { // TODO if (n_args != 0) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 0 positional arguments but %d were given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 0 positional arguments but %d were given", n_args)); } } @@ -298,7 +298,7 @@ STATIC mp_obj_t type_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); default: - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments")); } } @@ -308,7 +308,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj mp_obj_type_t *self = self_in; if (self->make_new == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%s' instances", qstr_str(self->name))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%s' instances", qstr_str(self->name))); } // make new instance @@ -367,6 +367,16 @@ STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { return false; } +STATIC mp_obj_t type_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + case MP_BINARY_OP_EQUAL: + // Types can be equal only if it's the same type structure, + // we don't even need to check for 2nd arg type. + return MP_BOOL(lhs_in == rhs_in); + } + return NULL; +} + const mp_obj_type_t mp_type_type = { { &mp_type_type }, .name = MP_QSTR_type, @@ -375,6 +385,7 @@ const mp_obj_type_t mp_type_type = { .call = type_call, .load_attr = type_load_attr, .store_attr = type_store_attr, + .binary_op = type_binary_op, }; mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { @@ -417,7 +428,7 @@ STATIC mp_obj_t super_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m if (n_args != 2 || n_kw != 0) { // 0 arguments are turned into 2 in the compiler // 1 argument is not yet implemented - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "super() requires 2 arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "super() requires 2 arguments")); } return mp_obj_new_super(args[0], args[1]); } @@ -517,7 +528,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes")); } for (uint i = 0; i < len; i++) { @@ -530,7 +541,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class")); } return mp_obj_is_subclass(object, classinfo); } @@ -550,7 +561,7 @@ STATIC mp_obj_t static_class_method_make_new(mp_obj_t self_in, uint n_args, uint assert(self_in == &mp_type_staticmethod || self_in == &mp_type_classmethod); if (n_args != 1 || n_kw != 0) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 1 positional argument but %d were given", n_args)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 1 positional argument but %d were given", n_args)); } mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t); diff --git a/py/parsenum.c b/py/parsenum.c index 7be53897a..c7cf68dad 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -19,7 +19,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { // check radix base if ((base != 0 && base < 2) || base > 36) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "ValueError: int() arg 2 must be >=2 and <= 36")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "ValueError: int() arg 2 must be >=2 and <= 36")); } // skip leading space @@ -93,11 +93,11 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { return MP_OBJ_NEW_SMALL_INT(int_val); value_error: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str)); overflow: // TODO reparse using bignum - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer")); } #define PARSE_DEC_IN_INTG (1) @@ -208,7 +208,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f // check we reached the end of the string if (str != top) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); } // return the object @@ -221,6 +221,6 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f } #else - nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported")); #endif } diff --git a/py/pfenv.c b/py/pfenv.c index 7ce721aca..0d6fab3c4 100644 --- a/py/pfenv.c +++ b/py/pfenv.c @@ -79,10 +79,10 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in // We can use 16 characters for 32-bit and 32 characters for 64-bit #define INT_BUF_SIZE (sizeof(machine_int_t) * 4) -int pfenv_print_int(const pfenv_t *pfenv, unsigned int x, int sgn, int base, int base_char, int flags, char fill, int width) { +int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width) { char sign = 0; if (sgn) { - if ((int)x < 0) { + if ((machine_int_t)x < 0) { sign = '-'; x = -x; } else if (flags & PF_FLAG_SHOW_SIGN) { diff --git a/py/pfenv.h b/py/pfenv.h index edceaf3e4..36b452b91 100644 --- a/py/pfenv.h +++ b/py/pfenv.h @@ -17,7 +17,7 @@ typedef struct _pfenv_t { void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len); int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width); -int pfenv_print_int(const pfenv_t *pfenv, unsigned int x, int sgn, int base, int base_char, int flags, char fill, int width); +int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width); #if MICROPY_ENABLE_FLOAT int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec); #endif diff --git a/py/py-version.sh b/py/py-version.sh new file mode 100755 index 000000000..f574b574f --- /dev/null +++ b/py/py-version.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +git_hash="$(git rev-parse --short HEAD 2> /dev/null || echo unknown)" +git_files_are_clean=1 +# Check if there are any modified files. +git diff --no-ext-diff --quiet --exit-code 2> /dev/null || git_files_are_clean=0 +# Check if there are any staged files. +git diff-index --cached --quiet HEAD -- 2> /dev/null || git_files_are_clean=0 +if [ "${git_files_are_clean}" != "1" ]; then + git_hash="${git_hash}-dirty" +fi +cat <<EOF +// This file was generated by py/py-version.sh +#define MICROPY_GIT_HASH "${git_hash}" +#define MICROPY_BUILD_DATE "$(date '+%Y-%m-%d')" +EOF @@ -78,17 +78,26 @@ PY_O_BASENAME = \ builtintables.o \ modarray.o \ modcollections.o \ + modio.o \ modmath.o \ modmicropython.o \ vm.o \ showbc.o \ repl.o \ - intdivmod.o \ + smallint.o \ pfenv.o \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) +# Anything that depends on FORCE will be considered out-of-date +FORCE: +.PHONY: FORCE + +$(PY_BUILD)/py-version.h: FORCE + $(Q)$(PY_SRC)/py-version.sh > $@.tmp + $(Q)if [ -f "$@" ] && cmp -s $@ $@.tmp; then rm $@.tmp; else echo "Generating $@"; mv $@.tmp $@; fi + # qstr data # Adding an order only dependency on $(PY_BUILD) causes $(PY_BUILD) to get @@ -103,7 +112,7 @@ $(PY_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(PY_SRC)/makeqst # the right .o's to get recompiled if the generated.h file changes. Adding # an order-only dependendency to all of the .o's will cause the generated .h # to get built before we try to compile any of them. -$(PY_O): | $(PY_BUILD)/qstrdefs.generated.h +$(PY_O): | $(PY_BUILD)/qstrdefs.generated.h $(PY_BUILD)/py-version.h # emitters diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 591c96a94..2271941a0 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -99,6 +99,7 @@ Q(float) Q(getattr) Q(hash) Q(id) +Q(io) Q(int) Q(isinstance) Q(issubclass) diff --git a/py/runtime.c b/py/runtime.c index e2e349564..c7b34c1e1 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 @@ -33,6 +33,14 @@ STATIC mp_map_t *map_locals; STATIC mp_map_t *map_globals; STATIC mp_map_t map_builtins; +STATIC mp_map_t map_main; + +const mp_obj_module_t mp_module___main__ = { + .base = { &mp_type_module }, + .name = MP_QSTR___main__, + .globals = (mp_map_t*)&map_main, +}; + // a good optimising compiler will inline this if necessary STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; @@ -41,17 +49,18 @@ STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) { void mp_init(void) { mp_emit_glue_init(); - // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) - map_locals = map_globals = mp_map_new(1); - - // init built-in hash table - mp_map_init(&map_builtins, 3); - // init global module stuff mp_module_init(); + mp_map_init(&map_main, 1); // add some builtins that can't be done in ROM - mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + mp_map_add_qstr(&map_main, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + + // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New()) + map_locals = map_globals = &map_main; + + // init built-in hash table + mp_map_init(&map_builtins, 3); #if MICROPY_CPYTHON_COMPAT // Precreate sys module, so "import sys" didn't throw exceptions. @@ -93,13 +102,15 @@ mp_obj_t mp_load_const_bytes(qstr qstr) { mp_obj_t mp_load_name(qstr qstr) { // logic: search locals, globals, builtins - DEBUG_OP_printf("load name %s\n", qstr_str(qstr)); - mp_map_elem_t *elem = mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP); - if (elem != NULL) { - return elem->value; - } else { - return mp_load_global(qstr); + DEBUG_OP_printf("load name %s\n", map_locals, qstr_str(qstr)); + // If we're at the outer scope (locals == globals), dispatch to load_global right away + if (map_locals != map_globals) { + mp_map_elem_t *elem = mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP); + if (elem != NULL) { + return elem->value; + } } + return mp_load_global(qstr); } mp_obj_t mp_load_global(qstr qstr) { @@ -113,7 +124,7 @@ mp_obj_t mp_load_global(qstr qstr) { if (o != MP_OBJ_NULL) { return o; } - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr))); } } return elem->value; @@ -139,6 +150,7 @@ void mp_store_name(qstr qstr, mp_obj_t obj) { void mp_delete_name(qstr qstr) { DEBUG_OP_printf("delete name %s\n", qstr_str(qstr)); + // TODO raise NameError if qstr not found mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); } @@ -179,7 +191,7 @@ mp_obj_t mp_unary_op(int op, mp_obj_t arg) { } } // TODO specify in error message what the operator is - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bad operand type for unary operator: '%s'", mp_obj_get_type_str(arg))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bad operand type for unary operator: '%s'", mp_obj_get_type_str(arg))); } } @@ -259,7 +271,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_LSHIFT: { if (rhs_val < 0) { // negative shift not allowed - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); } else if (rhs_val >= BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); @@ -274,7 +286,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_RSHIFT: if (rhs_val < 0) { // negative shift not allowed - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); } else { // standard precision is enough for right-shift lhs_val >>= rhs_val; @@ -289,7 +301,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 +314,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 +329,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 +342,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) { @@ -364,21 +354,35 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { lhs = mp_obj_new_float(lhs_val); goto generic_binary_op; #else - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support")); #endif } else { - // TODO check for overflow machine_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { + if (mp_small_int_mul_overflow(ans, lhs_val)) { + goto power_overflow; + } ans *= lhs_val; } - lhs_val *= lhs_val; + if (rhs_val == 1) { + break; + } rhs_val /= 2; + if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { + goto power_overflow; + } + lhs_val *= lhs_val; } lhs_val = ans; } break; + + power_overflow: + // use higher precision + lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs)); + goto generic_binary_op; + case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break; case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break; case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break; @@ -426,7 +430,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return mp_const_false; } - nlr_jump(mp_obj_new_exception_msg_varg( + nlr_raise(mp_obj_new_exception_msg_varg( &mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(rhs))); return mp_const_none; @@ -446,13 +450,13 @@ generic_binary_op: // TODO implement dispatch for reverse binary ops // TODO specify in error message what the operator is - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported operand types for binary operator: '%s', '%s'", mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs))); return mp_const_none; zero_division: - nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero")); } mp_obj_t mp_call_function_0(mp_obj_t fun) { @@ -490,7 +494,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, uint n_args, uint n_kw, const mp if (type->call != NULL) { return type->call(fun_in, n_args, n_kw, args); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in))); } } @@ -681,17 +685,19 @@ void mp_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) { return; too_short: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", seq_len)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", seq_len)); too_long: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", num)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", num)); } -mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { +mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) { DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr)); - // use load_method mp_obj_t dest[2]; - mp_load_method(base, attr, dest); - if (dest[1] == MP_OBJ_NULL) { + // use load_method, raising or not raising exception + ((defval == MP_OBJ_NULL) ? mp_load_method : mp_load_method_maybe)(base, attr, dest); + if (dest[0] == MP_OBJ_NULL) { + return defval; + } else if (dest[1] == MP_OBJ_NULL) { // load_method returned just a normal attribute return dest[0]; } else { @@ -700,6 +706,10 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { } } +mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { + return mp_load_attr_default(base, attr, MP_OBJ_NULL); +} + // no attribute found, returns: dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL // normal attribute found, returns: dest[0] == <attribute>, dest[1] == MP_OBJ_NULL // method attribute found, returns: dest[0] == <method>, dest[1] == <self> @@ -764,10 +774,10 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { // no attribute/method called attr // following CPython, we give a more detailed error message for type objects if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%s' has no attribute '%s'", qstr_str(((mp_obj_type_t*)base)->name), qstr_str(attr))); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr))); } } } @@ -780,7 +790,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { return; } } - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr))); } void mp_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { @@ -800,7 +810,22 @@ void mp_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } // TODO: call base classes here? } - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); + } +} + +void mp_delete_subscr(mp_obj_t base, mp_obj_t index) { + DEBUG_OP_printf("delete subscr %p[%p]\n", base, index); + /* list delete not implemented + if (MP_OBJ_IS_TYPE(base, &mp_type_list)) { + // list delete + mp_obj_list_delete(base, index); + } else */ + if (MP_OBJ_IS_TYPE(base, &mp_type_dict)) { + // dict delete + mp_obj_dict_delete(base, index); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base))); } } @@ -822,7 +847,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in) { return mp_obj_new_getitem_iter(dest); } else { // object not iterable - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); } } } @@ -842,7 +867,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { // __next__ exists, call it and return its result return mp_call_method_n_kw(0, 0, dest); } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); } } } @@ -868,11 +893,11 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { if (mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) { return MP_OBJ_NULL; } else { - nlr_jump(nlr.ret_val); + nlr_raise(nlr.ret_val); } } } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); } } } @@ -929,7 +954,7 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th if (dest[0] != MP_OBJ_NULL) { *ret_val = mp_call_method_n_kw(1, 0, &throw_value); // If .throw() method returned, we assume it's value to yield - // - any exception would be thrown with nlr_jump(). + // - any exception would be thrown with nlr_raise(). return MP_VM_RETURN_YIELD; } // If there's nowhere to throw exception into, then we assume that object @@ -1018,6 +1043,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_raise((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/runtime.h b/py/runtime.h index b233d23b4..6b3ab73d8 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -45,10 +45,12 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_ void mp_unpack_sequence(mp_obj_t seq, uint num, mp_obj_t *items); mp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value); mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); +mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval); void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); void mp_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val); +void mp_delete_subscr(mp_obj_t base, mp_obj_t index); mp_obj_t mp_getiter(mp_obj_t o); mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_NULL instead of raising StopIteration() diff --git a/py/sequence.c b/py/sequence.c index 3aae4b942..3a4d65d53 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -159,7 +159,7 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp } } - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence")); } mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value) { diff --git a/py/smallint.c b/py/smallint.c new file mode 100644 index 000000000..ac0cf2f5f --- /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 000000000..14234fa7b --- /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); diff --git a/py/stream.c b/py/stream.c index a0a2c68f8..56f475a0c 100644 --- a/py/stream.c +++ b/py/stream.c @@ -16,7 +16,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0]; if (o->type->stream_p.read == NULL) { // CPython: io.UnsupportedOperation, OSError subclass - nlr_jump(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); } machine_int_t sz; @@ -27,7 +27,7 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) { int error; machine_int_t out_sz = o->type->stream_p.read(o, buf, sz, &error); if (out_sz == -1) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); } else { mp_obj_t s = mp_obj_new_str(buf, out_sz, false); // will reallocate to use exact size m_free(buf, sz); @@ -39,7 +39,7 @@ STATIC mp_obj_t stream_write(mp_obj_t self_in, mp_obj_t arg) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)self_in; if (o->type->stream_p.write == NULL) { // CPython: io.UnsupportedOperation, OSError subclass - nlr_jump(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); } uint sz; @@ -47,7 +47,7 @@ STATIC mp_obj_t stream_write(mp_obj_t self_in, mp_obj_t arg) { int error; machine_int_t out_sz = o->type->stream_p.write(self_in, buf, sz, &error); if (out_sz == -1) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); } else { // http://docs.python.org/3/library/io.html#io.RawIOBase.write // "None is returned if the raw stream is set not to block and no single byte could be readily written to it." @@ -62,7 +62,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)self_in; if (o->type->stream_p.read == NULL) { // CPython: io.UnsupportedOperation, OSError subclass - nlr_jump(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); } int total_size = 0; @@ -74,7 +74,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { while (true) { machine_int_t out_sz = o->type->stream_p.read(self_in, p, current_read, &error); if (out_sz == -1) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); } if (out_sz == 0) { break; @@ -88,7 +88,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) { p = vstr_extend(vstr, current_read); if (p == NULL) { // TODO - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); } } } @@ -103,7 +103,7 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0]; if (o->type->stream_p.read == NULL) { // CPython: io.UnsupportedOperation, OSError subclass - nlr_jump(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported")); } machine_int_t max_size = -1; @@ -123,12 +123,12 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { char *p = vstr_add_len(vstr, 1); if (p == NULL) { // TODO - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); } machine_int_t out_sz = o->type->stream_p.read(o, p, 1, &error); if (out_sz == -1) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); } if (out_sz == 0) { // Back out previously added byte @@ -158,7 +158,7 @@ outer_dispatch_loop: if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) { mp_obj_t t = inject_exc; inject_exc = MP_OBJ_NULL; - nlr_jump(mp_make_raise_obj(t)); + nlr_raise(mp_make_raise_obj(t)); } // loop to execute byte code for (;;) { @@ -324,6 +324,11 @@ dispatch_loop: mp_delete_name(qst); break; + case MP_BC_DELETE_SUBSCR: + mp_delete_subscr(sp[-1], sp[0]); + sp -= 2; + break; + case MP_BC_DUP_TOP: obj1 = TOP(); PUSH(obj1); @@ -503,7 +508,7 @@ unwind_jump: // if TOS is an integer, does something else // else error if (mp_obj_is_exception_type(TOP())) { - nlr_jump(sp[-1]); + nlr_raise(sp[-1]); } if (TOP() == mp_const_none) { sp--; @@ -744,12 +749,12 @@ unwind_return: } } if (obj1 == MP_OBJ_NULL) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise")); } } else { obj1 = POP(); } - nlr_jump(mp_make_raise_obj(obj1)); + nlr_raise(mp_make_raise_obj(obj1)); case MP_BC_YIELD_VALUE: yield: @@ -762,7 +767,7 @@ yield: case MP_BC_YIELD_FROM: { //#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) #define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) -#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { nlr_jump(t); } +#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { nlr_raise(t); } mp_vm_return_kind_t ret_kind; obj1 = POP(); mp_obj_t t_exc = MP_OBJ_NULL; @@ -805,7 +810,7 @@ yield: GENERATOR_EXIT_IF_NEEDED(t_exc); break; } else { - nlr_jump(obj2); + nlr_raise(obj2); } } } @@ -849,8 +854,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); @@ -429,7 +429,7 @@ mp_obj_t pyb_ADC(mp_obj_t pin_name_obj) { } if (i == ADC_NUM_CHANNELS) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin_name)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin_name)); } // init ADC just for this channel @@ -440,7 +440,7 @@ mp_obj_t pyb_ADC(mp_obj_t pin_name_obj) { return o; pin_error: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not exist", pin_name)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not exist", pin_name)); } MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_obj, pyb_ADC); diff --git a/stm/audio.c b/stm/audio.c index a4e42918c..e9e872813 100644 --- a/stm/audio.c +++ b/stm/audio.c @@ -125,7 +125,7 @@ mp_obj_t pyb_audio_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { mp_obj_type_t *type = mp_obj_get_type(args[1]); if (type->buffer_p.get_buffer == NULL) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol")); } buffer_info_t bufinfo; type->buffer_p.get_buffer(args[1], &bufinfo, BUFFER_READ); diff --git a/stm/exti.c b/stm/exti.c index ab33481eb..c6dfd9d1a 100644 --- a/stm/exti.c +++ b/stm/exti.c @@ -110,10 +110,10 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp // get both the port number and line number. v_line = mp_obj_get_int(pin_obj); if (v_line < 16) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d < 16, use a Pin object", v_line)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d < 16, use a Pin object", v_line)); } if (v_line >= EXTI_NUM_VECTORS) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d >= max of %d", v_line, EXTI_NUM_VECTORS)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d >= max of %d", v_line, EXTI_NUM_VECTORS)); } } else { pin = pin_map_user_obj(pin_obj); @@ -121,16 +121,16 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp } int mode = mp_obj_get_int(mode_obj); if (!IS_EXTI_MODE(mode)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Mode: %d", mode)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Mode: %d", mode)); } int trigger = mp_obj_get_int(trigger_obj); if (!IS_EXTI_TRIGGER(trigger)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Trigger: %d", trigger)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Trigger: %d", trigger)); } exti_vector_t *v = &exti_vector[v_line]; if (v->callback_obj != mp_const_none && callback_obj != mp_const_none) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line)); } // We need to update callback and param atomically, so we disable the line diff --git a/stm/file.c b/stm/file.c index a8f66f4b0..8abb45b4e 100644 --- a/stm/file.c +++ b/stm/file.c @@ -93,3 +93,5 @@ mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) { } return self; } + +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_open_obj, pyb_io_open); diff --git a/stm/mpconfigport.h b/stm/mpconfigport.h index 3f48c43f0..4c8338be5 100644 --- a/stm/mpconfigport.h +++ b/stm/mpconfigport.h @@ -18,6 +18,8 @@ #define MICROPY_ENABLE_LFN (0) #define MICROPY_LFN_CODE_PAGE (1) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +extern const struct _mp_obj_fun_native_t mp_builtin_open_obj; + // type definitions for the specific machine #define BYTES_PER_WORD (4) diff --git a/stm/pin_map.c b/stm/pin_map.c index 9082afe49..c5754ca33 100644 --- a/stm/pin_map.c +++ b/stm/pin_map.c @@ -164,7 +164,7 @@ const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj) { pin_obj = mp_call_function_1(pin_map_obj.mapper, user_obj); if (pin_obj != mp_const_none) { if (!MP_OBJ_IS_TYPE(pin_obj, &pin_obj_type)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object")); } if (pin_map_obj.debug) { printf("Pin.mapper maps "); @@ -222,5 +222,5 @@ const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj) { return pin_obj; } - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name)); } diff --git a/stm/pybwlan.c b/stm/pybwlan.c index 8d8ce3243..f4e6f8021 100644 --- a/stm/pybwlan.c +++ b/stm/pybwlan.c @@ -123,12 +123,12 @@ mp_obj_t pyb_wlan_http_get(mp_obj_t host_name, mp_obj_t host_path) { last_ip = (192 << 24) | (168 << 16) | (0 << 8) | (3); } else { if (pyb_wlan_get_host(host_name) == mp_const_none) { - nlr_jump(mp_obj_new_exception_msg(QSTR_FROM_STR_STATIC("WlanError"), "unknown host")); + nlr_raise(mp_obj_new_exception_msg(QSTR_FROM_STR_STATIC("WlanError"), "unknown host")); } } int sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sd < 0) { - nlr_jump(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "socket failed: %d", sd)); + nlr_raise(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "socket failed: %d", sd)); } //printf("socket seemed to work\n"); //sys_tick_delay_ms(200); @@ -139,7 +139,7 @@ mp_obj_t pyb_wlan_http_get(mp_obj_t host_name, mp_obj_t host_path) { remote.sin_addr.s_addr = htonl(last_ip); int ret = connect(sd, (sockaddr*)&remote, sizeof(sockaddr)); if (ret != 0) { - nlr_jump(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "connect failed: %d", ret)); + nlr_raise(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "connect failed: %d", ret)); } //printf("connect seemed to work\n"); //sys_tick_delay_ms(200); @@ -160,7 +160,7 @@ mp_obj_t pyb_wlan_http_get(mp_obj_t host_name, mp_obj_t host_path) { ret = send(sd, query + sent, strlen(query + sent), 0); //printf("sent %d bytes\n", ret); if (ret < 0) { - nlr_jump(mp_obj_new_exception_msg(QSTR_FROM_STR_STATIC("WlanError"), "send failed")); + nlr_raise(mp_obj_new_exception_msg(QSTR_FROM_STR_STATIC("WlanError"), "send failed")); } sent += ret; //sys_tick_delay_ms(200); @@ -197,7 +197,7 @@ mp_obj_t pyb_wlan_http_get(mp_obj_t host_name, mp_obj_t host_path) { // read data ret = recv(sd, buf, 64, 0); if (ret < 0) { - nlr_jump(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "recv failed %d", ret)); + nlr_raise(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "recv failed %d", ret)); } vstr_add_strn(vstr, buf, ret); } @@ -217,7 +217,7 @@ mp_obj_t pyb_wlan_serve(void) { sys_tick_delay_ms(500); if (sd < 0) { printf("socket fail\n"); - nlr_jump(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "socket failed: %d", sd)); + nlr_raise(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "socket failed: %d", sd)); } /* @@ -238,7 +238,7 @@ mp_obj_t pyb_wlan_serve(void) { sys_tick_delay_ms(100); if (ret != 0) { printf("bind fail\n"); - nlr_jump(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "bind failed: %d", ret)); + nlr_raise(mp_obj_new_exception_msg_varg(QSTR_FROM_STR_STATIC("WlanError"), "bind failed: %d", ret)); } printf("bind seemed to work\n"); diff --git a/stmhal/adc.c b/stmhal/adc.c index 0b4f3e23e..8a1c23c4f 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -131,16 +131,16 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_ const pin_obj_t *pin = pin_map_user_obj(pin_obj); if ((pin->adc_num & PIN_ADC1) == 0) { // No ADC1 function on that pin - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin->name)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin->name)); } channel = pin->adc_channel; } if (!IS_ADC_CHANNEL(channel)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Not a valid ADC Channel: %d", channel)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Not a valid ADC Channel: %d", channel)); } if (pin_adc1[channel] == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Channel %d not available on this board", channel)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Channel %d not available on this board", channel)); } pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t); @@ -192,7 +192,7 @@ void adc_init_all(pyb_obj_adc_all_t *adc_all, uint32_t resolution) { case 10: resolution = ADC_RESOLUTION10b; break; case 12: resolution = ADC_RESOLUTION12b; break; default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "resolution %d not supported", resolution)); } diff --git a/stmhal/autoflash b/stmhal/autoflash index 0f4bfd039..dc28a97e2 100755 --- a/stmhal/autoflash +++ b/stmhal/autoflash @@ -1,7 +1,13 @@ #!/bin/sh # -# this script waits for a DFU device to be attached and then flashes it -# it then waits until the DFU mode is exited, and then loops +# This script loops doing the following: +# - wait for DFU device +# - flash DFU device +# - wait for DFU to exit +# - wait for serial port to appear +# - run a terminal + +SERIAL=/dev/ttyACM0 while true; do echo "waiting for DFU device..." @@ -11,8 +17,10 @@ while true; do fi sleep 1s done + echo "found DFU device, flashing" dfu-util -a 0 -D build/flash.dfu + echo "waiting for DFU to exit..." while true; do if lsusb | grep -q DFU; then @@ -21,4 +29,15 @@ while true; do fi break done + + echo "waiting for $SERIAL..." + while true; do + if ls /dev/tty* | grep -q $SERIAL; then + break + fi + sleep 1s + continue + done + sleep 1s + picocom $SERIAL done diff --git a/stmhal/dac.c b/stmhal/dac.c index 4dbf70022..22622d474 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -77,7 +77,7 @@ STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const pin = GPIO_PIN_5; dac_obj = &pyb_dac_channel_2; } else { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Dac %d does not exist", dac_id)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Dac %d does not exist", dac_id)); } // GPIO configuration @@ -182,7 +182,7 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { mp_obj_type_t *type = mp_obj_get_type(args[1]); if (type->buffer_p.get_buffer == NULL) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "buffer argument must support buffer protocol")); } buffer_info_t bufinfo; type->buffer_p.get_buffer(args[1], &bufinfo, BUFFER_READ); diff --git a/stmhal/exti.c b/stmhal/exti.c index a9b05644c..afb8c8e13 100644 --- a/stmhal/exti.c +++ b/stmhal/exti.c @@ -116,10 +116,10 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob // get both the port number and line number. v_line = mp_obj_get_int(pin_obj); if (v_line < 16) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d < 16, use a Pin object", v_line)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d < 16, use a Pin object", v_line)); } if (v_line >= EXTI_NUM_VECTORS) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d >= max of %d", v_line, EXTI_NUM_VECTORS)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d >= max of %d", v_line, EXTI_NUM_VECTORS)); } } else { pin = pin_map_user_obj(pin_obj); @@ -132,18 +132,18 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob mode != GPIO_MODE_EVT_RISING && mode != GPIO_MODE_EVT_FALLING && mode != GPIO_MODE_EVT_RISING_FALLING) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Mode: %d", mode)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Mode: %d", mode)); } int pull = mp_obj_get_int(pull_obj); if (pull != GPIO_NOPULL && pull != GPIO_PULLUP && pull != GPIO_PULLDOWN) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Pull: %d", pull)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Pull: %d", pull)); } exti_vector_t *v = &exti_vector[v_line]; if (v->callback_obj != mp_const_none && callback_obj != mp_const_none) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line)); } // We need to update callback and param atomically, so we disable the line diff --git a/stmhal/file.c b/stmhal/file.c index 9575ffd7e..a66b59b29 100644 --- a/stmhal/file.c +++ b/stmhal/file.c @@ -4,6 +4,8 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "runtime.h" +#include "stream.h" #include "file.h" #include "ff.h" @@ -16,27 +18,18 @@ void file_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, m printf("<file %p>", self_in); } -mp_obj_t file_obj_read(mp_obj_t self_in, mp_obj_t arg) { +STATIC machine_int_t file_read(mp_obj_t self_in, void *buf, machine_uint_t size, int *errcode) { pyb_file_obj_t *self = self_in; - int n = mp_obj_get_int(arg); - byte *buf = m_new(byte, n); - UINT n_out; - f_read(&self->fp, buf, n, &n_out); - return mp_obj_new_str(buf, n_out, false); + UINT sz_out; + *errcode = f_read(&self->fp, buf, size, &sz_out); + return sz_out; } -mp_obj_t file_obj_write(mp_obj_t self_in, mp_obj_t arg) { +STATIC machine_int_t file_write(mp_obj_t self_in, const void *buf, machine_uint_t size, int *errcode) { pyb_file_obj_t *self = self_in; - uint l; - const char *s = mp_obj_str_get_data(arg, &l); - UINT n_out; - FRESULT res = f_write(&self->fp, s, l, &n_out); - if (res != FR_OK) { - printf("File error: could not write to file; error code %d\n", res); - } else if (n_out != l) { - printf("File error: could not write all data to file; wrote %d / %d bytes\n", n_out, l); - } - return mp_const_none; + UINT sz_out; + *errcode = f_write(&self->fp, buf, size, &sz_out); + return sz_out; } mp_obj_t file_obj_close(mp_obj_t self_in) { @@ -45,30 +38,49 @@ mp_obj_t file_obj_close(mp_obj_t self_in) { return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_2(file_obj_read_obj, file_obj_read); -static MP_DEFINE_CONST_FUN_OBJ_2(file_obj_write_obj, file_obj_write); -static MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); + +mp_obj_t file_obj___exit__(uint n_args, const mp_obj_t *args) { + return file_obj_close(args[0]); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__); // TODO gc hook to close the file if not already closed STATIC const mp_map_elem_t file_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&file_obj_read_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&file_obj_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&file_obj_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___enter__), (mp_obj_t)&mp_identity_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___exit__), (mp_obj_t)&file_obj___exit___obj }, }; STATIC MP_DEFINE_CONST_DICT(file_locals_dict, file_locals_dict_table); +STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args); static const mp_obj_type_t file_obj_type = { { &mp_type_type }, .name = MP_QSTR_File, + .make_new = file_obj_make_new, .print = file_obj_print, + .getiter = mp_identity, + .iternext = mp_stream_unbuffered_iter, + .stream_p = { + .read = file_read, + .write = file_write, + }, .locals_dict = (mp_obj_t)&file_locals_dict, }; -STATIC mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) { - const char *filename = mp_obj_str_get_str(o_filename); - const char *mode = mp_obj_str_get_str(o_mode); +STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + mp_check_nargs(n_args, 1, 2, n_kw, false); + const char *filename = mp_obj_str_get_str(args[0]); + const char *mode = "r"; + if (n_args > 1) { + mode = mp_obj_str_get_str(args[1]); + } pyb_file_obj_t *self = m_new_obj(pyb_file_obj_t); self->base.type = &file_obj_type; if (mode[0] == 'r') { @@ -92,4 +104,10 @@ STATIC mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) { return self; } -MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_open_obj, pyb_io_open); +// Factory function for I/O stream classes +STATIC mp_obj_t pyb_io_open(uint n_args, const mp_obj_t *args) { + // TODO: analyze mode and buffering args and instantiate appropriate type + return file_obj_make_new((mp_obj_t)&file_obj_type, n_args, 0, args); +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, pyb_io_open); diff --git a/stmhal/i2c.c b/stmhal/i2c.c index f35d00b54..e998d5941 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -86,7 +86,7 @@ STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const // check i2c number if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1)); } // get i2c object @@ -130,7 +130,7 @@ STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args) { if (status != HAL_OK) { // TODO really need a HardwareError object, or something - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Read failed with code %d", status)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Read failed with code %d", status)); } return mp_obj_str_builder_end(o); @@ -152,14 +152,14 @@ STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args) { uint8_t data[1] = {mp_obj_get_int(args[3])}; status = HAL_I2C_Mem_Write(self->i2c_handle, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, 1, 200); } else { - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "data argument must be an integer or support the buffer protocol")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "data argument must be an integer or support the buffer protocol")); } //printf("Write got %d\n", status); if (status != HAL_OK) { // TODO really need a HardwareError object, or something - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Write failed with code %d", status)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Write failed with code %d", status)); } return mp_const_none; diff --git a/stmhal/input.c b/stmhal/input.c index d704c2cf7..0ded89866 100644 --- a/stmhal/input.c +++ b/stmhal/input.c @@ -14,7 +14,7 @@ STATIC mp_obj_t mp_builtin_input(uint n_args, const mp_obj_t *args) { vstr_init(&line, 16); int ret = readline(&line, ""); if (line.len == 0 && ret == VCP_CHAR_CTRL_D) { - nlr_jump(mp_obj_new_exception(&mp_type_EOFError)); + nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); } mp_obj_t o = mp_obj_new_str((const byte*)line.buf, line.len, false); vstr_clear(&line); diff --git a/stmhal/led.c b/stmhal/led.c index 3108ee779..5c2d2c60a 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -204,7 +204,7 @@ STATIC mp_obj_t led_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const // check led number if (!(0 <= led_id && led_id < NUM_LEDS)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Led %d does not exist", led_id)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Led %d does not exist", led_id)); } // return static led object diff --git a/stmhal/main.c b/stmhal/main.c index afef84e29..897271d14 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -434,7 +434,7 @@ soft_reset: #endif // run main script - if (reset_mode == 1) { + if (reset_mode == 1 && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { vstr_t *vstr = vstr_new(); vstr_add_str(vstr, "0:/"); if (pyb_config_source_dir == MP_OBJ_NULL) { diff --git a/stmhal/math.c b/stmhal/math.c index 8afdc82a6..9b815f118 100644 --- a/stmhal/math.c +++ b/stmhal/math.c @@ -1,4 +1,6 @@ #include <stdint.h> +#include <math.h> + typedef float float_t; typedef union { float f; @@ -44,12 +46,6 @@ double __aeabi_dmul(double x , double y) { return 0.0; } -/* -double sqrt(double x) { - // TODO - return 0.0; -} -*/ float sqrtf(float x) { asm volatile ( @@ -59,12 +55,18 @@ float sqrtf(float x) { return x; } +// some compilers define log2f in terms of logf +#ifdef log2f +#undef log2f +#endif +float log2f(float x) { return logf(x) / (float)_M_LN2; } + +static const float _M_LN10 = 2.30258509299404; // 0x40135d8e +float log10f(float x) { return logf(x) / (float)_M_LN10; } + +float tanhf(float x) { return sinhf(x) / coshf(x); } + // TODO we need import these functions from some library (eg musl or newlib) -float powf(float x, float y) { return 0.0; } -float logf(float x) { return 0.0; } -float log2f(float x) { return 0.0; } -float log10f(float x) { return 0.0; } -float tanhf(float x) { return 0.0; } float acoshf(float x) { return 0.0; } float asinhf(float x) { return 0.0; } float atanhf(float x) { return 0.0; } @@ -86,10 +88,12 @@ float erfcf(float x) { return 0.0; } float modff(float x, float *y) { return 0.0; } float frexpf(float x, int *exp) { return 0.0; } float ldexpf(float x, int exp) { return 0.0; } -int __fpclassifyf(float x) { return 0; } /*****************************************************************************/ +/*****************************************************************************/ // from musl-0.9.15 libm.h +/*****************************************************************************/ +/*****************************************************************************/ /* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ /* @@ -136,7 +140,25 @@ do { \ } while (0) /*****************************************************************************/ +/*****************************************************************************/ +// __fpclassifyf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +int __fpclassifyf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +/*****************************************************************************/ +/*****************************************************************************/ // scalbnf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ float scalbnf(float x, int n) { @@ -168,7 +190,274 @@ float scalbnf(float x, int n) } /*****************************************************************************/ +/*****************************************************************************/ +// powf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ +cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if (iy == 0) + return 1.0f; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3f800000) + return 1.0f; + /* NaN if either arg is NaN */ + if (ix > 0x7f800000 || iy > 0x7f800000) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x4b800000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3f800000) { + k = (iy>>23) - 0x7f; /* exponent */ + j = iy>>(23-k); + if ((j<<(23-k)) == iy) + yisint = 2 - (j & 1); + } + } + + /* special value of y */ + if (iy == 0x7f800000) { /* y is +-inf */ + if (ix == 0x3f800000) /* (-1)**+-inf is 1 */ + return 1.0f; + else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0f; + else if (ix != 0) /* (|x|<1)**+-inf = 0,inf if x!=0 */ + return hy >= 0 ? 0.0f: -y; + } + if (iy == 0x3f800000) /* y is +-1 */ + return hy >= 0 ? x : 1.0f/x; + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3f000000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if (ix == 0x7f800000 || ix == 0 || ix == 0x3f800000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0f/z; + if (hx < 0) { + if (((ix-0x3f800000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + sn = 1.0f; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + sn = -1.0f; + } + + /* |y| is huge */ + if (iy > 0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if (ix < 0x3f7ffff8) + return hy < 0 ? sn*huge*huge : sn*tiny*tiny; + if (ix > 0x3f800007) + return hy > 0 ? sn*huge*huge : sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1; /* t has 20 trailing zeros */ + w = (t*t)*(0.5f - t*(0.333333333333f - t*0.25f)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = v - (t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00800000) { + ax *= two24; + n -= 24; + GET_FLOAT_WORD(ix, ax); + } + n += ((ix)>>23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if (j <= 0x1cc471) /* |x|<sqrt(3/2) */ + k = 0; + else if (j < 0x5db3d7) /* |x|<sqrt(3) */ + k = 1; + else { + k = 0; + n += 1; + ix -= 0x00800000; + } + SET_FLOAT_WORD(ax, ix); + + /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ + u = ax - bp[k]; /* bp[0]=1.0, bp[1]=1.5 */ + v = 1.0f/(ax+bp[k]); + s = u*v; + s_h = s; + GET_FLOAT_WORD(is, s_h); + SET_FLOAT_WORD(s_h, is & 0xfffff000); + /* t_h=ax+bp[k] High */ + is = ((ix>>1) & 0xfffff000) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k<<21)); + t_l = ax - (t_h - bp[k]); + s_l = v*((u - s_h*t_h) - s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = 3.0f + s2 + r; + GET_FLOAT_WORD(is, t_h); + SET_FLOAT_WORD(t_h, is & 0xfffff000); + t_l = r - ((t_h - 3.0f) - s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + GET_FLOAT_WORD(is, p_h); + SET_FLOAT_WORD(p_h, is & 0xfffff000); + p_l = v - (p_h - u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h + p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h + z_l) + dp_h[k]) + t); + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is, y); + SET_FLOAT_WORD(y1, is & 0xfffff000); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + GET_FLOAT_WORD(j, z); + if (j > 0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j == 0x43000000) { /* if z == 128 */ + if (p_l + ovt > z - p_h) + return sn*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) > 0x43160000) /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn*tiny*tiny; /* underflow */ + else if (j == 0xc3160000) { /* z == -150 */ + if (p_l <= z-p_h) + return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>23) - 0x7f; + n = 0; + if (i > 0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23) - 0x7f; /* new k for n */ + SET_FLOAT_WORD(t, n & ~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + GET_FLOAT_WORD(is, t); + SET_FLOAT_WORD(t, is & 0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z - u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0f) - (w+z*w); + z = 1.0f - (r - z); + GET_FLOAT_WORD(j, z); + j += n<<23; + if ((j>>23) <= 0) /* subnormal output */ + z = scalbnf(z, n); + else + SET_FLOAT_WORD(z, j); + return sn*z; +} + +/*****************************************************************************/ +/*****************************************************************************/ // expf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ /* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ /* @@ -194,8 +483,8 @@ invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */ * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 */ -P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */ -P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */ +expf_P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */ +expf_P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */ float expf(float x) { @@ -243,7 +532,7 @@ float expf(float x) /* x is now in primary range */ xx = x*x; - c = x - xx*(P1+xx*P2); + c = x - xx*(expf_P1+xx*expf_P2); y = 1 + (x*c/(2-c) - lo + hi); if (k == 0) return y; @@ -251,7 +540,10 @@ float expf(float x) } /*****************************************************************************/ +/*****************************************************************************/ // expm1f from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ /* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ /* @@ -364,7 +656,10 @@ float expm1f(float x) } /*****************************************************************************/ +/*****************************************************************************/ // __expo2f from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ /* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ static const int k = 235; @@ -382,7 +677,81 @@ float __expo2f(float x) } /*****************************************************************************/ +/*****************************************************************************/ +// logf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +static const float +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float logf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} + +/*****************************************************************************/ +/*****************************************************************************/ // coshf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ float coshf(float x) { @@ -417,7 +786,10 @@ float coshf(float x) } /*****************************************************************************/ +/*****************************************************************************/ // sinhf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ float sinhf(float x) { diff --git a/stmhal/modos.c b/stmhal/modos.c index 5684d1105..6103b1b4f 100644 --- a/stmhal/modos.c +++ b/stmhal/modos.c @@ -38,7 +38,7 @@ STATIC mp_obj_t os_listdir(uint n_args, const mp_obj_t *args) { res = f_opendir(&dir, path); /* Open the directory */ if (res != FR_OK) { // TODO should be mp_type_FileNotFoundError - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "No such file or directory: '%s'", path)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "No such file or directory: '%s'", path)); } mp_obj_t dir_list = mp_obj_new_list(0, NULL); @@ -91,9 +91,9 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_o) { return mp_const_none; case FR_EXIST: // TODO should be FileExistsError - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path)); default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path)); } } @@ -107,7 +107,7 @@ STATIC mp_obj_t os_remove(mp_obj_t path_o) { case FR_OK: return mp_const_none; default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path)); } } @@ -121,7 +121,7 @@ STATIC mp_obj_t os_rmdir(mp_obj_t path_o) { case FR_OK: return mp_const_none; default: - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing directory '%s'", path)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing directory '%s'", path)); } } diff --git a/stmhal/pin_map.c b/stmhal/pin_map.c index 2313540a3..c0c6910b2 100644 --- a/stmhal/pin_map.c +++ b/stmhal/pin_map.c @@ -164,7 +164,7 @@ const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj) { pin_obj = mp_call_function_1(pin_map_obj.mapper, user_obj); if (pin_obj != mp_const_none) { if (!MP_OBJ_IS_TYPE(pin_obj, &pin_obj_type)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object")); } if (pin_map_obj.debug) { printf("Pin.mapper maps "); @@ -222,5 +222,5 @@ const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj) { return pin_obj; } - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name)); } diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index ffee4dd2e..8bc3ec6e5 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -23,6 +23,7 @@ #include "pyexec.h" #include "storage.h" #include "usb.h" +#include "build/py/py-version.h" pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; STATIC bool repl_display_debugging_info = 0; @@ -120,9 +121,8 @@ raw_repl_reset: } else if (c == VCP_CHAR_CTRL_D) { // input finished break; - } else if (c == '\r') { - vstr_add_char(&line, '\n'); - } else if (32 <= c && c <= 126) { + } else if (c <= 127) { + // let through any other ASCII character vstr_add_char(&line, c); } } @@ -156,7 +156,7 @@ int pyexec_friendly_repl(void) { #endif friendly_repl_reset: - stdout_tx_str("Micro Python build <git hash> on 25/1/2014; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n"); + stdout_tx_str("Micro Python build " MICROPY_GIT_HASH " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n"); stdout_tx_str("Type \"help()\" for more information.\r\n"); // to test ctrl-C diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 0a7fe821d..3212de85b 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -21,6 +21,8 @@ Q(SW) Q(servo) Q(pwm) Q(read) +Q(readall) +Q(readline) Q(write) Q(hid) Q(time) diff --git a/stmhal/readline.c b/stmhal/readline.c index 7df347f03..13c2dc93c 100644 --- a/stmhal/readline.c +++ b/stmhal/readline.c @@ -1,3 +1,4 @@ +#include <stdio.h> #include <string.h> #include <stm32f4xx_hal.h> @@ -11,10 +12,19 @@ #include "readline.h" #include "usb.h" +#if 0 // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + #define READLINE_HIST_SIZE (8) static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O }; + void readline_init(void) { memset(readline_hist, 0, READLINE_HIST_SIZE * sizeof(const char*)); } @@ -30,7 +40,8 @@ STATIC char *str_dup(const char *str) { int readline(vstr_t *line, const char *prompt) { stdout_tx_str(prompt); int orig_line_len = line->len; - int escape_seq = 0; + int escape_seq = ESEQ_NONE; + char escape_seq_buf[1] = {0}; int hist_cur = -1; int cursor_pos = orig_line_len; for (;;) { @@ -39,10 +50,16 @@ int readline(vstr_t *line, const char *prompt) { int redraw_step_back = 0; bool redraw_from_cursor = false; int redraw_step_forward = 0; - if (escape_seq == 0) { + if (escape_seq == ESEQ_NONE) { if (VCP_CHAR_CTRL_A <= c && c <= VCP_CHAR_CTRL_D && vstr_len(line) == orig_line_len) { // control character with empty line return c; + } else if (c == VCP_CHAR_CTRL_A) { + // CTRL-A with non-empty line is go-to-start-of-line + goto home_key; + } else if (c == VCP_CHAR_CTRL_E) { + // CTRL-E is go-to-end-of-line + goto end_key; } else if (c == '\r') { // newline stdout_tx_str("\r\n"); @@ -57,7 +74,7 @@ int readline(vstr_t *line, const char *prompt) { return 0; } else if (c == 27) { // escape sequence - escape_seq = 1; + escape_seq = ESEQ_ESC; } else if (c == 8 || c == 127) { // backspace/delete if (cursor_pos > orig_line_len) { @@ -73,55 +90,99 @@ int readline(vstr_t *line, const char *prompt) { redraw_from_cursor = true; redraw_step_forward = 1; } - } else if (escape_seq == 1) { - if (c == '[') { - escape_seq = 2; - } else { - escape_seq = 0; + } else if (escape_seq == ESEQ_ESC) { + switch (c) { + case '[': + escape_seq = ESEQ_ESC_BRACKET; + break; + case 'O': + escape_seq = ESEQ_ESC_O; + break; + default: + DEBUG_printf("(ESC %d)", c); + escape_seq = ESEQ_NONE; } - } else if (escape_seq == 2) { - escape_seq = 0; - if (c == 'A') { - // up arrow - if (hist_cur + 1 < READLINE_HIST_SIZE && readline_hist[hist_cur + 1] != NULL) { - // increase hist num - hist_cur += 1; - // set line to history - line->len = orig_line_len; - vstr_add_str(line, readline_hist[hist_cur]); - // set redraw parameters - redraw_step_back = cursor_pos - orig_line_len; - redraw_from_cursor = true; - redraw_step_forward = line->len - orig_line_len; - } - } else if (c == 'B') { - // down arrow - if (hist_cur >= 0) { - // decrease hist num - hist_cur -= 1; - // set line to history - vstr_cut_tail_bytes(line, line->len - orig_line_len); - if (hist_cur >= 0) { + } else if (escape_seq == ESEQ_ESC_BRACKET) { + if ('0' <= c && c <= '9') { + escape_seq = ESEQ_ESC_BRACKET_DIGIT; + escape_seq_buf[0] = c; + } else { + escape_seq = ESEQ_NONE; + if (c == 'A') { + // up arrow + if (hist_cur + 1 < READLINE_HIST_SIZE && readline_hist[hist_cur + 1] != NULL) { + // increase hist num + hist_cur += 1; + // set line to history + line->len = orig_line_len; vstr_add_str(line, readline_hist[hist_cur]); + // set redraw parameters + redraw_step_back = cursor_pos - orig_line_len; + redraw_from_cursor = true; + redraw_step_forward = line->len - orig_line_len; } - // set redraw parameters - redraw_step_back = cursor_pos - orig_line_len; - redraw_from_cursor = true; - redraw_step_forward = line->len - orig_line_len; - } - } else if (c == 'C') { - // right arrow - if (cursor_pos < line->len) { - redraw_step_forward = 1; + } else if (c == 'B') { + // down arrow + if (hist_cur >= 0) { + // decrease hist num + hist_cur -= 1; + // set line to history + vstr_cut_tail_bytes(line, line->len - orig_line_len); + if (hist_cur >= 0) { + vstr_add_str(line, readline_hist[hist_cur]); + } + // set redraw parameters + redraw_step_back = cursor_pos - orig_line_len; + redraw_from_cursor = true; + redraw_step_forward = line->len - orig_line_len; + } + } else if (c == 'C') { + // right arrow + if (cursor_pos < line->len) { + redraw_step_forward = 1; + } + } else if (c == 'D') { + // left arrow + if (cursor_pos > orig_line_len) { + redraw_step_back = 1; + } + } else if (c == 'H') { + // home + goto home_key; + } else if (c == 'F') { + // end + goto end_key; + } else { + DEBUG_printf("(ESC [ %d)", c); } - } else if (c == 'D') { - // left arrow - if (cursor_pos > orig_line_len) { - redraw_step_back = 1; + } + } else if (escape_seq == ESEQ_ESC_BRACKET_DIGIT) { + if (c == '~') { + if (escape_seq_buf[0] == '1' || escape_seq_buf[0] == '7') { +home_key: + redraw_step_back = cursor_pos - orig_line_len; + } else if (escape_seq_buf[0] == '4' || escape_seq_buf[0] == '8') { +end_key: + redraw_step_forward = line->len - cursor_pos; + } else { + DEBUG_printf("(ESC [ %c %d)", escape_seq_buf[0], c); } + } else { + DEBUG_printf("(ESC [ %c %d)", escape_seq_buf[0], c); + } + escape_seq = ESEQ_NONE; + } else if (escape_seq == ESEQ_ESC_O) { + switch (c) { + case 'H': + goto home_key; + case 'F': + goto end_key; + default: + DEBUG_printf("(ESC O %d)", c); + escape_seq = ESEQ_NONE; } } else { - escape_seq = 0; + escape_seq = ESEQ_NONE; } // redraw command prompt, efficiently diff --git a/stmhal/servo.c b/stmhal/servo.c index 9c757c565..79a6843b7 100644 --- a/stmhal/servo.c +++ b/stmhal/servo.c @@ -27,8 +27,6 @@ typedef struct _pyb_servo_obj_t { uint16_t pulse_dest; } pyb_servo_obj_t; -STATIC const mp_obj_type_t servo_obj_type; - STATIC pyb_servo_obj_t pyb_servo_obj[PYB_SERVO_NUM]; void servo_init(void) { @@ -36,7 +34,7 @@ void servo_init(void) { // reset servo objects for (int i = 0; i < PYB_SERVO_NUM; i++) { - pyb_servo_obj[i].base.type = &servo_obj_type; + pyb_servo_obj[i].base.type = &pyb_servo_type; pyb_servo_obj[i].servo_id = i + 1; pyb_servo_obj[i].time_left = 0; pyb_servo_obj[i].pulse_cur = 150; // units of 10us @@ -149,7 +147,7 @@ STATIC mp_obj_t pyb_servo_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con // check servo number if (!(0 <= servo_id && servo_id < PYB_SERVO_NUM)) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Servo %d does not exist", servo_id)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Servo %d does not exist", servo_id + 1)); } // get and init servo object diff --git a/stmhal/timer.c b/stmhal/timer.c index cfdb93587..1e77f0fea 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -174,7 +174,7 @@ void timer_interrupt(void) { mp_obj_t pyb_Timer(mp_obj_t timx_in) { TIM_TypeDef *TIMx = (TIM_TypeDef*)mp_obj_get_int(timx_in); if (!IS_TIM_INSTANCE(TIMx)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "argument 1 is not a TIM instance")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "argument 1 is not a TIM instance")); } pyb_hal_tim_t *tim = m_new_obj(pyb_hal_tim_t); tim->htim.Instance = TIMx; diff --git a/stmhal/usart.c b/stmhal/usart.c index 9bcc6be28..3cf8da6de 100644 --- a/stmhal/usart.c +++ b/stmhal/usart.c @@ -145,7 +145,7 @@ STATIC void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // check arguments if (!(n_args == 2 && n_kw == 0)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "Usart accepts 2 arguments")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Usart accepts 2 arguments")); } if (mp_obj_get_int(args[0]) > PYB_USART_MAX) { diff --git a/stmhal/usb.h b/stmhal/usb.h index 014b51eef..a235c4765 100644 --- a/stmhal/usb.h +++ b/stmhal/usb.h @@ -3,6 +3,7 @@ #define VCP_CHAR_CTRL_B (2) #define VCP_CHAR_CTRL_C (3) #define VCP_CHAR_CTRL_D (4) +#define VCP_CHAR_CTRL_E (5) typedef enum { USB_DEVICE_MODE_CDC_MSC, diff --git a/teensy/main.c b/teensy/main.c index ea8726f76..740d0b238 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -190,7 +190,7 @@ mp_obj_t pyb_gpio(int n_args, mp_obj_t *args) { return mp_const_none; pin_error: - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin)); + nlr_raise(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin)); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio); diff --git a/teensy/servo.c b/teensy/servo.c index 51714dbcc..6ccdb05e9 100644 --- a/teensy/servo.c +++ b/teensy/servo.c @@ -70,7 +70,7 @@ static mp_obj_t servo_obj_attach(mp_obj_t self_in, mp_obj_t pin_obj) { return mp_const_none; pin_error: - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin)); + nlr_raise(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin)); } static mp_obj_t servo_obj_detach(mp_obj_t self_in) { @@ -217,7 +217,7 @@ mp_obj_t pyb_Servo(void) { self->servo_id++; } m_del_obj(pyb_servo_obj_t, self); - nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "No available servo ids")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "No available servo ids")); return mp_const_none; } diff --git a/tests/basics/dict-del.py b/tests/basics/dict-del.py new file mode 100644 index 000000000..d908fea42 --- /dev/null +++ b/tests/basics/dict-del.py @@ -0,0 +1,21 @@ +for n in range(20): + print('testing dict with {} items'.format(n)) + for i in range(n): + # create dict + d = dict() + for j in range(n): + d[str(j)] = j + print(len(d)) + + # delete an item + del d[str(i)] + print(len(d)) + + # check items + for j in range(n): + if str(j) in d: + if j == i: + print(j, 'in d, but it should not be') + else: + if j != i: + print(j, 'not in d, but it should be') diff --git a/tests/basics/getattr1.py b/tests/basics/getattr1.py index 7b7e07392..9a96154ca 100644 --- a/tests/basics/getattr1.py +++ b/tests/basics/getattr1.py @@ -13,3 +13,5 @@ a = A() print(getattr(a, "var")) print(getattr(a, "var2")) print(getattr(a, "meth")(5)) +print(getattr(a, "_none_such", 123)) +print(getattr(list, "foo", 456)) diff --git a/tests/basics/globals-del.py b/tests/basics/globals-del.py new file mode 100644 index 000000000..a1638ac27 --- /dev/null +++ b/tests/basics/globals-del.py @@ -0,0 +1,27 @@ +""" +1 +""" + +def _f(): pass +FunctionType = type(_f) +LambdaType = type(lambda: None) +CodeType = None +MappingProxyType = None +SimpleNamespace = None + +def _g(): + yield 1 +GeneratorType = type(_g()) + +class _C: + def _m(self): pass +MethodType = type(_C()._m) + +BuiltinFunctionType = type(len) +BuiltinMethodType = type([].append) + +del _f + +# print only the first 8 chars, since we have different str rep to CPython +print(str(FunctionType)[:8]) +print(str(BuiltinFunctionType)[:8]) diff --git a/tests/basics/math-fun.py b/tests/basics/math-fun.py index eb80ab0f5..7a37c5845 100644 --- a/tests/basics/math-fun.py +++ b/tests/basics/math-fun.py @@ -34,7 +34,7 @@ functions = [('sqrt', sqrt, p_test_values), for function_name, function, test_vals in functions: print(function_name) for value in test_vals: - print("{:8.7g}".format(function(value))) + print("{:.7g}".format(function(value))) binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.), (-23., -42.), (1., 0.0), (1., -0.0)]) @@ -43,4 +43,4 @@ binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.) for function_name, function, test_vals in binary_functions: print(function_name) for value1, value2 in test_vals: - print("{:8.7g}".format(function(value1, value2))) + print("{:.7g}".format(function(value1, value2))) diff --git a/tests/basics/memoryerror.py b/tests/basics/memoryerror.py new file mode 100644 index 000000000..b4be420c3 --- /dev/null +++ b/tests/basics/memoryerror.py @@ -0,0 +1,6 @@ +l = list(range(10000)) +try: + 100000000 * l +except MemoryError: + print('MemoryError') +print(len(l), l[0], l[-1]) diff --git a/tests/basics/set_remove.py b/tests/basics/set_remove.py index 208ab137f..5627516c4 100644 --- a/tests/basics/set_remove.py +++ b/tests/basics/set_remove.py @@ -1,3 +1,4 @@ +# basic test s = {1} print(s.remove(1)) print(list(s)) @@ -7,3 +8,26 @@ except KeyError: pass else: print("failed to raise KeyError") + +# test sets of varying size +for n in range(20): + print('testing set with {} items'.format(n)) + for i in range(n): + # create set + s = set() + for j in range(n): + s.add(str(j)) + print(len(s)) + + # delete an item + s.remove(str(i)) + print(len(s)) + + # check items + for j in range(n): + if str(j) in s: + if j == i: + print(j, 'in s, but it should not be') + else: + if j != i: + print(j, 'not in s, but it should be') diff --git a/tests/basics/string-format-modulo.py b/tests/basics/string-format-modulo.py index 0b50c2674..b736e2a73 100644 --- a/tests/basics/string-format-modulo.py +++ b/tests/basics/string-format-modulo.py @@ -20,3 +20,44 @@ try: print("=%s=" % (1, 2)) except TypeError: print("TypeError") + +print("%s" % True) +print("%s" % 1) +print("%s" % 1.0) + +print("%r" % True) +print("%r" % 1) +print("%r" % 1.0) + +print("%c" % 48) +print("%c" % 'a') +print("%10s" % 'abc') +print("%-10s" % 'abc') +print("%d" % 10) +print("%+d" % 10) +print("% d" % 10) +print("%d" % -10) +print("%d" % 1.0) +print("%d" % True) +print("%i" % -10) +print("%i" % 1.0) +print("%i" % True) +print("%u" % -10) +print("%u" % 1.0) +print("%u" % True) +print("%x" % 18) +print("%x" % 18.0) +print("%o" % 18) +print("%o" % 18.0) +print("%X" % 18) +print("%X" % 18.0) +print("%#x" % 18) +print("%#X" % 18) +print("%#6x" % 18) +print("%#06x" % 18) +print("%e" % 1.23456) +print("%E" % 1.23456) +print("%f" % 1.23456) +print("%F" % 1.23456) +print("%g" % 1.23456) +print("%G" % 1.23456) diff --git a/tests/basics/string-format.py b/tests/basics/string-format.py index 290030a9e..8049c6f73 100644 --- a/tests/basics/string-format.py +++ b/tests/basics/string-format.py @@ -58,6 +58,9 @@ test("{:10.4f}", 123.456) test("{:10.4f}", -123.456) test("{:10.4g}", 123.456) test("{:10.4g}", -123.456) +test("{:e}", 100) +test("{:f}", 200) +test("{:g}", 300) test("{:10.4E}", 123.456) test("{:10.4E}", -123.456) diff --git a/tests/basics/types2.py b/tests/basics/types2.py new file mode 100644 index 000000000..83a69c918 --- /dev/null +++ b/tests/basics/types2.py @@ -0,0 +1,12 @@ +# Types are hashable +print(hash(type) != 0) +print(hash(int) != 0) +print(hash(list) != 0) +class Foo: pass +print(hash(Foo) != 0) + +print(int == int) +print(int != list) + +d = {} +d[int] = float diff --git a/tests/io/file-with.py b/tests/io/file-with.py new file mode 100644 index 000000000..ee1e70242 --- /dev/null +++ b/tests/io/file-with.py @@ -0,0 +1,21 @@ +f = open("io/data/file1") + +with f as f2: + print(f2.read()) + +# File should be closed +try: + f.read() +except: + # Note: CPython and us throw different exception trying to read from + # close file. + print("can't read file after with") + + +# Regression test: test that exception in with initialization properly +# thrown and doesn't crash. +try: + with open('__non_existent', 'r'): + pass +except OSError: + print("OSError") diff --git a/tests/misc/rge-sm.py b/tests/misc/rge-sm.py index 40c6029b4..1860f7a31 100644 --- a/tests/misc/rge-sm.py +++ b/tests/misc/rge-sm.py @@ -111,4 +111,4 @@ def singleTraj(system, trajStart, h=0.02, tend=1.0): #phaseDiagram(sysSM, (lambda i, j: [0.354, 0.654, 1.278, 0.8 + 0.2 * i, 0.1 + 0.1 * j]), (lambda a: (a[4], a[5])), h=0.1, tend=math.log(10**17)) # initial conditions at M_Z -singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.1, tend=math.log(10**17)) # true values +singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.5, tend=math.log(10**17)) # true values diff --git a/tests/run-tests b/tests/run-tests index 834f1f930..22ddbe58e 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -5,11 +5,14 @@ import subprocess import sys from glob import glob +# Tests require at least CPython 3.3. If your default python3 executable +# is of lower version, you can point MICROPY_CPYTHON3 environment var +# to the correct executable. if os.name == 'nt': - CPYTHON3 = 'python3.exe' + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') MP_PY = '../windows/micropython.exe' else: - CPYTHON3 = 'python3' + CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') MP_PY = '../unix/micropython' def rm_f(fname): @@ -27,12 +30,28 @@ if not sys.argv[1:]: else: tests = sys.argv[1:] +test_on_pyboard = False +if test_on_pyboard: + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0') + pyb.enter_raw_repl() + for test_file in tests: test_name = os.path.splitext(os.path.basename(test_file))[0] - output_expected = subprocess.check_output([CPYTHON3, '-B', test_file]) + # run CPython + try: + output_expected = subprocess.check_output([CPYTHON3, '-B', test_file]) + except subprocess.CalledProcessError: + output_expected = b'CPYTHON3 CRASH' + + # run Micro Python try: - output_mupy = subprocess.check_output([MP_PY, test_file]) + if test_on_pyboard: + pyb.enter_raw_repl() + output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') + else: + output_mupy = subprocess.check_output([MP_PY, test_file]) except subprocess.CalledProcessError: output_mupy = b'CRASH' diff --git a/tools/pyboard.py b/tools/pyboard.py index 3ce6da521..1c5c84f30 100644 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -12,6 +12,11 @@ Example usage: pyb.exec('pyb.Led(1).on()') pyb.exit_raw_repl() +To run a script from the local machine on the board and print out the results: + + import pyboard + pyboard.execfile('test.py', device='/dev/ttyACM0') + """ import time @@ -45,29 +50,51 @@ class Pyboard: def exec(self, command): command_bytes = bytes(command, encoding='ascii') - for i in range(0, len(command_bytes), 10): - self.serial.write(command_bytes[i:min(i+10, len(command_bytes))]) + for i in range(0, len(command_bytes), 32): + self.serial.write(command_bytes[i:min(i+32, len(command_bytes))]) time.sleep(0.01) self.serial.write(b'\x04') data = self.serial.read(2) if data != b'OK': raise Exception('could not exec command') data = self.serial.read(2) - while self.serial.inWaiting() > 0: - data = data + self.serial.read(self.serial.inWaiting()) - time.sleep(0.1) + timeout = 0 + while True: + if self.serial.inWaiting() > 0: + data = data + self.serial.read(self.serial.inWaiting()) + timeout = 0 + elif data.endswith(b'\x04>'): + break + else: + timeout += 1 + if timeout > 100: + break + time.sleep(0.1) if not data.endswith(b'\x04>'): print(data) - raise Exception('could not exec command') + raise Exception('timeout waiting for EOF reception') if data.startswith(b'Traceback') or data.startswith(b' File '): print(data) raise Exception('command failed') return data[:-2] + def execfile(self, filename): + with open(filename) as f: + pyfile = f.read() + return self.exec(pyfile) + def get_time(self): t = str(self.exec('pyb.time()'), encoding='ascii').strip().split()[1].split(':') return int(t[0]) * 3600 + int(t[1]) * 60 + int(t[2]) +def execfile(filename, device='/dev/ttyACM0'): + pyb = Pyboard(device) + pyb.enter_raw_repl() + output = pyb.execfile(filename) + print(str(output, encoding='ascii'), end='') + pyb.exit_raw_repl() + pyb.close() + def run_test(): device = '/dev/ttyACM0' pyb = Pyboard(device) diff --git a/unix-cpy/mpconfigport.h b/unix-cpy/mpconfigport.h index 6351f0c4f..752df4f49 100644 --- a/unix-cpy/mpconfigport.h +++ b/unix-cpy/mpconfigport.h @@ -3,6 +3,7 @@ #define MICROPY_EMIT_CPYTHON (1) #define MICROPY_ENABLE_LEXER_UNIX (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_ENABLE_MOD_IO (0) // type definitions for the specific machine diff --git a/unix/Makefile b/unix/Makefile index b0899ecac..ac1baf3d0 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -28,12 +28,12 @@ LDFLAGS_MOD += -lreadline endif ifeq ($(MICROPY_MOD_TIME),1) CFLAGS_MOD += -DMICROPY_MOD_TIME=1 -SRC_MOD += time.c +SRC_MOD += modtime.c endif ifeq ($(MICROPY_MOD_FFI),1) CFLAGS_MOD += `pkg-config --cflags libffi` -DMICROPY_MOD_FFI=1 LDFLAGS_MOD += -ldl -lffi -SRC_MOD += ffi.c +SRC_MOD += modffi.c endif @@ -50,7 +50,7 @@ SRC_C = \ main.c \ gccollect.c \ file.c \ - socket.c \ + modsocket.c \ $(SRC_MOD) OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) diff --git a/unix/file.c b/unix/file.c index bd54e7482..780e84718 100644 --- a/unix/file.c +++ b/unix/file.c @@ -17,14 +17,14 @@ typedef struct _mp_obj_fdfile_t { int fd; } mp_obj_fdfile_t; -static const mp_obj_type_t rawfile_type; +STATIC const mp_obj_type_t rawfile_type; -static void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_fdfile_t *self = self_in; print(env, "<io.FileIO %d>", self->fd); } -static machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { +STATIC machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { mp_obj_fdfile_t *o = o_in; machine_int_t r = read(o->fd, buf, size); if (r == -1) { @@ -33,7 +33,7 @@ static machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, return r; } -static machine_int_t fdfile_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) { +STATIC machine_int_t fdfile_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) { mp_obj_fdfile_t *o = o_in; machine_int_t r = write(o->fd, buf, size); if (r == -1) { @@ -42,27 +42,32 @@ static machine_int_t fdfile_write(mp_obj_t o_in, const void *buf, machine_uint_t return r; } -static mp_obj_t fdfile_close(mp_obj_t self_in) { +STATIC mp_obj_t fdfile_close(mp_obj_t self_in) { mp_obj_fdfile_t *self = self_in; close(self->fd); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close); -static mp_obj_t fdfile_fileno(mp_obj_t self_in) { +mp_obj_t fdfile___exit__(uint n_args, const mp_obj_t *args) { + return fdfile_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___exit__); + +STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) { mp_obj_fdfile_t *self = self_in; return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->fd); } -static MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); -static mp_obj_fdfile_t *fdfile_new(int fd) { +STATIC mp_obj_fdfile_t *fdfile_new(int fd) { mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t); o->base.type = &rawfile_type; o->fd = fd; return o; } -static mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { +STATIC mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_fdfile_t *o = m_new_obj(mp_obj_fdfile_t); o->base.type = type_in; @@ -100,7 +105,7 @@ static mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const int fd = open(fname, mode, 0644); if (fd == -1) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); } return fdfile_new(fd); } @@ -112,11 +117,13 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&fdfile_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___enter__), (mp_obj_t)&mp_identity_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR___exit__), (mp_obj_t)&fdfile___exit___obj }, }; STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table); -static const mp_obj_type_t rawfile_type = { +STATIC const mp_obj_type_t rawfile_type = { { &mp_type_type }, .name = MP_QSTR_io_dot_FileIO, .print = fdfile_print, diff --git a/unix/gccollect.c b/unix/gccollect.c index 450a69778..33748d240 100644 --- a/unix/gccollect.c +++ b/unix/gccollect.c @@ -78,9 +78,14 @@ void gc_collect(void) { gc_collect_start(); // this traces .data and .bss sections - extern char __bss_start, _end; - //printf(".bss: %p-%p\n", &__bss_start, &_end); - gc_collect_root((void**)&__bss_start, ((machine_uint_t)&_end - (machine_uint_t)&__bss_start) / sizeof(machine_uint_t)); +#ifdef __CYGWIN__ +#define BSS_START __bss_start__ +#else +#define BSS_START __bss_start +#endif + extern char BSS_START, _end; + //printf(".bss: %p-%p\n", &BSS_START, &_end); + gc_collect_root((void**)&BSS_START, ((machine_uint_t)&_end - (machine_uint_t)&BSS_START) / sizeof(machine_uint_t)); regs_t regs; gc_helper_get_regs(regs); // GC stack (and regs because we captured them) diff --git a/unix/main.c b/unix/main.c index 57eaa1997..b4a1646c2 100644 --- a/unix/main.c +++ b/unix/main.c @@ -6,6 +6,7 @@ #include <stdarg.h> #include <sys/stat.h> #include <sys/types.h> +#include <errno.h> #include "nlr.h" #include "misc.h" @@ -29,7 +30,8 @@ #if MICROPY_ENABLE_GC // Heap size of GC heap (if enabled) -long heap_size = 128*1024; +// Make it larger on a 64 bit machine, because pointers are larger. +long heap_size = 128*1024 * (sizeof(machine_uint_t) / 4); #endif // Stack top at the start of program @@ -40,7 +42,7 @@ void microsocket_init(); void time_init(); void ffi_init(); -static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { +STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { if (lex == NULL) { return; } @@ -92,10 +94,10 @@ static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind } } -static char *strjoin(const char *s1, int sep_char, const char *s2) { +STATIC char *strjoin(const char *s1, int sep_char, const char *s2) { int l1 = strlen(s1); int l2 = strlen(s2); - char *s = m_new(char, l1 + l2 + 2); + char *s = malloc(l1 + l2 + 2); memcpy(s, s1, l1); if (sep_char != 0) { s[l1] = sep_char; @@ -106,7 +108,7 @@ static char *strjoin(const char *s1, int sep_char, const char *s2) { return s; } -static char *prompt(char *p) { +STATIC char *prompt(char *p) { #if MICROPY_USE_READLINE char *line = readline(p); if (line) { @@ -131,7 +133,7 @@ static char *prompt(char *p) { return line; } -static void do_repl(void) { +STATIC void do_repl(void) { for (;;) { char *line = prompt(">>> "); if (line == NULL) { @@ -157,12 +159,12 @@ static void do_repl(void) { } } -static void do_file(const char *file) { +STATIC void do_file(const char *file) { mp_lexer_t *lex = mp_lexer_new_from_file(file); execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); } -static void do_str(const char *str) { +STATIC void do_str(const char *str) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, str, strlen(str), false); execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, false); } @@ -172,33 +174,33 @@ typedef struct _test_obj_t { int value; } test_obj_t; -static void test_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void test_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { test_obj_t *self = self_in; print(env, "<test %d>", self->value); } -static mp_obj_t test_get(mp_obj_t self_in) { +STATIC mp_obj_t test_get(mp_obj_t self_in) { test_obj_t *self = self_in; return mp_obj_new_int(self->value); } -static mp_obj_t test_set(mp_obj_t self_in, mp_obj_t arg) { +STATIC mp_obj_t test_set(mp_obj_t self_in, mp_obj_t arg) { test_obj_t *self = self_in; self->value = mp_obj_get_int(arg); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(test_get_obj, test_get); -static MP_DEFINE_CONST_FUN_OBJ_2(test_set_obj, test_set); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(test_get_obj, test_get); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(test_set_obj, test_set); -static const mp_map_elem_t test_locals_dict_table[] = { +STATIC const mp_map_elem_t test_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_get), (mp_obj_t)&test_get_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&test_set_obj }, }; STATIC MP_DEFINE_CONST_DICT(test_locals_dict, test_locals_dict_table); -static const mp_obj_type_t test_type = { +STATIC const mp_obj_type_t test_type = { { &mp_type_type }, .name = MP_QSTR_Test, .print = test_print, @@ -212,13 +214,24 @@ mp_obj_t test_obj_new(int value) { return o; } -int usage(void) { +int usage(char **argv) { printf( -"usage: py [-X <opt>] [-c <command>] [<filename>]\n" +"usage: %s [-X <opt>] [-c <command>] [<filename>]\n" "\n" -"Implementation specific options:\n" +"Implementation specific options:\n", argv[0] +); + int impl_opts_cnt = 0; +#if MICROPY_ENABLE_GC + printf( " heapsize=<n> -- set the heap size for the GC\n" ); + impl_opts_cnt++; +#endif + + if (impl_opts_cnt == 0) { + printf(" (none)\n"); + } + return 1; } @@ -236,7 +249,7 @@ mp_obj_t qstr_info(void) { #if MICROPY_ENABLE_GC // TODO: this doesn't belong here -static mp_obj_t pyb_gc(void) { +STATIC mp_obj_t pyb_gc(void) { gc_collect(); return mp_const_none; } @@ -249,7 +262,7 @@ void pre_process_options(int argc, char **argv) { if (argv[a][0] == '-') { if (strcmp(argv[a], "-X") == 0) { if (a + 1 >= argc) { - exit(usage()); + exit(usage(argv)); } if (0) { #if MICROPY_ENABLE_GC @@ -257,7 +270,7 @@ void pre_process_options(int argc, char **argv) { heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, NULL, 0); #endif } else { - exit(usage()); + exit(usage(argv)); } a++; } @@ -358,7 +371,7 @@ int main(int argc, char **argv) { if (argv[a][0] == '-') { if (strcmp(argv[a], "-c") == 0) { if (a + 1 >= argc) { - return usage(); + return usage(argv); } do_str(argv[a + 1]); executed = true; @@ -366,16 +379,22 @@ int main(int argc, char **argv) { } else if (strcmp(argv[a], "-X") == 0) { a += 1; } else { - return usage(); + return usage(argv); } } else { - // Set base dir of the script as first entry in sys.path char *basedir = realpath(argv[a], NULL); - if (basedir != NULL) { - char *p = strrchr(basedir, '/'); - path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir)); - free(basedir); + if (basedir == NULL) { + fprintf(stderr, "%s: can't open file '%s': [Errno %d] ", argv[0], argv[1], errno); + perror(""); + // CPython exits with 2 in such case + exit(2); } + + // Set base dir of the script as first entry in sys.path + char *p = strrchr(basedir, '/'); + path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir)); + free(basedir); + for (int i = a; i < argc; i++) { mp_obj_list_append(py_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i]))); } diff --git a/unix/ffi.c b/unix/modffi.c index cb63869e0..dd4c7012f 100644 --- a/unix/ffi.c +++ b/unix/modffi.c @@ -80,7 +80,7 @@ STATIC ffi_type *get_ffi_type(mp_obj_t o_in) } // TODO: Support actual libffi type objects - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Unknown type")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Unknown type")); } STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) @@ -118,7 +118,7 @@ STATIC mp_obj_t ffimod_func(uint n_args, const mp_obj_t *args) { void *sym = dlsym(self->handle, symname); if (sym == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); } int nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(args[3])); mp_obj_ffifunc_t *o = m_new_obj_var(mp_obj_ffifunc_t, ffi_type*, nparams); @@ -136,7 +136,7 @@ STATIC mp_obj_t ffimod_func(uint n_args, const mp_obj_t *args) { int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); if (res != FFI_OK) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error in ffi_prep_cif")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error in ffi_prep_cif")); } return o; @@ -173,12 +173,12 @@ STATIC mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); if (res != FFI_OK) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error in ffi_prep_cif")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error in ffi_prep_cif")); } res = ffi_prep_closure_loc(o->clo, &o->cif, call_py_func, func_in, o->func); if (res != FFI_OK) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "ffi_prep_closure_loc")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "ffi_prep_closure_loc")); } return o; @@ -192,7 +192,7 @@ STATIC mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symna void *sym = dlsym(self->handle, symname); if (sym == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); } mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t); o->base.type = &ffivar_type; @@ -208,7 +208,7 @@ STATIC mp_obj_t ffimod_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL); if (mod == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); } mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t); o->base.type = type_in; diff --git a/unix/socket.c b/unix/modsocket.c index 915400e44..6bdbc889d 100644 --- a/unix/socket.c +++ b/unix/modsocket.c @@ -27,14 +27,14 @@ typedef struct _mp_obj_socket_t { int fd; } mp_obj_socket_t; -static const mp_obj_type_t microsocket_type; +STATIC const mp_obj_type_t microsocket_type; // Helper functions #define RAISE_ERRNO(err_flag, error_val) \ { if (err_flag == -1) \ - { nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error_val)); } } + { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error_val)); } } -static void get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) { +STATIC void get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) { mp_obj_base_t *o = (mp_obj_base_t *)obj; if (o->type->buffer_p.get_buffer == NULL) { goto error; @@ -46,10 +46,10 @@ static void get_buffer(mp_obj_t obj, buffer_info_t *bufinfo) { return; error: - nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "Operation not supported")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Operation not supported")); } -static mp_obj_socket_t *socket_new(int fd) { +STATIC mp_obj_socket_t *socket_new(int fd) { mp_obj_socket_t *o = m_new_obj(mp_obj_socket_t); o->base.type = µsocket_type; o->fd = fd; @@ -57,12 +57,12 @@ static mp_obj_socket_t *socket_new(int fd) { } -static void socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { mp_obj_socket_t *self = self_in; print(env, "<_socket %d>", self->fd); } -static machine_int_t socket_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { +STATIC machine_int_t socket_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { mp_obj_socket_t *o = o_in; machine_int_t r = read(o->fd, buf, size); if (r == -1) { @@ -71,7 +71,7 @@ static machine_int_t socket_read(mp_obj_t o_in, void *buf, machine_uint_t size, return r; } -static machine_int_t socket_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) { +STATIC machine_int_t socket_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) { mp_obj_socket_t *o = o_in; machine_int_t r = write(o->fd, buf, size); if (r == -1) { @@ -80,20 +80,20 @@ static machine_int_t socket_write(mp_obj_t o_in, const void *buf, machine_uint_t return r; } -static mp_obj_t socket_close(mp_obj_t self_in) { +STATIC mp_obj_t socket_close(mp_obj_t self_in) { mp_obj_socket_t *self = self_in; close(self->fd); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); -static mp_obj_t socket_fileno(mp_obj_t self_in) { +STATIC mp_obj_t socket_fileno(mp_obj_t self_in) { mp_obj_socket_t *self = self_in; return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->fd); } -static MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno); -static mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = self_in; buffer_info_t bufinfo; get_buffer(addr_in, &bufinfo); @@ -101,9 +101,9 @@ static mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { RAISE_ERRNO(r, errno); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); -static mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { mp_obj_socket_t *self = self_in; buffer_info_t bufinfo; get_buffer(addr_in, &bufinfo); @@ -111,17 +111,17 @@ static mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { RAISE_ERRNO(r, errno); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); -static mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_obj_socket_t *self = self_in; int r = listen(self->fd, MP_OBJ_SMALL_INT_VALUE(backlog_in)); RAISE_ERRNO(r, errno); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); -static mp_obj_t socket_accept(mp_obj_t self_in) { +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { mp_obj_socket_t *self = self_in; struct sockaddr addr; socklen_t addr_len = sizeof(addr); @@ -134,9 +134,9 @@ static mp_obj_t socket_accept(mp_obj_t self_in) { return t; } -static MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); -static mp_obj_t socket_recv(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t socket_recv(uint n_args, const mp_obj_t *args) { mp_obj_socket_t *self = args[0]; int sz = MP_OBJ_SMALL_INT_VALUE(args[1]); int flags = 0; @@ -152,9 +152,9 @@ static mp_obj_t socket_recv(uint n_args, const mp_obj_t *args) { buf = m_realloc(buf, sz, out_sz); return MP_OBJ_NEW_QSTR(qstr_from_strn_take(buf, out_sz, out_sz)); } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_obj, 2, 3, socket_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_obj, 2, 3, socket_recv); -static mp_obj_t socket_send(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t socket_send(uint n_args, const mp_obj_t *args) { mp_obj_socket_t *self = args[0]; int flags = 0; @@ -169,9 +169,9 @@ static mp_obj_t socket_send(uint n_args, const mp_obj_t *args) { return MP_OBJ_NEW_SMALL_INT((machine_int_t)out_sz); } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_send_obj, 2, 3, socket_send); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_send_obj, 2, 3, socket_send); -static mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { mp_obj_socket_t *self = args[0]; int level = MP_OBJ_SMALL_INT_VALUE(args[1]); int option = mp_obj_get_int(args[2]); @@ -192,9 +192,9 @@ static mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { RAISE_ERRNO(r, errno); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); -static mp_obj_t socket_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { +STATIC mp_obj_t socket_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { int family = AF_INET; int type = SOCK_STREAM; int proto = 0; @@ -217,7 +217,7 @@ static mp_obj_t socket_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const return socket_new(fd); } -static const mp_map_elem_t microsocket_locals_dict_table[] = { +STATIC const mp_map_elem_t microsocket_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&socket_fileno_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&mp_identity_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, @@ -240,7 +240,7 @@ static const mp_map_elem_t microsocket_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(microsocket_locals_dict, microsocket_locals_dict_table); -static const mp_obj_type_t microsocket_type = { +STATIC const mp_obj_type_t microsocket_type = { { &mp_type_type }, .name = MP_QSTR_socket, .print = socket_print, @@ -254,38 +254,38 @@ static const mp_obj_type_t microsocket_type = { .locals_dict = (mp_obj_t)µsocket_locals_dict, }; -static mp_obj_t mod_socket_htons(mp_obj_t arg) { +STATIC mp_obj_t mod_socket_htons(mp_obj_t arg) { return MP_OBJ_NEW_SMALL_INT((machine_int_t)htons(MP_OBJ_SMALL_INT_VALUE(arg))); } -static MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_htons_obj, mod_socket_htons); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_htons_obj, mod_socket_htons); -static mp_obj_t mod_socket_inet_aton(mp_obj_t arg) { +STATIC mp_obj_t mod_socket_inet_aton(mp_obj_t arg) { assert(MP_OBJ_IS_TYPE(arg, &mp_type_str)); const char *s = mp_obj_str_get_str(arg); struct in_addr addr; if (!inet_aton(s, &addr)) { - nlr_jump(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid IP address")); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Invalid IP address")); } return mp_obj_new_int(addr.s_addr); } -static MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_inet_aton_obj, mod_socket_inet_aton); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_inet_aton_obj, mod_socket_inet_aton); #if MICROPY_SOCKET_EXTRA -static mp_obj_t mod_socket_gethostbyname(mp_obj_t arg) { +STATIC mp_obj_t mod_socket_gethostbyname(mp_obj_t arg) { assert(MP_OBJ_IS_TYPE(arg, &mp_type_str)); const char *s = mp_obj_str_get_str(arg); struct hostent *h = gethostbyname(s); if (h == NULL) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", errno)); } assert(h->h_length == 4); return mp_obj_new_int(*(int*)*h->h_addr_list); } -static MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_gethostbyname_obj, mod_socket_gethostbyname); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_gethostbyname_obj, mod_socket_gethostbyname); #endif -static mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { // TODO: Implement all args assert(n_args == 2); assert(MP_OBJ_IS_STR(args[0])); @@ -309,7 +309,7 @@ static mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { int res = getaddrinfo(host, serv, NULL/*&hints*/, &addr); if (res != 0) { - nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); } assert(addr); @@ -331,13 +331,13 @@ static mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { } return list; } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod_socket_getaddrinfo); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod_socket_getaddrinfo); extern mp_obj_type_t sockaddr_in_type; #define C(name) { #name, name } -static const struct sym_entry { +STATIC const struct sym_entry { const char *sym; int val; } constants[] = { diff --git a/unix/time.c b/unix/modtime.c index fb5213358..032528947 100644 --- a/unix/time.c +++ b/unix/modtime.c @@ -10,13 +10,13 @@ #include "obj.h" #include "runtime.h" -static mp_obj_t mod_time_time() { +STATIC mp_obj_t mod_time_time() { return mp_obj_new_int((machine_int_t)time(NULL)); } -static MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); // Note: this is deprecated since CPy3.3, but pystone still uses it. -static mp_obj_t mod_time_clock() { +STATIC mp_obj_t mod_time_clock() { // return mp_obj_new_int((machine_int_t)clock()); // POSIX requires CLOCKS_PER_SEC equals 1000000, so that's what we assume // float cannot represent full range of int32 precisely, so we pre-divide @@ -24,9 +24,9 @@ static mp_obj_t mod_time_clock() { // to preserve integer part resolution. return mp_obj_new_float((float)(clock() / 1000) / 1000.0); } -static MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_clock_obj, mod_time_clock); -static mp_obj_t mod_time_sleep(mp_obj_t arg) { +STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { #if MICROPY_ENABLE_FLOAT struct timeval tv; mp_float_t val = mp_obj_get_float(arg); @@ -39,7 +39,7 @@ static mp_obj_t mod_time_sleep(mp_obj_t arg) { #endif return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); void time_init() { mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("time")); diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 8950337d4..254d14d98 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -3,6 +3,7 @@ #define MICROPY_EMIT_X64 (1) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_ENABLE_GC (1) #define MICROPY_MEM_STATS (1) #define MICROPY_DEBUG_PRINTERS (1) #define MICROPY_ENABLE_REPL_HELPERS (1) |
